Use more appropriate spans on object unsafe traits and provide structured suggestions when possible

This commit is contained in:
Esteban Küber 2020-01-31 18:48:35 -08:00
parent 413bfa4b98
commit a52ec87a17
22 changed files with 178 additions and 62 deletions

View File

@ -1073,9 +1073,15 @@ pub fn report_object_safety_error(
err.span_label(span, &msg);
}
}
if let (Some(_), Some(note)) = (trait_span, violation.solution()) {
match (trait_span, violation.solution()) {
(Some(_), Some((note, None))) => {
err.help(&note);
}
(Some(_), Some((note, Some((sugg, span))))) => {
err.span_suggestion(span, &note, sugg, Applicability::MachineApplicable);
}
// Only provide the help if its a local trait, otherwise it's not actionable.
err.help(&note);
_ => {}
}
}
}

View File

@ -13,6 +13,7 @@ use super::elaborate_predicates;
use crate::traits::{self, Obligation, ObligationCause};
use crate::ty::subst::{InternalSubsts, Subst};
use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
@ -48,14 +49,20 @@ impl ObjectSafetyViolation {
"it cannot use `Self` as a type parameter in the supertraits or `where`-clauses"
.into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => {
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
format!("associated function `{}` has no `self` parameter", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf, _) => format!(
"method `{}` references the `Self` type in its parameters or return type",
ObjectSafetyViolation::Method(
name,
)
.into(),
MethodViolationCode::ReferencesSelfInput(_),
DUMMY_SP,
) => format!("method `{}` references the `Self` type in its parameters", name).into(),
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => {
format!("method `{}` references the `Self` type in this parameter", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
format!("method `{}` references the `Self` type in its return type", name).into()
}
ObjectSafetyViolation::Method(
name,
MethodViolationCode::WhereClauseReferencesSelf,
@ -78,23 +85,31 @@ impl ObjectSafetyViolation {
}
}
pub fn solution(&self) -> Option<String> {
pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> {
Some(match *self {
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf => {
return None;
}
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => format!(
"consider turning `{}` into a method by giving it a `&self` argument or \
constraining it with `where Self: Sized`",
name
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => (
format!(
"consider turning `{}` into a method by giving it a `&self` argument or \
constraining it so it does not apply to trait objects",
name
),
sugg.map(|(sugg, sp)| (sugg.to_string(), sp)),
),
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
ObjectSafetyViolation::Method(
name,
MethodViolationCode::UndispatchableReceiver,
span,
) => (
format!("consider changing method `{}`'s `self` parameter to be `&self`", name)
.into()
}
.into(),
Some(("&Self".to_string(), span)),
),
ObjectSafetyViolation::AssocConst(name, _)
| ObjectSafetyViolation::Method(name, ..) => {
format!("consider moving `{}` to another trait", name)
(format!("consider moving `{}` to another trait", name), None)
}
})
}
@ -119,10 +134,13 @@ impl ObjectSafetyViolation {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum MethodViolationCode {
/// e.g., `fn foo()`
StaticMethod,
StaticMethod(Option<(&'static str, Span)>),
/// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
ReferencesSelf,
/// e.g., `fn foo(&self, x: Self)`
ReferencesSelfInput(usize),
/// e.g., `fn foo(&self) -> Self`
ReferencesSelfOutput,
/// e.g., `fn foo(&self) where Self: Clone`
WhereClauseReferencesSelf,
@ -193,7 +211,7 @@ fn object_safety_violations_for_trait(
.filter(|item| item.kind == ty::AssocKind::Method)
.filter_map(|item| {
object_safety_violation_for_method(tcx, trait_def_id, &item)
.map(|code| ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span))
.map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span))
})
.filter(|violation| {
if let ObjectSafetyViolation::Method(
@ -224,9 +242,15 @@ fn object_safety_violations_for_trait(
)
};
err.span_label(*span, &msg);
if let (Some(_), Some(note)) = (node, violation.solution()) {
match (node, violation.solution()) {
(Some(_), Some((note, None))) => {
err.help(&note);
}
(Some(_), Some((note, Some((sugg, span))))) => {
err.span_suggestion(span, &note, sugg, Applicability::MachineApplicable);
}
// Only provide the help if its a local trait, otherwise it's not actionable.
err.help(&note);
_ => {}
}
err.emit();
false
@ -398,7 +422,7 @@ fn object_safety_violation_for_method(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
) -> Option<(MethodViolationCode, Span)> {
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self : Sized` requisite is otherwise
// exempt from the regulations.
@ -406,7 +430,26 @@ fn object_safety_violation_for_method(
return None;
}
virtual_call_violation_for_method(tcx, trait_def_id, method)
let violation = virtual_call_violation_for_method(tcx, trait_def_id, method);
// Get an accurate span depending on the violation.
violation.map(|v| {
let node = tcx.hir().get_if_local(method.def_id);
let span = match (v, node) {
(MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node
.fn_decl()
.and_then(|decl| decl.inputs.get(arg + 1))
.map_or(method.ident.span, |arg| arg.span),
(MethodViolationCode::UndispatchableReceiver, Some(node)) => node
.fn_decl()
.and_then(|decl| decl.inputs.get(0))
.map_or(method.ident.span, |arg| arg.span),
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
node.fn_decl().map_or(method.ident.span, |decl| decl.output.span())
}
_ => method.ident.span,
};
(v, span)
})
}
/// Returns `Some(_)` if this method cannot be called on a trait
@ -420,18 +463,26 @@ fn virtual_call_violation_for_method<'tcx>(
) -> Option<MethodViolationCode> {
// The method's first parameter must be named `self`
if !method.method_has_self_argument {
return Some(MethodViolationCode::StaticMethod);
// We'll attempt to provide a structured suggestion for `Self: Sized`.
let sugg =
tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map(
|generics| match generics.where_clause.predicates {
[] => (" where Self: Sized", generics.where_clause.span),
[.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
},
);
return Some(MethodViolationCode::StaticMethod(sugg));
}
let sig = tcx.fn_sig(method.def_id);
for input_ty in &sig.skip_binder().inputs()[1..] {
for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
return Some(MethodViolationCode::ReferencesSelfInput(i));
}
}
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) {
return Some(MethodViolationCode::ReferencesSelf);
return Some(MethodViolationCode::ReferencesSelfOutput);
}
// We can't monomorphize things like `fn foo<A>(...)`.

View File

@ -2631,4 +2631,25 @@ impl Node<'_> {
_ => None,
}
}
pub fn fn_decl(&self) -> Option<&FnDecl<'_>> {
match self {
Node::TraitItem(TraitItem { kind: TraitItemKind::Method(fn_sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Method(fn_sig, _), .. })
| Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
Some(fn_decl)
}
_ => None,
}
}
pub fn generics(&self) -> Option<&Generics<'_>> {
match self {
Node::TraitItem(TraitItem { generics, .. })
| Node::ImplItem(ImplItem { generics, .. })
| Node::Item(Item { kind: ItemKind::Fn(_, generics, _), .. }) => Some(generics),
_ => None,
}
}
}

View File

@ -172,7 +172,7 @@ impl<'a> Parser<'a> {
/// ```
pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
let mut where_clause =
WhereClause { predicates: Vec::new(), span: self.prev_span.to(self.prev_span) };
WhereClause { predicates: Vec::new(), span: self.prev_span.shrink_to_hi() };
if !self.eat_keyword(kw::Where) {
return Ok(where_clause);

View File

@ -2,7 +2,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object
--> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:6
|
LL | trait NotObjectSafe { fn eq(&self, other: Self); }
| ------------- -- ...because method `eq` references the `Self` type in its parameters or return type
| ------------- ---- ...because method `eq` references the `Self` type in this parameter
| |
| this trait cannot be made into an object...
LL | impl NotObjectSafe for dyn NotObjectSafe { }

View File

@ -15,7 +15,10 @@ LL | fn foo();
LL | let trait_obj: &dyn SomeTrait = SomeTrait;
| ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
--> $DIR/E0033-teach.rs:12:9

View File

@ -15,7 +15,10 @@ LL | fn foo();
LL | let trait_obj: &dyn SomeTrait = SomeTrait;
| ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
--> $DIR/E0033.rs:10:9

View File

@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object
LL | trait Trait {
| ----- this trait cannot be made into an object...
LL | fn foo(&self) -> Self;
| --- ...because method `foo` references the `Self` type in its parameters or return type
| ---- ...because method `foo` references the `Self` type in its return type
...
LL | fn call_foo(x: Box<dyn Trait>) {
| ^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object

View File

@ -20,7 +20,10 @@ LL | fn static_fn() {}
LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object
|
= help: consider turning `static_fn` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `static_fn` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn static_fn() where Self: Sized {}
| ^^^^^^^^^^^^^^^^^
error[E0038]: the trait `NonObjectSafe3` cannot be made into an object
--> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35
@ -41,7 +44,7 @@ error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
LL | trait NonObjectSafe4 {
| -------------- this trait cannot be made into an object...
LL | fn foo(&self, &Self);
| --- ...because method `foo` references the `Self` type in its parameters or return type
| ----- ...because method `foo` references the `Self` type in this parameter
...
LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object

View File

@ -9,7 +9,10 @@ LL | fn foo() -> Self;
LL | fn car() -> dyn NotObjectSafe {
| ^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() -> Self where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error[E0038]: the trait `NotObjectSafe` cannot be made into an object
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:13
@ -22,7 +25,10 @@ LL | fn foo() -> Self;
LL | fn cat() -> Box<dyn NotObjectSafe> {
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() -> Self where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -9,7 +9,10 @@ LL | fn qiz();
LL | foos: &'static [&'static (dyn Qiz + 'static)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
|
= help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn qiz() where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object
LL | trait Bar {
| --- this trait cannot be made into an object...
LL | fn bar(&self, x: &Self);
| --- ...because method `bar` references the `Self` type in its parameters or return type
| ----- ...because method `bar` references the `Self` type in this parameter
...
LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ the trait `Bar` cannot be made into an object
@ -17,7 +17,7 @@ error[E0038]: the trait `Baz` cannot be made into an object
LL | trait Baz {
| --- this trait cannot be made into an object...
LL | fn baz(&self) -> Self;
| --- ...because method `baz` references the `Self` type in its parameters or return type
| ---- ...because method `baz` references the `Self` type in its return type
...
LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
| ^^^^^^^^ the trait `Baz` cannot be made into an object

View File

@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object
LL | trait Bar {
| --- this trait cannot be made into an object...
LL | fn bar(&self, x: &Self);
| --- ...because method `bar` references the `Self` type in its parameters or return type
| ----- ...because method `bar` references the `Self` type in this parameter
...
LL | t
| ^ the trait `Bar` cannot be made into an object
@ -19,7 +19,7 @@ error[E0038]: the trait `Baz` cannot be made into an object
LL | trait Baz {
| --- this trait cannot be made into an object...
LL | fn baz(&self) -> Self;
| --- ...because method `baz` references the `Self` type in its parameters or return type
| ---- ...because method `baz` references the `Self` type in its return type
...
LL | t
| ^ the trait `Baz` cannot be made into an object

View File

@ -9,7 +9,10 @@ LL | fn foo() {}
LL | fn diverges() -> Box<dyn Foo> {
| ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() where Self: Sized {}
| ^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -9,9 +9,12 @@ LL | fn foo() {}
LL | let b: Box<dyn Foo> = Box::new(Bar);
| ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<Bar>`
= note: required by cast to type `std::boxed::Box<dyn Foo>`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() where Self: Sized {}
| ^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -4,12 +4,13 @@ error[E0038]: the trait `Foo` cannot be made into an object
LL | trait Foo {
| --- this trait cannot be made into an object...
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: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
...
LL | let x = Rc::new(5usize) as Rc<dyn Foo>;
| ^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= help: consider changing method `foo`'s `self` parameter to be `&self`
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:33:13
@ -17,12 +18,14 @@ error[E0038]: the trait `Foo` cannot be made into an object
LL | trait Foo {
| --- this trait cannot be made into an object...
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: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
...
LL | let x = Rc::new(5usize) as Rc<dyn Foo>;
| ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= help: consider changing method `foo`'s `self` parameter to be `&self`
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
= note: required by cast to type `std::rc::Rc<dyn Foo>`

View File

@ -4,12 +4,14 @@ error[E0038]: the trait `Foo` cannot be made into an object
LL | trait Foo {
| --- this trait cannot be made into an object...
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: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
...
LL | let x = Rc::new(5usize) as Rc<dyn Foo>;
| ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= help: consider changing method `foo`'s `self` parameter to be `&self`
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
= note: required by cast to type `std::rc::Rc<dyn Foo>`

View File

@ -44,7 +44,10 @@ LL | fn f(a: B) -> B;
| |
| ...because associated function `f` has no `self` parameter
|
= help: consider turning `f` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `f` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn f(a: B) -> B where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View File

@ -9,9 +9,12 @@ LL | fn foo();
LL | let _: &dyn Tr = &St;
| ^^^ the trait `Tr` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St`
= note: required by cast to type `&dyn Tr`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error[E0038]: the trait `Tr` cannot be made into an object
--> $DIR/trait-object-safety.rs:15:12
@ -24,7 +27,10 @@ LL | fn foo();
LL | let _: &dyn Tr = &St;
| ^^^^^^^ the trait `Tr` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
|
LL | fn foo() where Self: Sized;
| ^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -14,9 +14,9 @@ error[E0038]: the trait `bar` cannot be made into an object
--> $DIR/trait-test-2.rs:11:16
|
LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
| --- --- ---- ...because method `blah` has generic type parameters
| | |
| | ...because method `dup` references the `Self` type in its parameters or return type
| --- ---- ---- ...because method `blah` has generic type parameters
| | |
| | ...because method `dup` references the `Self` type in its return type
| this trait cannot be made into an object...
...
LL | (box 10 as Box<dyn bar>).dup();
@ -29,9 +29,9 @@ error[E0038]: the trait `bar` cannot be made into an object
--> $DIR/trait-test-2.rs:11:6
|
LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
| --- --- ---- ...because method `blah` has generic type parameters
| | |
| | ...because method `dup` references the `Self` type in its parameters or return type
| --- ---- ---- ...because method `blah` has generic type parameters
| | |
| | ...because method `dup` references the `Self` type in its return type
| this trait cannot be made into an object...
...
LL | (box 10 as Box<dyn bar>).dup();

View File

@ -14,7 +14,7 @@ error[E0038]: the trait `MyAdd` cannot be made into an object
--> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:18
|
LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; }
| ----- --- ...because method `add` references the `Self` type in its parameters or return type
| ----- ---- ...because method `add` references the `Self` type in its return type
| |
| this trait cannot be made into an object...
...

View File

@ -4,7 +4,7 @@ error[E0038]: the trait `A` cannot be made into an object
LL | trait A {
| - this trait cannot be made into an object...
LL | fn foo(&self, _x: &Self);
| --- ...because method `foo` references the `Self` type in its parameters or return type
| ----- ...because method `foo` references the `Self` type in this parameter
...
LL | let _x: &dyn A;
| ^^^^^^ the trait `A` cannot be made into an object