Skip to content
Open
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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/compare_eii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ fn report_eii_mismatch<'tcx>(
infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)),
trait_err_span.map(|sp| (sp.into(), Cow::from("type in declaration"), false)),
Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
expected: ty::Binder::dummy(declaration_sig),
found: ty::Binder::dummy(external_impl_sig),
Expand Down
67 changes: 61 additions & 6 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_middle::ty::{
TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
Unnormalized, Upcast,
};
use rustc_span::{BytePos, DUMMY_SP, Span, bug, span_bug};
use rustc_span::{BytePos, DUMMY_SP, Span, bug, kw, span_bug};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::regions::InferCtxtRegionExt;
Expand Down Expand Up @@ -624,12 +624,16 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
"method `{}` has an incompatible return type for trait",
trait_m.name()
);
diag.span_context(tcx.def_span(impl_m.container_id(tcx)).shrink_to_lo());
infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
tcx.hir_get_if_local(impl_m.def_id)
.and_then(|node| node.fn_decl())
.map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)),
tcx.hir_get_if_local(trait_m.def_id).and_then(|node| node.fn_decl()).map(|decl| {
let mut span: MultiSpan = decl.output.span().into();
span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo());
span.push_span_context(tcx.def_span(trait_m.def_id).shrink_to_lo());
(span, Cow::from("return type in trait"), false)
}),
Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
expected: trait_return_ty.into(),
found: impl_return_ty.into(),
Expand Down Expand Up @@ -1013,6 +1017,7 @@ fn report_trait_method_mismatch<'tcx>(
"method `{}` has an incompatible type for trait",
trait_m.name()
);
diag.span_context(tcx.def_span(impl_m.container_id(tcx)).shrink_to_lo());
match &terr {
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
if trait_m.is_method() =>
Expand Down Expand Up @@ -1078,10 +1083,53 @@ fn report_trait_method_mismatch<'tcx>(
}

cause.span = impl_err_span;

let mut labels = vec![];
let mut context = vec![];
if let TypeError::ArgumentSorts(_, i) = &terr
&& let Some(ty) =
tcx.fn_sig(trait_m.def_id).skip_binder().inputs_and_output().skip_binder().get(*i)
&& let ty::Param(param) = ty.kind()
// The expected type corresponds to a type parameter, which migh thave a default type or
// have been explicitly set in the `impl` with a different type.
&& let generics = tcx.generics_of(trait_m.def_id)
&& let param = generics.type_param(*param, tcx)
&& let GenericParamDefKind::Type { has_default: true, .. } = param.kind
{
context.push(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo());

let param_name = param.name;
let msg = if let Some(ty) = trait_sig.inputs_and_output.get(*i)
&& infcx.can_eq(param_env, *ty, tcx.type_of(param.def_id).skip_binder())
{
format!("expected to match the default of type parameter `{param_name}`")
} else if let Some(ty) = trait_sig.inputs_and_output.get(*i)
&& let ty::Param(p) = tcx.type_of(param.def_id).skip_binder().kind()
&& p.name == kw::SelfUpper
&& infcx.can_eq(param_env, *ty, impl_trait_ref.self_ty())
{
format!("expected to match the `Self` default of type parameter `{param_name}`")
} else {
format!("expected to match type parameter `{param_name}`")
};
labels.push((tcx.def_span(param.def_id), msg));
}

infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)),
trait_err_span.map(|sp| {
let mut span: MultiSpan = sp.into();
span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo());
span.push_span_context(tcx.def_span(trait_m.def_id).shrink_to_lo());
for (sp, label) in labels {
span.push_span_label(sp, label);
}
for sp in context {
span.push_span_context(sp);
}
(span, Cow::from("type in trait"), false)
}),
Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
expected: ty::Binder::dummy(trait_sig),
found: ty::Binder::dummy(impl_sig),
Expand Down Expand Up @@ -2284,6 +2332,8 @@ fn compare_const_clause_entailment<'tcx>(
"implemented const `{}` has an incompatible type for trait",
trait_ct.name()
);
diag.span_context(tcx.def_span(impl_ct.container_id(tcx)).shrink_to_lo());
diag.span_context(tcx.def_span(impl_ct.def_id).shrink_to_lo());

