Skip to content

Commit 7df376b

Browse files
committed
Auto merge of #142712 - davidtwco:sized-hierarchy-missing-default-bounds, r=<try>
hir_analysis: add missing sizedness bounds Default sizedness bounds were not being added to `explicit_super_predicates_of` and `explicit_implied_predicates_of` which meant that a trait bound added to a associated type projection would be missing the implied predicate of the default sizedness supertrait of that trait. An unexpected consequence of this change was that the check for multiple principals was now finding an additional `MetaSized` principal when eagerly expanding trait aliases - this required modifying lowering to no longer add default bounds to trait aliases.
2 parents c720f49 + eac7da1 commit 7df376b

27 files changed

+220
-206
lines changed

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
660660
| PredicateFilter::SelfOnly
661661
| PredicateFilter::SelfTraitThatDefines(_)
662662
| PredicateFilter::SelfAndAssociatedTypeBounds => {
663+
icx.lowerer().add_sizedness_bounds(
664+
&mut bounds,
665+
self_param_ty,
666+
superbounds,
667+
None,
668+
Some(trait_def_id),
669+
item.span,
670+
);
663671
icx.lowerer().add_default_super_traits(
664672
trait_def_id,
665673
&mut bounds,

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
6464

6565
self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span);
6666

67-
let (elaborated_trait_bounds, elaborated_projection_bounds) =
67+
let (mut elaborated_trait_bounds, elaborated_projection_bounds) =
6868
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
69+
70+
// FIXME(sized-hierarchy): https://github.com/rust-lang/rust/pull/142712#issuecomment-3013231794
71+
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
72+
elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did);
73+
6974
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
7075
.into_iter()
7176
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));

compiler/rustc_middle/src/ty/context.rs

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

495+
fn is_sizedness_trait(self, def_id: DefId) -> bool {
496+
self.is_sizedness_trait(def_id)
497+
}
498+
495499
fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
496500
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
497501
}
@@ -1644,6 +1648,10 @@ impl<'tcx> TyCtxt<'tcx> {
16441648
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
16451649
}
16461650

1651+
pub fn is_sizedness_trait(self, def_id: DefId) -> bool {
1652+
matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized))
1653+
}
1654+
16471655
/// Returns a range of the start/end indices specified with the
16481656
/// `rustc_layout_scalar_valid_range` attribute.
16491657
// 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/confirmation.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
144144
obligation: &PolyTraitObligation<'tcx>,
145145
idx: usize,
146146
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
147-
let tcx = self.tcx();
148-
149147
let placeholder_trait_predicate =
150148
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
151149
let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty());
@@ -194,28 +192,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
194192
.map_err(|_| SelectionError::Unimplemented)?,
195193
);
196194

