Skip to content

Commit 6391f23

Browse files
authored
Rollup merge of #98506 - compiler-errors:object-safety-suggestions, r=oli-obk
Fix span issues in object safety suggestions Fixes #98500
2 parents 38bfa9c + eff865c commit 6391f23

File tree

7 files changed

+121
-74
lines changed

7 files changed

+121
-74
lines changed

compiler/rustc_middle/src/traits/mod.rs

+29-38
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ pub enum ObjectSafetyViolation {
863863

864864
impl ObjectSafetyViolation {
865865
pub fn error_msg(&self) -> Cow<'static, str> {
866-
match *self {
866+
match self {
867867
ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
868868
ObjectSafetyViolation::SupertraitSelf(ref spans) => {
869869
if spans.iter().any(|sp| *sp != DUMMY_SP) {
@@ -873,7 +873,7 @@ impl ObjectSafetyViolation {
873873
.into()
874874
}
875875
}
876-
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_, _, _), _) => {
876+
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
877877
format!("associated function `{}` has no `self` parameter", name).into()
878878
}
879879
ObjectSafetyViolation::Method(
@@ -897,9 +897,11 @@ impl ObjectSafetyViolation {
897897
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
898898
format!("method `{}` has generic type parameters", name).into()
899899
}
900-
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
901-
format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
902-
}
900+
ObjectSafetyViolation::Method(
901+
name,
902+
MethodViolationCode::UndispatchableReceiver(_),
903+
_,
904+
) => format!("method `{}`'s `self` parameter cannot be dispatched on", name).into(),
903905
ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => {
904906
format!("it contains associated `const` `{}`", name).into()
905907
}
@@ -911,51 +913,40 @@ impl ObjectSafetyViolation {
911913
}
912914

913915
pub fn solution(&self, err: &mut Diagnostic) {
914-
match *self {
916+
match self {
915917
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {}
916918
ObjectSafetyViolation::Method(
917919
name,
918-
MethodViolationCode::StaticMethod(sugg, self_span, has_args),
920+
MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
919921
_,
920922
) => {
921923
err.span_suggestion(
922-
self_span,
923-
&format!(
924+
add_self_sugg.1,
925+
format!(
924926
"consider turning `{}` into a method by giving it a `&self` argument",
925927
name
926928
),
927-
format!("&self{}", if has_args { ", " } else { "" }),
929+
add_self_sugg.0.to_string(),
930+
Applicability::MaybeIncorrect,
931+
);
932+
err.span_suggestion(
933+
make_sized_sugg.1,
934+
format!(
935+
"alternatively, consider constraining `{}` so it does not apply to \
936+
trait objects",
937+
name
938+
),
939+
make_sized_sugg.0.to_string(),
928940
Applicability::MaybeIncorrect,
929941
);
930-
match sugg {
931-
Some((sugg, span)) => {
932-
err.span_suggestion(
933-
span,
934-
&format!(
935-
"alternatively, consider constraining `{}` so it does not apply to \
936-
trait objects",
937-
name
938-
),
939-
sugg,
940-
Applicability::MaybeIncorrect,
941-
);
942-
}
943-
None => {
944-
err.help(&format!(
945-
"consider turning `{}` into a method by giving it a `&self` \
946-
argument or constraining it so it does not apply to trait objects",
947-
name
948-
));
949-
}
950-
}
951942
}
952943
ObjectSafetyViolation::Method(
953944
name,
954-
MethodViolationCode::UndispatchableReceiver,
955-
span,
945+
MethodViolationCode::UndispatchableReceiver(Some(span)),
946+
_,
956947
) => {
957948
err.span_suggestion(
958-
span,
949+
*span,
959950
&format!(
960951
"consider changing method `{}`'s `self` parameter to be `&self`",
961952
name
@@ -991,13 +982,13 @@ impl ObjectSafetyViolation {
991982
}
992983

993984
/// Reasons a method might not be object-safe.
994-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
985+
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
995986
pub enum MethodViolationCode {
996987
/// e.g., `fn foo()`
997-
StaticMethod(Option<(&'static str, Span)>, Span, bool /* has args */),
988+
StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>),
998989

999990
/// e.g., `fn foo(&self, x: Self)`
1000-
ReferencesSelfInput(usize),
991+
ReferencesSelfInput(Option<Span>),
1001992

1002993
/// e.g., `fn foo(&self) -> Self`
1003994
ReferencesSelfOutput,
@@ -1009,7 +1000,7 @@ pub enum MethodViolationCode {
10091000
Generic,
10101001

10111002
/// the method's receiver (`self` argument) can't be dispatched on
1012-
UndispatchableReceiver,
1003+
UndispatchableReceiver(Option<Span>),
10131004
}
10141005

10151006
/// These are the error cases for `codegen_fulfill_obligation`.

compiler/rustc_trait_selection/src/traits/object_safety.rs

+45-33
Original file line numberDiff line numberDiff line change
@@ -366,15 +366,9 @@ fn object_safety_violation_for_method(
366366
// Get an accurate span depending on the violation.
367367
violation.map(|v| {
368368
let node = tcx.hir().get_if_local(method.def_id);
369-
let span = match (v, node) {
370-
(MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node
371-
.fn_decl()
372-
.and_then(|decl| decl.inputs.get(arg + 1))
373-
.map_or(method.ident(tcx).span, |arg| arg.span),
374-
(MethodViolationCode::UndispatchableReceiver, Some(node)) => node
375-
.fn_decl()
376-
.and_then(|decl| decl.inputs.get(0))
377-
.map_or(method.ident(tcx).span, |arg| arg.span),
369+
let span = match (&v, node) {
370+
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
371+
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
378372
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
379373
node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
380374
}
@@ -397,32 +391,41 @@ fn virtual_call_violation_for_method<'tcx>(
397391

398392
// The method's first parameter must be named `self`
399393
if !method.fn_has_self_parameter {
400-
// We'll attempt to provide a structured suggestion for `Self: Sized`.
401-
let sugg =
402-
tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map(
403-
|generics| match generics.predicates {
404-
[] => (" where Self: Sized", generics.where_clause_span),
405-
[.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
406-
},
407-
);
408-
// Get the span pointing at where the `self` receiver should be.
409-
let sm = tcx.sess.source_map();
410-
let self_span = method.ident(tcx).span.to(tcx
411-
.hir()
412-
.span_if_local(method.def_id)
413-
.unwrap_or_else(|| sm.next_point(method.ident(tcx).span))
414-
.shrink_to_hi());
415-
let self_span = sm.span_through_char(self_span, '(').shrink_to_hi();
416-
return Some(MethodViolationCode::StaticMethod(
417-
sugg,
418-
self_span,
419-
!sig.inputs().skip_binder().is_empty(),
420-
));
394+
let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
395+
generics,
396+
kind: hir::TraitItemKind::Fn(sig, _),
397+
..
398+
})) = tcx.hir().get_if_local(method.def_id).as_ref()
399+
{
400+
let sm = tcx.sess.source_map();
401+
Some((
402+
(
403+
format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
404+
sm.span_through_char(sig.span, '(').shrink_to_hi(),
405+
),
406+
(
407+
format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
408+
generics.tail_span_for_predicate_suggestion(),
409+
),
410+
))
411+
} else {
412+
None
413+
};
414+
return Some(MethodViolationCode::StaticMethod(sugg));
421415
}
422416

423-
for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
417+
for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
424418
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
425-
return Some(MethodViolationCode::ReferencesSelfInput(i));
419+
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
420+
kind: hir::TraitItemKind::Fn(sig, _),
421+
..
422+
})) = tcx.hir().get_if_local(method.def_id).as_ref()
423+
{
424+
Some(sig.decl.inputs[i].span)
425+
} else {
426+
None
427+
};
428+
return Some(MethodViolationCode::ReferencesSelfInput(span));
426429
}
427430
}
428431
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
@@ -456,7 +459,16 @@ fn virtual_call_violation_for_method<'tcx>(
456459
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
457460
if receiver_ty != tcx.types.self_param {
458461
if !receiver_is_dispatchable(tcx, method, receiver_ty) {
459-
return Some(MethodViolationCode::UndispatchableReceiver);
462+
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
463+
kind: hir::TraitItemKind::Fn(sig, _),
464+
..
465+
})) = tcx.hir().get_if_local(method.def_id).as_ref()
466+
{
467+
Some(sig.decl.inputs[0].span)
468+
} else {
469+
None
470+
};
471+
return Some(MethodViolationCode::UndispatchableReceiver(span));
460472
} else {
461473
// Do sanity check to make sure the receiver actually has the layout of a pointer.
462474

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use std::sync::Arc;
2+
3+
pub trait A {
4+
fn f();
5+
fn f2(self: &Arc<Self>);
6+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// aux-build:not-object-safe.rs
2+
3+
extern crate not_object_safe;
4+
5+
pub trait B where
6+
Self: not_object_safe::A,
7+
{
8+
fn f2(&self);
9+
}
10+
11+
struct S(Box<dyn B>);
12+
//~^ ERROR the trait `B` cannot be made into an object
13+
14+
fn main() {}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0038]: the trait `B` cannot be made into an object
2+
--> $DIR/issue-98500.rs:11:14
3+
|
4+
LL | struct S(Box<dyn B>);
5+
| ^^^^^ `B` cannot be made into an object
6+
|
7+
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>
8+
--> $DIR/auxiliary/not-object-safe.rs:4:8
9+
|
10+
LL | fn f();
11+
| ^ ...because associated function `f` has no `self` parameter
12+
LL | fn f2(self: &Arc<Self>);
13+
| ^^ ...because method `f2`'s `self` parameter cannot be dispatched on
14+
|
15+
::: $DIR/issue-98500.rs:5:11
16+
|
17+
LL | pub trait B where
18+
| - this trait cannot be made into an object...
19+
= help: consider moving `f` to another trait
20+
= help: consider moving `f2` to another trait
21+
22+
error: aborting due to previous error
23+
24+
For more information about this error, try `rustc --explain E0038`.

src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![allow(unused_variables, dead_code)]
33

44
trait Trait {
5-
fn foo(&self) where Self: Other, Self: Sized, { }
5+
fn foo(&self) where Self: Other, Self: Sized { }
66
fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type
77
}
88

src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ LL | fn foo(&self) where Self: Other, { }
2828
| +++++
2929
help: alternatively, consider constraining `foo` so it does not apply to trait objects
3030
|
31-
LL | fn foo() where Self: Other, Self: Sized, { }
32-
| +++++++++++++
31+
LL | fn foo() where Self: Other, Self: Sized { }
32+
| ~~~~~~~~~~~~~
3333
help: consider changing method `bar`'s `self` parameter to be `&self`
3434
|
3535
LL | fn bar(self: &Self) {}

0 commit comments

Comments
 (0)