Skip to content

hir_analysis: add missing sizedness bounds #142712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
| PredicateFilter::SelfOnly
| PredicateFilter::SelfTraitThatDefines(_)
| PredicateFilter::SelfAndAssociatedTypeBounds => {
icx.lowerer().add_sizedness_bounds(
&mut bounds,
self_param_ty,
superbounds,
None,
Some(trait_def_id),
item.span,
);
icx.lowerer().add_default_super_traits(
trait_def_id,
&mut bounds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

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

let (elaborated_trait_bounds, elaborated_projection_bounds) =
let (mut elaborated_trait_bounds, elaborated_projection_bounds) =
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());

// FIXME(sized-hierarchy): https://github.com/rust-lang/rust/pull/142712#issuecomment-3013231794
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did);

let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
.into_iter()
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.is_default_trait(def_id)
}

fn is_sizedness_trait(self, def_id: DefId) -> bool {
self.is_sizedness_trait(def_id)
}

fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
}
Expand Down Expand Up @@ -1645,6 +1649,10 @@ impl<'tcx> TyCtxt<'tcx> {
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
}

pub fn is_sizedness_trait(self, def_id: DefId) -> bool {
matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized))
}

/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
Expand Down
41 changes: 29 additions & 12 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ where
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_trait_candidates(
&mut self,
prefer_alias_over_param_candidates: bool,
mut candidates: Vec<Candidate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
if let TypingMode::Coherence = self.typing_mode() {
Expand All @@ -1368,6 +1369,26 @@ where
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
}

let potential_alias_bound_response =
candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)).then(|| {
let alias_bounds: Vec<_> = candidates
.iter()
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
.map(|c| c.result)
.collect();
if let Some(response) = self.try_merge_responses(&alias_bounds) {
(response, Some(TraitGoalProvenVia::AliasBound))
} else {
(self.bail_with_ambiguity(&alias_bounds), None)
}
});

if prefer_alias_over_param_candidates
&& let Some(alias_bound_response) = potential_alias_bound_response
{
return Ok(alias_bound_response);
}

// If there are non-global where-bounds, prefer where-bounds
// (including global ones) over everything else.
let has_non_global_where_bounds = candidates
Expand All @@ -1386,17 +1407,8 @@ where
};
}

if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
let alias_bounds: Vec<_> = candidates
.iter()
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
.map(|c| c.result)
.collect();
return if let Some(response) = self.try_merge_responses(&alias_bounds) {
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
} else {
Ok((self.bail_with_ambiguity(&alias_bounds), None))
};
if let Some(response) = potential_alias_bound_response {
return Ok(response);
}

self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
Expand Down Expand Up @@ -1431,7 +1443,12 @@ where
goal: Goal<I, TraitPredicate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
self.merge_trait_candidates(candidates)

let did = goal.predicate.def_id();
let is_sizedness_or_auto_or_default_goal = self.cx().is_sizedness_trait(did)
|| self.cx().trait_is_auto(did)
|| self.cx().is_default_trait(did);
self.merge_trait_candidates(is_sizedness_or_auto_or_default_goal, candidates)
}

fn try_stall_coroutine_witness(
Expand Down
24 changes: 0 additions & 24 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
idx: usize,
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let tcx = self.tcx();

let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty());
Expand Down Expand Up @@ -196,28 +194,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| SelectionError::Unimplemented)?,
);

// FIXME(compiler-errors): I don't think this is needed.
if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() {
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args);
for (predicate, _) in predicates {
let normalized = normalize_with_depth_to(
self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
predicate,
&mut obligations,
);
obligations.push(Obligation::with_depth(
self.tcx(),
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
normalized,
));
}
}

Ok(obligations)
}

Expand Down
28 changes: 23 additions & 5 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
} else {
let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
if let Some(candidate) = self.winnow_candidates(has_non_region_infer, candidates) {
let did = stack.obligation.predicate.def_id();
let is_sizedness_or_auto_or_default_predicate = self.tcx().is_sizedness_trait(did)
|| self.tcx().trait_is_auto(did)
|| self.tcx().is_default_trait(did);
if let Some(candidate) = self.winnow_candidates(
has_non_region_infer,
is_sizedness_or_auto_or_default_predicate,
candidates,
) {
self.filter_reservation_impls(candidate)
} else {
Ok(None)
Expand Down Expand Up @@ -1826,6 +1834,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
fn winnow_candidates(
&mut self,
has_non_region_infer: bool,
prefer_alias_over_param_candidates: bool,
mut candidates: Vec<EvaluatedCandidate<'tcx>>,
) -> Option<SelectionCandidate<'tcx>> {
if candidates.len() == 1 {
Expand Down Expand Up @@ -1879,6 +1888,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
break;
}

let alias_bound = candidates
.iter()
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });

if prefer_alias_over_param_candidates {
match alias_bound {
Some(Some(index)) => return Some(ProjectionCandidate(index)),
Some(None) => {}
None => return None,
}
}

// The next highest priority is for non-global where-bounds. However, while we don't
// prefer global where-clauses here, we do bail with ambiguity when encountering both
// a global and a non-global where-clause.
Expand Down Expand Up @@ -1912,10 +1934,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// fairly arbitrary but once again necessary for backwards compatibility.
// If there are multiple applicable candidates which don't affect type inference,
// choose the one with the lowest index.
let alias_bound = candidates
.iter()
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
match alias_bound {
Some(Some(index)) => return Some(ProjectionCandidate(index)),
Some(None) => {}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ pub trait Interner:

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

fn is_sizedness_trait(self, def_id: Self::DefId) -> bool;

fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;

fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ trait Bop {

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

Expand Down
61 changes: 49 additions & 12 deletions tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,58 @@ help: consider relaxing the implicit `Sized` restriction
LL | type Bar: Default + ?Sized
| ++++++++

error[E0599]: the function or associated item `default` exists for associated type `<T as Bop>::Bar`, but its trait bounds were not satisfied
--> $DIR/assoc_type_bounds_sized_used.rs:11:30
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/assoc_type_bounds_sized_used.rs:11:13
|
LL | fn bop<T: Bop + ?Sized>() {
| - this type parameter needs to be `Sized`
LL | let _ = <T as Bop>::Bar::default();
| ^^^^^^^ function or associated item cannot be called on `<T as Bop>::Bar` due to unsatisfied trait bounds
| ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `Bop::Bar`
--> $DIR/assoc_type_bounds_sized_used.rs:7:15
|
LL | type Bar: Default
| --- required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bop::Bar`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn bop<T: Bop + ?Sized>() {
LL + fn bop<T: Bop>() {
|
= note: the following trait bounds were not satisfied:
`T: Sized`
which is required by `<T as Bop>::Bar: Default`
help: consider restricting the type parameter to satisfy the trait bound
help: consider relaxing the implicit `Sized` restriction
|
LL | type Bar: Default + ?Sized
| ++++++++

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/assoc_type_bounds_sized_used.rs:11:13
|
LL | fn bop<T: Bop + ?Sized>() where T: Sized {
| ++++++++++++++
LL | fn bop<T: Bop + ?Sized>() {
| - this type parameter needs to be `Sized`
LL | let _ = <T as Bop>::Bar::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `Bop::Bar`
--> $DIR/assoc_type_bounds_sized_used.rs:7:15
|
LL | type Bar: Default
| --- required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bop::Bar`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn bop<T: Bop + ?Sized>() {
LL + fn bop<T: Bop>() {
|
help: consider relaxing the implicit `Sized` restriction
|
LL | type Bar: Default + ?Sized
| ++++++++

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0277`.
35 changes: 1 addition & 34 deletions tests/ui/generic-associated-types/bugs/issue-100013.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,3 @@
error: lifetime bound not satisfied
--> $DIR/issue-100013.rs:15:5
|
LL | / async { // a coroutine checked for autotrait impl `Send`
LL | | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
LL | | async {}.await; // a yield point
LL | | }
| |_____^
|
= 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)

error: lifetime bound not satisfied
--> $DIR/issue-100013.rs:22:5
|
LL | / async { // a coroutine checked for autotrait impl `Send`
LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
LL | | async {}.await; // a yield point
LL | | }
| |_____^
|
= 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)

error: lifetime may not live long enough
--> $DIR/issue-100013.rs:23:17
|
Expand All @@ -33,16 +11,5 @@ LL | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
|
= help: consider adding the following bound: `'a: 'b`

error: lifetime bound not satisfied
--> $DIR/issue-100013.rs:29:5
|
LL | / async { // a coroutine checked for autotrait impl `Send`
LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
LL | | async {}.await; // a yield point
LL | | }
| |_____^
|
= 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)

error: aborting due to 4 previous errors
error: aborting due to 1 previous error

9 changes: 1 addition & 8 deletions tests/ui/generic-associated-types/issue-92096.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//@ check-pass
//@ edition:2018

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

fn main() {}
8 changes: 0 additions & 8 deletions tests/ui/generic-associated-types/issue-92096.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0282]: type annotations needed for `<X as Trait<'static>>::Out<_>`
--> $DIR/norm-before-method-resolution-opaque-type.rs:21:9
|
LL | let x = *x;
| ^
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
LL | let x: <_ as Trait<'static>>::Out<_> = *x;
| +++++++++++++++++++++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0507]: cannot move out of `*x` which is behind a shared reference
--> $DIR/norm-before-method-resolution-opaque-type.rs:22:13
--> $DIR/norm-before-method-resolution-opaque-type.rs:21:13
|
LL | let x = *x;
| ^^ move occurs because `*x` has type `<X as Trait<'_>>::Out<Foo>`, which does not implement the `Copy` trait
Expand Down
Loading
Loading