Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,35 @@ use crate::traits::{
};

impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
/// Checks for an explicit `Self: Trait` bound on an associated type impl.
fn is_explicit_self_trait_bound_on_impl_assoc_type(
&self,
body_def_id: LocalDefId,
cause_code: &ObligationCauseCode<'tcx>,
trait_def_id: DefId,
) -> bool {
let ObligationCauseCode::WhereClause(item_def_id, span) = *cause_code.peel_derives() else {
return false;
};
// Continue only if there is an impl associated type corresponding to the expected trait item.
if !self.tcx.opt_associated_item(body_def_id.to_def_id()).is_some_and(|assoc_item| {
assoc_item.trait_item_def_id().is_some_and(|trait_item_def_id| {
trait_item_def_id == item_def_id
&& matches!(assoc_item.kind, ty::AssocKind::Type { .. })
})
}) {
return false;
}
Comment thread
ozankenangungor marked this conversation as resolved.
Resolved

self.tcx.clauses_of(item_def_id).instantiate_own_identity().any(|(clause, clause_span)| {
clause_span == span
&& clause.skip_norm_wip().as_trait_clause().is_some_and(|trait_pred| {
trait_pred.def_id() == trait_def_id
&& trait_pred.skip_binder().self_ty().is_self_param()
})
})
}

/// The `root_obligation` parameter should be the `root_obligation` field
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
/// then it should be the same as `obligation`.
Expand Down Expand Up @@ -175,6 +204,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Err(guar) = leaf_trait_predicate.error_reported() {
return guar;
}
if self.is_explicit_self_trait_bound_on_impl_assoc_type(
obligation.cause.body_def_id,
obligation.cause.code(),
leaf_trait_predicate.def_id(),
) && let ty::Param(param_ty) =
*leaf_trait_predicate.skip_binder().self_ty().kind()
{
span = param_ty.span_from_generics(
self.tcx,
obligation.cause.body_def_id.to_def_id(),
);
}
Comment thread
ozankenangungor marked this conversation as resolved.
Resolved
// Silence redundant errors on binding access that are already
// reported on the binding definition (#56607).
if let Err(guar) = self.fn_arg_obligation(&obligation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4031,6 +4031,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& !bounds.iter()
.filter_map(|bound| bound.trait_ref())
.any(|tr| tr.trait_def_id().is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized)))
// Only suggest relaxing the implicit `Sized` restriction if the
// failing obligation is that restriction. Relaxing it cannot
// satisfy an explicit where clause of the item, e.g.
// `type Assoc where Self: Sized;`.
&& !generics.predicates.iter().any(|pred| {
pred.kind.in_where_clause() && pred.span.contains(span)
})
{
let (span, separator) = if let [.., last] = bounds {
(last.span().shrink_to_hi(), " +")
Expand Down
39 changes: 31 additions & 8 deletions compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,42 @@ impl<'tcx> BestObligation<'tcx> {
alias: ty::AliasTerm<'tcx>,
) -> ControlFlow<PredicateObligation<'tcx>> {
let tcx = goal.infcx().tcx;
let obligation = Obligation::new(
tcx,
self.obligation.cause.clone(),
goal.goal().param_env,
alias.trait_ref(tcx),
);

let trait_ref = alias.trait_ref(tcx);
let obligation =
Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, trait_ref);

self.with_derived_obligation(obligation, |this| {
goal.infcx().visit_proof_tree_at_depth(
goal.goal().with(tcx, alias.trait_ref(tcx)),
goal.goal().with(tcx, trait_ref),
goal.depth() + 1,
this,
)
})
})?;

let def_id = alias.expect_projection_def_id();

for (clause, span) in tcx.clauses_of(def_id).instantiate_own(tcx, alias.args) {
let clause = clause.skip_norm_wip();

let cause = ObligationCause::new(
self.obligation.cause.span,
self.obligation.cause.body_def_id,
ObligationCauseCode::WhereClause(def_id, span),
);

let obligation = Obligation::new(tcx, cause, goal.goal().param_env, clause);

self.with_derived_obligation(obligation, |this| {
goal.infcx().visit_proof_tree_at_depth(
goal.goal().with(tcx, clause),
goal.depth() + 1,
this,
)
})?;
}

ControlFlow::Continue(())
}

/// If we have no candidates, then it's likely that there is a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ 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 1 previous error

Expand Down
92 changes: 92 additions & 0 deletions tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//@ compile-flags: -Znext-solver

// Tests the diagnostics for associated-item own clauses (e.g. `type Assoc
// where Self: Sized;`) that are not satisfied by an impl. The recovered error
// should point at the type that fails the clause and only suggest fixes that
// would actually satisfy it.

// The impl associated type already carries other where clauses, but is
// missing the `Self: Sized` clause required by the trait item. Relaxing the
// implicit `Sized` restriction of the associated type would not satisfy that
// clause.
trait TraitWithBound {
type Assoc
where
Self: Sized,
Self: 'static;
}

impl<T: ?Sized> TraitWithBound for T {
//~^ ERROR the size for values of type `T` cannot be known at compilation time
type Assoc = i32
where
Self: 'static;
}

// The value of the impl associated type does not satisfy the implicit `Sized`
// restriction of the trait item. Relaxing that restriction is the right fix,
// so the suggestion must still be emitted even though the trait item carries
// other explicit where clauses.
trait TraitWithOtherClause {
type Assoc
where
Self: 'static;
}

impl TraitWithOtherClause for () {
type Assoc = [u8];
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
}

// A trait item without any explicit where clauses: the ordinary
// implicit-`Sized` diagnostic is unchanged.
trait NormalAssoc {
type Assoc;
}

impl NormalAssoc for () {
type Assoc = [u8];
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
}

