Improve spans for RPITIT object-safety errors
This commit is contained in:
parent
c4165f3a96
commit
9a9d0f40b8
5 changed files with 69 additions and 14 deletions
|
@ -924,10 +924,13 @@ impl ObjectSafetyViolation {
|
|||
}
|
||||
ObjectSafetyViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::ReferencesImplTraitInTrait,
|
||||
MethodViolationCode::ReferencesImplTraitInTrait(_),
|
||||
_,
|
||||
) => format!("method `{}` references an `impl Trait` type in its return type", name)
|
||||
.into(),
|
||||
ObjectSafetyViolation::Method(name, MethodViolationCode::AsyncFn, _) => {
|
||||
format!("method `{}` is `async`", name).into()
|
||||
}
|
||||
ObjectSafetyViolation::Method(
|
||||
name,
|
||||
MethodViolationCode::WhereClauseReferencesSelf,
|
||||
|
@ -1035,7 +1038,10 @@ pub enum MethodViolationCode {
|
|||
ReferencesSelfOutput,
|
||||
|
||||
/// 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`
|
||||
WhereClauseReferencesSelf,
|
||||
|
|
|
@ -375,6 +375,7 @@ fn object_safety_violation_for_method(
|
|||
let span = match (&v, node) {
|
||||
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
|
||||
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
|
||||
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
|
||||
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
|
||||
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()) {
|
||||
return Some(MethodViolationCode::ReferencesSelfOutput);
|
||||
}
|
||||
if contains_illegal_impl_trait_in_trait(tcx, sig.output()) {
|
||||
return Some(MethodViolationCode::ReferencesImplTraitInTrait);
|
||||
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
|
||||
return Some(code);
|
||||
}
|
||||
|
||||
// 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>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_def_id: DefId,
|
||||
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?
|
||||
ty.skip_binder().walk().any(|arg| {
|
||||
ty.skip_binder().walk().find_map(|arg| {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& 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 {
|
||||
false
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
13
src/test/ui/async-await/in-trait/object-safety.rs
Normal file
13
src/test/ui/async-await/in-trait/object-safety.rs
Normal 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
|
||||
}
|
27
src/test/ui/async-await/in-trait/object-safety.stderr
Normal file
27
src/test/ui/async-await/in-trait/object-safety.stderr
Normal 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`.
|
|
@ -5,12 +5,12 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>;
|
|||
| ^^^^^^^^^^^^ `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:8
|
||||
--> $DIR/object-safety.rs:7:22
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
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
|
||||
|
||||
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
|
||||
|
|
||||
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 {
|
||||
| --- this trait cannot be made into an object...
|
||||
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
|
||||
|
||||
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
|
||||
|
|
||||
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 {
|
||||
| --- this trait cannot be made into an object...
|
||||
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
|
||||
= note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>`
|
||||
= note: required by cast to type `Box<dyn Foo>`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue