Skip to content

Commit e2c5867

Browse files
authored
Rollup merge of rust-lang#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`
2 parents 0d2de94 + 8d2dbba commit e2c5867

File tree

5 files changed

+114
-24
lines changed

5 files changed

+114
-24
lines changed

compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,19 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
2424
| ty::FnDef(..)
2525
| ty::FnPtr(_)
2626
| ty::Error(_)
27-
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
2827
| ty::Never
2928
| ty::Char => Ok(vec![]),
3029

31-
// Treat this like `struct str([u8]);`
30+
// Treat `str` like it's defined as `struct str([u8]);`
3231
ty::Str => Ok(vec![tcx.mk_slice(tcx.types.u8)]),
3332

3433
ty::Dynamic(..)
3534
| ty::Param(..)
3635
| ty::Foreign(..)
3736
| ty::Alias(ty::Projection, ..)
38-
| ty::Placeholder(..) => Err(NoSolution),
39-
40-
ty::Bound(..)
41-
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
37+
| ty::Placeholder(..)
38+
| ty::Bound(..)
39+
| ty::Infer(_) => {
4240
bug!("unexpected type `{ty}`")
4341
}
4442

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+60-18
Original file line numberDiff line numberDiff line change
@@ -147,24 +147,66 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
147147
ecx: &mut EvalCtxt<'_, 'tcx>,
148148
goal: Goal<'tcx, Self>,
149149
) -> QueryResult<'tcx> {
150-
// This differs from the current stable behavior and
151-
// fixes #84857. Due to breakage found via crater, we
152-
// currently instead lint patterns which can be used to
153-
// exploit this unsoundness on stable, see #93367 for
154-
// more details.
155-
//
156-
// Using `TreatProjections::NextSolverLookup` is fine here because
157-
// `instantiate_constituent_tys_for_auto_trait` returns nothing for
158-
// projection types anyways. So it doesn't really matter what we do
159-
// here, and this is faster.
160-
if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
161-
goal.predicate.def_id(),
162-
goal.predicate.self_ty(),
163-
TreatProjections::NextSolverLookup,
164-
Some,
165-
) {
166-
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
167-
return Err(NoSolution);
150+
let self_ty = goal.predicate.self_ty();
151+
match *self_ty.kind() {
152+
// Stall int and float vars until they are resolved to a concrete
153+
// numerical type. That's because the check for impls below treats
154+
// int vars as matching any impl. Even if we filtered such impls,
155+
// we probably don't want to treat an `impl !AutoTrait for i32` as
156+
// disqualifying the built-in auto impl for `i64: AutoTrait` either.
157+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
158+
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
159+
}
160+
161+
// These types cannot be structurally decomposed into constitutent
162+
// types, and therefore have no builtin impl.
163+
ty::Dynamic(..)
164+
| ty::Param(..)
165+
| ty::Foreign(..)
166+
| ty::Alias(ty::Projection, ..)
167+
| ty::Placeholder(..) => return Err(NoSolution),
168+
169+
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
170+
171+
// For rigid types, we only register a builtin auto implementation
172+
// if there is no implementation that could ever apply to the self
173+
// type.
174+
//
175+
// This differs from the current stable behavior and fixes #84857.
176+
// Due to breakage found via crater, we currently instead lint
177+
// patterns which can be used to exploit this unsoundness on stable,
178+
// see #93367 for more details.
179+
ty::Bool
180+
| ty::Char
181+
| ty::Int(_)
182+
| ty::Uint(_)
183+
| ty::Float(_)
184+
| ty::Str
185+
| ty::Array(_, _)
186+
| ty::Slice(_)
187+
| ty::RawPtr(_)
188+
| ty::Ref(_, _, _)
189+
| ty::FnDef(_, _)
190+
| ty::FnPtr(_)
191+
| ty::Closure(_, _)
192+
| ty::Generator(_, _, _)
193+
| ty::GeneratorWitness(_)
194+
| ty::GeneratorWitnessMIR(_, _)
195+
| ty::Never
196+
| ty::Tuple(_)
197+
| ty::Error(_)
198+
| ty::Adt(_, _)
199+
| ty::Alias(ty::Opaque, _) => {
200+
if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
201+
goal.predicate.def_id(),
202+
goal.predicate.self_ty(),
203+
TreatProjections::NextSolverLookup,
204+
Some,
205+
) {
206+
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
207+
return Err(NoSolution);
208+
}
209+
}
168210
}
169211

170212
ecx.probe_and_evaluate_goal_for_constituent_tys(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
fn needs_send(_: impl Send) {}
5+
6+
fn main() {
7+
needs_send(1);
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0277]: the trait bound `i32: Foo` is not satisfied
2+
--> $DIR/stall-num-var-auto-trait.rs:18:15
3+
|
4+
LL | needs_foo(x);
5+
| --------- ^ the trait `Foo` is not implemented for `i32`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required by a bound in `needs_foo`
10+
--> $DIR/stall-num-var-auto-trait.rs:14:22
11+
|
12+
LL | fn needs_foo(x: impl Foo) {}
13+
| ^^^ required by this bound in `needs_foo`
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// revisions: fallback constrain
3+
//[constrain] check-pass
4+
5+
// Tests that we stall the `{integer}: Foo` obligation until after we
6+
// constrain the int type (or fallback occurs).
7+
8+
#![feature(negative_impls, auto_traits)]
9+
10+
auto trait Foo {}
11+
12+
impl !Foo for i32 {}
13+
14+
fn needs_foo(x: impl Foo) {}
15+
16+
fn main() {
17+
let mut x = 0;
18+
needs_foo(x);
19+
//[fallback]~^ ERROR the trait bound `i32: Foo` is not satisfied
20+
21+
#[cfg(constrain)]
22+
{
23+
x = 1u64;
24+
}
25+
}

0 commit comments

Comments
 (0)