Rollup merge of #142458 - oli-obk:dyn-incompat, r=compiler-errors

Merge unboxed trait object error suggestion into regular dyn incompat error

Another hir-walker removed from the well-formed queries. This error was always a duplicate of another, but it was able to provide more information because it could invoke `is_dyn_compatible` without worrying about cycle errors. That's also the reason we can't put the error directly into hir_ty_lowering when lowering a `dyn Trait` within an associated item signature. So instead I packed it into the error handling of wf obligation checking.
This commit is contained in:
Guillaume Gomez 2025-06-22 17:35:32 +02:00 committed by GitHub
commit 371426334b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 92 additions and 221 deletions

View File

@ -382,8 +382,6 @@ fn check_trait_item<'tcx>(
_ => (None, trait_item.span),
};
check_dyn_incompatible_self_trait_by_name(tcx, trait_item);
// Check that an item definition in a subtrait is shadowing a supertrait item.
lint_item_shadowing_supertrait_item(tcx, def_id);
@ -832,70 +830,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
}
}
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
match ty.kind {
hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
[s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
_ => false,
},
_ => false,
}
}
/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items.
///
/// In such cases, suggest using `Self` instead.
fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
let (trait_ident, trait_def_id) =
match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) {
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id),
_ => return,
},
_ => return,
};
let mut trait_should_be_self = vec![];
match &item.kind {
hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
if could_be_self(trait_def_id.def_id, ty) =>
{
trait_should_be_self.push(ty.span)
}
hir::TraitItemKind::Fn(sig, _) => {
for ty in sig.decl.inputs {
if could_be_self(trait_def_id.def_id, ty) {
trait_should_be_self.push(ty.span);
}
}
match sig.decl.output {
hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => {
trait_should_be_self.push(ty.span);
}
_ => {}
}
}
_ => {}
}
if !trait_should_be_self.is_empty() {
if tcx.is_dyn_compatible(trait_def_id) {
return;
}
let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
tcx.dcx()
.struct_span_err(
trait_should_be_self,
"associated item referring to unboxed trait object for its own trait",
)
.with_span_label(trait_ident.span, "in this trait")
.with_multipart_suggestion(
"you might have meant to use `Self` to refer to the implementing type",
sugg,
Applicability::MachineApplicable,
)
.emit();
}
}
fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) {
let item_name = tcx.item_name(trait_item_def_id.to_def_id());
let trait_def_id = tcx.local_parent(trait_item_def_id);

View File

@ -1,7 +1,8 @@
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_infer::traits::{ObligationCause, ObligationCauseCode, WellFormedLoc};
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions};
@ -107,6 +108,17 @@ fn diagnostic_hir_wf_check<'tcx>(
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
if let hir::TyKind::TraitObject(..) = ty.kind {
if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
self.tcx.def_kind(self.def_id)
{
self.cause = Some(ObligationCause::new(
ty.span,
self.def_id,
ObligationCauseCode::DynCompatible(ty.span),
));
}
}
self.cause_depth = self.depth
}
}

View File

@ -397,6 +397,8 @@ pub enum ObligationCauseCode<'tcx> {
RustCall,
DynCompatible(Span),
/// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than
/// the ADT it's being implemented for.
AlwaysApplicableImpl,

View File

@ -2721,6 +2721,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
ObligationCauseCode::TupleElem => {
err.note("only the last element of a tuple may have a dynamically sized type");
}
ObligationCauseCode::DynCompatible(span) => {
err.multipart_suggestion(
"you might have meant to use `Self` to refer to the implementing type",
vec![(span, "Self".into())],
Applicability::MachineApplicable,
);
}
ObligationCauseCode::WhereClause(item_def_id, span)
| ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
| ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..)

View File

