about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-05-26 03:47:27 +0000
committerMichael Goulet <michael@errs.io>2023-05-26 14:42:52 +0000
commit3d09b990d7e3d8539a3b9655894e7e05dcc9ebf2 (patch)
treedfa6749ec2e57eb37209bcda7db1a849247534d2
parenta810b584cf7bf6f3d0eb02cef441b510475514f9 (diff)
downloadrust-3d09b990d7e3d8539a3b9655894e7e05dcc9ebf2.tar.gz
rust-3d09b990d7e3d8539a3b9655894e7e05dcc9ebf2.zip
Wait until type_of to remap HIR opaques back to their defn params
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs94
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs12
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs2
-rw-r--r--tests/ui/traits/new-solver/dont-remap-tait-substs.rs19
-rw-r--r--tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr11
7 files changed, 92 insertions, 55 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 51a84ce6cad..b759a848bf5 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -188,9 +188,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
 
     // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
     // predefined opaques in the typeck root.
-    // FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since
-    // the HIR typeck map defining usages back to their definition params,
-    // they won't actually match up with the usages in this body...
     if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
         checker.register_predefined_opaques_in_new_solver();
     }
@@ -1042,10 +1039,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             .typeck(self.body.source.def_id().expect_local())
             .concrete_opaque_types
             .iter()
-            .map(|(&def_id, &hidden_ty)| {
-                let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id);
-                (ty::OpaqueTypeKey { def_id, substs }, hidden_ty)
-            })
+            .map(|(k, v)| (*k, *v))
             .collect();
 
         let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index f7c5b44678f..da82ce1d523 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -59,7 +59,20 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
         }
     }
 
-    let Some(hidden) = locator.found else {
+    if let Some(hidden) = locator.found {
+        // Only check against typeck if we didn't already error
+        if !hidden.ty.references_error() {
+            for concrete_type in locator.typeck_types {
+                if concrete_type.ty != tcx.erase_regions(hidden.ty)
+                    && !(concrete_type, hidden).references_error()
+                {
+                    hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
+                }
+            }
+        }
+
+        hidden.ty
+    } else {
         let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
             name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
@@ -70,21 +83,8 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
                 _ => "item",
             },
         });
-        return tcx.ty_error(reported);
-    };
-
-    // Only check against typeck if we didn't already error
-    if !hidden.ty.references_error() {
-        for concrete_type in locator.typeck_types {
-            if concrete_type.ty != tcx.erase_regions(hidden.ty)
-                && !(concrete_type, hidden).references_error()
-            {
-                hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
-            }
-        }
+        tcx.ty_error(reported)
     }
-
-    hidden.ty
 }
 
 struct TaitConstraintLocator<'tcx> {
@@ -130,13 +130,28 @@ impl TaitConstraintLocator<'_> {
             self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
             return;
         }
-        let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
+
+        let mut constrained = false;
+        for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
+            if opaque_type_key.def_id != self.def_id {
+                continue;
+            }
+            constrained = true;
+            let concrete_type =
+                self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
+                    opaque_type_key,
+                    self.tcx,
+                    true,
+                ));
+            if self.typeck_types.iter().all(|prev| prev.ty != concrete_type.ty) {
+                self.typeck_types.push(concrete_type);
+            }
+        }
+
+        if !constrained {
             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;
@@ -190,8 +205,8 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
     }
 }
 
-pub(super) fn find_opaque_ty_constraints_for_rpit(
-    tcx: TyCtxt<'_>,
+pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
+    tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     owner_def_id: LocalDefId,
 ) -> Ty<'_> {
@@ -208,17 +223,40 @@ pub(super) fn find_opaque_ty_constraints_for_rpit(
             Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
             other => bug!("{:?} is not a valid scope for an opaque type item", other),
         }
-    }
 
