about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-17 01:06:36 +0000
committerbors <bors@rust-lang.org>2023-07-17 01:06:36 +0000
commit4c7af429f3122cbde3df648783e9b4d31cd62525 (patch)
tree6bbf42943909e40177cb55bbd7be2fce0e54ef46
parentf1eab64d4f7ece5eead36098cdaeb1a8f0d5405c (diff)
parentc9ce51b5c78541bef1a3b3de61655629deef77b1 (diff)
downloadrust-4c7af429f3122cbde3df648783e9b4d31cd62525.tar.gz
rust-4c7af429f3122cbde3df648783e9b4d31cd62525.zip
Auto merge of #113336 - compiler-errors:new-solver-iat, r=lcnr
Add support for inherent projections in new solver

Not hard to support these, and it cuts out a really big chunk of failing UI tests with `--compare-mode=next-solver`

r? `@lcnr` (feel free to reassign, anyone can review this)
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/inherent_projection.rs44
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs18
-rw-r--r--compiler/rustc_trait_selection/src/solve/weak_types.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs16
-rw-r--r--tests/ui/associated-inherent-types/inference.rs2
-rw-r--r--tests/ui/traits/new-solver/alias-bound-unsound.rs9
-rw-r--r--tests/ui/traits/new-solver/alias-bound-unsound.stderr65
9 files changed, 154 insertions, 13 deletions
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 66d8a79de42..cdb0b2240a4 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1313,7 +1313,7 @@ impl<'tcx> AliasTy<'tcx> {
     ///     I_i impl subst
     ///     P_j GAT subst
     /// ```
-    pub fn rebase_args_onto_impl(
+    pub fn rebase_inherent_args_onto_impl(
         self,
         impl_args: ty::GenericArgsRef<'tcx>,
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/inherent_projection.rs
new file mode 100644
index 00000000000..d10a14ff742
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/inherent_projection.rs
@@ -0,0 +1,44 @@
+use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::ty;
+
+use super::EvalCtxt;
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    pub(super) fn normalize_inherent_associated_type(
+        &mut self,
+        goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        let tcx = self.tcx();
+        let inherent = goal.predicate.projection_ty;
+        let expected = goal.predicate.term.ty().expect("inherent consts are treated separately");
+
+        let impl_def_id = tcx.parent(inherent.def_id);
+        let impl_substs = self.fresh_args_for_item(impl_def_id);
+
+        // Equate impl header and add impl where clauses
+        self.eq(
+            goal.param_env,
+            inherent.self_ty(),
+            tcx.type_of(impl_def_id).instantiate(tcx, impl_substs),
+        )?;
+
+        // Equate IAT with the RHS of the project goal
+        let inherent_substs = inherent.rebase_inherent_args_onto_impl(impl_substs, tcx);
+        self.eq(
+            goal.param_env,
+            expected,
+            tcx.type_of(inherent.def_id).instantiate(tcx, inherent_substs),
+        )
+        .expect("expected goal term to be fully unconstrained");
+
+        // Check both where clauses on the impl and IAT
+        self.add_goals(
+            tcx.predicates_of(inherent.def_id)
+                .instantiate(tcx, inherent_substs)
+                .into_iter()
+                .map(|(pred, _)| goal.with(tcx, pred)),
+        );
+
+        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 1d9c975a97a..7c15c3c0e8b 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -25,6 +25,7 @@ mod assembly;
 mod canonicalize;
 mod eval_ctxt;
 mod fulfill;
+mod inherent_projection;
 pub mod inspect;
 mod normalize;
 mod opaques;
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 564451a31ed..d677fbdc7f4 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -48,7 +48,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                             self.merge_candidates(candidates)
                         }
                         ty::AssocItemContainer::ImplContainer => {
-                            bug!("IATs not supported here yet")
+                            self.normalize_inherent_associated_type(goal)
                         }
                     }
                 } else {
@@ -112,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
     ) -> QueryResult<'tcx> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
             if projection_pred.projection_def_id() == goal.predicate.def_id() {
+                let tcx = ecx.tcx();
                 ecx.probe_candidate("assumption").enter(|ecx| {
                     let assumption_projection_pred =
                         ecx.instantiate_binder_with_infer(projection_pred);
@@ -122,6 +123,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                     )?;
                     ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
                         .expect("expected goal term to be fully unconstrained");
+
+                    // Add GAT where clauses from the trait's definition
+                    ecx.add_goals(
+                        tcx.predicates_of(goal.predicate.def_id())
+                            .instantiate_own(tcx, goal.predicate.projection_ty.args)
+                            .map(|(pred, _)| goal.with(tcx, pred)),
+                    );
+
                     then(ecx)
                 })
             } else {
@@ -160,6 +169,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 .map(|pred| goal.with(tcx, pred));
             ecx.add_goals(where_clause_bounds);
 
+            // Add GAT where clauses from the trait's definition
+            ecx.add_goals(
+                tcx.predicates_of(goal.predicate.def_id())
+                    .instantiate_own(tcx, goal.predicate.projection_ty.args)
+                    .map(|(pred, _)| goal.with(tcx, pred)),
+            );
+
             // In case the associated item is hidden due to specialization, we have to
             // return ambiguity this would otherwise be incomplete, resulting in
             // unsoundness during coherence (#105782).
diff --git a/compiler/rustc_trait_selection/src/solve/weak_types.rs b/compiler/rustc_trait_selection/src/solve/weak_types.rs
index 2c176d4cfd6..c7717879a4a 100644
--- a/compiler/rustc_trait_selection/src/solve/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/weak_types.rs
@@ -14,6 +14,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
         self.eq(goal.param_env, expected, actual)?;
+
+        // Check where clauses
+        self.add_goals(
+            tcx.predicates_of(weak_ty.def_id)
+                .instantiate(tcx, weak_ty.args)
+                .predicates
+                .into_iter()
+                .map(|pred| goal.with(tcx, pred)),
+        );
+
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index e137ed9cda8..a39fc1f1771 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1402,9 +1402,17 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
     let impl_def_id = tcx.parent(alias_ty.def_id);
     let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id);
 
