Stall auto-trait assembly for int/float vars in new solver

This commit is contained in:
Michael Goulet 2023-04-03 23:24:47 +00:00
parent 2a198c7f62
commit 8d2dbba63e
5 changed files with 114 additions and 24 deletions

View File

@ -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}`")
}

View File

@ -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(

View File

@ -0,0 +1,8 @@
// compile-flags: -Ztrait-solver=next
// check-pass
fn needs_send(_: impl Send) {}
fn main() {
needs_send(1);
}

View File

@ -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`.

View File

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