Auto merge of #124567 - Jules-Bertholet:and-eats-andmut, r=Nadrieril
Match ergonomics 2024: let `&` patterns eat `&mut` r? `@Nadrieril` cc https://github.com/rust-lang/rust/issues/123076 `@rustbot` label A-edition-2024 A-patterns
This commit is contained in:
commit
35c5e67c69
13 changed files with 419 additions and 212 deletions
|
@ -78,7 +78,7 @@ struct TopInfo<'tcx> {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct PatInfo<'tcx, 'a> {
|
struct PatInfo<'tcx, 'a> {
|
||||||
binding_mode: ByRef,
|
binding_mode: ByRef,
|
||||||
max_ref_mutbl: Mutability,
|
max_ref_mutbl: MutblCap,
|
||||||
top_info: TopInfo<'tcx>,
|
top_info: TopInfo<'tcx>,
|
||||||
decl_origin: Option<DeclOrigin<'a>>,
|
decl_origin: Option<DeclOrigin<'a>>,
|
||||||
|
|
||||||
|
@ -127,22 +127,61 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mode for adjusting the expected type and binding mode.
|
/// Mode for adjusting the expected type and binding mode.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
enum AdjustMode {
|
enum AdjustMode {
|
||||||
/// Peel off all immediate reference types.
|
/// Peel off all immediate reference types.
|
||||||
Peel,
|
Peel,
|
||||||
/// Reset binding mode to the initial mode.
|
/// Reset binding mode to the initial mode.
|
||||||
/// Used for destructuring assignment, where we don't want any match ergonomics.
|
/// Used for destructuring assignment, where we don't want any match ergonomics.
|
||||||
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.
|
|
||||||
ResetAndConsumeRef(Mutability),
|
|
||||||
/// Pass on the input binding mode and expected type.
|
/// Pass on the input binding mode and expected type.
|
||||||
Pass,
|
Pass,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `ref mut` patterns (explicit or match-ergonomics)
|
||||||
|
/// are not allowed behind an `&` reference.
|
||||||
|
///
|
||||||
|
/// This includes explicit `ref mut` behind `&` patterns
|
||||||
|
/// that match against `&mut` references,
|
||||||
|
/// where the code would have compiled
|
||||||
|
/// had the pattern been written as `&mut`.
|
||||||
|
/// However, the borrow checker will not catch
|
||||||
|
/// this last case, so we need to throw an error ourselves.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
enum MutblCap {
|
||||||
|
/// Mutability restricted to immutable.
|
||||||
|
Not,
|
||||||
|
|
||||||
|
/// Mutability restricted to immutable, but only because of the pattern
|
||||||
|
/// (not the scrutinee type).
|
||||||
|
///
|
||||||
|
/// The contained span, if present, points to an `&` pattern
|
||||||
|
/// that is the reason for the restriction,
|
||||||
|
/// and which will be reported in a diagnostic.
|
||||||
|
WeaklyNot(Option<Span>),
|
||||||
|
|
||||||
|
/// No restriction on mutability
|
||||||
|
Mut,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutblCap {
|
||||||
|
#[must_use]
|
||||||
|
fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
|
||||||
|
match self {
|
||||||
|
MutblCap::Not => MutblCap::Not,
|
||||||
|
_ => MutblCap::WeaklyNot(span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn as_mutbl(self) -> Mutability {
|
||||||
|
match self {
|
||||||
|
MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
|
||||||
|
MutblCap::Mut => Mutability::Mut,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
/// Type check the given top level pattern against the `expected` type.
|
/// Type check the given top level pattern against the `expected` type.
|
||||||
///
|
///
|
||||||
|
@ -163,7 +202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let info = TopInfo { expected, origin_expr, span };
|
let info = TopInfo { expected, origin_expr, span };
|
||||||
let pat_info = PatInfo {
|
let pat_info = PatInfo {
|
||||||
binding_mode: ByRef::No,
|
binding_mode: ByRef::No,
|
||||||
max_ref_mutbl: Mutability::Mut,
|
max_ref_mutbl: MutblCap::Mut,
|
||||||
top_info: info,
|
top_info: info,
|
||||||
decl_origin,
|
decl_origin,
|
||||||
current_depth: 0,
|
current_depth: 0,
|
||||||
|
@ -172,14 +211,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type check the given `pat` against the `expected` type
|
/// Type check the given `pat` against the `expected` type
|
||||||
/// with the provided `def_bm` (default binding mode).
|
/// with the provided `binding_mode` (default binding mode).
|
||||||
///
|
///
|
||||||
/// Outside of this module, `check_pat_top` should always be used.
|
/// Outside of this module, `check_pat_top` should always be used.
|
||||||
/// Conversely, inside this module, `check_pat_top` should never be used.
|
/// Conversely, inside this module, `check_pat_top` should never be used.
|
||||||
#[instrument(level = "debug", skip(self, pat_info))]
|
#[instrument(level = "debug", skip(self, pat_info))]
|
||||||
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
||||||
let PatInfo { binding_mode: def_bm, max_ref_mutbl, top_info: ti, current_depth, .. } =
|
let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
|
||||||
pat_info;
|
|
||||||
|
|
||||||
let path_res = match &pat.kind {
|
let path_res = match &pat.kind {
|
||||||
PatKind::Path(qpath) => Some(
|
PatKind::Path(qpath) => Some(
|
||||||
|
@ -188,10 +226,10 @@ 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, max_ref_mutbl, ref_pattern_already_consumed) =
|
let (expected, binding_mode, max_ref_mutbl) =
|
||||||
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl);
|
self.calc_default_binding_mode(pat, expected, binding_mode, adjust_mode, max_ref_mutbl);
|
||||||
let pat_info = PatInfo {
|
let pat_info = PatInfo {
|
||||||
binding_mode: def_bm,
|
binding_mode,
|
||||||
max_ref_mutbl,
|
max_ref_mutbl,
|
||||||
top_info: ti,
|
top_info: ti,
|
||||||
decl_origin: pat_info.decl_origin,
|
decl_origin: pat_info.decl_origin,
|
||||||
|
@ -204,8 +242,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
PatKind::Never => expected,
|
PatKind::Never => expected,
|
||||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||||
PatKind::Binding(ba, var_id, _, sub) => {
|
PatKind::Binding(ba, var_id, ident, sub) => {
|
||||||
self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
|
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
|
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
|
||||||
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
||||||
|
@ -227,14 +265,7 @@ 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(
|
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -287,52 +318,22 @@ 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_br: ByRef,
|
def_br: ByRef,
|
||||||
adjust_mode: AdjustMode,
|
adjust_mode: AdjustMode,
|
||||||
max_ref_mutbl: Mutability,
|
max_ref_mutbl: MutblCap,
|
||||||
) -> (Ty<'tcx>, ByRef, Mutability, bool) {
|
) -> (Ty<'tcx>, ByRef, MutblCap) {
|
||||||
if let ByRef::Yes(mutbl) = def_br {
|
if let ByRef::Yes(Mutability::Mut) = def_br {
|
||||||
debug_assert!(mutbl <= max_ref_mutbl);
|
debug_assert!(max_ref_mutbl == MutblCap::Mut);
|
||||||
}
|
}
|
||||||
match adjust_mode {
|
match adjust_mode {
|
||||||
AdjustMode::Pass => (expected, def_br, max_ref_mutbl, false),
|
AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
|
||||||
AdjustMode::Reset => (expected, ByRef::No, Mutability::Mut, false),
|
AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut),
|
||||||
AdjustMode::ResetAndConsumeRef(ref_pat_mutbl) => {
|
|
||||||
let mutbls_match = def_br == ByRef::Yes(ref_pat_mutbl);
|
|
||||||
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
|
||||||
if mutbls_match {
|
|
||||||
debug!("consuming inherited reference");
|
|
||||||
(expected, ByRef::No, cmp::min(max_ref_mutbl, ref_pat_mutbl), true)
|
|
||||||
} else {
|
|
||||||
let (new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability::Mut {
|
|
||||||
self.peel_off_references(
|
|
||||||
pat,
|
|
||||||
expected,
|
|
||||||
def_br,
|
|
||||||
Mutability::Not,
|
|
||||||
max_ref_mutbl,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(expected, def_br.cap_ref_mutability(Mutability::Not), Mutability::Not)
|
|
||||||
};
|
|
||||||
(new_ty, new_bm, max_ref_mutbl, false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(expected, ByRef::No, max_ref_mutbl, mutbls_match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AdjustMode::Peel => {
|
AdjustMode::Peel => {
|
||||||
let peeled =
|
self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl)
|
||||||
self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl);
|
|
||||||
(peeled.0, peeled.1, peeled.2, false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,17 +379,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// a reference type wherefore peeling doesn't give up any expressiveness.
|
// a reference type wherefore peeling doesn't give up any expressiveness.
|
||||||
_ => AdjustMode::Peel,
|
_ => AdjustMode::Peel,
|
||||||
},
|
},
|
||||||
// When encountering a `& mut? pat` pattern, reset to "by value".
|
// Ref patterns are complicated, we handle them in `check_pat_ref`.
|
||||||
// This is so that `x` and `y` here are by value, as they appear to be:
|
PatKind::Ref(..) => AdjustMode::Pass,
|
||||||
//
|
|
||||||
// ```
|
|
||||||
// match &(&22, &44) {
|
|
||||||
// (&x, &y) => ...
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// See issue #46688.
|
|
||||||
PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*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.
|
||||||
|
@ -414,8 +406,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
mut def_br: ByRef,
|
mut def_br: ByRef,
|
||||||
max_peelable_mutability: Mutability,
|
max_peelable_mutability: Mutability,
|
||||||
mut max_ref_mutability: Mutability,
|
mut max_ref_mutability: MutblCap,
|
||||||
) -> (Ty<'tcx>, ByRef, Mutability) {
|
) -> (Ty<'tcx>, ByRef, MutblCap) {
|
||||||
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
|
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||||
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
|
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
|
||||||
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
|
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
|
||||||
|
@ -449,9 +441,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||||
def_br = def_br.cap_ref_mutability(max_ref_mutability);
|
def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl());
|
||||||
if def_br == ByRef::Yes(Mutability::Not) {
|
if def_br == ByRef::Yes(Mutability::Not) {
|
||||||
max_ref_mutability = Mutability::Not;
|
max_ref_mutability = MutblCap::Not;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,8 +660,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn check_pat_ident(
|
fn check_pat_ident(
|
||||||
&self,
|
&self,
|
||||||
pat: &'tcx Pat<'tcx>,
|
pat: &'tcx Pat<'tcx>,
|
||||||
ba: BindingMode,
|
user_bind_annot: BindingMode,
|
||||||
var_id: HirId,
|
var_id: HirId,
|
||||||
|
ident: Ident,
|
||||||
sub: Option<&'tcx Pat<'tcx>>,
|
sub: Option<&'tcx Pat<'tcx>>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
pat_info: PatInfo<'tcx, '_>,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
|
@ -677,7 +670,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
|
let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
|
||||||
|
|
||||||
// Determine the binding mode...
|
// Determine the binding mode...
|
||||||
let bm = match ba {
|
let bm = match user_bind_annot {
|
||||||
BindingMode(ByRef::No, Mutability::Mut)
|
BindingMode(ByRef::No, Mutability::Mut)
|
||||||
if !(pat.span.at_least_rust_2024()
|
if !(pat.span.at_least_rust_2024()
|
||||||
&& self.tcx.features().mut_preserve_binding_mode_2024)
|
&& self.tcx.features().mut_preserve_binding_mode_2024)
|
||||||
|
@ -693,8 +686,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
BindingMode(ByRef::No, Mutability::Mut)
|
BindingMode(ByRef::No, Mutability::Mut)
|
||||||
}
|
}
|
||||||
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
||||||
BindingMode(ByRef::Yes(_), _) => ba,
|
BindingMode(ByRef::Yes(_), _) => user_bind_annot,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if bm.0 == ByRef::Yes(Mutability::Mut)
|
||||||
|
&& let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
|
||||||
|
{
|
||||||
|
let mut err = struct_span_code_err!(
|
||||||
|
self.tcx.dcx(),
|
||||||
|
ident.span,
|
||||||
|
E0596,
|
||||||
|
"cannot borrow as mutable inside an `&` pattern"
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(span) = and_pat_span {
|
||||||
|
err.span_suggestion(
|
||||||
|
span,
|
||||||
|
"replace this `&` with `&mut`",
|
||||||
|
"&mut ",
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
|
||||||
// ...and store it in a side table:
|
// ...and store it in a side table:
|
||||||
self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
|
self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
|
||||||
|
|
||||||
|
@ -720,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// If there are multiple arms, make sure they all agree on
|
// If there are multiple arms, make sure they all agree on
|
||||||
// what the type of the binding `x` ought to be.
|
// what the type of the binding `x` ought to be.
|
||||||
if var_id != pat.hir_id {
|
if var_id != pat.hir_id {
|
||||||
self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti);
|
self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = sub {
|
if let Some(p) = sub {
|
||||||
|
@ -2105,72 +2120,136 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
pat: &'tcx Pat<'tcx>,
|
pat: &'tcx Pat<'tcx>,
|
||||||
inner: &'tcx Pat<'tcx>,
|
inner: &'tcx Pat<'tcx>,
|
||||||
mutbl: Mutability,
|
pat_mutbl: Mutability,
|
||||||
expected: Ty<'tcx>,
|
mut expected: Ty<'tcx>,
|
||||||
pat_info: PatInfo<'tcx, '_>,
|
mut pat_info: PatInfo<'tcx, '_>,
|
||||||
consumed_inherited_ref: bool,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
if consumed_inherited_ref
|
// FIXME: repace with `bool` once final decision on 1 vs 2 layers is made
|
||||||
&& pat.span.at_least_rust_2024()
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
&& self.tcx.features().ref_pat_eat_one_layer_2024
|
enum MatchErgonomicsMode {
|
||||||
{
|
EatOneLayer,
|
||||||
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
EatTwoLayers,
|
||||||
self.check_pat(inner, expected, pat_info);
|
Legacy,
|
||||||
expected
|
}
|
||||||
|
|
||||||
|
let match_ergonomics_mode =
|
||||||
|
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||||
|
MatchErgonomicsMode::EatOneLayer
|
||||||
|
} else if self.tcx.features().ref_pat_everywhere {
|
||||||
|
MatchErgonomicsMode::EatTwoLayers
|
||||||
|
} else {
|
||||||
|
MatchErgonomicsMode::Legacy
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut inherited_ref_mutbl_match = false;
|
||||||
|
if match_ergonomics_mode != MatchErgonomicsMode::Legacy {
|
||||||
|
if pat_mutbl == Mutability::Not {
|
||||||
|
// Prevent the inner pattern from binding with `ref mut`.
|
||||||
|
pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(
|
||||||
|
inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
|
||||||
|
inherited_ref_mutbl_match = pat_mutbl <= inh_mut;
|
||||||
|
}
|
||||||
|
|
||||||
|
if inherited_ref_mutbl_match {
|
||||||
|
pat_info.binding_mode = ByRef::No;
|
||||||
|
if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer {
|
||||||
|
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||||
|
self.check_pat(inner, expected, pat_info);
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
} else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer
|
||||||
|
&& pat_mutbl == Mutability::Mut
|
||||||
|
{
|
||||||
|
// `&mut` patterns pell off `&` references
|
||||||
|
let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references(
|
||||||
|
pat,
|
||||||
|
expected,
|
||||||
|
pat_info.binding_mode,
|
||||||
|
Mutability::Not,
|
||||||
|
pat_info.max_ref_mutbl,
|
||||||
|
);
|
||||||
|
expected = new_expected;
|
||||||
|
pat_info.binding_mode = new_bm;
|
||||||
|
pat_info.max_ref_mutbl = max_ref_mutbl;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let tcx = self.tcx;
|
// Reset binding mode on old editions
|
||||||
let expected = self.shallow_resolve(expected);
|
pat_info.binding_mode = ByRef::No;
|
||||||
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
|
pat_info.max_ref_mutbl = MutblCap::Mut
|
||||||
Ok(()) => {
|
}
|
||||||
// `demand::subtype` would be good enough, but using `eqtype` turns
|
|
||||||
// out to be equally general. See (note_1) for details.
|
|
||||||
|
|
||||||
// Take region, inner-type from expected type if we can,
|
let tcx = self.tcx;
|
||||||
// to avoid creating needless variables. This also helps with
|
expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||||
// the bad interactions of the given hack detailed in (note_1).
|
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
|
||||||
debug!("check_pat_ref: expected={:?}", expected);
|
Ok(()) => {
|
||||||
match *expected.kind() {
|
// `demand::subtype` would be good enough, but using `eqtype` turns
|
||||||
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
|
// out to be equally general. See (note_1) for details.
|
||||||
_ => {
|
|
||||||
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
|
|
||||||
// We already matched against a match-ergonmics inserted reference,
|
|
||||||
// so we don't need to match against a reference from the original type.
|
|
||||||
// Save this infor for use in lowering later
|
|
||||||
self.typeck_results
|
|
||||||
.borrow_mut()
|
|
||||||
.skipped_ref_pats_mut()
|
|
||||||
.insert(pat.hir_id);
|
|
||||||
(expected, expected)
|
|
||||||
} else {
|
|
||||||
let inner_ty = self.next_ty_var(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
|
// Take region, inner-type from expected type if we can,
|
||||||
// `fn foo(foo: &u32)`
|
// to avoid creating needless variables. This also helps with
|
||||||
if let Some(mut err) = err {
|
// the bad interactions of the given hack detailed in (note_1).
|
||||||
self.borrow_pat_suggestion(&mut err, pat);
|
debug!("check_pat_ref: expected={:?}", expected);
|
||||||
err.emit();
|
match *expected.kind() {
|
||||||
}
|
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => {
|
||||||
(ref_ty, inner_ty)
|
if r_mutbl == Mutability::Not
|
||||||
}
|
&& match_ergonomics_mode != MatchErgonomicsMode::Legacy
|
||||||
|
{
|
||||||
|
pat_info.max_ref_mutbl = MutblCap::Not;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(expected, r_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// `&` pattern eats `&mut` reference
|
||||||
|
ty::Ref(_, r_ty, Mutability::Mut)
|
||||||
|
if pat_mutbl == Mutability::Not
|
||||||
|
&& match_ergonomics_mode != MatchErgonomicsMode::Legacy =>
|
||||||
|
{
|
||||||
|
(expected, r_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ if inherited_ref_mutbl_match
|
||||||
|
&& match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers =>
|
||||||
|
{
|
||||||
|
// We already matched against a match-ergonmics inserted reference,
|
||||||
|
// so we don't need to match against a reference from the original type.
|
||||||
|
// Save this info for use in lowering later
|
||||||
|
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||||
|
(expected, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
let inner_ty = self.next_ty_var(inner.span);
|
||||||
|
let ref_ty = self.new_ref_ty(pat.span, pat_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
|
||||||
|
// `fn foo(foo: &u32)`
|
||||||
|
if let Some(mut err) = err {
|
||||||
|
self.borrow_pat_suggestion(&mut err, pat);
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
(ref_ty, inner_ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(guar) => {
|
}
|
||||||
let err = Ty::new_error(tcx, guar);
|
Err(guar) => {
|
||||||
(err, err)
|
let err = Ty::new_error(tcx, guar);
|
||||||
}
|
(err, err)
|
||||||
};
|
}
|
||||||
self.check_pat(inner, inner_ty, pat_info);
|
};
|
||||||
ref_ty
|
self.check_pat(inner, inner_ty, pat_info);
|
||||||
}
|
ref_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a reference type with a fresh region variable.
|
/// Create a reference type with a fresh region variable.
|
||||||
|
|
|
@ -53,6 +53,12 @@ pub fn main() {
|
||||||
if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
|
if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
|
||||||
let _: u32 = x;
|
let _: u32 = x;
|
||||||
}
|
}
|
||||||
|
if let Some(&Some(&x)) = Some(&Some(&mut 0)) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let Some(&Some(x)) = &mut Some(Some(0)) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
|
||||||
let &mut x = &&mut 0;
|
let &mut x = &&mut 0;
|
||||||
let _: &u32 = x;
|
let _: &u32 = x;
|
||||||
|
|
|
@ -14,18 +14,20 @@ pub fn main() {
|
||||||
let _: &mut u32 = x;
|
let _: &mut u32 = x;
|
||||||
//~^ ERROR: mismatched types
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
if let Some(&Some(&_)) = Some(&Some(&mut 0)) {
|
|
||||||
//~^ ERROR: mismatched types
|
|
||||||
}
|
|
||||||
if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
|
if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
|
||||||
//~^ ERROR: mismatched types
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
|
if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
|
||||||
//~^ ERROR: mismatched types
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
|
if let Some(&mut Some(x)) = &Some(Some(0)) {
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
}
|
||||||
|
if let Some(&mut Some(x)) = &Some(Some(0)) {
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
let &mut _ = &&0;
|
||||||
let &mut _= &&0;
|
|
||||||
//~^ ERROR: mismatched types
|
//~^ ERROR: mismatched types
|
||||||
|
|
||||||
let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
|
let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
|
||||||
|
|
|
@ -34,17 +34,6 @@ LL | let _: &mut u32 = x;
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23
|
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23
|
||||||
|
|
|
|
||||||
LL | if let Some(&Some(&_)) = Some(&Some(&mut 0)) {
|
|
||||||
| ^^ ------------------- this expression has type `Option<&Option<&mut {integer}>>`
|
|
||||||
| |
|
|
||||||
| types differ in mutability
|
|
||||||
|
|
|
||||||
= note: expected mutable reference `&mut {integer}`
|
|
||||||
found reference `&_`
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:23
|
|
||||||
|
|
|
||||||
LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
|
LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
|
||||||
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
|
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
|
||||||
| |
|
| |
|
||||||
|
@ -54,7 +43,7 @@ LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
|
||||||
found mutable reference `&mut _`
|
found mutable reference `&mut _`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:29
|
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:29
|
||||||
|
|
|
|
||||||
LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
|
LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
|
||||||
| ^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
|
| ^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
|
||||||
|
@ -65,10 +54,32 @@ LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
|
||||||
found mutable reference `&mut _`
|
found mutable reference `&mut _`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:9
|
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:17
|
||||||
|
|
|
|
||||||
LL | let &mut _= &&0;
|
LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
|
||||||
| ^^^^^^ --- this expression has type `&&{integer}`
|
| ^^^^^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
|
||||||
|
| |
|
||||||
|
| expected `Option<{integer}>`, found `&mut _`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<{integer}>`
|
||||||
|
found mutable reference `&mut _`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17
|
||||||
|
|
|
||||||
|
LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
|
||||||
|
| ^^^^^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
|
||||||
|
| |
|
||||||
|
| expected `Option<{integer}>`, found `&mut _`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<{integer}>`
|
||||||
|
found mutable reference `&mut _`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:30:9
|
||||||
|
|
|
||||||
|
LL | let &mut _ = &&0;
|
||||||
|
| ^^^^^^ --- this expression has type `&&{integer}`
|
||||||
| |
|
| |
|
||||||
| expected integer, found `&mut _`
|
| expected integer, found `&mut _`
|
||||||
|
|
|
|
||||||
|
@ -76,7 +87,7 @@ LL | let &mut _= &&0;
|
||||||
found mutable reference `&mut _`
|
found mutable reference `&mut _`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
|
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:33:9
|
||||||
|
|
|
|
||||||
LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
|
LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
|
||||||
| ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
|
| ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
|
||||||
|
@ -86,6 +97,6 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
|
||||||
= note: expected type `{integer}`
|
= note: expected type `{integer}`
|
||||||
found mutable reference `&mut _`
|
found mutable reference `&mut _`
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -8,4 +8,7 @@ pub fn main() {
|
||||||
//~^ ERROR: cannot move out of a shared reference [E0507]
|
//~^ ERROR: cannot move out of a shared reference [E0507]
|
||||||
let _: &u32 = x;
|
let _: &u32 = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let &ref mut x = &0;
|
||||||
|
//~^ cannot borrow data in a `&` reference as mutable [E0596]
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,13 @@ help: consider borrowing the pattern binding
|
||||||
LL | if let Some(&Some(ref x)) = Some(&Some(&mut 0)) {
|
LL | if let Some(&Some(ref x)) = Some(&Some(&mut 0)) {
|
||||||
| +++
|
| +++
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0596]: cannot borrow data in a `&` reference as mutable
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:12:10
|
||||||
|
|
|
||||||
|
LL | let &ref mut x = &0;
|
||||||
|
| ^^^^^^^^^ cannot borrow as mutable
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0507`.
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0507, E0596.
|
||||||
|
For more information about an error, try `rustc --explain E0507`.
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
//@ edition: 2024
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
//@ run-rustfix
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(ref_pat_eat_one_layer_2024)]
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut u8 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut u8 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pat {
|
||||||
|
($var:ident) => { ref mut $var };
|
||||||
|
}
|
||||||
|
let &mut pat!(x) = &mut 0;
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut u8 = x;
|
||||||
|
|
||||||
|
let &mut (ref mut a, ref mut b) = &mut (true, false);
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
//~| ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut bool = a;
|
||||||
|
let _: &mut bool = b;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
//@ edition: 2024
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
//@ run-rustfix
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(ref_pat_eat_one_layer_2024)]
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut u8 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut u8 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pat {
|
||||||
|
($var:ident) => { ref mut $var };
|
||||||
|
}
|
||||||
|
let &pat!(x) = &mut 0;
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut u8 = x;
|
||||||
|
|
||||||
|
let &(ref mut a, ref mut b) = &mut (true, false);
|
||||||
|
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
//~| ERROR: cannot borrow as mutable inside an `&` pattern
|
||||||
|
let _: &mut bool = a;
|
||||||
|
let _: &mut bool = b;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
error[E0596]: cannot borrow as mutable inside an `&` pattern
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:8:31
|
||||||
|
|
|
||||||
|
LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| help: replace this `&` with `&mut`: `&mut`
|
||||||
|
|
||||||
|
error[E0596]: cannot borrow as mutable inside an `&` pattern
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:13:31
|
||||||
|
|
|
||||||
|
LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| help: replace this `&` with `&mut`: `&mut`
|
||||||
|
|
||||||
|
error[E0596]: cannot borrow as mutable inside an `&` pattern
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:21:15
|
||||||
|
|
|
||||||
|
LL | let &pat!(x) = &mut 0;
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| help: replace this `&` with `&mut`: `&mut`
|
||||||
|
|
||||||
|
error[E0596]: cannot borrow as mutable inside an `&` pattern
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:19
|
||||||
|
|
|
||||||
|
LL | let &(ref mut a, ref mut b) = &mut (true, false);
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| help: replace this `&` with `&mut`: `&mut`
|
||||||
|
|
||||||
|
error[E0596]: cannot borrow as mutable inside an `&` pattern
|
||||||
|
--> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:30
|
||||||
|
|
|
||||||
|
LL | let &(ref mut a, ref mut b) = &mut (true, false);
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| help: replace this `&` with `&mut`: `&mut`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0596`.
|
|
@ -5,11 +5,7 @@ pub fn main() {
|
||||||
//~^ ERROR: mismatched types [E0308]
|
//~^ ERROR: mismatched types [E0308]
|
||||||
let _: u32 = x;
|
let _: u32 = x;
|
||||||
}
|
}
|
||||||
if let &Some(x) = &mut Some(0) {
|
if let Some(&mut x) = Some(&0) {
|
||||||
//~^ ERROR: mismatched types [E0308]
|
|
||||||
let _: u32 = x;
|
|
||||||
}
|
|
||||||
if let Some(&x) = &mut Some(0) {
|
|
||||||
//~^ ERROR: mismatched types [E0308]
|
//~^ ERROR: mismatched types [E0308]
|
||||||
let _: u32 = x;
|
let _: u32 = x;
|
||||||
}
|
}
|
38
tests/ui/match/ref_pat_everywhere-fail.stderr
Normal file
38
tests/ui/match/ref_pat_everywhere-fail.stderr
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/ref_pat_everywhere-fail.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/ref_pat_everywhere-fail.rs:8:17
|
||||||
|
|
|
||||||
|
LL | if let Some(&mut x) = Some(&0) {
|
||||||
|
| ^^^^^^ -------- this expression has type `Option<&{integer}>`
|
||||||
|
| |
|
||||||
|
| types differ in mutability
|
||||||
|
|
|
||||||
|
= note: expected reference `&{integer}`
|
||||||
|
found mutable reference `&mut _`
|
||||||
|
note: to declare a mutable binding use: `mut x`
|
||||||
|
--> $DIR/ref_pat_everywhere-fail.rs:8:17
|
||||||
|
|
|
||||||
|
LL | if let Some(&mut x) = Some(&0) {
|
||||||
|
| ^^^^^^
|
||||||
|
help: consider removing `&mut` from the pattern
|
||||||
|
|
|
||||||
|
LL | if let Some(x) = Some(&0) {
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -1,44 +0,0 @@
|
||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/ref_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/ref_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[E0308]: mismatched types
|
|
||||||
--> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17
|
|
||||||
|
|
|
||||||
LL | if let Some(&x) = &mut Some(0) {
|
|
||||||
| ^^ ------------ this expression has type `&mut Option<{integer}>`
|
|
||||||
| |
|
|
||||||
| expected integer, found `&_`
|
|
||||||
|
|
|
||||||
= note: expected type `{integer}`
|
|
||||||
found reference `&_`
|
|
||||||
help: consider removing `&` from the pattern
|
|
||||||
|
|
|
||||||
LL | if let Some(x) = &mut Some(0) {
|
|
||||||
| ~
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
|
|
@ -15,4 +15,10 @@ pub fn main() {
|
||||||
if let Some(Some(&x)) = &Some(&mut Some(0)) {
|
if let Some(Some(&x)) = &Some(&mut Some(0)) {
|
||||||
let _: u32 = x;
|
let _: u32 = x;
|
||||||
}
|
}
|
||||||
|
if let &Some(x) = &mut Some(0) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
|
if let Some(&x) = &mut Some(0) {
|
||||||
|
let _: u32 = x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue