diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs index c2fe41169c117..d01d4863139b5 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/src/librustc_mir_build/build/block.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { })); debug!("ast_block_stmts: pattern={:?}", pattern); - this.visit_bindings( + this.visit_primary_bindings( &pattern, UserTypeProjections::none(), &mut |this, _, _, _, node, span, _, _| { diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index 43e9f305245cf..9538732e8e0e3 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -511,7 +511,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option { debug!("declare_bindings: pattern={:?}", pattern); - self.visit_bindings( + self.visit_primary_bindings( &pattern, UserTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { @@ -563,7 +563,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.schedule_drop(span, region_scope, local_id, DropKind::Value); } - pub(super) fn visit_bindings( + /// Visit all of the primary bindings in a patterns, that is, visit the + /// leftmost occurrence of each variable bound in a pattern. A variable + /// will occur more than once in an or-pattern. + pub(super) fn visit_primary_bindings( &mut self, pattern: &Pat<'tcx>, pattern_user_ty: UserTypeProjections, @@ -578,12 +581,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { UserTypeProjections, ), ) { - debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); + debug!( + "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}", + pattern, pattern_user_ty + ); match *pattern.kind { - PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => { - f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); + PatKind::Binding { + mutability, + name, + mode, + var, + ty, + ref subpattern, + is_primary, + .. + } => { + if is_primary { + f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); + } if let Some(subpattern) = subpattern.as_ref() { - self.visit_bindings(subpattern, pattern_user_ty, f); + self.visit_primary_bindings(subpattern, pattern_user_ty, f); } } @@ -592,20 +609,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let from = u32::try_from(prefix.len()).unwrap(); let to = u32::try_from(suffix.len()).unwrap(); for subpattern in prefix { - self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f); + self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } for subpattern in slice { - self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f); + self.visit_primary_bindings( + subpattern, + pattern_user_ty.clone().subslice(from, to), + f, + ); } for subpattern in suffix { - self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f); + self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } } PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {} PatKind::Deref { ref subpattern } => { - self.visit_bindings(subpattern, pattern_user_ty.deref(), f); + self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); } PatKind::AscribeUserType { @@ -630,14 +651,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { projs: Vec::new(), }; let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span); - self.visit_bindings(subpattern, subpattern_user_ty, f) + self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); - debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty); - self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); + debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty); + self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f); } } @@ -645,11 +666,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field); - self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); + self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f); } } PatKind::Or { ref pats } => { - self.visit_bindings(&pats[0], pattern_user_ty, f); + // In cases where we recover from errors the primary bindings + // may not all be in the leftmost subpattern. For example in + // `let (x | y) = ...`, the primary binding of `y` occurs in + // the right subpattern + for subpattern in pats { + self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f); + } } } } @@ -1955,7 +1982,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { is_block_tail: None, local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { binding_mode, - // hypothetically, `visit_bindings` could try to unzip + // hypothetically, `visit_primary_bindings` could try to unzip // an outermost hir::Ty as we descend, matching up // idents in pat; but complex w/ unclear UI payoff. // Instead, just abandon providing diagnostic info. diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/src/librustc_mir_build/build/matches/simplify.rs index d74d8b5c7f318..09543cd1ce4e6 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/src/librustc_mir_build/build/matches/simplify.rs @@ -129,7 +129,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatKind::Binding { name, mutability, mode, var, ty, ref subpattern } => { + PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => { candidate.bindings.push(Binding { name, mutability, diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index f38471da94ee2..e9aa7f597beb6 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -133,6 +133,9 @@ crate enum PatKind<'tcx> { var: hir::HirId, ty: Ty<'tcx>, subpattern: Option>, + /// Is this the leftmost occurance of the binding, i.e., is `var` the + /// `HirId` of this pattern? + is_primary: bool, }, /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with @@ -601,6 +604,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { var: id, ty: var_ty, subpattern: self.lower_opt_pattern(sub), + is_primary: id == pat.hir_id, } } @@ -977,7 +981,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { user_ty_span, }, }, - PatKind::Binding { mutability, name, mode, var, ty, ref subpattern } => { + PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => { PatKind::Binding { mutability: mutability.fold_with(folder), name: name.fold_with(folder), @@ -985,6 +989,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { var: var.fold_with(folder), ty: ty.fold_with(folder), subpattern: subpattern.fold_with(folder), + is_primary, } } PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { diff --git a/src/test/ui/or-patterns/mismatched-bindings-async-fn.rs b/src/test/ui/or-patterns/mismatched-bindings-async-fn.rs new file mode 100644 index 0000000000000..5c5c68f81d1f2 --- /dev/null +++ b/src/test/ui/or-patterns/mismatched-bindings-async-fn.rs @@ -0,0 +1,16 @@ +// Regression test for #71297 +// edition:2018 + +#![feature(or_patterns)] + +async fn a((x | s): String) {} +//~^ ERROR variable `x` is not bound in all patterns +//~| ERROR variable `s` is not bound in all patterns + +async fn b() { + let x | s = String::new(); + //~^ ERROR variable `x` is not bound in all patterns + //~| ERROR variable `s` is not bound in all patterns +} + +fn main() {} diff --git a/src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr b/src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr new file mode 100644 index 0000000000000..b9c742664110e --- /dev/null +++ b/src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr @@ -0,0 +1,35 @@ +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/mismatched-bindings-async-fn.rs:6:17 + | +LL | async fn a((x | s): String) {} + | - ^ pattern doesn't bind `x` + | | + | variable not in all patterns + +error[E0408]: variable `s` is not bound in all patterns + --> $DIR/mismatched-bindings-async-fn.rs:6:13 + | +LL | async fn a((x | s): String) {} + | ^ - variable not in all patterns + | | + | pattern doesn't bind `s` + +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/mismatched-bindings-async-fn.rs:11:13 + | +LL | let x | s = String::new(); + | - ^ pattern doesn't bind `x` + | | + | variable not in all patterns + +error[E0408]: variable `s` is not bound in all patterns + --> $DIR/mismatched-bindings-async-fn.rs:11:9 + | +LL | let x | s = String::new(); + | ^ - variable not in all patterns + | | + | pattern doesn't bind `s` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0408`.