-    concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
-        let table = tcx.typeck(owner_def_id);
-        if let Some(guar) = table.tainted_by_errors {
+        concrete.ty
+    } else {
+        let tables = tcx.typeck(owner_def_id);
+        if let Some(guar) = tables.tainted_by_errors {
             // Some error in the
             // owner fn prevented us from populating
             // the `concrete_opaque_types` table.
             tcx.ty_error(guar)
         } else {
-            table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
+            // Fall back to the RPIT we inferred during HIR typeck
+            let mut opaque_ty: Option<ty::OpaqueHiddenType<'tcx>> = None;
+            for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
+                if opaque_type_key.def_id != def_id {
+                    continue;
+                }
+                let concrete_type =
+                    tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
+                        opaque_type_key,
+                        tcx,
+                        true,
+                    ));
+                if let Some(prev) = &mut opaque_ty {
+                    if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
+                        prev.report_mismatch(&concrete_type, def_id, tcx).emit();
+                    }
+                } else {
+                    opaque_ty = Some(concrete_type);
+                }
+            }
+
+            if let Some(opaque_ty) = opaque_ty {
+                opaque_ty.ty
+            } 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,
@@ -226,9 +264,9 @@ pub(super) fn find_opaque_ty_constraints_for_rpit(
                 // For backwards compatibility reasons, we fall back to
                 // `()` until we the diverging default is changed.
                 tcx.mk_diverging_default()
-            })
+            }
         }
-    })
+    }
 }
 
 struct RpitConstraintChecker<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0f21fc1e662..964acc4eb77 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -583,19 +583,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 continue;
             }
 
-            let hidden_type =
-                self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
-                    opaque_type_key,
-                    self.tcx(),
-                    true,
-                ));
-
+            // Here we only detect impl trait definition conflicts when they
+            // are equal modulo regions.
             if let Some(last_opaque_ty) = self
                 .typeck_results
                 .concrete_opaque_types
-                .insert(opaque_type_key.def_id, hidden_type)
+                .insert(opaque_type_key, hidden_type)
                 && last_opaque_ty.ty != hidden_type.ty
             {
+                assert!(!self.tcx().trait_solver_next());
                 hidden_type
                     .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
                     .stash(
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index e04dbbff9a7..68bae5828c5 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -159,7 +159,7 @@ pub struct TypeckResults<'tcx> {
     /// These types are mapped back to the opaque's identity substitutions
     /// (with erased regions), which is why we don't associated substs with any
     /// of these usages.
-    pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+    pub concrete_opaque_types: FxIndexMap<ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
diff --git a/tests/ui/traits/new-solver/dont-remap-tait-substs.rs b/tests/ui/traits/new-solver/dont-remap-tait-substs.rs
new file mode 100644
index 00000000000..028222f4e6d
--- /dev/null
+++ b/tests/ui/traits/new-solver/dont-remap-tait-substs.rs
@@ -0,0 +1,19 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+// Makes sure we don't prepopulate the MIR typeck of `define`
+// with `Foo<T, U> = T`, but instead, `Foo<B, A> = B`, so that
+// the param-env predicates actually apply.
+
+#![feature(type_alias_impl_trait)]
+
+type Foo<T: Send, U> = impl NeedsSend<T>;
+
+trait NeedsSend<T> {}
+impl<T: Send> NeedsSend<T> for T {}
+
+fn define<A, B: Send>(a: A, b: B) {
+    let y: Option<Foo<B, A>> = Some(b);
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
index 9ae2c34b935..da845e86147 100644
--- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
+++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
@@ -8,7 +8,6 @@ type X<A, B> = impl Into<&'static A>;
 
 fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
     //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
-    //~| ERROR concrete type differs from previous defining opaque type use
     (a, a)
 }
 
diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
index 0d24d42ba62..66a6b0bbf74 100644
--- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
+++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
@@ -10,15 +10,6 @@ help: consider introducing a `where` clause, but there might be an alternative b
 LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
    |                                                                ++++++++++++++++++++++++++
 
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/multiple-def-uses-in-one-fn.rs:9:45
-   |
-LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
-   |                                             ^^^^^^^^^^^^^^^^^^
-   |                                             |
-   |                                             expected `&B`, got `&A`
-   |                                             this expression supplies two conflicting concrete types for the same opaque type
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.