diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index a8bbc89dbded5..956671fc66ed2 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -105,16 +105,26 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { } fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option>) -> Ty<'tcx> { + // We evaluate expressions twice occasionally in diagnostics for better + // type information or because it needs type information out-of-order. + // In order to not ICE and not lead to knock-on ambiguity errors, if we + // try to re-assign a type to a local, then just take out the previous + // type and delay a bug. + if let Some(&local) = self.fcx.locals.borrow_mut().get(&nid) { + self.fcx.dcx().span_delayed_bug(span, "evaluated expression more than once"); + return local; + } + match ty_opt { None => { // Infer the variable's type. let var_ty = self.fcx.next_ty_var(span); - assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None); + self.fcx.locals.borrow_mut().insert(nid, var_ty); var_ty } Some(typ) => { // Take type that the user specified. - assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None); + self.fcx.locals.borrow_mut().insert(nid, typ); typ } } diff --git a/tests/ui/typeck/gather-locals-twice.rs b/tests/ui/typeck/gather-locals-twice.rs new file mode 100644 index 0000000000000..e9351146f4564 --- /dev/null +++ b/tests/ui/typeck/gather-locals-twice.rs @@ -0,0 +1,7 @@ +// Regression test for . + +fn main() { + () += { let x; }; + //~^ ERROR binary assignment operation `+=` cannot be applied to type `()` + //~| ERROR invalid left-hand side of assignment +} diff --git a/tests/ui/typeck/gather-locals-twice.stderr b/tests/ui/typeck/gather-locals-twice.stderr new file mode 100644 index 0000000000000..7598ef8e7ea4c --- /dev/null +++ b/tests/ui/typeck/gather-locals-twice.stderr @@ -0,0 +1,20 @@ +error[E0368]: binary assignment operation `+=` cannot be applied to type `()` + --> $DIR/gather-locals-twice.rs:4:5 + | +LL | () += { let x; }; + | --^^^^^^^^^^^^^^ + | | + | cannot use `+=` on type `()` + +error[E0067]: invalid left-hand side of assignment + --> $DIR/gather-locals-twice.rs:4:8 + | +LL | () += { let x; }; + | -- ^^ + | | + | cannot assign to this expression + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0067, E0368. +For more information about an error, try `rustc --explain E0067`.