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; + } +}