Implement "&<pat> everywhere"
The original proposal allows reference patterns with "compatible" mutability, however it's not clear what that means so for now we require an exact match. I don't know the type system code well, so if something seems to not make sense it's probably because I made a mistake
This commit is contained in:
parent
877d36b192
commit
f37a4d55ee
11 changed files with 257 additions and 29 deletions
|
@ -339,6 +339,8 @@ declare_features! (
|
||||||
(incomplete, adt_const_params, "1.56.0", Some(95174)),
|
(incomplete, adt_const_params, "1.56.0", Some(95174)),
|
||||||
/// Allows defining an `#[alloc_error_handler]`.
|
/// Allows defining an `#[alloc_error_handler]`.
|
||||||
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
|
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
|
||||||
|
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
|
||||||
|
(incomplete, and_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
|
||||||
/// Allows trait methods with arbitrary self types.
|
/// Allows trait methods with arbitrary self types.
|
||||||
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
|
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
|
||||||
/// Allows using `const` operands in inline assembly.
|
/// Allows using `const` operands in inline assembly.
|
||||||
|
|
|
@ -131,6 +131,12 @@ enum AdjustMode {
|
||||||
Peel,
|
Peel,
|
||||||
/// Reset binding mode to the initial mode.
|
/// Reset binding mode to the initial mode.
|
||||||
Reset,
|
Reset,
|
||||||
|
/// Produced by ref patterns.
|
||||||
|
/// Reset the binding mode to the initial mode,
|
||||||
|
/// and if the old biding mode was by-reference
|
||||||
|
/// with mutability matching the pattern,
|
||||||
|
/// mark the pattern as having consumed this reference.
|
||||||
|
RefReset(Mutability),
|
||||||
/// Pass on the input binding mode and expected type.
|
/// Pass on the input binding mode and expected type.
|
||||||
Pass,
|
Pass,
|
||||||
}
|
}
|
||||||
|
@ -174,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||||
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
|
let (expected, def_bm, ref_pattern_already_consumed) =
|
||||||
|
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
|
||||||
let pat_info = PatInfo {
|
let pat_info = PatInfo {
|
||||||
binding_mode: def_bm,
|
binding_mode: def_bm,
|
||||||
top_info: ti,
|
top_info: ti,
|
||||||
|
@ -211,7 +218,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
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::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
|
PatKind::Deref(inner) => self.check_pat_deref(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,
|
||||||
|
ref_pattern_already_consumed,
|
||||||
|
),
|
||||||
PatKind::Slice(before, slice, after) => {
|
PatKind::Slice(before, slice, after) => {
|
||||||
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
|
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
|
||||||
}
|
}
|
||||||
|
@ -264,17 +278,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
/// Compute the new expected type and default binding mode from the old ones
|
/// Compute the new expected type and default binding mode from the old ones
|
||||||
/// as well as the pattern form we are currently checking.
|
/// as well as the pattern form we are currently checking.
|
||||||
|
///
|
||||||
|
/// Last entry is only relevant for ref patterns (`&` and `&mut`);
|
||||||
|
/// if `true`, then the ref pattern consumed a match ergonomics inserted reference
|
||||||
|
/// and so does no need to match against a reference in the scrutinee type.
|
||||||
fn calc_default_binding_mode(
|
fn calc_default_binding_mode(
|
||||||
&self,
|
&self,
|
||||||
pat: &'tcx Pat<'tcx>,
|
pat: &'tcx Pat<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingAnnotation,
|
def_bm: BindingAnnotation,
|
||||||
adjust_mode: AdjustMode,
|
adjust_mode: AdjustMode,
|
||||||
) -> (Ty<'tcx>, BindingAnnotation) {
|
) -> (Ty<'tcx>, BindingAnnotation, bool) {
|
||||||
match adjust_mode {
|
match adjust_mode {
|
||||||
AdjustMode::Pass => (expected, def_bm),
|
AdjustMode::Pass => (expected, def_bm, false),
|
||||||
AdjustMode::Reset => (expected, INITIAL_BM),
|
AdjustMode::Reset => (expected, INITIAL_BM, false),
|
||||||
AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm),
|
AdjustMode::RefReset(mutbl) => (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)),
|
||||||
|
AdjustMode::Peel => {
|
||||||
|
let peeled = self.peel_off_references(pat, expected, def_bm);
|
||||||
|
(peeled.0, peeled.1, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// See issue #46688.
|
// See issue #46688.
|
||||||
PatKind::Ref(..) => AdjustMode::Reset,
|
PatKind::Ref(_, mutbl) => AdjustMode::RefReset(*mutbl),
|
||||||
// A `_` pattern works with any expected type, so there's no need to do anything.
|
// A `_` pattern works with any expected type, so there's no need to do anything.
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
// A malformed pattern doesn't have an expected type, so let's just accept any type.
|
// A malformed pattern doesn't have an expected type, so let's just accept any type.
|
||||||
|
@ -840,8 +862,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&& let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
|
&& let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
|
||||||
&& let ty::Dynamic(..) = mt.ty.kind()
|
&& let ty::Dynamic(..) = mt.ty.kind()
|
||||||
{
|
{
|
||||||
// This is "x = SomeTrait" being reduced from
|
// This is "x = dyn SomeTrait" being reduced from
|
||||||
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
|
// "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
|
||||||
let type_str = self.ty_to_string(expected);
|
let type_str = self.ty_to_string(expected);
|
||||||
let mut err = struct_span_code_err!(
|
let mut err = struct_span_code_err!(
|
||||||
self.dcx(),
|
self.dcx(),
|
||||||
|
@ -2036,6 +2058,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
mutbl: Mutability,
|
mutbl: Mutability,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
pat_info: PatInfo<'tcx, '_>,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
|
already_consumed: bool,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let expected = self.shallow_resolve(expected);
|
let expected = self.shallow_resolve(expected);
|
||||||
|
@ -2051,26 +2074,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
match *expected.kind() {
|
match *expected.kind() {
|
||||||
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
|
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
|
||||||
_ => {
|
_ => {
|
||||||
let inner_ty = self.next_ty_var(TypeVariableOrigin {
|
if already_consumed && self.tcx.features().and_pat_everywhere {
|
||||||
kind: TypeVariableOriginKind::TypeInference,
|
// We already matched against a match-ergonmics inserted reference,
|
||||||
span: inner.span,
|
// so we don't need to match against a reference from the original type.
|
||||||
});
|
// Save this infor for use in lowering later
|
||||||
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
|
self.typeck_results
|
||||||
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
.borrow_mut()
|
||||||
let err = self.demand_eqtype_pat_diag(
|
.ref_pats_that_dont_deref_mut()
|
||||||
pat.span,
|
.insert(pat.hir_id);
|
||||||
expected,
|
(expected, expected)
|
||||||
ref_ty,
|
} else {
|
||||||
pat_info.top_info,
|
let inner_ty = self.next_ty_var(TypeVariableOrigin {
|
||||||
);
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
|
span: inner.span,
|
||||||
|
});
|
||||||
|
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
|
||||||
|
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
||||||
|
let err = self.demand_eqtype_pat_diag(
|
||||||
|
pat.span,
|
||||||
|
expected,
|
||||||
|
ref_ty,
|
||||||
|
pat_info.top_info,
|
||||||
|
);
|
||||||
|
|
||||||
// Look for a case like `fn foo(&foo: u32)` and suggest
|
// Look for a case like `fn foo(&foo: u32)` and suggest
|
||||||
// `fn foo(foo: &u32)`
|
// `fn foo(foo: &u32)`
|
||||||
if let Some(mut err) = err {
|
if let Some(mut err) = err {
|
||||||
self.borrow_pat_suggestion(&mut err, pat);
|
self.borrow_pat_suggestion(&mut err, pat);
|
||||||
err.emit();
|
err.emit();
|
||||||
|
}
|
||||||
|
(ref_ty, inner_ty)
|
||||||
}
|
}
|
||||||
(ref_ty, inner_ty)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,6 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.visit_ref_pats_that_dont_deref(p.hir_id);
|
||||||
self.visit_pat_adjustments(p.span, p.hir_id);
|
self.visit_pat_adjustments(p.span, p.hir_id);
|
||||||
|
|
||||||
self.visit_node_id(p.span, p.hir_id);
|
self.visit_node_id(p.span, p.hir_id);
|
||||||
|
@ -674,6 +675,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
fn visit_ref_pats_that_dont_deref(&mut self, hir_id: hir::HirId) {
|
||||||
|
if self.fcx.typeck_results.borrow_mut().ref_pats_that_dont_deref_mut().remove(hir_id) {
|
||||||
|
debug!("node is a ref pat that doesn't deref");
|
||||||
|
self.typeck_results.ref_pats_that_dont_deref_mut().insert(hir_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_liberated_fn_sigs(&mut self) {
|
fn visit_liberated_fn_sigs(&mut self) {
|
||||||
let fcx_typeck_results = self.fcx.typeck_results.borrow();
|
let fcx_typeck_results = self.fcx.typeck_results.borrow();
|
||||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||||
|
|
|
@ -96,6 +96,10 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
|
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
|
||||||
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
|
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
|
||||||
|
|
||||||
|
/// Set of reference patterns that match against a match-ergonomics inserted reference
|
||||||
|
/// (as opposed to against a reference in the scrutinee type).
|
||||||
|
ref_pats_that_dont_deref: ItemLocalSet,
|
||||||
|
|
||||||
/// Records the reasons that we picked the kind of each closure;
|
/// Records the reasons that we picked the kind of each closure;
|
||||||
/// not all closures are present in the map.
|
/// not all closures are present in the map.
|
||||||
closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
|
closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
|
||||||
|
@ -228,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
adjustments: Default::default(),
|
adjustments: Default::default(),
|
||||||
pat_binding_modes: Default::default(),
|
pat_binding_modes: Default::default(),
|
||||||
pat_adjustments: Default::default(),
|
pat_adjustments: Default::default(),
|
||||||
|
ref_pats_that_dont_deref: Default::default(),
|
||||||
closure_kind_origins: Default::default(),
|
closure_kind_origins: Default::default(),
|
||||||
liberated_fn_sigs: Default::default(),
|
liberated_fn_sigs: Default::default(),
|
||||||
fru_field_types: Default::default(),
|
fru_field_types: Default::default(),
|
||||||
|
@ -435,6 +440,14 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
|
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ref_pats_that_dont_deref(&self) -> LocalSetInContext<'_> {
|
||||||
|
LocalSetInContext { hir_owner: self.hir_owner, data: &self.ref_pats_that_dont_deref }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ref_pats_that_dont_deref_mut(&mut self) -> LocalSetInContextMut<'_> {
|
||||||
|
LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.ref_pats_that_dont_deref }
|
||||||
|
}
|
||||||
|
|
||||||
/// Does the pattern recursively contain a `ref mut` binding in it?
|
/// Does the pattern recursively contain a `ref mut` binding in it?
|
||||||
///
|
///
|
||||||
/// This is used to determined whether a `deref` pattern should emit a `Deref`
|
/// This is used to determined whether a `deref` pattern should emit a `Deref`
|
||||||
|
@ -629,6 +642,49 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct LocalSetInContext<'a> {
|
||||||
|
hir_owner: OwnerId,
|
||||||
|
data: &'a ItemLocalSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LocalSetInContext<'a> {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.data.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, id: hir::HirId) -> bool {
|
||||||
|
validate_hir_id_for_typeck_results(self.hir_owner, id);
|
||||||
|
self.data.contains(&id.local_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LocalSetInContextMut<'a> {
|
||||||
|
hir_owner: OwnerId,
|
||||||
|
data: &'a mut ItemLocalSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LocalSetInContextMut<'a> {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.data.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, id: hir::HirId) -> bool {
|
||||||
|
validate_hir_id_for_typeck_results(self.hir_owner, id);
|
||||||
|
self.data.contains(&id.local_id)
|
||||||
|
}
|
||||||
|
pub fn insert(&mut self, id: hir::HirId) -> bool {
|
||||||
|
validate_hir_id_for_typeck_results(self.hir_owner, id);
|
||||||
|
self.data.insert(id.local_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, id: hir::HirId) -> bool {
|
||||||
|
validate_hir_id_for_typeck_results(self.hir_owner, id);
|
||||||
|
self.data.remove(&id.local_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
#[encodable]
|
#[encodable]
|
||||||
|
|
|
@ -65,9 +65,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
// we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
|
// we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
|
||||||
// adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
|
// adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
|
||||||
// gets the least-dereferenced type).
|
// gets the least-dereferenced type).
|
||||||
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
|
let unadjusted = if self.typeck_results.ref_pats_that_dont_deref().contains(pat.hir_id) {
|
||||||
|
match pat.kind {
|
||||||
|
hir::PatKind::Ref(inner, _) => self.lower_pattern_unadjusted(inner),
|
||||||
|
_ => span_bug!(pat.span, "non ref pattern marked as non-deref ref pattern"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.lower_pattern_unadjusted(pat)
|
||||||
|
};
|
||||||
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
|
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
|
||||||
unadjusted_pat,
|
unadjusted,
|
||||||
|pat: Box<_>, ref_ty| {
|
|pat: Box<_>, ref_ty| {
|
||||||
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
|
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
|
||||||
Box::new(Pat {
|
Box::new(Pat {
|
||||||
|
|
|
@ -380,6 +380,7 @@ symbols! {
|
||||||
alu32,
|
alu32,
|
||||||
always,
|
always,
|
||||||
and,
|
and,
|
||||||
|
and_pat_everywhere,
|
||||||
and_then,
|
and_then,
|
||||||
anon,
|
anon,
|
||||||
anon_adt,
|
anon_adt,
|
||||||
|
|
12
tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
Normal file
12
tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(and_pat_everywhere)]
|
||||||
|
pub fn main() {
|
||||||
|
if let Some(&x) = Some(0) {
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let &Some(x) = &mut Some(0) {
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
}
|
29
tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
Normal file
29
tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/and_pat_everywhere-mutability-mismatch.rs:4:17
|
||||||
|
|
|
||||||
|
LL | if let Some(&x) = Some(0) {
|
||||||
|
| ^^ ------- this expression has type `Option<{integer}>`
|
||||||
|
| |
|
||||||
|
| expected integer, found `&_`
|
||||||
|
|
|
||||||
|
= note: expected type `{integer}`
|
||||||
|
found reference `&_`
|
||||||
|
help: consider removing `&` from the pattern
|
||||||
|
|
|
||||||
|
LL | if let Some(x) = Some(0) {
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/and_pat_everywhere-mutability-mismatch.rs:8:12
|
||||||
|
|
|
||||||
|
LL | if let &Some(x) = &mut Some(0) {
|
||||||
|
| ^^^^^^^^ ------------ this expression has type `&mut Option<{integer}>`
|
||||||
|
| |
|
||||||
|
| types differ in mutability
|
||||||
|
|
|
||||||
|
= note: expected mutable reference `&mut Option<{integer}>`
|
||||||
|
found reference `&_`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
15
tests/ui/match/and_pat_everywhere.rs
Normal file
15
tests/ui/match/and_pat_everywhere.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//@ run-pass
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(and_pat_everywhere)]
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
if let Some(Some(&x)) = &Some(&Some(0)) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let Some(&Some(x)) = &Some(Some(0)) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
}
|
14
tests/ui/match/feature-gate-and_pat_everywhere.rs
Normal file
14
tests/ui/match/feature-gate-and_pat_everywhere.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
pub fn main() {
|
||||||
|
if let Some(Some(&x)) = &Some(&Some(0)) {
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let Some(&Some(x)) = &Some(Some(0)) {
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
}
|
49
tests/ui/match/feature-gate-and_pat_everywhere.stderr
Normal file
49
tests/ui/match/feature-gate-and_pat_everywhere.stderr
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/feature-gate-and_pat_everywhere.rs:2:22
|
||||||
|
|
|
||||||
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
|
||||||
|
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
|
||||||
|
| |
|
||||||
|
| expected integer, found `&_`
|
||||||
|
|
|
||||||
|
= note: expected type `{integer}`
|
||||||
|
found reference `&_`
|
||||||
|
help: consider removing `&` from the pattern
|
||||||
|
|
|
||||||
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/feature-gate-and_pat_everywhere.rs:6:17
|
||||||
|
|
|
||||||
|
LL | if let Some(&Some(x)) = &Some(Some(0)) {
|
||||||
|
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
|
||||||
|
| |
|
||||||
|
| expected `Option<{integer}>`, found `&_`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<{integer}>`
|
||||||
|
found reference `&_`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/feature-gate-and_pat_everywhere.rs:10:22
|
||||||
|
|
|
||||||
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
|
||||||
|
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
|
||||||
|
| |
|
||||||
|
| expected integer, found `&mut _`
|
||||||
|
|
|
||||||
|
= note: expected type `{integer}`
|
||||||
|
found mutable reference `&mut _`
|
||||||
|
note: to declare a mutable binding use: `mut x`
|
||||||
|
--> $DIR/feature-gate-and_pat_everywhere.rs:10:22
|
||||||
|
|
|
||||||
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
|
||||||
|
| ^^^^^^
|
||||||
|
help: consider removing `&mut` from the pattern
|
||||||
|
|
|
||||||
|
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue