Skip to content
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

maybe_lint_impl_trait: separate is_downgradable from is_object_safe #120164

Merged
merged 1 commit into from
Jan 22, 2024
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
16 changes: 9 additions & 7 deletions compiler/rustc_hir_analysis/src/astconv/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return false;
};
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
let mut is_downgradable = true;
let is_object_safe = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|o| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) if Some(id) == owner => {
// When we're dealing with a recursive trait, we don't want to downgrade
// the error, so we consider them to be object safe always. (#119652)
true
Res::Def(DefKind::Trait, id) => {
if Some(id) == owner {
// For recursive traits, don't downgrade the error. (#119652)
is_downgradable = false;
}
tcx.check_is_object_safe(id)
}
Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
_ => false,
})
}
Expand Down Expand Up @@ -130,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
],
Applicability::MachineApplicable,
);
} else if diag.is_error() {
} else if diag.is_error() && is_downgradable {
// We'll emit the object safety error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
Expand All @@ -156,7 +158,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
if !is_object_safe {
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
if diag.is_error() {
if diag.is_error() && is_downgradable {
// We'll emit the object safety error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ trait A: Sized {
//~| ERROR the trait `A` cannot be made into an object
}
trait B {
fn f(a: B) -> B;
fn f(b: B) -> B;
//~^ ERROR trait objects must include the `dyn` keyword
//~| ERROR trait objects must include the `dyn` keyword
//~| ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `B` cannot be made into an object
}
trait C {
fn f(&self, a: C) -> C;
fn f(&self, c: C) -> C;
//~^ ERROR trait objects must include the `dyn` keyword
//~| ERROR trait objects must include the `dyn` keyword
//~| ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `C` cannot be made into an object
}

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -30,42 +30,72 @@ error: associated item referring to unboxed trait object for its own trait
|
LL | trait B {
| - in this trait
LL | fn f(a: B) -> B;
LL | fn f(b: B) -> B;
| ^ ^
|
help: you might have meant to use `Self` to refer to the implementing type
|
LL | fn f(a: Self) -> Self;
LL | fn f(b: Self) -> Self;
| ~~~~ ~~~~

error[E0038]: the trait `B` cannot be made into an object
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
|
LL | fn f(a: B) -> B;
LL | fn f(b: B) -> B;
| ^ `B` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:8
|
LL | trait B {
| - this trait cannot be made into an object...
LL | fn f(a: B) -> B;
LL | fn f(b: B) -> B;
| ^ ...because associated function `f` has no `self` parameter
help: consider turning `f` into a method by giving it a `&self` argument
|
LL | fn f(&self, a: B) -> B;
LL | fn f(&self, b: B) -> B;
| ++++++
help: alternatively, consider constraining `f` so it does not apply to trait objects
|
LL | fn f(a: B) -> B where Self: Sized;
LL | fn f(b: B) -> B where Self: Sized;
| +++++++++++++++++

error: associated item referring to unboxed trait object for its own trait
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18: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: Self) -> Self;
| ~~~~ ~~~~

error[E0038]: the trait `C` cannot be made into an object
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
|
LL | fn f(&self, c: C) -> C;
| ----- ^ `C` cannot be made into an object
| |
| help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self`
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10
|
LL | trait C {
| - this trait cannot be made into an object...
LL | fn f(&self, c: C) -> C;
| ^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
|
LL | fn f(a: A) -> A;
| ^
|
= note: `A` it is not object safe, so it can't be `dyn`
help: use a new generic type parameter, constrained by `A`
|
LL | fn f<T: A>(a: T) -> A;
Expand All @@ -74,95 +104,73 @@ help: you can also use an opaque type, but users won't be able to specify the ty
|
LL | fn f(a: impl A) -> A;
| ++++
help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
|
LL | fn f(a: &dyn A) -> A;
| ++++

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
|
LL | fn f(a: A) -> A;
| ^
|
help: use `impl A` to return an opaque type, as long as you return a single underlying type
help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type
|
LL | fn f(a: A) -> impl A;
| ++++
help: alternatively, you can return an owned trait object
|
LL | fn f(a: A) -> Box<dyn A>;
| +++++++ +

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
|
LL | fn f(a: B) -> B;
LL | fn f(b: B) -> B;
| ^
|
= note: `B` it is not object safe, so it can't be `dyn`
help: use a new generic type parameter, constrained by `B`
|
LL | fn f<T: B>(a: T) -> B;
LL | fn f<T: B>(b: T) -> B;
| ++++++ ~
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
LL | fn f(a: impl B) -> B;
| ++++
help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
|
LL | fn f(a: &dyn B) -> B;
LL | fn f(b: impl B) -> B;
| ++++

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19
|
LL | fn f(a: B) -> B;
LL | fn f(b: B) -> B;
| ^
|
help: use `impl B` to return an opaque type, as long as you return a single underlying type
help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type
|
LL | fn f(a: B) -> impl B;
LL | fn f(b: B) -> impl B;
| ++++
help: alternatively, you can return an owned trait object
|
LL | fn f(a: B) -> Box<dyn B>;
| +++++++ +

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
|
LL | fn f(&self, a: C) -> C;
LL | fn f(&self, c: C) -> C;
| ^
|
= note: `C` it is not object safe, so it can't be `dyn`
help: use a new generic type parameter, constrained by `C`
|
LL | fn f<T: C>(&self, a: T) -> C;
LL | fn f<T: C>(&self, c: T) -> C;
| ++++++ ~
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
LL | fn f(&self, a: impl C) -> C;
| ++++
help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
|
LL | fn f(&self, a: &dyn C) -> C;
LL | fn f(&self, c: impl C) -> C;
| ++++

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26
|
LL | fn f(&self, a: C) -> C;
LL | fn f(&self, c: C) -> C;
| ^
|
help: use `impl C` to return an opaque type, as long as you return a single underlying type
help: `C` is not object safe, use `impl C` to return an opaque type, as long as you return a single underlying type
|
LL | fn f(&self, a: C) -> impl C;
LL | fn f(&self, c: C) -> impl C;
| ++++
help: alternatively, you can return an owned trait object
|
LL | fn f(&self, a: C) -> Box<dyn C>;
| +++++++ +

error: aborting due to 10 previous errors
error: aborting due to 12 previous errors

Some errors have detailed explanations: E0038, E0782.
For more information about an error, try `rustc --explain E0038`.
Loading