Skip to content

Commit 03e0fda

Browse files
committed
trait_sel: sizedness goals prefer alias candidates
For sizedness, default and auto trait predicates, now prefer non-param candidates if any exist. As these traits do not have generic parameters, it never makes sense to prefer an non-alias candidate, as there can never be a more permissive candidate.
1 parent f053d9e commit 03e0fda

File tree

14 files changed

+103
-76
lines changed

14 files changed

+103
-76
lines changed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
493493
self.is_default_trait(def_id)
494494
}
495495

496+
fn is_sizedness_trait(self, def_id: DefId) -> bool {
497+
self.is_sizedness_trait(def_id)
498+
}
499+
496500
fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
497501
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
498502
}
@@ -1652,6 +1656,10 @@ impl<'tcx> TyCtxt<'tcx> {
16521656
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
16531657
}
16541658

1659+
pub fn is_sizedness_trait(self, def_id: DefId) -> bool {
1660+
matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized))
1661+
}
1662+
16551663
/// Returns a range of the start/end indices specified with the
16561664
/// `rustc_layout_scalar_valid_range` attribute.
16571665
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,7 @@ where
13431343
#[instrument(level = "debug", skip(self), ret)]
13441344
pub(super) fn merge_trait_candidates(
13451345
&mut self,
1346+
prefer_alias_over_param_candidates: bool,
13461347
mut candidates: Vec<Candidate<I>>,
13471348
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
13481349
if let TypingMode::Coherence = self.typing_mode() {
@@ -1368,6 +1369,26 @@ where
13681369
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
13691370
}
13701371

1372+
let potential_alias_bound_response =
1373+
candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)).then(|| {
1374+
let alias_bounds: Vec<_> = candidates
1375+
.iter()
1376+
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
1377+
.map(|c| c.result)
1378+
.collect();
1379+
if let Some(response) = self.try_merge_responses(&alias_bounds) {
1380+
(response, Some(TraitGoalProvenVia::AliasBound))
1381+
} else {
1382+
(self.bail_with_ambiguity(&alias_bounds), None)
1383+
}
1384+
});
1385+
1386+
if prefer_alias_over_param_candidates
1387+
&& let Some(alias_bound_response) = potential_alias_bound_response
1388+
{
1389+
return Ok(alias_bound_response);
1390+
}
1391+
13711392
// If there are non-global where-bounds, prefer where-bounds
13721393
// (including global ones) over everything else.
13731394
let has_non_global_where_bounds = candidates
@@ -1386,17 +1407,8 @@ where
13861407
};
13871408
}
13881409

1389-
if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1390-
let alias_bounds: Vec<_> = candidates
1391-
.iter()
1392-
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
1393-
.map(|c| c.result)
1394-
.collect();
1395-
return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1396-
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1397-
} else {
1398-
Ok((self.bail_with_ambiguity(&alias_bounds), None))
1399-
};
1410+
if let Some(response) = potential_alias_bound_response {
1411+
return Ok(response);
14001412
}
14011413

14021414
self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
@@ -1431,7 +1443,12 @@ where
14311443
goal: Goal<I, TraitPredicate<I>>,
14321444
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
14331445
let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1434-
self.merge_trait_candidates(candidates)
1446+
1447+
let did = goal.predicate.def_id();
1448+
let is_sizedness_or_auto_or_default_goal = self.cx().is_sizedness_trait(did)
1449+
|| self.cx().trait_is_auto(did)
1450+
|| self.cx().is_default_trait(did);
1451+
self.merge_trait_candidates(is_sizedness_or_auto_or_default_goal, candidates)
14351452
}
14361453

