Skip to content

Commit 0d71860

Browse files
committed
bye bye assemble_candidates_via_self_ty
1 parent fb4bca0 commit 0d71860

13 files changed

+129
-133
lines changed

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

+28-106
Original file line numberDiff line numberDiff line change
@@ -271,64 +271,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
271271
&mut self,
272272
goal: Goal<'tcx, G>,
273273
) -> Vec<Candidate<'tcx>> {
274-
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
275-
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
276-
return vec![ambig];
277-
}
278-
279-
let mut candidates = self.assemble_candidates_via_self_ty(goal, 0);
280-
281-
self.assemble_unsize_to_dyn_candidate(goal, &mut candidates);
282-
283-
self.assemble_blanket_impl_candidates(goal, &mut candidates);
284-
285-
self.assemble_param_env_candidates(goal, &mut candidates);
286-
287-
self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
288-
289-
candidates
290-
}
291-
292-
/// `?0: Trait` is ambiguous, because it may be satisfied via a builtin rule,
293-
/// object bound, alias bound, etc. We are unable to determine this until we can at
294-
/// least structurally resolve the type one layer.
295-
///
296-
/// It would also require us to consider all impls of the trait, which is both pretty
297-
/// bad for perf and would also constrain the self type if there is just a single impl.
298-
fn assemble_self_ty_infer_ambiguity_response<G: GoalKind<'tcx>>(
299-
&mut self,
300-
goal: Goal<'tcx, G>,
301-
) -> Option<Candidate<'tcx>> {
302-
if goal.predicate.self_ty().is_ty_var() {
303-
debug!("adding self_ty_infer_ambiguity_response");
274+
let dummy_candidate = |this: &mut EvalCtxt<'_, 'tcx>, certainty| {
304275
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
305-
let result = self
306-
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
307-
.unwrap();
308-
let mut dummy_probe = self.inspect.new_probe();
276+
let result = this.evaluate_added_goals_and_make_canonical_response(certainty).unwrap();
277+
let mut dummy_probe = this.inspect.new_probe();
309278
dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
310-
self.inspect.finish_probe(dummy_probe);
311-
Some(Candidate { source, result })
312-
} else {
313-
None
279+
this.inspect.finish_probe(dummy_probe);
280+
vec![Candidate { source, result }]
281+
};
282+
283+
let Some(normalized_self_ty) =
284+
self.try_normalize_ty(goal.param_env, goal.predicate.self_ty())
285+
else {
286+
debug!("overflow while evaluating self type");
287+
return dummy_candidate(self, Certainty::OVERFLOW);
288+
};
289+
290+
if normalized_self_ty.is_ty_var() {
291+
debug!("self type has been normalized to infer");
292+
return dummy_candidate(self, Certainty::AMBIGUOUS);
314293
}
315-
}
316294

317-
/// Assemble candidates which apply to the self type. This only looks at candidate which
318-
/// apply to the specific self type and ignores all others.
319-
///
320-
/// Returns `None` if the self type is still ambiguous.
321-
fn assemble_candidates_via_self_ty<G: GoalKind<'tcx>>(
322-
&mut self,
323-
goal: Goal<'tcx, G>,
324-
num_steps: usize,
325-
) -> Vec<Candidate<'tcx>> {
295+
let goal =
296+
goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty));
326297
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
327-
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
328-
return vec![ambig];
329-
}
330298

331-
let mut candidates = Vec::new();
299+
let mut candidates = vec![];
332300

333301
self.assemble_non_blanket_impl_candidates(goal, &mut candidates);
334302

@@ -338,61 +306,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
338306

339307
self.assemble_object_bound_candidates(goal, &mut candidates);
340308

341-
self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates, num_steps);
342-
candidates
343-
}
309+
self.assemble_unsize_to_dyn_candidate(goal, &mut candidates);
344310

