Add barest-bones deref patterns
Co-authored-by: Deadbeef <ent3rm4n@gmail.com>
This commit is contained in:
parent
a128516cf9
commit
120d3570aa
@ -413,7 +413,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Box(..) => {
|
PatKind::Box(..) => {
|
||||||
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
|
if !self.features.deref_patterns {
|
||||||
|
// Allow box patterns under `deref_patterns`.
|
||||||
|
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
|
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
|
||||||
gate!(
|
gate!(
|
||||||
@ -607,13 +610,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !visitor.features.deref_patterns {
|
||||||
|
// Allow box patterns under `deref_patterns`.
|
||||||
|
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
|
||||||
|
}
|
||||||
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
|
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
|
||||||
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
|
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
|
||||||
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
|
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
|
||||||
// be too.
|
// be too.
|
||||||
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
|
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
|
||||||
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
|
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
|
||||||
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
|
|
||||||
gate_all_legacy_dont_use!(
|
gate_all_legacy_dont_use!(
|
||||||
exclusive_range_pattern,
|
exclusive_range_pattern,
|
||||||
"exclusive range pattern syntax is experimental"
|
"exclusive range pattern syntax is experimental"
|
||||||
|
@ -436,6 +436,8 @@ declare_features! (
|
|||||||
(unstable, deprecated_safe, "1.61.0", Some(94978)),
|
(unstable, deprecated_safe, "1.61.0", Some(94978)),
|
||||||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||||
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
|
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
|
||||||
|
/// Allows deref patterns.
|
||||||
|
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)),
|
||||||
/// Controls errors in trait implementations.
|
/// Controls errors in trait implementations.
|
||||||
(unstable, do_not_recommend, "1.67.0", Some(51992)),
|
(unstable, do_not_recommend, "1.67.0", Some(51992)),
|
||||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||||
|
@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
|
|||||||
use rustc_span::hygiene::DesugaringKind;
|
use rustc_span::hygiene::DesugaringKind;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||||
use rustc_span::{BytePos, DUMMY_SP};
|
|
||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::FieldIdx;
|
||||||
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
||||||
use ty::VariantDef;
|
use ty::VariantDef;
|
||||||
@ -211,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
PatKind::Tuple(elements, ddpos) => {
|
PatKind::Tuple(elements, ddpos) => {
|
||||||
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
|
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
|
||||||
}
|
}
|
||||||
|
PatKind::Box(inner) if self.tcx.features().deref_patterns => {
|
||||||
|
self.check_pat_deref(pat.span, inner, expected, pat_info)
|
||||||
|
}
|
||||||
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
|
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
|
||||||
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||||
PatKind::Slice(before, slice, after) => {
|
PatKind::Slice(before, slice, after) => {
|
||||||
@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
box_ty
|
box_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_pat_deref(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
inner: &'tcx Pat<'tcx>,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
// FIXME(deref_patterns): use `DerefPure` for soundness
|
||||||
|
// FIXME(deref_patterns): use `DerefMut` when required
|
||||||
|
// <expected as Deref>::Target
|
||||||
|
let ty = Ty::new_projection(
|
||||||
|
tcx,
|
||||||
|
tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
|
||||||
|
[expected],
|
||||||
|
);
|
||||||
|
let ty = self.normalize(span, ty);
|
||||||
|
let ty = self.try_structurally_resolve_type(span, ty);
|
||||||
|
self.check_pat(inner, ty, pat_info);
|
||||||
|
expected
|
||||||
|
}
|
||||||
|
|
||||||
// Precondition: Pat is Ref(inner)
|
// Precondition: Pat is Ref(inner)
|
||||||
fn check_pat_ref(
|
fn check_pat_ref(
|
||||||
&self,
|
&self,
|
||||||
|
@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> {
|
|||||||
AscribeUserType { subpattern, .. }
|
AscribeUserType { subpattern, .. }
|
||||||
| Binding { subpattern: Some(subpattern), .. }
|
| Binding { subpattern: Some(subpattern), .. }
|
||||||
| Deref { subpattern }
|
| Deref { subpattern }
|
||||||
|
| DerefPattern { subpattern }
|
||||||
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
||||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||||
@ -762,6 +763,11 @@ pub enum PatKind<'tcx> {
|
|||||||
subpattern: Box<Pat<'tcx>>,
|
subpattern: Box<Pat<'tcx>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Deref pattern, written `box P` for now.
|
||||||
|
DerefPattern {
|
||||||
|
subpattern: Box<Pat<'tcx>>,
|
||||||
|
},
|
||||||
|
|
||||||
/// One of the following:
|
/// One of the following:
|
||||||
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
|
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
|
||||||
/// exhaustiveness checking will detect if you use the same string twice in different
|
/// exhaustiveness checking will detect if you use the same string twice in different
|
||||||
@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||||||
}
|
}
|
||||||
write!(f, "{subpattern}")
|
write!(f, "{subpattern}")
|
||||||
}
|
}
|
||||||
|
PatKind::DerefPattern { ref subpattern } => {
|
||||||
|
write!(f, "k#deref {subpattern}")
|
||||||
|
}
|
||||||
PatKind::Constant { value } => write!(f, "{value}"),
|
PatKind::Constant { value } => write!(f, "{value}"),
|
||||||
PatKind::InlineConstant { def: _, ref subpattern } => {
|
PatKind::InlineConstant { def: _, ref subpattern } => {
|
||||||
write!(f, "{} (from inline const)", subpattern)
|
write!(f, "{} (from inline const)", subpattern)
|
||||||
|
@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
AscribeUserType { subpattern, ascription: _ }
|
AscribeUserType { subpattern, ascription: _ }
|
||||||
| Deref { subpattern }
|
| Deref { subpattern }
|
||||||
|
| DerefPattern { subpattern }
|
||||||
| Binding {
|
| Binding {
|
||||||
subpattern: Some(subpattern),
|
subpattern: Some(subpattern),
|
||||||
mutability: _,
|
mutability: _,
|
||||||
|
@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::DerefPattern { ref subpattern } => {
|
||||||
|
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::AscribeUserType {
|
PatKind::AscribeUserType {
|
||||||
ref subpattern,
|
ref subpattern,
|
||||||
ascription: thir::Ascription { ref annotation, variance: _ },
|
ascription: thir::Ascription { ref annotation, variance: _ },
|
||||||
|
@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
|||||||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::DerefPattern { .. } => {
|
||||||
|
// FIXME(deref_patterns)
|
||||||
|
// Treat it like a wildcard for now.
|
||||||
|
default_irrefutable()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MatchPair { place, test_case, subpairs, pattern }
|
MatchPair { place, test_case, subpairs, pattern }
|
||||||
|
@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||||||
| PatKind::Variant { .. }
|
| PatKind::Variant { .. }
|
||||||
| PatKind::Leaf { .. }
|
| PatKind::Leaf { .. }
|
||||||
| PatKind::Deref { .. }
|
| PatKind::Deref { .. }
|
||||||
|
| PatKind::DerefPattern { .. }
|
||||||
| PatKind::Range { .. }
|
| PatKind::Range { .. }
|
||||||
| PatKind::Slice { .. }
|
| PatKind::Slice { .. }
|
||||||
| PatKind::Array { .. } => {
|
| PatKind::Array { .. } => {
|
||||||
@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
visit::walk_pat(self, pat);
|
visit::walk_pat(self, pat);
|
||||||
}
|
}
|
||||||
PatKind::Deref { .. } => {
|
PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
|
||||||
let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
|
let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
|
||||||
visit::walk_pat(self, pat);
|
visit::walk_pat(self, pat);
|
||||||
self.inside_adt = old_inside_adt;
|
self.inside_adt = old_inside_adt;
|
||||||
|
@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
return self.lower_path(qpath, pat.hir_id, pat.span);
|
return self.lower_path(qpath, pat.hir_id, pat.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => {
|
||||||
|
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
|
||||||
|
}
|
||||||
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
|
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
|
||||||
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||||
}
|
}
|
||||||
|
@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||||||
self.print_pat(subpattern, depth_lvl + 2);
|
self.print_pat(subpattern, depth_lvl + 2);
|
||||||
print_indented!(self, "}", depth_lvl + 1);
|
print_indented!(self, "}", depth_lvl + 1);
|
||||||
}
|
}
|
||||||
|
PatKind::DerefPattern { subpattern } => {
|
||||||
|
print_indented!(self, "DerefPattern { ", depth_lvl + 1);
|
||||||
|
print_indented!(self, "subpattern:", depth_lvl + 2);
|
||||||
|
self.print_pat(subpattern, depth_lvl + 2);
|
||||||
|
print_indented!(self, "}", depth_lvl + 1);
|
||||||
|
}
|
||||||
PatKind::Constant { value } => {
|
PatKind::Constant { value } => {
|
||||||
print_indented!(self, "Constant {", depth_lvl + 1);
|
print_indented!(self, "Constant {", depth_lvl + 1);
|
||||||
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||||
|
@ -462,6 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||||||
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
|
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
PatKind::DerefPattern { .. } => {
|
||||||
|
// FIXME(deref_patterns): At least detect that `box _` is irrefutable.
|
||||||
|
fields = vec![];
|
||||||
|
arity = 0;
|
||||||
|
ctor = Opaque(OpaqueId::new());
|
||||||
|
}
|
||||||
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
|
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Tuple(fs) => {
|
ty::Tuple(fs) => {
|
||||||
|
@ -674,6 +674,7 @@ symbols! {
|
|||||||
deref_method,
|
deref_method,
|
||||||
deref_mut,
|
deref_mut,
|
||||||
deref_mut_method,
|
deref_mut_method,
|
||||||
|
deref_patterns,
|
||||||
deref_target,
|
deref_target,
|
||||||
derive,
|
derive,
|
||||||
derive_const,
|
derive_const,
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
warning: trait aliases are experimental
|
|
||||||
--> $DIR/cfg-false-feature.rs:12:1
|
|
||||||
|
|
|
||||||
LL | trait A = Clone;
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
|
|
||||||
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
|
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
|
||||||
= warning: unstable syntax can change at any point in the future, causing a hard error!
|
|
||||||
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
|
|
||||||
|
|
||||||
warning: box pattern syntax is experimental
|
warning: box pattern syntax is experimental
|
||||||
--> $DIR/cfg-false-feature.rs:16:9
|
--> $DIR/cfg-false-feature.rs:16:9
|
||||||
|
|
|
|
||||||
@ -22,5 +10,17 @@ LL | let box _ = Box::new(0);
|
|||||||
= warning: unstable syntax can change at any point in the future, causing a hard error!
|
= warning: unstable syntax can change at any point in the future, causing a hard error!
|
||||||
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
|
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
|
||||||
|
|
||||||
|
warning: trait aliases are experimental
|
||||||
|
--> $DIR/cfg-false-feature.rs:12:1
|
||||||
|
|
|
||||||
|
LL | trait A = Clone;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
|
||||||
|
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= warning: unstable syntax can change at any point in the future, causing a hard error!
|
||||||
|
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
|
||||||
|
|
||||||
warning: 2 warnings emitted
|
warning: 2 warnings emitted
|
||||||
|
|
||||||
|
9
tests/ui/feature-gates/feature-gate-deref_patterns.rs
Normal file
9
tests/ui/feature-gates/feature-gate-deref_patterns.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fn main() {
|
||||||
|
// We reuse the `box` syntax so this doesn't actually test the feature gate but eh.
|
||||||
|
let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental
|
||||||
|
println!("x: {}", x);
|
||||||
|
|
||||||
|
// `box` syntax is allowed to be cfg-ed out for historical reasons (#65742).
|
||||||
|
#[cfg(FALSE)]
|
||||||
|
let box _x = Box::new('c');
|
||||||
|
}
|
13
tests/ui/feature-gates/feature-gate-deref_patterns.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-deref_patterns.stderr
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
error[E0658]: box pattern syntax is experimental
|
||||||
|
--> $DIR/feature-gate-deref_patterns.rs:3:9
|
||||||
|
|
|
||||||
|
LL | let box x = Box::new('c');
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
|
||||||
|
= help: add `#![feature(box_patterns)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
31
tests/ui/pattern/deref-patterns/typeck.rs
Normal file
31
tests/ui/pattern/deref-patterns/typeck.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//@ check-pass
|
||||||
|
#![feature(deref_patterns)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let vec: Vec<u32> = Vec::new();
|
||||||
|
match vec {
|
||||||
|
box [..] => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match Box::new(true) {
|
||||||
|
box true => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match &Box::new(true) {
|
||||||
|
box true => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match &Rc::new(0) {
|
||||||
|
box (1..) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
// FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a
|
||||||
|
// place of type `str`.
|
||||||
|
// match "foo".to_string() {
|
||||||
|
// box "foo" => {}
|
||||||
|
// _ => {}
|
||||||
|
// }
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user