Skip to content

Commit fa9862b

Browse files
Nadrierilfee1-dead
authored andcommitted
Add barest-bones deref patterns
Co-authored-by: Deadbeef <ent3rm4n@gmail.com>
1 parent 6ec953c commit fa9862b

File tree

16 files changed

+138
-17
lines changed

16 files changed

+138
-17
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
413413
}
414414
}
415415
PatKind::Box(..) => {
416-
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
416+
if !self.features.deref_patterns {
417+
// Allow box patterns under `deref_patterns`.
418+
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
419+
}
417420
}
418421
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
419422
gate!(
@@ -607,13 +610,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
607610
};
608611
}
609612

613+
if !visitor.features.deref_patterns {
614+
// Allow box patterns under `deref_patterns`.
615+
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
616+
}
610617
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
611618
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
612619
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
613620
// be too.
614621
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
615622
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
616-
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
617623
gate_all_legacy_dont_use!(
618624
exclusive_range_pattern,
619625
"exclusive range pattern syntax is experimental"

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,8 @@ declare_features! (
436436
(unstable, deprecated_safe, "1.61.0", Some(94978)),
437437
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
438438
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
439+
/// Allows deref patterns.
440+
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)),
439441
/// Controls errors in trait implementations.
440442
(unstable, do_not_recommend, "1.67.0", Some(51992)),
441443
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.

compiler/rustc_hir_typeck/src/pat.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
1818
use rustc_span::hygiene::DesugaringKind;
1919
use rustc_span::source_map::Spanned;
2020
use rustc_span::symbol::{kw, sym, Ident};
21-
use rustc_span::Span;
22-
use rustc_span::{BytePos, DUMMY_SP};
21+
use rustc_span::{BytePos, Span, DUMMY_SP};
2322
use rustc_target::abi::FieldIdx;
2423
use rustc_trait_selection::traits::{ObligationCause, Pattern};
2524
use ty::VariantDef;
@@ -211,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
211210
PatKind::Tuple(elements, ddpos) => {
212211
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
213212
}
213+
PatKind::Box(inner) if self.tcx.features().deref_patterns => {
214+
self.check_pat_deref(pat.span, inner, expected, pat_info)
215+
}
214216
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
215217
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
216218
PatKind::Slice(before, slice, after) => {
@@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19751977
box_ty
19761978
}
19771979

1980+
fn check_pat_deref(
1981+
&self,
1982+
span: Span,
1983+
inner: &'tcx Pat<'tcx>,
1984+
expected: Ty<'tcx>,
1985+
pat_info: PatInfo<'tcx, '_>,
1986+
) -> Ty<'tcx> {
1987+
let tcx = self.tcx;
1988+
// FIXME(deref_patterns): use `DerefPure` for soundness
1989+
// FIXME(deref_patterns): use `DerefMut` when required
1990+
// <expected as Deref>::Target
1991+
let ty = Ty::new_projection(
1992+
tcx,
1993+
tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
1994+
[expected],
1995+
);
1996+
let ty = self.normalize(span, ty);
1997+
let ty = self.try_structurally_resolve_type(span, ty);
1998+
self.check_pat(inner, ty, pat_info);
1999+
expected
2000+
}
2001+
19782002
// Precondition: Pat is Ref(inner)
19792003
fn check_pat_ref(
19802004
&self,

compiler/rustc_middle/src/thir.rs

+9
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> {
647647
AscribeUserType { subpattern, .. }
648648
| Binding { subpattern: Some(subpattern), .. }
649649
| Deref { subpattern }
650+
| DerefPattern { subpattern }
650651
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
651652
Leaf { subpatterns } | Variant { subpatterns, .. } => {
652653
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
@@ -762,6 +763,11 @@ pub enum PatKind<'tcx> {
762763
subpattern: Box<Pat<'tcx>>,
763764
},
764765

766+
/// Deref pattern, written `box P` for now.
767+
DerefPattern {
768+
subpattern: Box<Pat<'tcx>>,
769+
},
770+
765771
/// One of the following:
766772
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
767773
/// exhaustiveness checking will detect if you use the same string twice in different
@@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
11721178
}
11731179
write!(f, "{subpattern}")
11741180
}
1181+
PatKind::DerefPattern { ref subpattern } => {
1182+
write!(f, "k#deref {subpattern}")
1183+
}
11751184
PatKind::Constant { value } => write!(f, "{value}"),
11761185
PatKind::InlineConstant { def: _, ref subpattern } => {
11771186
write!(f, "{} (from inline const)", subpattern)

compiler/rustc_middle/src/thir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
229229
match &pat.kind {
230230
AscribeUserType { subpattern, ascription: _ }
231231
| Deref { subpattern }
232+
| DerefPattern { subpattern }
232233
| Binding {
233234
subpattern: Some(subpattern),
234235
mutability: _,

compiler/rustc_mir_build/src/build/matches/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
879879
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
880880
}
881881

882+
PatKind::DerefPattern { ref subpattern } => {
883+
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
884+
}
885+
882886
PatKind::AscribeUserType {
883887
ref subpattern,
884888
ascription: thir::Ascription { ref annotation, variance: _ },

compiler/rustc_mir_build/src/build/matches/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
256256
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
257257
default_irrefutable()
258258
}
259+
260+
PatKind::DerefPattern { .. } => {
261+
// FIXME(deref_patterns)
262+
// Treat it like a wildcard for now.
263+
default_irrefutable()
264+
}
259265
};
260266

261267
MatchPair { place, test_case, subpairs, pattern }

compiler/rustc_mir_build/src/check_unsafety.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
250250
| PatKind::Variant { .. }
251251
| PatKind::Leaf { .. }
252252
| PatKind::Deref { .. }
253+
| PatKind::DerefPattern { .. }
253254
| PatKind::Range { .. }
254255
| PatKind::Slice { .. }
255256
| PatKind::Array { .. } => {
@@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
310311
}
311312
visit::walk_pat(self, pat);
312313
}
313-
PatKind::Deref { .. } => {
314+
PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
314315
let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
315316
visit::walk_pat(self, pat);
316317
self.inside_adt = old_inside_adt;

compiler/rustc_mir_build/src/thir/pattern/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
257257
return self.lower_path(qpath, pat.hir_id, pat.span);
258258
}
259259

