about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs7
-rw-r--r--tests/ui/pattern/slice-pattern-refutable.stderr12
-rw-r--r--tests/ui/pattern/slice-patterns-ambiguity.stderr14
4 files changed, 33 insertions, 26 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index d6948081505..364499378b0 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -146,18 +146,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag());
         let mut typeck = self.typeck_results.borrow_mut();
         let mut node_ty = typeck.node_types_mut();
-        if let Some(ty) = node_ty.get(id)
-            && let Err(e) = ty.error_reported()
-        {
-            // Do not overwrite nodes that were already marked as `{type error}`. This allows us to
-            // silence unnecessary errors from obligations that were set earlier than a type error
-            // was produced, but that is overwritten by later analysis. This happens in particular
-            // for `Sized` obligations introduced in gather_locals. (#117846)
-            self.set_tainted_by_errors(e);
-            return;
-        }
 
-        node_ty.insert(id, ty);
+        if let Some(prev) = node_ty.insert(id, ty) {
+            if prev.references_error() {
+                node_ty.insert(id, prev);
+            } else if !ty.references_error() {
+                // Could change this to a bug, but there's lots of diagnostic code re-lowering
+                // or re-typechecking nodes that were already typecked.
+                // Lots of that diagnostics code relies on subtle effects of re-lowering, so we'll
+                // let it keep doing that and just ensure that compilation won't succeed.
+                self.dcx().span_delayed_bug(
+                    self.tcx.hir().span(id),
+                    format!("`{prev}` overridden by `{ty}` for {id:?} in {:?}", self.body_id),
+                );
+            }
+        }
 
         if let Err(e) = ty.error_reported() {
             self.set_tainted_by_errors(e);
@@ -1104,7 +1107,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let Res::Local(hid) = res {
             let ty = self.local_ty(span, hid);
             let ty = self.normalize(span, ty);
-            self.write_ty(hir_id, ty);
             return (ty, res);
         }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index c1f08d237eb..fffea8f640b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1750,10 +1750,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
+    pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) -> Ty<'tcx> {
         // Determine and write the type which we'll check the pattern against.
         let decl_ty = self.local_ty(decl.span, decl.hir_id);
-        self.write_ty(decl.hir_id, decl_ty);
 
         // Type check the initializer.
         if let Some(ref init) = decl.init {
@@ -1785,11 +1784,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             self.diverges.set(previous_diverges);
         }
+        decl_ty
     }
 
     /// Type check a `let` statement.
     fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
-        self.check_decl(local.into());
+        let ty = self.check_decl(local.into());
+        self.write_ty(local.hir_id, ty);
         if local.pat.is_never_pattern() {
             self.diverges.set(Diverges::Always {
                 span: local.pat.span,
diff --git a/tests/ui/pattern/slice-pattern-refutable.stderr b/tests/ui/pattern/slice-pattern-refutable.stderr
index df5b58d3e9c..3d9f769d134 100644
--- a/tests/ui/pattern/slice-pattern-refutable.stderr
+++ b/tests/ui/pattern/slice-pattern-refutable.stderr
@@ -1,13 +1,15 @@
 error[E0282]: type annotations needed
-  --> $DIR/slice-pattern-refutable.rs:14:9
+  --> $DIR/slice-pattern-refutable.rs:14:28
    |
 LL |     let [a, b, c] = Zeroes.into() else {
-   |         ^^^^^^^^^
+   |         ---------          ^^^^
+   |         |
+   |         type must be known at this point
    |
-help: consider giving this pattern a type
+help: try using a fully qualified path to specify the expected types
    |
-LL |     let [a, b, c]: /* Type */ = Zeroes.into() else {
-   |                  ++++++++++++
+LL |     let [a, b, c] = <Zeroes as Into<T>>::into(Zeroes) else {
+   |                     ++++++++++++++++++++++++++      ~
 
 error[E0282]: type annotations needed
   --> $DIR/slice-pattern-refutable.rs:21:31
diff --git a/tests/ui/pattern/slice-patterns-ambiguity.stderr b/tests/ui/pattern/slice-patterns-ambiguity.stderr
index 3ef99d0e2d1..690776196ce 100644
--- a/tests/ui/pattern/slice-patterns-ambiguity.stderr
+++ b/tests/ui/pattern/slice-patterns-ambiguity.stderr
@@ -1,13 +1,15 @@
-error[E0282]: type annotations needed for `&_`
-  --> $DIR/slice-patterns-ambiguity.rs:25:9
+error[E0282]: type annotations needed
+  --> $DIR/slice-patterns-ambiguity.rs:25:26
    |
 LL |     let &[a, b] = Zeroes.into() else {
-   |         ^^^^^^^
+   |          ------          ^^^^
+   |          |
+   |          type must be known at this point
    |
-help: consider giving this pattern a type, where the placeholders `_` are specified
+help: try using a fully qualified path to specify the expected types
    |
-LL |     let &[a, b]: &_ = Zeroes.into() else {
-   |                ++++
+LL |     let &[a, b] = <Zeroes as Into<&_>>::into(Zeroes) else {
+   |                   +++++++++++++++++++++++++++      ~
 
 error[E0282]: type annotations needed
   --> $DIR/slice-patterns-ambiguity.rs:32:29