about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/writeback.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs46
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr14
5 files changed, 55 insertions, 23 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_analysis/src/check/writeback.rs
index 9aeee091fdd..e3e4a934ab5 100644
--- a/compiler/rustc_hir_analysis/src/check/writeback.rs
+++ b/compiler/rustc_hir_analysis/src/check/writeback.rs
@@ -560,13 +560,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 continue;
             }
 
-            let hidden_type = hidden_type
-                .remap_generic_params_to_declaration_params(
-                    opaque_type_key,
-                    self.fcx.infcx.tcx,
-                    true,
-                )
-                .ty;
+            let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
+                opaque_type_key,
+                self.fcx.infcx.tcx,
+                true,
+            );
 
             self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index ad9b124c8ab..0a69f965e75 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -564,6 +564,11 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
         /// checked against it (we also carry the span of that first
         /// type).
         found: Option<ty::OpaqueHiddenType<'tcx>>,
+
+        /// In the presence of dead code, typeck may figure out a hidden type
+        /// while borrowck will now. We collect these cases here and check at
+        /// the end that we actually found a type that matches (modulo regions).
+        typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
     }
 
     impl ConstraintLocator<'_> {
@@ -590,18 +595,23 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
                 self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
                 return;
             }
-            if !tables.concrete_opaque_types.contains_key(&self.def_id) {
+            let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
                 debug!("no constraints in typeck results");
                 return;
+            };
+            if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) {
+                self.typeck_types.push(typeck_hidden_ty);
             }
+
             // Use borrowck to get the type with unerased regions.
             let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
             debug!(?concrete_opaque_types);
             if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
                 debug!(?concrete_type, "found constraint");
-                if let Some(prev) = self.found {
-                    if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
+                if let Some(prev) = &mut self.found {
+                    if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
                         prev.report_mismatch(&concrete_type, self.tcx);
+                        prev.ty = self.tcx.ty_error();
                     }
                 } else {
                     self.found = Some(concrete_type);
@@ -648,7 +658,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let scope = tcx.hir().get_defining_scope(hir_id);
-    let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None };
+    let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] };
 
     debug!(?scope);
 
@@ -678,16 +688,26 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
         }
     }
 
-    match locator.found {
-        Some(hidden) => hidden.ty,
-        None => {
-            tcx.sess.emit_err(UnconstrainedOpaqueType {
-                span: tcx.def_span(def_id),
-                name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
-            });
-            tcx.ty_error()
+    let Some(hidden) = locator.found else {
+        tcx.sess.emit_err(UnconstrainedOpaqueType {
+            span: tcx.def_span(def_id),
+            name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
+        });
+        return tcx.ty_error();
+    };
+
+    // Only check against typeck if we didn't already error
+    if !hidden.ty.references_error() {
+        for concrete_type in locator.typeck_types {
+            if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
+                && !(concrete_type, hidden).references_error()
+            {
+                hidden.report_mismatch(&concrete_type, tcx);
+            }
         }
     }
+
+    hidden.ty
 }
 
 fn find_opaque_ty_constraints_for_rpit(
@@ -788,7 +808,7 @@ fn find_opaque_ty_constraints_for_rpit(
             // the `concrete_opaque_types` table.
             tcx.ty_error()
         } else {
-            table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| {
+            table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
                 // We failed to resolve the opaque type or it
                 // resolves to itself. We interpret this as the
                 // no values of the hidden type ever being constructed,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8277d141358..8a9160d2466 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -542,7 +542,7 @@ pub struct TypeckResults<'tcx> {
     /// by this function. We also store the
     /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
     /// even if they are only set in dead code (which doesn't show up in MIR).
-    pub concrete_opaque_types: VecMap<LocalDefId, Ty<'tcx>>,
+    pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs
index 7740f774ebc..0b8157fe33d 100644
--- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs
+++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs
@@ -1,5 +1,5 @@
 #![feature(type_alias_impl_trait)]
-// check-pass
+
 fn main() {}
 
 // two definitions with different types
@@ -9,7 +9,7 @@ fn foo() -> Foo {
     ""
 }
 
-fn bar() -> Foo {
+fn bar() -> Foo { //~ ERROR: concrete type differs from previous defining opaque type use
     panic!()
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr
new file mode 100644
index 00000000000..09dadb0afce
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr
@@ -0,0 +1,14 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/different_defining_uses_never_type.rs:12:13
+   |
+LL | fn bar() -> Foo {
+   |             ^^^ expected `&'static str`, got `()`
+   |
+note: previous use here
+  --> $DIR/different_defining_uses_never_type.rs:9:5
+   |
+LL |     ""
+   |     ^^
+
+error: aborting due to previous error
+