about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <jtitor@2k36.org>2023-04-11 12:18:49 +0900
committerGitHub <noreply@github.com>2023-04-11 12:18:49 +0900
commita69cc45d8265e37646be24158137de5a428099ca (patch)
tree5381933b10ea99724dc1ab2b0283724ebd31c6c6
parentc617ddf4f32f2ac93b05017b8b1b4164b76b1ee1 (diff)
parent8d2dbba63eaa61252c4c533e1490ac75f97374b9 (diff)
downloadrust-a69cc45d8265e37646be24158137de5a428099ca.tar.gz
rust-a69cc45d8265e37646be24158137de5a428099ca.zip
Rollup merge of #109752 - compiler-errors:new-solver-stall-auto-trait-for-num-var, r=lcnr
Stall auto trait assembly in new solver for int/float vars

Make sure that we don't match int/float vars against *all* manual auto trait impls due to this check:

https://github.com/rust-lang/rust/blob/2fb0e8d162a021f8a795fb603f5d8c0017855160/compiler/rustc_trait_selection/src/solve/trait_goals.rs#L151-L169

Since `find_map_relevant_impl` treats all impls as candidates for int/float vars, due to the way that `fast_reject::simplify_type` works.

This fixes compiler-errors/next-solver-hir-issues#11.

r? ``@lcnr``
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs78
-rw-r--r--tests/ui/traits/new-solver/int-var-is-send.rs8
-rw-r--r--tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr17
-rw-r--r--tests/ui/traits/new-solver/stall-num-var-auto-trait.rs25
5 files changed, 114 insertions, 24 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index cbec39d8285..1a566e87dc8 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -24,21 +24,19 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::FnDef(..)
         | ty::FnPtr(_)
         | ty::Error(_)
-        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Never
         | ty::Char => Ok(vec![]),
 
-        // Treat this like `struct str([u8]);`
+        // Treat `str` like it's defined as `struct str([u8]);`
         ty::Str => Ok(vec![tcx.mk_slice(tcx.types.u8)]),
 
         ty::Dynamic(..)
         | ty::Param(..)
         | ty::Foreign(..)
         | ty::Alias(ty::Projection, ..)
-        | ty::Placeholder(..) => Err(NoSolution),
-
-        ty::Bound(..)
-        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+        | ty::Placeholder(..)
+        | ty::Bound(..)
+        | ty::Infer(_) => {
             bug!("unexpected type `{ty}`")
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 81f89fd950c..cb7cf9b936c 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -147,24 +147,66 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        // This differs from the current stable behavior and
-        // fixes #84857. Due to breakage found via crater, we
-        // currently instead lint patterns which can be used to
-        // exploit this unsoundness on stable, see #93367 for
-        // more details.
-        //
-        // Using `TreatProjections::NextSolverLookup` is fine here because
-        // `instantiate_constituent_tys_for_auto_trait` returns nothing for
-        // projection types anyways. So it doesn't really matter what we do
-        // here, and this is faster.
-        if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
-            goal.predicate.def_id(),
-            goal.predicate.self_ty(),
-            TreatProjections::NextSolverLookup,
-            Some,
-        ) {
-            debug!(?def_id, ?goal, "disqualified auto-trait implementation");
-            return Err(NoSolution);
+        let self_ty = goal.predicate.self_ty();
+        match *self_ty.kind() {
+            // Stall int and float vars until they are resolved to a concrete
+            // numerical type. That's because the check for impls below treats
+            // int vars as matching any impl. Even if we filtered such impls,
+            // we probably don't want to treat an `impl !AutoTrait for i32` as
+            // disqualifying the built-in auto impl for `i64: AutoTrait` either.
+            ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
+                return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+            }
+
+            // These types cannot be structurally decomposed into constitutent
+            // types, and therefore have no builtin impl.
+            ty::Dynamic(..)
+            | ty::Param(..)
+            | ty::Foreign(..)
+            | ty::Alias(ty::Projection, ..)
+            | ty::Placeholder(..) => return Err(NoSolution),
+
+            ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
+
+            // For rigid types, we only register a builtin auto implementation
+            // if there is no implementation that could ever apply to the self
+            // type.
+            //
+            // This differs from the current stable behavior and fixes #84857.
+            // Due to breakage found via crater, we currently instead lint
+            // patterns which can be used to exploit this unsoundness on stable,
+            // see #93367 for more details.
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Closure(_, _)
+            | ty::Generator(_, _, _)
+            | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(_, _)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Error(_)
+            | ty::Adt(_, _)
+            | ty::Alias(ty::Opaque, _) => {
+                if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
+                    goal.predicate.def_id(),
+                    goal.predicate.self_ty(),
+                    TreatProjections::NextSolverLookup,
+                    Some,
+                ) {
+                    debug!(?def_id, ?goal, "disqualified auto-trait implementation");
+                    return Err(NoSolution);
+                }
+            }
         }
 
         ecx.probe_and_evaluate_goal_for_constituent_tys(
diff --git a/tests/ui/traits/new-solver/int-var-is-send.rs b/tests/ui/traits/new-solver/int-var-is-send.rs
new file mode 100644
index 00000000000..083aa90e1f6
--- /dev/null
+++ b/tests/ui/traits/new-solver/int-var-is-send.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+fn needs_send(_: impl Send) {}
+
+fn main() {
+    needs_send(1);
+}
diff --git a/tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr b/tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr
new file mode 100644
index 00000000000..a3ab7836c19
--- /dev/null
+++ b/tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/stall-num-var-auto-trait.rs:18:15
+   |
+LL |     needs_foo(x);
+   |     --------- ^ the trait `Foo` is not implemented for `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_foo`
+  --> $DIR/stall-num-var-auto-trait.rs:14:22
+   |
+LL | fn needs_foo(x: impl Foo) {}
+   |                      ^^^ required by this bound in `needs_foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/stall-num-var-auto-trait.rs b/tests/ui/traits/new-solver/stall-num-var-auto-trait.rs
new file mode 100644
index 00000000000..0539c3a4292
--- /dev/null
+++ b/tests/ui/traits/new-solver/stall-num-var-auto-trait.rs
@@ -0,0 +1,25 @@
+// compile-flags: -Ztrait-solver=next
+// revisions: fallback constrain
+//[constrain] check-pass
+
+// Tests that we stall the `{integer}: Foo` obligation until after we
+// constrain the int type (or fallback occurs).
+
+#![feature(negative_impls, auto_traits)]
+
+auto trait Foo {}
+
+impl !Foo for i32 {}
+
+fn needs_foo(x: impl Foo) {}
+
+fn main() {
+    let mut x = 0;
+    needs_foo(x);
+    //[fallback]~^ ERROR the trait bound `i32: Foo` is not satisfied
+
+    #[cfg(constrain)]
+    {
+        x = 1u64;
+    }
+}