345-
/// If the self type of a goal is an alias we first try to normalize the self type
346-
/// and compute the candidates for the normalized self type in case that succeeds.
347-
///
348-
/// These candidates are used in addition to the ones with the alias as a self type.
349-
/// We do this to simplify both builtin candidates and for better performance.
350-
///
351-
/// We generate the builtin candidates on the fly by looking at the self type, e.g.
352-
/// add `FnPtr` candidates if the self type is a function pointer. Handling builtin
353-
/// candidates while the self type is still an alias seems difficult. This is similar
354-
/// to `try_structurally_resolve_type` during hir typeck (FIXME once implemented).
355-
///
356-
/// Looking at all impls for some trait goal is prohibitively expensive. We therefore
357-
/// only look at implementations with a matching self type. Because of this function,
358-
/// we can avoid looking at all existing impls if the self type is an alias.
359-
#[instrument(level = "debug", skip_all)]
360-
fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
361-
&mut self,
362-
goal: Goal<'tcx, G>,
363-
candidates: &mut Vec<Candidate<'tcx>>,
364-
num_steps: usize,
365-
) {
366-
let tcx = self.tcx();
367-
let &ty::Alias(_, alias) = goal.predicate.self_ty().kind() else { return };
368-
369-
candidates.extend(self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
370-
if tcx.recursion_limit().value_within_limit(num_steps) {
371-
let normalized_ty = ecx.next_ty_infer();
372-
let normalizes_to_goal =
373-
goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() });
374-
ecx.add_goal(GoalSource::Misc, normalizes_to_goal);
375-
if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
376-
debug!("self type normalization failed");
377-
return vec![];
378-
}
379-
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
380-
debug!(?normalized_ty, "self type normalized");
381-
// NOTE: Alternatively we could call `evaluate_goal` here and only
382-
// have a `Normalized` candidate. This doesn't work as long as we
383-
// use `CandidateSource` in winnowing.
384-
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
385-
ecx.assemble_candidates_via_self_ty(goal, num_steps + 1)
386-
} else {
387-
match ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) {
388-
Ok(result) => vec![Candidate {
389-
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
390-
result,
391-
}],
392-
Err(NoSolution) => vec![],
393-
}
394-
}
395-
}));
311+
self.assemble_blanket_impl_candidates(goal, &mut candidates);
312+
313+
self.assemble_param_env_candidates(goal, &mut candidates);
314+
315+
self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
316+
317+
candidates
396318
}
397319

398320
#[instrument(level = "debug", skip_all)]

compiler/rustc_trait_selection/src/solve/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
288288

