about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-02-22 01:39:41 +0000
committerMichael Goulet <michael@errs.io>2023-02-24 02:53:25 +0000
commited30efff3b2d9e4636d3b1b9e9dc275362b64a62 (patch)
tree4f255fca234a2179e7800078900efb3eb178a4d9
parent2540c2b76138b988629b48f54381835f13f18792 (diff)
downloadrust-ed30efff3b2d9e4636d3b1b9e9dc275362b64a62.tar.gz
rust-ed30efff3b2d9e4636d3b1b9e9dc275362b64a62.zip
Comments, another test
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs43
-rw-r--r--tests/ui/traits/new-solver/more-object-bound.rs27
-rw-r--r--tests/ui/traits/new-solver/more-object-bound.stderr19
3 files changed, 87 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
index bd4950d8067..9b6cce86fff 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -235,6 +235,40 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     }
 }
 
+/// Assemble a list of predicates that would be present on a theoretical
+/// user impl for an object type. These predicates must be checked any time
+/// we assemble a built-in object candidate for an object type, since they
+/// are not implied by the well-formedness of the type.
+///
+/// For example, given the following traits:
+///
+/// ```rust,ignore (theoretical code)
+/// trait Foo: Baz {
+///     type Bar: Copy;
+/// }
+///
+/// trait Baz {}
+/// ```
+///
+/// For the dyn type `dyn Foo<Item = Ty>`, we can imagine there being a
+/// pair of theoretical impls:
+///
+/// ```rust,ignore (theoretical code)
+/// impl Foo for dyn Foo<Item = Ty>
+/// where
+///     Self: Baz,
+///     <Self as Foo>::Bar: Copy,
+/// {
+///     type Bar = Ty;
+/// }
+///
+/// impl Baz for dyn Foo<Item = Ty> {}
+/// ```
+///
+/// However, in order to make such impls well-formed, we need to do an
+/// additional step of eagerly folding the associated types in the where
+/// clauses of the impl. In this example, that means replacing
+/// `<Self as Foo>::Bar` with `Ty` in the first impl.
 pub(crate) fn predicates_for_object_candidate<'tcx>(
     ecx: &EvalCtxt<'_, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -247,6 +281,8 @@ pub(crate) fn predicates_for_object_candidate<'tcx>(
         tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.substs).predicates,
     );
     for item in tcx.associated_items(trait_ref.def_id).in_definition_order() {
+        // FIXME(associated_const_equality): Also add associated consts to
+        // the requirements here.
         if item.kind == ty::AssocKind::Type {
             requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs));
         }
@@ -290,13 +326,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
         if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
             && let Some(replacement) = self.mapping.get(&alias_ty.def_id)
         {
+            // We may have a case where our object type's projection bound is higher-ranked,
+            // but the where clauses we instantiated are not. We can solve this by instantiating
+            // the binder at the usage site.
             let proj = self.ecx.instantiate_binder_with_infer(*replacement);
-            // Technically this folder could be fallible?
+            // FIXME: Technically this folder could be fallible?
             let nested = self
                 .ecx
                 .eq(self.param_env, alias_ty, proj.projection_ty)
                 .expect("expected to be able to unify goal projection with dyn's projection");
-            // Technically we could register these too..
+            // FIXME: Technically we could register these too..
             assert!(nested.is_empty(), "did not expect unification to have any nested goals");
             proj.term.ty().unwrap()
         } else {
diff --git a/tests/ui/traits/new-solver/more-object-bound.rs b/tests/ui/traits/new-solver/more-object-bound.rs
new file mode 100644
index 00000000000..712759ef0e6
--- /dev/null
+++ b/tests/ui/traits/new-solver/more-object-bound.rs
@@ -0,0 +1,27 @@
+// compile-flags: -Ztrait-solver=next
+// From #80800
+
+trait SuperTrait {
+    type A;
+    type B;
+}
+
+trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
+
+fn transmute<A, B>(x: A) -> B {
+    foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    //~^ ERROR type annotations needed: cannot satisfy `dyn Trait<A = A, B = B>: Trait`
+}
+
+fn foo<A, B, T: ?Sized>(x: T::A) -> B
+where
+    T: Trait<B = B>,
+{
+    x
+}
+
+static X: u8 = 0;
+fn main() {
+    let x = transmute::<&u8, &[u8; 1_000_000]>(&X);
+    println!("{:?}", x[100_000]);
+}
diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr
new file mode 100644
index 00000000000..208fdecb08f
--- /dev/null
+++ b/tests/ui/traits/new-solver/more-object-bound.stderr
@@ -0,0 +1,19 @@
+error[E0283]: type annotations needed: cannot satisfy `dyn Trait<A = A, B = B>: Trait`
+  --> $DIR/more-object-bound.rs:12:5
+   |
+LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: cannot satisfy `dyn Trait<A = A, B = B>: Trait`
+note: required by a bound in `foo`
+  --> $DIR/more-object-bound.rs:18:8
+   |
+LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B
+   |    --- required by a bound in this function
+LL | where
+LL |     T: Trait<B = B>,
+   |        ^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.