let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
// Add a label to the Span containing just the type of the const
Expand All @@ -2294,7 +2344,12 @@ fn compare_const_clause_entailment<'tcx>(
infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
trait_c_span.map(|span| (span, Cow::from("type in trait"), false)),
trait_c_span.map(|span| {
let mut span: MultiSpan = span.into();
span.push_span_context(tcx.def_span(trait_ct.container_id(tcx)).shrink_to_lo());
span.push_span_context(tcx.def_span(trait_ct.def_id).shrink_to_lo());
(span, Cow::from("type in trait"), false)
}),
Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
expected: trait_ty.into(),
found: impl_ty.into(),
Expand Down
31 changes: 21 additions & 10 deletions compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ use rustc_abi::ExternAbi;
use rustc_attr_ir::diagnostic::{CustomDiagnostic, Directive, FormatArgs};
use rustc_attr_ir::find_attr;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize};
use rustc_errors::{
Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
};
use rustc_hir as hir;
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_hir::intravisit::Visitor;
Expand Down Expand Up @@ -1463,7 +1465,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
diag: &mut Diag<'_>,
cause: &ObligationCause<'tcx>,
secondary_span: Option<(Span, Cow<'static, str>, bool)>,
secondary_span: Option<(MultiSpan, Cow<'static, str>, bool)>,
mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
terr: TypeError<'tcx>,
prefer_label: bool,
Expand Down Expand Up @@ -1639,9 +1641,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
};

let mut label_or_note = |span: Span, msg: Cow<'static, str>| {
if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
diag.span_label(span, msg);
let mut label_or_note = |span: MultiSpan, msg: Cow<'static, str>| {
if !span.has_span_labels()
&& span.span_context().is_empty()
&& ((prefer_label && is_simple_error)
|| span.primary_spans() == diag.span.primary_spans())
{
for span in span.primary_spans() {
diag.span_label(*span, msg.clone());
}
} else {
diag.span_note(span, msg);
}
Expand All @@ -1657,9 +1665,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
terr.to_string(self.tcx)
};
label_or_note(secondary_span, terr);
label_or_note(span, secondary_msg);
label_or_note(span.into(), secondary_msg);
} else {
label_or_note(span, terr.to_string(self.tcx));
label_or_note(span.into(), terr.to_string(self.tcx));
label_or_note(secondary_span, secondary_msg);
}
} else if let Some(values) = values
Expand All @@ -1671,12 +1679,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
let found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
if expected == found {
label_or_note(span, terr.to_string(self.tcx));
label_or_note(span.into(), terr.to_string(self.tcx));
} else {
label_or_note(span, Cow::from(format!("expected {expected}, found {found}")));
label_or_note(
span.into(),
Cow::from(format!("expected {expected}, found {found}")),
);
}
} else {
label_or_note(span, terr.to_string(self.tcx));
label_or_note(span.into(), terr.to_string(self.tcx));
}

