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(¬e);
+ }
+ (Some(_), Some((note, Some((sugg, span))))) => {
+ err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable);
+ }
// Only provide the help if its a local trait, otherwise it's not actionable.
- err.help(¬e);
+ _ => {}
}
}
}
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;
"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,
}
}
- 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)
}
})
}
#[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)`
+ ReferencesSelfInput(usize),
- /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
- ReferencesSelf,
+ /// e.g., `fn foo(&self) -> Self`
+ ReferencesSelfOutput,
/// e.g., `fn foo(&self) where Self: Clone`
WhereClauseReferencesSelf,
.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(
)
};
err.span_label(*span, &msg);
- if let (Some(_), Some(note)) = (node, violation.solution()) {
+ match (node, violation.solution()) {
+ (Some(_), Some((note, None))) => {
+ err.help(¬e);
+ }
+ (Some(_), Some((note, Some((sugg, span))))) => {
+ err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable);
+ }
// Only provide the help if its a local trait, otherwise it's not actionable.
- err.help(¬e);
+ _ => {}
}
err.emit();
false
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.
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
) -> 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>(...)`.
_ => 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,
+ }
+ }
}
/// ```
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);
--> $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 { }
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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>`
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>`
| |
| ...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
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
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
--> $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();
--> $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();
--> $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...
...
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