Skip to content

Commit 2e1f7ab

Browse files
Nadrierilfee1-dead
andcommitted
Add barest-bones deref patterns
Co-authored-by: Deadbeef <[email protected]>
1 parent 4282576 commit 2e1f7ab

File tree

16 files changed

+156
-18
lines changed

16 files changed

+156
-18
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
402402
}
403403
}
404404
PatKind::Box(..) => {
405-
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
405+
if !self.features.deref_patterns {
406+
// Allow box patterns under `deref_patterns`.
407+
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
408+
}
406409
}
407410
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
408411
gate!(
@@ -603,14 +606,17 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
603606
};
604607
}
605608

609+
if !visitor.features.deref_patterns {
610+
// Allow box patterns under `deref_patterns`.
611+
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
612+
}
606613
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
607614
gate_all_legacy_dont_use!(associated_type_bounds, "associated type bounds are unstable");
608615
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
609616
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
610617
// be too.
611618
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
612619
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
613-
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
614620
gate_all_legacy_dont_use!(
615621
exclusive_range_pattern,
616622
"exclusive range pattern syntax is experimental"

compiler/rustc_feature/src/unstable.rs

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

compiler/rustc_hir_typeck/src/pat.rs

+44-3
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ 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;
24-
use rustc_trait_selection::traits::{ObligationCause, Pattern};
23+
use rustc_trait_selection::traits::{
24+
error_reporting::TypeErrCtxtExt, ObligationCause, Pattern, StructurallyNormalizeExt,
25+
TraitEngine, TraitEngineExt,
26+
};
2527
use ty::VariantDef;
2628

2729
use std::cmp;
@@ -202,6 +204,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
202204
PatKind::Tuple(elements, ddpos) => {
203205
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
204206
}
207+
PatKind::Box(inner) if self.tcx.features().deref_patterns => {
208+
self.check_pat_deref(pat.span, inner, expected, pat_info)
209+
}
205210
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
206211
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
207212
PatKind::Slice(before, slice, after) => {
@@ -1966,6 +1971,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19661971
box_ty
19671972
}
19681973

1974+
fn check_pat_deref(
1975+
&self,
1976+
span: Span,
1977+
inner: &'tcx Pat<'tcx>,
1978+
expected: Ty<'tcx>,
1979+
pat_info: PatInfo<'tcx, '_>,
1980+
) -> Ty<'tcx> {
1981+
let tcx = self.tcx;
1982+
// FIXME(deref_patterns): use `DerefPure` for soundness
1983+
// FIXME(deref_patterns): use `DerefMut` when required
1984+
// <expected as Deref>::Target
1985+
let ty = Ty::new_projection(
1986+
tcx,
1987+
tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
1988+
[expected],
1989+
);
1990+
1991+
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(&self.infcx);
1992+
let cause = self.pattern_cause(pat_info.top_info, span);
1993+
let normalized_ty = match self
1994+
.infcx
1995+
.at(&cause, self.param_env)
1996+
.structurally_normalize(ty, &mut *fulfill_cx)
1997+
{
1998+
Ok(normalized_ty) => normalized_ty,
1999+
Err(errors) => {
2000+
let reported = self.infcx.err_ctxt().report_fulfillment_errors(errors);
2001+
return Ty::new_error(tcx, reported);
2002+
}
2003+
};
2004+
2005+
let ty = self.resolve_vars_if_possible(normalized_ty);
2006+
self.check_pat(inner, ty, pat_info);
2007+
expected
2008+
}
2009+
19692010
// Precondition: Pat is Ref(inner)
19702011
fn check_pat_ref(
19712012
&self,

compiler/rustc_middle/src/thir.rs

+9
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ impl<'tcx> Pat<'tcx> {
636636
AscribeUserType { subpattern, .. }
637637
| Binding { subpattern: Some(subpattern), .. }
638638
| Deref { subpattern }
639+
| DerefPattern { subpattern }
639640
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
640641
Leaf { subpatterns } | Variant { subpatterns, .. } => {
641642
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
@@ -751,6 +752,11 @@ pub enum PatKind<'tcx> {
751752
subpattern: Box<Pat<'tcx>>,
752753
},
753754

755+
/// Deref pattern, written `box P` for now.
756+
DerefPattern {
757+
subpattern: Box<Pat<'tcx>>,
758+
},
759+
754760
/// One of the following:
755761
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
756762
/// exhaustiveness checking will detect if you use the same string twice in different
@@ -1161,6 +1167,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
11611167
}
11621168
write!(f, "{subpattern}")
11631169
}
1170+
PatKind::DerefPattern { ref subpattern } => {
1171+
write!(f, "box {subpattern}")
1172+
}
11641173
PatKind::Constant { value } => write!(f, "{value}"),
11651174
PatKind::InlineConstant { def: _, ref subpattern } => {
11661175
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
@@ -870,6 +870,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
870870
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
871871
}
872872

873+
PatKind::DerefPattern { ref subpattern } => {
874+
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
875+
}
876+
873877
PatKind::AscribeUserType {
874878
ref subpattern,
875879
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
@@ -463,6 +463,11 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
463463
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
464464
};
465465
}
466+
PatKind::DerefPattern { .. } => {
467+
// FIXME(deref_patterns): At least detect that `box _` is irrefutable.
468+
fields = vec![];
469+
ctor = Opaque(OpaqueId::new());
470+
}
466471
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
467472
match ty.kind() {
468473
ty::Tuple(fs) => {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,7 @@ symbols! {
673673
deref_method,
674674
deref_mut,
675675
deref_mut_method,
676+
deref_patterns,
676677
deref_target,
677678
derive,
678679
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)