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 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) {
|
||||
}
|
||||
}
|
||||
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, .. }) => {
|
||||
gate!(
|
||||
@ -607,13 +610,16 @@ macro_rules! gate_all_legacy_dont_use {
|
||||
};
|
||||
}
|
||||
|
||||
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");
|
||||
// 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
|
||||
// be too.
|
||||
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!(box_patterns, "box pattern syntax is experimental");
|
||||
gate_all_legacy_dont_use!(
|
||||
exclusive_range_pattern,
|
||||
"exclusive range pattern syntax is experimental"
|
||||
|
@ -436,6 +436,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, deprecated_safe, "1.61.0", Some(94978)),
|
||||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
|
||||
/// Allows deref patterns.
|
||||
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)),
|
||||
/// Controls errors in trait implementations.
|
||||
(unstable, do_not_recommend, "1.67.0", Some(51992)),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
|
@ -18,8 +18,7 @@
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{BytePos, DUMMY_SP};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
||||
use ty::VariantDef;
|
||||
@ -211,6 +210,9 @@ fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<
|
||||
PatKind::Tuple(elements, ddpos) => {
|
||||
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::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
@ -1975,6 +1977,28 @@ fn check_pat_box(
|
||||
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)
|
||||
fn check_pat_ref(
|
||||
&self,
|
||||
|
@ -647,6 +647,7 @@ fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
|
||||
AscribeUserType { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||
@ -762,6 +763,11 @@ pub enum PatKind<'tcx> {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
/// Deref pattern, written `box P` for now.
|
||||
DerefPattern {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
/// One of the following:
|
||||
/// * `&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
|
||||
@ -1172,6 +1178,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
}
|
||||
write!(f, "{subpattern}")
|
||||
}
|
||||
PatKind::DerefPattern { ref subpattern } => {
|
||||
write!(f, "k#deref {subpattern}")
|
||||
}
|
||||
PatKind::Constant { value } => write!(f, "{value}"),
|
||||
PatKind::InlineConstant { def: _, ref 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 {
|
||||
AscribeUserType { subpattern, ascription: _ }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| Binding {
|
||||
subpattern: Some(subpattern),
|
||||
mutability: _,
|
||||
|
@ -879,6 +879,10 @@ pub(super) fn visit_primary_bindings(
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern } => {
|
||||
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
|
||||
}
|
||||
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
ascription: thir::Ascription { ref annotation, variance: _ },
|
||||
|
@ -256,6 +256,12 @@ pub(in crate::build) fn new(
|
||||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { .. } => {
|
||||
// FIXME(deref_patterns)
|
||||
// Treat it like a wildcard for now.
|
||||
default_irrefutable()
|
||||
}
|
||||
};
|
||||
|
||||
MatchPair { place, test_case, subpairs, pattern }
|
||||
|
@ -250,6 +250,7 @@ fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
|
||||
| PatKind::Variant { .. }
|
||||
| PatKind::Leaf { .. }
|
||||
| PatKind::Deref { .. }
|
||||
| PatKind::DerefPattern { .. }
|
||||
| PatKind::Range { .. }
|
||||
| PatKind::Slice { .. }
|
||||
| PatKind::Array { .. } => {
|
||||
@ -310,7 +311,7 @@ fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
|
||||
}
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
PatKind::Deref { .. } => {
|
||||
PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
|
||||
let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
|
||||
visit::walk_pat(self, pat);
|
||||
self.inside_adt = old_inside_adt;
|
||||
|
@ -257,6 +257,9 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
|
||||
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) => {
|
||||
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||
}
|
||||
|
@ -688,6 +688,12 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
|
||||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
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 } => {
|
||||
print_indented!(self, "Constant {", depth_lvl + 1);
|
||||
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||
|
@ -462,6 +462,12 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
|
||||
_ => 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, .. } => {
|
||||
match ty.kind() {
|
||||
ty::Tuple(fs) => {
|
||||
|
@ -674,6 +674,7 @@
|
||||
deref_method,
|
||||
deref_mut,
|
||||
deref_mut_method,
|
||||
deref_patterns,
|
||||
deref_target,
|
||||
derive,
|
||||
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
|
||||
--> $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!
|
||||
= 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
|
||||
|
||||
|
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…
Reference in New Issue
Block a user