@ -31,7 +31,7 @@ use crate::traits::{
///
/// Currently that is `Self` in supertraits. This is needed
/// because `dyn_compatibility_violations` can't be used during
/// type collection.
/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself.
#[instrument(level = "debug", skip(tcx), ret)]
pub fn hir_ty_lowering_dyn_compatibility_violations(
tcx: TyCtxt<'_>,

View File

@ -87,6 +87,11 @@ help: alternatively, consider constraining `g` so it does not apply to trait obj
|
LL | trait A { fn g(b: B) -> B where Self: Sized; }
| +++++++++++++++++
help: you might have meant to use `Self` to refer to the implementing type
|
LL - trait B { fn f(a: A) -> A; }
LL + trait B { fn f(a: Self) -> A; }
|
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/avoid-ice-on-warning-3.rs:14:19
@ -124,6 +129,11 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj
|
LL | trait B { fn f(a: A) -> A where Self: Sized; }
| +++++++++++++++++
help: you might have meant to use `Self` to refer to the implementing type
|
LL - trait A { fn g(b: B) -> B; }
LL + trait A { fn g(b: Self) -> B; }
|
error: aborting due to 2 previous errors; 6 warnings emitted

View File

@ -8,8 +8,7 @@ trait GatTrait {
trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
fn c(&self) -> dyn SuperTrait<T>;
//~^ ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `SuperTrait` is not dyn compatible
//~^ ERROR the trait `SuperTrait` is not dyn compatible
}
fn main() {}

View File

@ -7,20 +7,6 @@ LL | Self: 'a;
| ^^
= help: consider adding an explicit lifetime bound `Self: 'a`...
error: associated item referring to unboxed trait object for its own trait
--> $DIR/supertrait-mentions-GAT.rs:10:20
|
LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
| ---------- in this trait
LL | fn c(&self) -> dyn SuperTrait<T>;
| ^^^^^^^^^^^^^^^^^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn c(&self) -> dyn SuperTrait<T>;
LL + fn c(&self) -> Self;
|
error[E0038]: the trait `SuperTrait` is not dyn compatible
--> $DIR/supertrait-mentions-GAT.rs:10:20
|
@ -37,8 +23,13 @@ LL | type Gat<'a>
LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
| ---------- this trait is not dyn compatible...
= help: consider moving `Gat` to another trait
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn c(&self) -> dyn SuperTrait<T>;
LL + fn c(&self) -> Self;
|
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0038, E0311.
For more information about an error, try `rustc --explain E0038`.

View File

@ -4,19 +4,16 @@ trait A: Sized {
fn f(a: A) -> A;
//~^ ERROR expected a type, found a trait
//~| ERROR expected a type, found a trait
//~| ERROR associated item referring to unboxed trait object for its own trait
}
trait B {
fn f(b: B) -> B;
//~^ ERROR expected a type, found a trait
//~| ERROR expected a type, found a trait
//~| ERROR associated item referring to unboxed trait object for its own trait
}
trait C {
fn f(&self, c: C) -> C;
//~^ ERROR expected a type, found a trait
//~| ERROR expected a type, found a trait
//~| ERROR associated item referring to unboxed trait object for its own trait
}
fn main() {}

View File

@ -26,22 +26,8 @@ help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as
LL | fn f(a: A) -> impl A;
| ++++
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13
|
LL | trait A: Sized {
| - in this trait
LL | fn f(a: A) -> A;
| ^ ^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: A) -> A;
LL + fn f(a: Self) -> Self;
|
error[E0782]: expected a type, found a trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:9:13
|
LL | fn f(b: B) -> B;
| ^
@ -58,7 +44,7 @@ LL | fn f(b: impl B) -> B;
| ++++
error[E0782]: expected a type, found a trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:19
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:9:19
|
LL | fn f(b: B) -> B;
| ^
@ -68,22 +54,8 @@ help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as
LL | fn f(b: B) -> impl B;
| ++++
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13
|
LL | trait B {
| - in this trait
LL | fn f(b: B) -> B;
| ^ ^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(b: B) -> B;
LL + fn f(b: Self) -> Self;
|
error[E0782]: expected a type, found a trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:14:20
|
LL | fn f(&self, c: C) -> C;
| ^
@ -100,7 +72,7 @@ LL | fn f(&self, c: impl C) -> C;
| ++++
error[E0782]: expected a type, found a trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:26
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:14:26
|
LL | fn f(&self, c: C) -> C;
| ^
@ -110,20 +82,6 @@ help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as
LL | fn f(&self, c: C) -> impl C;
| ++++
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20
|
LL | trait C {
| - in this trait
LL | fn f(&self, c: C) -> C;
| ^ ^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(&self, c: C) -> C;
LL + fn f(&self, c: Self) -> Self;
|
error: aborting due to 9 previous errors
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0782`.

View File

@ -2,13 +2,11 @@
#![allow(bare_trait_objects)]
trait A: Sized {
fn f(a: dyn A) -> dyn A;
//~^ ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `A` is not dyn compatible
//~^ ERROR the trait `A` is not dyn compatible
}
trait B {
fn f(a: dyn B) -> dyn B;
//~^ ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `B` is not dyn compatible
//~^ ERROR the trait `B` is not dyn compatible
}
trait C {
fn f(&self, a: dyn C) -> dyn C;

View File

@ -1,17 +1,3 @@
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13
|
LL | trait A: Sized {
| - in this trait
LL | fn f(a: dyn A) -> dyn A;
| ^^^^^ ^^^^^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: dyn A) -> dyn A;
LL + fn f(a: Self) -> Self;
|
error[E0038]: the trait `A` is not dyn compatible
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13
|
@ -26,30 +12,21 @@ LL | trait A: Sized {
| - ^^^^^ ...because it requires `Self: Sized`
| |
| this trait is not dyn compatible...
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13
|
LL | trait B {
| - in this trait
LL | fn f(a: dyn B) -> dyn B;
| ^^^^^ ^^^^^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: dyn B) -> dyn B;
LL + fn f(a: Self) -> Self;
LL - fn f(a: dyn A) -> dyn A;
LL + fn f(a: Self) -> dyn A;
|
error[E0038]: the trait `B` is not dyn compatible
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:8:13
|
LL | fn f(a: dyn B) -> dyn B;
| ^^^^^ `B` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8
--> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:8:8
|
LL | trait B {
| - this trait is not dyn compatible...
@ -63,7 +40,12 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj
|
LL | fn f(a: dyn B) -> dyn B where Self: Sized;
| +++++++++++++++++
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: dyn B) -> dyn B;
LL + fn f(a: Self) -> dyn B;
|
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0038`.

View File

@ -1,12 +1,10 @@
trait A: Sized {
fn f(a: dyn A) -> dyn A;
//~^ ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `A` is not dyn compatible
//~^ ERROR the trait `A` is not dyn compatible
}
trait B {
fn f(a: dyn B) -> dyn B;
//~^ ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `B` is not dyn compatible
//~^ ERROR the trait `B` is not dyn compatible
}
trait C {
fn f(&self, a: dyn C) -> dyn C;

View File

@ -1,17 +1,3 @@
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13
|
LL | trait A: Sized {
| - in this trait
LL | fn f(a: dyn A) -> dyn A;
| ^^^^^ ^^^^^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: dyn A) -> dyn A;
LL + fn f(a: Self) -> Self;
|
error[E0038]: the trait `A` is not dyn compatible
--> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13
|
@ -26,30 +12,21 @@ LL | trait A: Sized {
| - ^^^^^ ...because it requires `Self: Sized`
| |
| this trait is not dyn compatible...
error: associated item referring to unboxed trait object for its own trait
--> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13
|
LL | trait B {
| - in this trait
LL | fn f(a: dyn B) -> dyn B;
| ^^^^^ ^^^^^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: dyn B) -> dyn B;
LL + fn f(a: Self) -> Self;
LL - fn f(a: dyn A) -> dyn A;
LL + fn f(a: Self) -> dyn A;
|
error[E0038]: the trait `B` is not dyn compatible
--> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13
--> $DIR/dyn-incompatible-trait-should-use-self.rs:6:13
|
LL | fn f(a: dyn B) -> dyn B;
| ^^^^^ `B` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/dyn-incompatible-trait-should-use-self.rs:7:8
--> $DIR/dyn-incompatible-trait-should-use-self.rs:6:8
|
LL | trait B {
| - this trait is not dyn compatible...
@ -63,7 +40,12 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj
|
LL | fn f(a: dyn B) -> dyn B where Self: Sized;
| +++++++++++++++++
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn f(a: dyn B) -> dyn B;
LL + fn f(a: Self) -> dyn B;
|
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0038`.

View File

@ -11,6 +11,7 @@ trait Foo {
//~| HELP if this is a dyn-compatible trait, use `dyn`
//~| ERROR the trait `Clone` is not dyn compatible [E0038]
//~| HELP there is an associated type with the same name
//~| HELP use `Self` to refer to the implementing type
}
trait DbHandle: Sized {}
@ -26,6 +27,7 @@ trait DbInterface {
//~| HELP if this is a dyn-compatible trait, use `dyn`
//~| ERROR the trait `DbHandle` is not dyn compatible [E0038]
//~| HELP there is an associated type with the same name
//~| HELP use `Self` to refer to the implementing type
}
fn main() {}

View File

@ -35,13 +35,18 @@ LL | fn foo() -> Clone;
= note: the trait is not dyn compatible because it requires `Self: Sized`
= note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn foo() -> Clone;
LL + fn foo() -> Self;
|
help: there is an associated type with the same name
|
LL | fn foo() -> Self::Clone;
| ++++++
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-116434-2015.rs:20:20
--> $DIR/issue-116434-2015.rs:21:20
|
LL | fn handle() -> DbHandle;
| ^^^^^^^^
@ -54,7 +59,7 @@ LL | fn handle() -> dyn DbHandle;
| +++
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-116434-2015.rs:20:20
--> $DIR/issue-116434-2015.rs:21:20
|
LL | fn handle() -> DbHandle;
| ^^^^^^^^
@ -68,19 +73,24 @@ LL | fn handle() -> dyn DbHandle;
| +++
error[E0038]: the trait `DbHandle` is not dyn compatible
--> $DIR/issue-116434-2015.rs:20:20
--> $DIR/issue-116434-2015.rs:21:20
|
LL | fn handle() -> DbHandle;
| ^^^^^^^^ `DbHandle` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/issue-116434-2015.rs:16:17
--> $DIR/issue-116434-2015.rs:17:17
|
LL | trait DbHandle: Sized {}
| -------- ^^^^^ ...because it requires `Self: Sized`
| |
| this trait is not dyn compatible...
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn handle() -> DbHandle;
LL + fn handle() -> Self;
|
help: there is an associated type with the same name
|
LL | fn handle() -> Self::DbHandle;

View File

@ -5,7 +5,6 @@ trait Trait<const N: dyn Trait = bar> {
//~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters
//~| ERROR expected value, found builtin type `u32`
//~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
//~| ERROR associated item referring to unboxed trait object for its own trait
bar
//~^ ERROR cannot find value `bar` in this scope
}

View File

@ -20,7 +20,7 @@ LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
| ^^^ not a value
error[E0425]: cannot find value `bar` in this scope
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:9:9
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:8:9
|
LL | bar
| ^^^ not found in this scope
@ -45,22 +45,7 @@ error: defaults for const parameters are only allowed in `struct`, `enum`, `type
LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: associated item referring to unboxed trait object for its own trait
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:48
|
LL | trait Trait<const N: dyn Trait = bar> {
| ----- in this trait
...
LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
| ^^^^^^^^^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL - fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
LL + fn fnc<const N: dyn Trait = u32>(&self) -> Self {
|
error: aborting due to 7 previous errors
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0391, E0403, E0423, E0425.
For more information about an error, try `rustc --explain E0391`.

View File

@ -13,6 +13,11 @@ LL | trait T {
LL | const CONST: (bool, dyn T);
| ^^^^^ ...because it contains this associated `const`
= help: consider moving `CONST` to another trait
help: you might have meant to use `Self` to refer to the implementing type
|
LL - const CONST: (bool, dyn T);
LL + const CONST: (bool, Self);
|
error: aborting due to 1 previous error