if let Some(param_env) = param_env {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
..
}),
) => Some((
ty.span,
ty.span.into(),
with_forced_trimmed_paths!(Cow::from(format!(
"type mismatch resolving `{}`",
self.tcx.short_string(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
error[E0326]: implemented const `FROM` has an incompatible type for trait
--> $DIR/associated-const-generic-obligations.rs:14:17
|
LL | impl<T: Foo> Bar for T {
LL | const FROM: &'static str = "foo";
| ^^^^^^^^^^^^ expected associated type, found `&'static str`
|
note: type in trait
--> $DIR/associated-const-generic-obligations.rs:10:17
|
LL | trait Bar: Foo {
LL | const FROM: Self::Out;
| ^^^^^^^^^
= note: expected associated type `<T as Foo>::Out`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
error[E0326]: implemented const `BAR` has an incompatible type for trait
--> $DIR/associated-const-impl-wrong-type.rs:8:16
|
LL | impl Foo for SignedBar {
LL | const BAR: i32 = -1;
| ^^^ expected `u32`, found `i32`
|
note: type in trait
--> $DIR/associated-const-impl-wrong-type.rs:2:16
|
LL | trait Foo {
LL | const BAR: u32;
| ^^^

Expand Down
6 changes: 6 additions & 0 deletions tests/ui/associated-types/defaults-specialization.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
error[E0053]: method `make` has an incompatible type for trait
--> $DIR/defaults-specialization.rs:18:18
|
LL | default impl<T> Tr for A<T> {
LL | fn make() -> u8 { 0 }
| ^^ expected associated type, found `u8`
|
note: type in trait
--> $DIR/defaults-specialization.rs:8:18
|
LL | trait Tr {
...
LL | fn make() -> Self::Ty {
| ^^^^^^^^
= note: expected signature `fn() -> <A<T> as Tr>::Ty`
Expand All @@ -20,6 +23,7 @@ LL + fn make() -> <A<T> as Tr>::Ty { 0 }
error[E0053]: method `make` has an incompatible type for trait
--> $DIR/defaults-specialization.rs:34:18
|
LL | impl<T> Tr for B<T> {
LL | default type Ty = bool;
| --------------- associated type is `default` and may be overridden
LL |
Expand All @@ -29,6 +33,8 @@ LL | fn make() -> bool { true }
note: type in trait
--> $DIR/defaults-specialization.rs:8:18
|
LL | trait Tr {
...
LL | fn make() -> Self::Ty {
| ^^^^^^^^
= note: expected signature `fn() -> <B<T> as Tr>::Ty`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:28
|
LL | impl MyTrait for i32 {
LL | async fn foo(&self) -> i32 {
| ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
|
note: type in trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:7:22
|
LL | trait MyTrait {
LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature `fn(&_) -> Pin<Box<dyn Future<Output = i32>>>`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/dont-project-to-specializable-projection.rs:14:35
|
LL | impl<T> MyTrait<T> for MyStruct {
LL | default async fn foo(_: T) -> &'static str {
| ^^^^^^^^^^^^ expected associated type, found future
|
note: type in trait
--> $DIR/dont-project-to-specializable-projection.rs:10:27
|
LL | trait MyTrait<T> {
LL | async fn foo(_: T) -> &'static str;
| ^^^^^^^^^^^^
= note: expected signature `fn(_) -> impl Future<Output = &'static str>`
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/compare-method/bad-self-type.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0053]: method `poll` has an incompatible type for trait
--> $DIR/bad-self-type.rs:10:13
|
LL | impl Future for MyFuture {
LL | type Output = ();
LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> {
| ^^^^ expected `Pin<&mut MyFuture>`, found `MyFuture`
|
Expand All @@ -14,12 +16,14 @@ LL | fn poll(self: Pin<&mut MyFuture>, _: &mut Context<'_>) -> Poll<()> {
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/bad-self-type.rs:22:18
|
LL | impl T for MyFuture {
LL | fn foo(self: Box<Self>) {}
| ^^^^^^^^^ expected `MyFuture`, found `Box<MyFuture>`
|
note: type in trait
--> $DIR/bad-self-type.rs:17:12
|
LL | trait T {
LL | fn foo(self);
| ^^^^
= note: expected signature `fn(MyFuture)`
Expand All @@ -33,12 +37,16 @@ LL + fn foo(self) {}
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/bad-self-type.rs:24:17
|
LL | impl T for MyFuture {
...
LL | fn bar(self) {}
| ^ expected `Option<()>`, found `()`
|
note: type in trait
--> $DIR/bad-self-type.rs:18:21
|
LL | trait T {
LL | fn foo(self);
LL | fn bar(self) -> Option<()>;
| ^^^^^^^^^^
= note: expected signature `fn(MyFuture) -> Option<()>`
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/compare-method/default-type-parameter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
trait Trait<T = ()> {
fn foo() -> T;
}

struct S;

impl Trait for S {
fn foo() -> u32 { 0 } //~ ERROR
}
impl Trait<i32> for () {
fn foo() -> u32 { 0 } //~ ERROR
}

fn main() {}
47 changes: 47 additions & 0 deletions tests/ui/compare-method/default-type-parameter.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/default-type-parameter.rs:8:17
|
LL | impl Trait for S {
LL | fn foo() -> u32 { 0 }
| ^^^ expected `()`, found `u32`
|
note: type in trait
--> $DIR/default-type-parameter.rs:2:17
|
LL | trait Trait<T = ()> {
| ------ expected to match the default of type parameter `T`
LL | fn foo() -> T;
| ^
= note: expected signature `fn() -> ()`
found signature `fn() -> u32`
help: change the output type to match the trait
|
LL - fn foo() -> u32 { 0 }
LL + fn foo() -> () { 0 }
|

error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/default-type-parameter.rs:11:17
|
LL | impl Trait<i32> for () {
LL | fn foo() -> u32 { 0 }
| ^^^ expected `i32`, found `u32`
|
note: type in trait
--> $DIR/default-type-parameter.rs:2:17
|
LL | trait Trait<T = ()> {
| ------ expected to match type parameter `T`
LL | fn foo() -> T;
| ^
= note: expected signature `fn() -> i32`
found signature `fn() -> u32`
help: change the output type to match the trait
|
LL - fn foo() -> u32 { 0 }
LL + fn foo() -> i32 { 0 }
|

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0053`.
Loading
Loading