1
Fork 0

Improve spans for RPITIT object-safety errors

This commit is contained in:
Michael Goulet 2022-11-19 02:32:55 +00:00
parent c4165f3a96
commit 9a9d0f40b8
5 changed files with 69 additions and 14 deletions

View file

@ -924,10 +924,13 @@ impl ObjectSafetyViolation {
} }
ObjectSafetyViolation::Method( ObjectSafetyViolation::Method(
name, name,
MethodViolationCode::ReferencesImplTraitInTrait, MethodViolationCode::ReferencesImplTraitInTrait(_),
_, _,
) => format!("method `{}` references an `impl Trait` type in its return type", name) ) => format!("method `{}` references an `impl Trait` type in its return type", name)
.into(), .into(),
ObjectSafetyViolation::Method(name, MethodViolationCode::AsyncFn, _) => {
format!("method `{}` is `async`", name).into()
}
ObjectSafetyViolation::Method( ObjectSafetyViolation::Method(
name, name,
MethodViolationCode::WhereClauseReferencesSelf, MethodViolationCode::WhereClauseReferencesSelf,
@ -1035,7 +1038,10 @@ pub enum MethodViolationCode {
ReferencesSelfOutput, ReferencesSelfOutput,
/// e.g., `fn foo(&self) -> impl Sized` /// e.g., `fn foo(&self) -> impl Sized`
ReferencesImplTraitInTrait, ReferencesImplTraitInTrait(Span),
/// e.g., `async fn foo(&self)`
AsyncFn,
/// e.g., `fn foo(&self) where Self: Clone` /// e.g., `fn foo(&self) where Self: Clone`
WhereClauseReferencesSelf, WhereClauseReferencesSelf,

View file

@ -375,6 +375,7 @@ fn object_safety_violation_for_method(
let span = match (&v, node) { let span = match (&v, node) {
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => { (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span()) node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
} }
@ -437,8 +438,8 @@ fn virtual_call_violation_for_method<'tcx>(
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
return Some(MethodViolationCode::ReferencesSelfOutput); return Some(MethodViolationCode::ReferencesSelfOutput);
} }
if contains_illegal_impl_trait_in_trait(tcx, sig.output()) { if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
return Some(MethodViolationCode::ReferencesImplTraitInTrait); return Some(code);
} }
// We can't monomorphize things like `fn foo<A>(...)`. // We can't monomorphize things like `fn foo<A>(...)`.
@ -864,16 +865,24 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
pub fn contains_illegal_impl_trait_in_trait<'tcx>( pub fn contains_illegal_impl_trait_in_trait<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
fn_def_id: DefId,
ty: ty::Binder<'tcx, Ty<'tcx>>, ty: ty::Binder<'tcx, Ty<'tcx>>,
) -> bool { ) -> Option<MethodViolationCode> {
// This would be caught below, but rendering the error as a separate
// `async-specific` message is better.
if tcx.asyncness(fn_def_id).is_async() {
return Some(MethodViolationCode::AsyncFn);
}
// FIXME(RPITIT): Perhaps we should use a visitor here? // FIXME(RPITIT): Perhaps we should use a visitor here?
ty.skip_binder().walk().any(|arg| { ty.skip_binder().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack() if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Projection(proj) = ty.kind() && let ty::Projection(proj) = ty.kind()
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
{ {
tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.item_def_id)))
} else { } else {
false None
} }
}) })
} }

View file

@ -0,0 +1,13 @@
// edition:2021
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
trait Foo {
async fn foo(&self);
}
fn main() {
let x: &dyn Foo = todo!();
//~^ ERROR the trait `Foo` cannot be made into an object
}

View file

@ -0,0 +1,27 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/object-safety.rs:3:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/object-safety.rs:11:12
|
LL | let x: &dyn Foo = todo!();
| ^^^^^^^^ `Foo` 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-safety.rs:7:14
|
LL | trait Foo {
| --- this trait cannot be made into an object...
LL | async fn foo(&self);
| ^^^ ...because method `foo` is `async`
= help: consider moving `foo` to another trait
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0038`.

View file

@ -5,12 +5,12 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>;
| ^^^^^^^^^^^^ `Foo` cannot be made into an object | ^^^^^^^^^^^^ `Foo` 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> 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-safety.rs:7:8 --> $DIR/object-safety.rs:7:22
| |
LL | trait Foo { LL | trait Foo {
| --- this trait cannot be made into an object... | --- this trait cannot be made into an object...
LL | fn baz(&self) -> impl Debug; LL | fn baz(&self) -> impl Debug;
| ^^^ ...because method `baz` references an `impl Trait` type in its return type | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
= help: consider moving `baz` to another trait = help: consider moving `baz` to another trait
error[E0038]: the trait `Foo` cannot be made into an object error[E0038]: the trait `Foo` cannot be made into an object
@ -20,12 +20,12 @@ LL | let s = i.baz();
| ^^^^^^^ `Foo` cannot be made into an object | ^^^^^^^ `Foo` 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> 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-safety.rs:7:8 --> $DIR/object-safety.rs:7:22
| |
LL | trait Foo { LL | trait Foo {
| --- this trait cannot be made into an object... | --- this trait cannot be made into an object...
LL | fn baz(&self) -> impl Debug; LL | fn baz(&self) -> impl Debug;
| ^^^ ...because method `baz` references an `impl Trait` type in its return type | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
= help: consider moving `baz` to another trait = help: consider moving `baz` to another trait
error[E0038]: the trait `Foo` cannot be made into an object error[E0038]: the trait `Foo` cannot be made into an object
@ -35,12 +35,12 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>;
| ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | ^^^^^^^^^^^^^^^^ `Foo` 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> 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-safety.rs:7:8 --> $DIR/object-safety.rs:7:22
| |
LL | trait Foo { LL | trait Foo {
| --- this trait cannot be made into an object... | --- this trait cannot be made into an object...
LL | fn baz(&self) -> impl Debug; LL | fn baz(&self) -> impl Debug;
| ^^^ ...because method `baz` references an `impl Trait` type in its return type | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
= help: consider moving `baz` to another trait = help: consider moving `baz` to another trait
= note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>` = note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>`
= note: required by cast to type `Box<dyn Foo>` = note: required by cast to type `Box<dyn Foo>`