260+
hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => {
261+
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
262+
}
260263
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
261264
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
262265
}

compiler/rustc_mir_build/src/thir/print.rs

+6
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
688688
self.print_pat(subpattern, depth_lvl + 2);
689689
print_indented!(self, "}", depth_lvl + 1);
690690
}
691+
PatKind::DerefPattern { subpattern } => {
692+
print_indented!(self, "DerefPattern { ", depth_lvl + 1);
693+
print_indented!(self, "subpattern:", depth_lvl + 2);
694+
self.print_pat(subpattern, depth_lvl + 2);
695+
print_indented!(self, "}", depth_lvl + 1);
696+
}
691697
PatKind::Constant { value } => {
692698
print_indented!(self, "Constant {", depth_lvl + 1);
693699
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);

compiler/rustc_pattern_analysis/src/rustc.rs

+5
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
462462
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
463463
};
464464
}
465+
PatKind::DerefPattern { .. } => {
466+
// FIXME(deref_patterns): At least detect that `box _` is irrefutable.
467+
fields = vec![];
468+
ctor = Opaque(OpaqueId::new());
469+
}
465470
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
466471
match ty.kind() {
467472
ty::Tuple(fs) => {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ symbols! {
674674
deref_method,
675675
deref_mut,
676676
deref_mut_method,
677+
deref_patterns,
677678
deref_target,
678679
derive,
679680
derive_const,

tests/ui/cfg/cfg-false-feature.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
warning: trait aliases are experimental
2-
--> $DIR/cfg-false-feature.rs:12:1
3-
|
4-
LL | trait A = Clone;
5-
| ^^^^^^^^^^^^^^^^
6-
|
7-
= note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
8-
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
9-
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10-
= warning: unstable syntax can change at any point in the future, causing a hard error!
11-
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
12-
131
warning: box pattern syntax is experimental
142
--> $DIR/cfg-false-feature.rs:16:9
153
|
@@ -22,5 +10,17 @@ LL | let box _ = Box::new(0);
2210
= warning: unstable syntax can change at any point in the future, causing a hard error!
2311
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
2412

13+
warning: trait aliases are experimental
14+
--> $DIR/cfg-false-feature.rs:12:1
15+
|
16+
LL | trait A = Clone;
17+
| ^^^^^^^^^^^^^^^^
18+
|
19+
= note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
20+
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
21+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
22+
= warning: unstable syntax can change at any point in the future, causing a hard error!
23+
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
24+
2525
warning: 2 warnings emitted
2626

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
// We reuse the `box` syntax so this doesn't actually test the feature gate but eh.
3+
let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental
4+
println!("x: {}", x);
5+
6+
// `box` syntax is allowed to be cfg-ed out for historical reasons (#65742).
7+
#[cfg(FALSE)]
8+
let box _x = Box::new('c');
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: box pattern syntax is experimental
2+
--> $DIR/feature-gate-deref_patterns.rs:3:9
3+
|
4+
LL | let box x = Box::new('c');
5+
| ^^^^^
6+
|
7+
= note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
8+
= help: add `#![feature(box_patterns)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0658`.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//@ check-pass
2+
#![feature(deref_patterns)]
3+
#![allow(incomplete_features)]
4+
5+
use std::rc::Rc;
6+
7+
fn main() {
8+
let vec: Vec<u32> = Vec::new();
9+
match vec {
10+
box [..] => {}
11+
_ => {}
12+
}
13+
match Box::new(true) {
14+
box true => {}
15+
_ => {}
16+
}
17+
match &Box::new(true) {
18+
box true => {}
19+
_ => {}
20+
}
21+
match &Rc::new(0) {
22+
box (1..) => {}
23+
_ => {}
24+
}
25+
// FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a
26+
// place of type `str`.
27+
// match "foo".to_string() {
28+
// box "foo" => {}
29+
// _ => {}
30+
// }
31+
}

0 commit comments

Comments
 (0)