197-
// FIXME(compiler-errors): I don't think this is needed.
198-
if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() {
199-
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args);
200-
for (predicate, _) in predicates {
201-
let normalized = normalize_with_depth_to(
202-
self,
203-
obligation.param_env,
204-
obligation.cause.clone(),
205-
obligation.recursion_depth + 1,
206-
predicate,
207-
&mut obligations,
208-
);
209-
obligations.push(Obligation::with_depth(
210-
self.tcx(),
211-
obligation.cause.clone(),
212-
obligation.recursion_depth + 1,
213-
obligation.param_env,
214-
normalized,
215-
));
216-
}
217-
}
218-
219195
Ok(obligations)
220196
}
221197

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
485485
}
486486
} else {
487487
let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
488-
if let Some(candidate) = self.winnow_candidates(has_non_region_infer, candidates) {
488+
let did = stack.obligation.predicate.def_id();
489+
let is_sizedness_or_auto_or_default_predicate = self.tcx().is_sizedness_trait(did)
490+
|| self.tcx().trait_is_auto(did)
491+
|| self.tcx().is_default_trait(did);
492+
if let Some(candidate) = self.winnow_candidates(
493+
has_non_region_infer,
494+
is_sizedness_or_auto_or_default_predicate,
495+
candidates,
496+
) {
489497
self.filter_reservation_impls(candidate)
490498
} else {
491499
Ok(None)
@@ -1826,6 +1834,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18261834
fn winnow_candidates(
18271835
&mut self,
18281836
has_non_region_infer: bool,
1837+
prefer_alias_over_param_candidates: bool,
18291838
mut candidates: Vec<EvaluatedCandidate<'tcx>>,
18301839
) -> Option<SelectionCandidate<'tcx>> {
18311840
if candidates.len() == 1 {
@@ -1879,6 +1888,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18791888
break;
18801889
}
18811890

1891+
let alias_bound = candidates
1892+
.iter()
1893+
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
1894+
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
1895+
1896+
if prefer_alias_over_param_candidates {
1897+
match alias_bound {
1898+
Some(Some(index)) => return Some(ProjectionCandidate(index)),
1899+
Some(None) => {}
1900+
None => return None,
1901+
}
1902+
}
1903+
18821904
// The next highest priority is for non-global where-bounds. However, while we don't
18831905
// prefer global where-clauses here, we do bail with ambiguity when encountering both
18841906
// a global and a non-global where-clause.
@@ -1912,10 +1934,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19121934
// fairly arbitrary but once again necessary for backwards compatibility.
19131935
// If there are multiple applicable candidates which don't affect type inference,
19141936
// choose the one with the lowest index.
1915-
let alias_bound = candidates
1916-
.iter()
1917-
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
1918-
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
19191937
match alias_bound {
19201938
Some(Some(index)) => return Some(ProjectionCandidate(index)),
19211939
Some(None) => {}

compiler/rustc_type_ir/src/interner.rs

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

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

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

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

tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ trait Bop {
99

1010
fn bop<T: Bop + ?Sized>() {
1111
let _ = <T as Bop>::Bar::default();
12-
//~^ ERROR: trait bounds were not satisfied
12+
//~^ ERROR: the size for values of type `T` cannot be known at compilation time
13+
//~| ERROR: the size for values of type `T` cannot be known at compilation time
1314
//~| ERROR: the size for values of type `T` cannot be known at compilation time
1415
}
1516

tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,58 @@ help: consider relaxing the implicit `Sized` restriction
2424
LL | type Bar: Default + ?Sized
2525
| ++++++++
2626

27-
error[E0599]: the function or associated item `default` exists for associated type `<T as Bop>::Bar`, but its trait bounds were not satisfied
28-
--> $DIR/assoc_type_bounds_sized_used.rs:11:30
27+
error[E0277]: the size for values of type `T` cannot be known at compilation time
28+
--> $DIR/assoc_type_bounds_sized_used.rs:11:13
2929
|
30+
LL | fn bop<T: Bop + ?Sized>() {
31+
| - this type parameter needs to be `Sized`
3032
LL | let _ = <T as Bop>::Bar::default();
31-
| ^^^^^^^ function or associated item cannot be called on `<T as Bop>::Bar` due to unsatisfied trait bounds
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
34+
|
35+
note: required by a bound in `Bop::Bar`
36+
--> $DIR/assoc_type_bounds_sized_used.rs:7:15
37+
|
38+
LL | type Bar: Default
39+
| --- required by a bound in this associated type
40+
LL | where
41+
LL | Self: Sized;
42+
| ^^^^^ required by this bound in `Bop::Bar`
43+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
44+
|
45+
LL - fn bop<T: Bop + ?Sized>() {
46+
LL + fn bop<T: Bop>() {
3247
|
33-
= note: the following trait bounds were not satisfied:
34-
`T: Sized`
35-
which is required by `<T as Bop>::Bar: Default`
36-
help: consider restricting the type parameter to satisfy the trait bound
48+
help: consider relaxing the implicit `Sized` restriction
49+
|
50+
LL | type Bar: Default + ?Sized
51+
| ++++++++
52+
53+
error[E0277]: the size for values of type `T` cannot be known at compilation time
54+
--> $DIR/assoc_type_bounds_sized_used.rs:11:13
3755
|
38-
LL | fn bop<T: Bop + ?Sized>() where T: Sized {
39-
| ++++++++++++++
56+
LL | fn bop<T: Bop + ?Sized>() {
57+
| - this type parameter needs to be `Sized`
58+
LL | let _ = <T as Bop>::Bar::default();
59+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
60+
|
61+
note: required by a bound in `Bop::Bar`
62+
--> $DIR/assoc_type_bounds_sized_used.rs:7:15
63+
|
64+
LL | type Bar: Default
65+
| --- required by a bound in this associated type
66+
LL | where
67+
LL | Self: Sized;
68+
| ^^^^^ required by this bound in `Bop::Bar`
69+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
70+
|
71+
LL - fn bop<T: Bop + ?Sized>() {
72+
LL + fn bop<T: Bop>() {
73+
|
74+
help: consider relaxing the implicit `Sized` restriction
75+
|
76+
LL | type Bar: Default + ?Sized
77+
| ++++++++
4078

41-
error: aborting due to 2 previous errors
79+
error: aborting due to 3 previous errors
4280

43-
Some errors have detailed explanations: E0277, E0599.
44-
For more information about an error, try `rustc --explain E0277`.
81+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,3 @@
1-
error: lifetime bound not satisfied
2-
--> $DIR/issue-100013.rs:15:5
3-
|
4-
LL | / async { // a coroutine checked for autotrait impl `Send`
5-
LL | | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
6-
LL | | async {}.await; // a yield point
7-
LL | | }
8-
| |_____^
9-
|
10-
= note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
11-
12-
error: lifetime bound not satisfied
13-
--> $DIR/issue-100013.rs:22:5
14-
|
15-
LL | / async { // a coroutine checked for autotrait impl `Send`
16-
LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
17-
LL | | async {}.await; // a yield point
18-
LL | | }
19-
| |_____^
20-
|
21-
= note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
22-
231
error: lifetime may not live long enough
242
--> $DIR/issue-100013.rs:23:17
253
|
@@ -33,16 +11,5 @@ LL | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
3311
|
3412
= help: consider adding the following bound: `'a: 'b`
3513

36-
error: lifetime bound not satisfied
37-
--> $DIR/issue-100013.rs:29:5
38-
|
39-
LL | / async { // a coroutine checked for autotrait impl `Send`
40-
LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
41-
LL | | async {}.await; // a yield point
42-
LL | | }
43-
| |_____^
44-
|
45-
= note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
46-
47-
error: aborting due to 4 previous errors
14+
error: aborting due to 1 previous error
4815

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//@ check-pass
12
//@ edition:2018
23

34
use std::future::Future;
@@ -15,14 +16,6 @@ where
1516
C: Client + Send + Sync,
1617
{
1718
async move { c.connect().await }
18-
//~^ ERROR `C` does not live long enough
19-
//
20-
// FIXME(#71723). This is because we infer at some point a value of
21-
//
22-
// impl Future<Output = <C as Client>::Connection<'_>>
23-
//
24-
// and then we somehow fail the WF check because `where C: 'a` is not known,
25-
// but I'm not entirely sure how that comes about.
2619
}
2720

2821
fn main() {}

tests/ui/generic-associated-types/issue-92096.stderr

Lines changed: 0 additions & 8 deletions
This file was deleted.
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

0 commit comments

Comments
 (0)