14371454
fn try_stall_coroutine_witness(

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
473473
}
474474
} else {
475475
let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
476-
if let Some(candidate) = self.winnow_candidates(has_non_region_infer, candidates) {
476+
let did = stack.obligation.predicate.def_id();
477+
let is_sizedness_or_auto_or_default_predicate = self.tcx().is_sizedness_trait(did)
478+
|| self.tcx().trait_is_auto(did)
479+
|| self.tcx().is_default_trait(did);
480+
if let Some(candidate) = self.winnow_candidates(
481+
has_non_region_infer,
482+
is_sizedness_or_auto_or_default_predicate,
483+
candidates,
484+
) {
477485
self.filter_reservation_impls(candidate)
478486
} else {
479487
Ok(None)
@@ -1822,6 +1830,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18221830
fn winnow_candidates(
18231831
&mut self,
18241832
has_non_region_infer: bool,
1833+
prefer_alias_over_param_candidates: bool,
18251834
mut candidates: Vec<EvaluatedCandidate<'tcx>>,
18261835
) -> Option<SelectionCandidate<'tcx>> {
18271836
if candidates.len() == 1 {
@@ -1875,6 +1884,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18751884
break;
18761885
}
18771886

1887+
let alias_bound = candidates
1888+
.iter()
1889+
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
1890+
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
1891+
1892+
if prefer_alias_over_param_candidates {
1893+
match alias_bound {
1894+
Some(Some(index)) => return Some(ProjectionCandidate(index)),
1895+
Some(None) => {}
1896+
None => return None,
1897+
}
1898+
}
1899+
18781900
// The next highest priority is for non-global where-bounds. However, while we don't
18791901
// prefer global where-clauses here, we do bail with ambiguity when encountering both
18801902
// a global and a non-global where-clause.
@@ -1908,10 +1930,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19081930
// fairly arbitrary but once again necessary for backwards compatibility.
19091931
// If there are multiple applicable candidates which don't affect type inference,
19101932
// choose the one with the lowest index.
1911-
let alias_bound = candidates
1912-
.iter()
1913-
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
1914-
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
19151933
match alias_bound {
19161934
Some(Some(index)) => return Some(ProjectionCandidate(index)),
19171935
Some(None) => {}

compiler/rustc_type_ir/src/interner.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ pub trait Interner:
301301

302302
fn is_default_trait(self, def_id: Self::DefId) -> bool;
303303

304+
fn is_sizedness_trait(self, def_id: Self::DefId) -> bool;
305+
304306
fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;
305307

306308
fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;

tests/ui/generic-associated-types/issue-93262.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ check-pass
1+
//@ check-fail
22

33
pub trait Trait {
44
type Assoc<'a> where Self: 'a;
@@ -11,7 +11,7 @@ where
1111

1212
pub struct Type;
1313

14-
impl<T: Trait> Foo<T> for Type
14+
impl<T: Trait> Foo<T> for Type //~ ERROR: the parameter type `T` may not live long enough
1515
where
1616
for<'a> T::Assoc<'a>: Clone
1717
{}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0311]: the parameter type `T` may not live long enough
2+
--> $DIR/issue-93262.rs:14:16
3+
|
4+
LL | impl<T: Trait> Foo<T> for Type
5+
| ^^^^^^
6+
| |
7+
| the parameter type `T` must be valid for lifetime `'a`...
8+
| ...so that the type `T` will meet its required lifetime bounds...
9+
|
10+
note: ...that is required by this bound
11+
--> $DIR/issue-93262.rs:9:27
12+
|
13+
LL | for<'a> T::Assoc<'a>: Clone
14+
| ^^^^^
15+
= help: consider adding an explicit lifetime bound `T: 'a`...
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0311`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0282]: type annotations needed for `<X as Trait<'static>>::Out<_>`
2+
--> $DIR/norm-before-method-resolution-opaque-type.rs:21:9
3+
|
4+
LL | let x = *x;
5+
| ^
6+
|
7+
help: consider giving `x` an explicit type, where the placeholders `_` are specified
8+
|
9+
LL | let x: <_ as Trait<'static>>::Out<_> = *x;
10+
| +++++++++++++++++++++++++++++++
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0282`.

tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0507]: cannot move out of `*x` which is behind a shared reference
2-
--> $DIR/norm-before-method-resolution-opaque-type.rs:22:13
2+
--> $DIR/norm-before-method-resolution-opaque-type.rs:21:13
33
|
44
LL | let x = *x;
55
| ^^ move occurs because `*x` has type `<X as Trait<'_>>::Out<Foo>`, which does not implement the `Copy` trait

tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//@ revisions: old next
22
//@[next] compile-flags: -Znext-solver
3-
//@[next] check-pass
43

54
#![feature(type_alias_impl_trait)]
65
trait Trait<'a> {
@@ -20,6 +19,7 @@ where
2019
for<'a> <X as Trait<'a>>::Out<()>: Copy,
2120
{
2221
let x = *x; //[old]~ ERROR: cannot move out of `*x`
22+
//[next]~^ ERROR: type annotations needed
2323
todo!();
2424
}
2525

tests/ui/nll/issue-50716.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ trait A {
55
type X: ?Sized;
66
}
77

8-
fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) //~ ERROR
8+
fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
99
where
1010
for<'b> &'b T: A,
1111
<&'static T as A>::X: Sized

0 commit comments

Comments
 (0)