-    let impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
-    let impl_ty =
-        normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
+    let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
+    if !selcx.infcx.next_trait_solver() {
+        impl_ty = normalize_with_depth_to(
+            selcx,
+            param_env,
+            cause.clone(),
+            depth + 1,
+            impl_ty,
+            obligations,
+        );
+    }
 
     // Infer the generic parameters of the impl by unifying the
     // impl type with the self type of the projection.
@@ -1421,7 +1429,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
         }
     }
 
-    alias_ty.rebase_args_onto_impl(impl_args, tcx)
+    alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx)
 }
 
 enum Projected<'tcx> {
diff --git a/tests/ui/associated-inherent-types/inference.rs b/tests/ui/associated-inherent-types/inference.rs
index ebd8e1d5594..66f879c5a71 100644
--- a/tests/ui/associated-inherent-types/inference.rs
+++ b/tests/ui/associated-inherent-types/inference.rs
@@ -1,5 +1,7 @@
 // Testing inference capabilities.
 // check-pass
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
 
 #![feature(inherent_associated_types)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs
index 959f1afa04e..38d83d289f1 100644
--- a/tests/ui/traits/new-solver/alias-bound-unsound.rs
+++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs
@@ -16,12 +16,17 @@ trait Foo {
 
 impl Foo for () {
     type Item = String where String: Copy;
+    //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy`
 }
 
 fn main() {
     let x = String::from("hello, world");
     drop(<() as Foo>::copy_me(&x));
-    //~^ ERROR the type `&<() as Foo>::Item` is not well-formed
-    //~| ERROR `<() as Foo>::Item` is not well-formed
+    //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized`
+    //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
+    //~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed`
+    //~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item`
+    //~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed`
+    //~| ERROR type annotations needed
     println!("{x}");
 }
diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr
index 5800e2c4340..abc6677c132 100644
--- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr
+++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr
@@ -1,14 +1,69 @@
-error: the type `&<() as Foo>::Item` is not well-formed
-  --> $DIR/alias-bound-unsound.rs:23:31
+error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy`
+  --> $DIR/alias-bound-unsound.rs:18:17
+   |
+LL |     type Item = String where String: Copy;
+   |                 ^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
+note: required by a bound in `Foo::Item`
+  --> $DIR/alias-bound-unsound.rs:8:16
+   |
+LL |     type Item: Copy
+   |                ^^^^ required by this bound in `Foo::Item`
+
+error[E0282]: type annotations needed
+  --> $DIR/alias-bound-unsound.rs:24:5
+   |
+LL |     drop(<() as Foo>::copy_me(&x));
+   |     ^^^^ cannot infer type of the type parameter `T` declared on the function `drop`
+   |
+help: consider specifying the generic argument
+   |
+LL |     drop::<T>(<() as Foo>::copy_me(&x));
+   |         +++++
+
+error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed`
+  --> $DIR/alias-bound-unsound.rs:24:31
    |
 LL |     drop(<() as Foo>::copy_me(&x));
    |                               ^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
 
-error: the type `<() as Foo>::Item` is not well-formed
-  --> $DIR/alias-bound-unsound.rs:23:10
+error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item`
+  --> $DIR/alias-bound-unsound.rs:24:31
+   |
+LL |     drop(<() as Foo>::copy_me(&x));
+   |                               ^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
+
+error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed`
+  --> $DIR/alias-bound-unsound.rs:24:10
+   |
+LL |     drop(<() as Foo>::copy_me(&x));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
+
+error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
+  --> $DIR/alias-bound-unsound.rs:24:10
    |
 LL |     drop(<() as Foo>::copy_me(&x));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
+
+error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Sized`
+  --> $DIR/alias-bound-unsound.rs:24:10
+   |
+LL |     drop(<() as Foo>::copy_me(&x));
+   |          ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
+   = note: the return type of a function must have a statically known size
 
-error: aborting due to 2 previous errors
+error: aborting due to 7 previous errors
 
+Some errors have detailed explanations: E0275, E0282.
+For more information about an error, try `rustc --explain E0275`.