289289
/// Normalize a type when it is structually matched on.
290290
///
291-
/// For self types this is generally already handled through
292-
/// `assemble_candidates_after_normalizing_self_ty`, so anything happening
293-
/// in [`EvalCtxt::assemble_candidates_via_self_ty`] does not have to normalize
294-
/// the self type. It is required when structurally matching on any other
295-
/// arguments of a trait goal, e.g. when assembling builtin unsize candidates.
291+
/// In nearly all cases this function must be used before matching on a type.
292+
/// Not doing so is likely to be incomplete and therefore unsound during
293+
/// coherence.
296294
#[instrument(level = "debug", skip(self), ret)]
297295
fn try_normalize_ty(
298296
&mut self,

tests/ui/traits/next-solver/alias-bound-unsound.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ trait Foo {
1616

1717
impl Foo for () {
1818
type Item = String where String: Copy;
19-
//~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy`
19+
//~^ ERROR overflow evaluating the requirement `String: Copy`
2020
}
2121

2222
fn main() {

tests/ui/traits/next-solver/alias-bound-unsound.stderr

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy`
2-
--> $DIR/alias-bound-unsound.rs:18:17
1+
error[E0275]: overflow evaluating the requirement `String: Copy`
2+
--> $DIR/alias-bound-unsound.rs:18:38
33
|
44
LL | type Item = String where String: Copy;
5-
| ^^^^^^
5+
| ^^^^
66
|
77
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
8-
note: required by a bound in `Foo::Item`
9-
--> $DIR/alias-bound-unsound.rs:8:16
8+
note: the requirement `String: Copy` appears on the `impl`'s associated type `Item` but not on the corresponding trait's associated type
9+
--> $DIR/alias-bound-unsound.rs:8:10
1010
|
11+
LL | trait Foo {
12+
| --- in this trait
1113
LL | type Item: Copy
12-
| ^^^^ required by this bound in `Foo::Item`
14+
| ^^^^ this trait's associated type doesn't have the requirement `String: Copy`
1315

1416
error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item`
1517
--> $DIR/alias-bound-unsound.rs:24:31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// check-pass
2+
// compile-flags: -Znext-solver
3+
4+
trait Reader: Default {
5+
fn read_u8_array<A>(&self) -> Result<A, ()> {
6+
todo!()
7+
}
8+
9+
fn read_u8(&self) -> Result<u8, ()> {
10+
let a: [u8; 1] = self.read_u8_array::<_>()?;
11+
// This results in a nested `<Result<?0, ()> as Try>::Residual: Sized` goal.
12+
// The self type normalizes to `?0`. We previously did not force that to be
13+
// ambiguous but instead incompletely applied the `Self: Sized` candidate
14+
// from the `ParamEnv`, resulting in a type error.
15+
Ok(a[0])
16+
}
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
2+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
3+
|
4+
LL | needs_send::<Foo>();
5+
| ^^^
6+
|
7+
= note: cannot satisfy `Foo: Send`
8+
note: required by a bound in `needs_send`
9+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
10+
|
11+
LL | fn needs_send<T: Send>() {}
12+
| ^^^^ required by this bound in `needs_send`
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0283`.

tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
2-
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
2+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
33
|
44
LL | needs_send::<Foo>();
55
| ^^^
66
|
77
= note: cannot satisfy `Foo: Send`
88
note: required by a bound in `needs_send`
9-
--> $DIR/dont-type_of-tait-in-defining-scope.rs:13:18
9+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
1010
|
1111
LL | fn needs_send<T: Send>() {}
1212
| ^^^^ required by this bound in `needs_send`

tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// revisions: is_send not_send
22
// compile-flags: -Znext-solver
3-
//[is_send] check-pass
43

54
#![feature(type_alias_impl_trait)]
65

@@ -14,7 +13,7 @@ fn needs_send<T: Send>() {}
1413

1514
fn test(_: Foo) {
1615
needs_send::<Foo>();
17-
//[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send`
16+
//~^ ERROR type annotations needed: cannot satisfy `Foo: Send`
1817
}
1918

2019
fn defines(_: Foo) {

tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc
1717
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
1818
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
1919
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
20+
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Sized`
2021
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
2122
}
2223

tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr

+18-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ note: required by a bound in `needs_bar`
1919
LL | fn needs_bar<S: Bar>() {}
2020
| ^^^ required by this bound in `needs_bar`
2121

22+
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Sized`
23+
--> $DIR/recursive-self-normalization-2.rs:15:17
24+
|
25+
LL | needs_bar::<T::Assoc1>();
26+
| ^^^^^^^^^
27+
|
28+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`)
29+
note: required by a bound in `needs_bar`
30+
--> $DIR/recursive-self-normalization-2.rs:12:14
31+
|
32+
LL | fn needs_bar<S: Bar>() {}
33+
| ^ required by this bound in `needs_bar`
34+
help: consider relaxing the implicit `Sized` restriction
35+
|
36+
LL | fn needs_bar<S: Bar + ?Sized>() {}
37+
| ++++++++
38+
2239
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
2340
--> $DIR/recursive-self-normalization-2.rs:15:5
2441
|
@@ -45,6 +62,6 @@ LL | needs_bar::<T::Assoc1>();
4562
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`)
4663
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
4764

48-
error: aborting due to 5 previous errors
65+
error: aborting due to 6 previous errors
4966

5067
For more information about this error, try `rustc --explain E0275`.

tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() {
1313
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
1414
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
1515
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
16+
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Sized`
1617
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
1718
}
1819

tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr

+18-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ note: required by a bound in `needs_bar`
1919
LL | fn needs_bar<S: Bar>() {}
2020
| ^^^ required by this bound in `needs_bar`
2121

22+
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Sized`
23+
--> $DIR/recursive-self-normalization.rs:11:17
24+
|
25+
LL | needs_bar::<T::Assoc>();
26+
| ^^^^^^^^
27+
|
28+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`)
29+
note: required by a bound in `needs_bar`
30+
--> $DIR/recursive-self-normalization.rs:8:14
31+
|
32+
LL | fn needs_bar<S: Bar>() {}
33+
| ^ required by this bound in `needs_bar`
34+
help: consider relaxing the implicit `Sized` restriction
35+
|
36+
LL | fn needs_bar<S: Bar + ?Sized>() {}
37+
| ++++++++
38+
2239
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
2340
--> $DIR/recursive-self-normalization.rs:11:5
2441
|
@@ -45,6 +62,6 @@ LL | needs_bar::<T::Assoc>();
4562
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`)
4663
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
4764

48-
error: aborting due to 5 previous errors
65+
error: aborting due to 6 previous errors
4966

5067
For more information about this error, try `rustc --explain E0275`.

tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,14 @@
44
// revisions: current next
55
//[next] compile-flags: -Znext-solver
66
// check-pass
7-
87
#![feature(type_alias_impl_trait)]
98

10-
trait Dummy {}
11-
impl Dummy for () {}
12-
13-
type F = impl Dummy;
14-
fn f() -> F {}
15-
169
trait Test {
1710
fn test(self);
1811
}
1912

20-
impl Test for F {
13+
14+
impl Test for define::F {
2115
fn test(self) {}
2216
}
2317

@@ -27,7 +21,17 @@ impl Test for i32 {
2721
fn test(self) {}
2822
}
2923

24+
mod define {
25+
use super::*;
26+
27+
pub trait Dummy {}
28+
impl Dummy for () {}
29+
30+
pub type F = impl Dummy;
31+
pub fn f() -> F {}
32+
}
33+
3034
fn main() {
31-
let x: F = f();
35+
let x = define::f();
3236
x.test();
3337
}

0 commit comments

Comments
 (0)