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
33 changes: 18 additions & 15 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc_macros::{
Decodable, Encodable, StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
};
use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec;

Expand Down Expand Up @@ -870,8 +870,8 @@ impl DynCompatibilityViolation {
add_self_sugg: add_self_sugg.clone(),
make_sized_sugg: make_sized_sugg.clone(),
},
Self::Method(name, MethodViolation::UndispatchableReceiver(Some(span)), _) => {
DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span)
Self::Method(name, MethodViolation::UndispatchableReceiver(Some((span, lt))), _) => {
DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span, *lt)
}
Self::Method(name, ..) | Self::AssocConst(name, ..) | Self::GenericAssocTy(name, _) => {
DynCompatibilityViolationSolution::MoveToAnotherTrait(*name)
Expand Down Expand Up @@ -909,7 +909,7 @@ pub enum DynCompatibilityViolationSolution {
add_self_sugg: (String, Span),
make_sized_sugg: (String, Span),
},
ChangeToRefSelf(Symbol, Span),
ChangeToRefSelf(Symbol, Span, Symbol),
MoveToAnotherTrait(Symbol),
}

Expand All @@ -922,30 +922,30 @@ impl DynCompatibilityViolationSolution {
add_self_sugg,
make_sized_sugg,
} => {
err.span_suggestion(
err.span_suggestion_verbose(
add_self_sugg.1,
format!(
"consider turning `{name}` into a method by giving it a `&self` \
argument, so that it is accessible through the trait object's vtable"
"consider turning `{name}` into a method by giving it a `&self` argument, \
so that it is accessible through the trait object's vtable",
),
add_self_sugg.0,
Applicability::MaybeIncorrect,
);
err.span_suggestion(
err.span_suggestion_verbose(
make_sized_sugg.1,
format!(
"alternatively, consider constraining `{name}` so it is explicitly \
marked as not applying to trait objects"
"alternatively, consider constraining `{name}` so it is explicitly marked \
as not applying to trait objects",
),
make_sized_sugg.0,
Applicability::MaybeIncorrect,
);
}
DynCompatibilityViolationSolution::ChangeToRefSelf(name, span) => {
err.span_suggestion(
DynCompatibilityViolationSolution::ChangeToRefSelf(name, span, lt) => {
err.span_suggestion_verbose(
span,
format!("consider changing method `{name}`'s `self` parameter to be `&self`"),
"&Self",
format!("&{lt}{}self", if lt != sym::empty { " " } else { "" }),
Applicability::MachineApplicable,
);
}
Expand Down Expand Up @@ -983,8 +983,11 @@ pub enum MethodViolation {
/// e.g., `fn (mut ap: ...)`
CVariadic,

/// the method's receiver (`self` argument) can't be dispatched on
UndispatchableReceiver(Option<Span>),
/// The method's receiver (`self` argument) can't be dispatched on
///
/// The `Span` points at the receiver. The `Symbol` is the lifetime's name `'a` when we have
/// Arbitrary Self Types like `self: &'a ()`.
UndispatchableReceiver(Option<(Span, Symbol)>),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second field Symbol is little bit confusing. It feels like a symbol for the receiver's type or self kw itself, rather than its (maybe empty) lifetime to me 😅. How would you feel about making it as a named field or add a doc comment for it?

}

/// Reasons an associated const might not be dyn compatible.
Expand Down
36 changes: 30 additions & 6 deletions compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_middle::ty::{
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized,
Upcast, elaborate,
};
use rustc_span::{DUMMY_SP, Span};
use rustc_span::{DUMMY_SP, Span, kw, sym};
use smallvec::SmallVec;
use tracing::{debug, instrument};

Expand Down Expand Up @@ -403,7 +403,7 @@ pub fn dyn_compatibility_violations_for_assoc_item(
// Get an accurate span depending on the violation.
let span = match (&v, node) {
(MethodViolation::ReferencesSelfInput(Some(span)), _) => *span,
(MethodViolation::UndispatchableReceiver(Some(span)), _) => *span,
(MethodViolation::UndispatchableReceiver(Some((span, _))), _) => *span,
(MethodViolation::ReferencesImplTraitInTrait(span), _) => *span,
(MethodViolation::ReferencesSelfOutput, Some(node)) => {
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
Expand Down Expand Up @@ -519,16 +519,40 @@ fn virtual_call_violations_for_method<'tcx>(
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
if receiver_ty != tcx.types.self_param {
if !receiver_is_dispatchable(tcx, method, receiver_ty) {
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, _),
let span_n_lt = if let Some(hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, trait_fn),
..
})) = tcx.hir_get_if_local(method.def_id).as_ref()
{
Some(sig.decl.inputs[0].span)
// If we have `self: &'a Ty`, get `'a`, so that we can suggest `&'a self`.
let lt = match sig.decl.inputs[0].kind {
hir::TyKind::Ref(lt, _) if lt.ident.name == kw::UnderscoreLifetime => {
sym::empty
}
hir::TyKind::Ref(lt, _) => lt.ident.name,
_ => sym::empty,
};
// Get the `Span` for all of `self: Ty`, not just `Ty`.
match trait_fn {
hir::TraitFn::Required([Some(name), ..])
if name.span.eq_ctxt(sig.decl.inputs[0].span) =>
{
Some(name.span.to(sig.decl.inputs[0].span))
}
hir::TraitFn::Provided(body_id)
if let body = tcx.hir_body(*body_id)
&& let Some(p) = body.params.get(0)
&& p.span.eq_ctxt(p.ty_span) =>
{
Some(p.span.to(p.ty_span))
}
_ => None,
}
.map(|sp| (sp, lt))
} else {
None
};
errors.push(MethodViolation::UndispatchableReceiver(span));
errors.push(MethodViolation::UndispatchableReceiver(span_n_lt));
} else {
// We confirm that the `receiver_is_dispatchable` is accurate later,
// see `check_receiver_correct`. It should be kept in sync with this code.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
error[E0038]: the trait `Fetcher` is not dyn compatible
--> $DIR/undispatchable-receiver-and-wc-references-Self.rs:19:21
|
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
| ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
...
LL | fn fetcher() -> Box<dyn Fetcher> {
| ^^^^^^^^^^^ `Fetcher` 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/undispatchable-receiver-and-wc-references-Self.rs:11:22
--> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:16
|
LL | pub trait Fetcher: Send + Sync {
| ------- this trait is not dyn compatible...
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
| ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
| ^^^^^^^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
help: consider changing method `get`'s `self` parameter to be `&self`
|
LL - fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
LL + fn get<'a>(&'a self) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
|

error[E0038]: the trait `Fetcher` is not dyn compatible
--> $DIR/undispatchable-receiver-and-wc-references-Self.rs:25:19
|
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
| ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
...
LL | let fetcher = fetcher();
| ^^^^^^^^^ `Fetcher` 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/undispatchable-receiver-and-wc-references-Self.rs:11:22
--> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:16
|
LL | pub trait Fetcher: Send + Sync {
| ------- this trait is not dyn compatible...
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
| ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
| ^^^^^^^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
help: consider changing method `get`'s `self` parameter to be `&self`
|
LL - fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
LL + fn get<'a>(&'a self) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
|

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,22 @@ LL | fn method(self: &unsafe<'ops> &'a dyn Bar) {}
error[E0038]: the trait `Foo` is not dyn compatible
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:17:13
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| --------------------- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
...
LL | fn test(x: &dyn Foo) {
| ^^^^^^^ `Foo` 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/unsafe-binders-bare-trait-object-next-solver.rs:10:21
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:15
|
LL | trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
| --- this trait is not dyn compatible...
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on
help: consider changing method `method`'s `self` parameter to be `&self`
|
LL - fn method(self: &unsafe<'ops> &'a Bar) {}
LL + fn method(&self) {}
|

error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:19:7
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
error[E0038]: the trait `Trait` is not dyn compatible
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:33
|
LL | fn ptr(self: Ptr<Self>);
| --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
...
LL | Ptr(Box::new(4)) as Ptr<dyn Trait>;
| ^^^^^ `Trait` 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/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:12
|
LL | trait Trait {
| ----- this trait is not dyn compatible...
LL | fn ptr(self: Ptr<Self>);
| ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
| ^^^^^^^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
= help: only type `i32` implements `Trait`; consider using it directly instead.
help: consider changing method `ptr`'s `self` parameter to be `&self`
|
LL - fn ptr(self: Ptr<Self>);
LL + fn ptr(&self);
|

error: aborting due to 1 previous error

Expand Down
12 changes: 7 additions & 5 deletions tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
error[E0038]: the trait `Foo` is not dyn compatible
--> $DIR/arbitrary-self-types-dyn-incompatible.rs:29:39
|
LL | fn foo(self: &Rc<Self>) -> usize;
| --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
...
LL | let x = Rc::new(5usize) as Rc<dyn Foo>;
| ^^^ `Foo` 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/arbitrary-self-types-dyn-incompatible.rs:4:18
--> $DIR/arbitrary-self-types-dyn-incompatible.rs:4:12
|
LL | trait Foo {
| --- this trait is not dyn compatible...
LL | fn foo(self: &Rc<Self>) -> usize;
| ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
| ^^^^^^^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
= help: only type `usize` implements `Foo`; consider using it directly instead.
help: consider changing method `foo`'s `self` parameter to be `&self`
|
LL - fn foo(self: &Rc<Self>) -> usize;
LL + fn foo(&self) -> usize;
|

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
error[E0038]: the trait `Foo` is not dyn compatible
--> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:12:13
|
LL | fn method(self: &W) {}
| -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
...
LL | fn test(x: &dyn Foo) {
| ^^^^^^^ `Foo` 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/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21
--> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:15
|
LL | trait Foo: Deref<Target = W> {
| --- this trait is not dyn compatible...
LL | fn method(self: &W) {}
| ^^ ...because method `method`'s `self` parameter cannot be dispatched on
| ^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on
help: consider changing method `method`'s `self` parameter to be `&self`
|
LL - fn method(self: &W) {}
LL + fn method(&self) {}
|

error[E0307]: invalid `self` parameter type: `&W`
--> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

trait Trait {
fn foo(&self) where Self: Other, Self: Sized { }
fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type
fn bar(&self) {} //~ ERROR invalid `self` parameter type
}

fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LL | trait Trait {
LL | fn foo() where Self: Other, { }
| ^^^ ...because associated function `foo` has no `self` parameter
LL | fn bar(self: ()) {}
| ^^ ...because method `bar`'s `self` parameter cannot be dispatched on
| ^^^^^^^^ ...because method `bar`'s `self` parameter cannot be dispatched on
help: consider turning `foo` into a method by giving it a `&self` argument, so that it is accessible through the trait object's vtable
|
LL | fn foo(&self) where Self: Other, { }
Expand All @@ -25,7 +25,7 @@ LL | fn foo() where Self: Other, Self: Sized { }
help: consider changing method `bar`'s `self` parameter to be `&self`
|
LL - fn bar(self: ()) {}
LL + fn bar(self: &Self) {}
LL + fn bar(&self) {}
|

error[E0307]: invalid `self` parameter type: `()`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ LL | impl LeakTr for LeakS {}
error[E0038]: the trait `DynCompatCheck2` is not dyn compatible
--> $DIR/maybe-bounds-in-dyn-traits.rs:90:17
|
LL | fn mut_foo(&mut self) {}
| --------- help: consider changing method `mut_foo`'s `self` parameter to be `&self`: `&Self`
...
LL | let _: &dyn DynCompatCheck2 = &NonLeakS;
| ^^^^^^^^^^^^^^^ `DynCompatCheck2` is not dyn compatible
|
Expand All @@ -34,6 +31,11 @@ LL | trait DynCompatCheck2: ?Leak {
LL | fn mut_foo(&mut self) {}
| ^^^^^^^^^ ...because method `mut_foo`'s `self` parameter cannot be dispatched on
= help: only type `NonLeakS` implements `DynCompatCheck2`; consider using it directly instead.
help: consider changing method `mut_foo`'s `self` parameter to be `&self`
|
LL - fn mut_foo(&mut self) {}
LL + fn mut_foo(&self) {}
|

error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/maybe-bounds-in-dyn-traits.rs:98:26
Expand Down
Loading