// A projection use site outside of an impl: the recovery also applies there.
trait NonImplTrait {
type Assoc
where
Self: Sized;
}

fn non_impl_use<T: ?Sized>() {
let _: <T as NonImplTrait>::Assoc;
//~^ ERROR the size for values of type `T` cannot be known at compilation time
//~| ERROR the trait bound `T: NonImplTrait` is not satisfied
}

// Own clauses with traits other than `Sized` are handled the same way.
trait Marker {}

trait TraitWithMarker {
type Assoc
where
Self: Marker;
}

impl<T> TraitWithMarker for T {
//~^ ERROR the trait bound `T: Marker` is not satisfied
type Assoc = i32;
}

// Own clauses on traits with a custom `#[rustc_on_unimplemented]` diagnostic
// keep their custom label.
trait TraitWithSend {
type Assoc
where
Self: Send;
}

impl<T> TraitWithSend for T {
//~^ ERROR `T` cannot be sent between threads safely
type Assoc = i32;
}

fn main() {}
135 changes: 135 additions & 0 deletions tests/ui/traits/next-solver/assoc-item-own-bound-diagnostics.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/assoc-item-own-bound-diagnostics.rs:19:6
|
LL | impl<T: ?Sized> TraitWithBound for T {
| ^
| |
| doesn't have a size known at compile-time
| this type parameter needs to be `Sized`
|
note: required by a bound in `TraitWithBound::Assoc`
--> $DIR/assoc-item-own-bound-diagnostics.rs:15:15
|
LL | trait TraitWithBound {
LL | type Assoc
LL | where
LL | Self: Sized,
| ^^^^^ required by this bound in `TraitWithBound::Assoc`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - impl<T: ?Sized> TraitWithBound for T {
LL + impl<T> TraitWithBound for T {
|

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/assoc-item-own-bound-diagnostics.rs:37:18
|
LL | type Assoc = [u8];
| ^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `TraitWithOtherClause::Assoc`
--> $DIR/assoc-item-own-bound-diagnostics.rs:31:5
|
LL | trait TraitWithOtherClause {
LL | / type Assoc
LL | | where
LL | | Self: 'static;
| |______________________^ required by this bound in `TraitWithOtherClause::Assoc`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assoc: ?Sized
| ++++++++

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/assoc-item-own-bound-diagnostics.rs:48:18
|
LL | type Assoc = [u8];
| ^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `NormalAssoc::Assoc`
--> $DIR/assoc-item-own-bound-diagnostics.rs:44:5
|
LL | trait NormalAssoc {
LL | type Assoc;
| ^^^^^^^^^^^ required by this bound in `NormalAssoc::Assoc`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assoc: ?Sized;
| ++++++++

error[E0277]: the trait bound `T: Marker` is not satisfied
--> $DIR/assoc-item-own-bound-diagnostics.rs:74:6
|
LL | impl<T> TraitWithMarker for T {
| ^ the trait `Marker` is not implemented for `T`
|
note: required by a bound in `TraitWithMarker::Assoc`
--> $DIR/assoc-item-own-bound-diagnostics.rs:71:15
|
LL | trait TraitWithMarker {
LL | type Assoc
LL | where
LL | Self: Marker;
| ^^^^^^ required by this bound in `TraitWithMarker::Assoc`
help: consider restricting type parameter `T` with trait `Marker`
|
LL | impl<T: Marker> TraitWithMarker for T {
| ++++++++

error[E0277]: `T` cannot be sent between threads safely
--> $DIR/assoc-item-own-bound-diagnostics.rs:87:6
|
LL | impl<T> TraitWithSend for T {
| ^ `T` cannot be sent between threads safely
|
note: required by a bound in `TraitWithSend::Assoc`
--> $DIR/assoc-item-own-bound-diagnostics.rs:84:15
|
LL | trait TraitWithSend {
LL | type Assoc
LL | where
LL | Self: Send;
| ^^^^ required by this bound in `TraitWithSend::Assoc`
help: consider restricting type parameter `T` with trait `Send`
|
LL | impl<T: std::marker::Send> TraitWithSend for T {
| +++++++++++++++++++

error[E0277]: the trait bound `T: NonImplTrait` is not satisfied
--> $DIR/assoc-item-own-bound-diagnostics.rs:60:13
|
LL | let _: <T as NonImplTrait>::Assoc;
| ^ the trait `NonImplTrait` is not implemented for `T`
|
help: consider further restricting type parameter `T` with trait `NonImplTrait`
|
LL | fn non_impl_use<T: ?Sized + NonImplTrait>() {
| ++++++++++++++

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/assoc-item-own-bound-diagnostics.rs:60:13
|
LL | fn non_impl_use<T: ?Sized>() {
| - this type parameter needs to be `Sized`
LL | let _: <T as NonImplTrait>::Assoc;
| ^ doesn't have a size known at compile-time
|
note: required by a bound in `NonImplTrait::Assoc`
--> $DIR/assoc-item-own-bound-diagnostics.rs:56:15
|
LL | trait NonImplTrait {
LL | type Assoc
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `NonImplTrait::Assoc`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn non_impl_use<T: ?Sized>() {
LL + fn non_impl_use<T>() {
|

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0277`.
17 changes: 17 additions & 0 deletions tests/ui/traits/next-solver/assoc-item-own-bound.current.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/assoc-item-own-bound.rs:18:18
|
LL | impl<T: ?Sized> Trait for T {
| - this type parameter needs to be `Sized`
LL | type Assoc = i32;
| ^^^ doesn't have a size known at compile-time
|
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - impl<T: ?Sized> Trait for T {
LL + impl<T> Trait for T {
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
Loading
Loading