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
70 changes: 63 additions & 7 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 @@ -625,12 +625,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 @@ -1014,6 +1018,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 @@ -1079,10 +1084,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());

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.

What does this context do? Removing this line doesn't seem to change any test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It will ensure that line that starts the containing trait will be displayed. It would only happen with weirdly formatted code or really long signatures.


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}`")

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.

We seem to not have test for this, could you help to add one?

} 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());

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.

This also doesn't seem to change anything when removed. What is the intention of adding this line?

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 @@ -2190,7 +2238,8 @@ fn compare_const_generic_param_types<'tcx>(
infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
param_trait_ty_span.map(|span| (span, Cow::from("type in trait"), false)),
param_trait_ty_span
.map(|span| (span.into(), Cow::from("type in trait"), false)),
Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
expected: trait_ty.into(),
found: impl_ty.into(),
Expand Down Expand Up @@ -2365,6 +2414,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 @@ -2375,7 +2426,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 @@ -1462,7 +1464,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 @@ -1638,9 +1640,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 @@ -1656,9 +1664,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 @@ -1670,12 +1678,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 @@ -1919,7 +1919,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
5 changes: 5 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 {
...

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.

non-blocking style nit: will it be possible to have...?

    LL | trait Tr {
       |  ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That change is something to bring up to rust-lang/annotate-snippets-rs. I don't think that rendering is necessarily ideal, because it would be hard to differentiate between the actual code being

trait Tr {
 ...

and

trait Tr {
// this like will be skipped by the diagnostic renderer and replaced with ` ...`

By having it on the other side of the gutter, it makes that a bit clearer.

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.

I see, makes sense.

LL | fn make() -> Self::Ty {
| ^^^^^^^^
= note: expected signature `fn() -> <A<T> as Tr>::Ty`
Expand All @@ -30,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
Expand Up @@ -4,7 +4,8 @@ use std::future::Future;
use std::pin::Pin;

trait MyTrait {
fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
fn foo(&self)
-> Pin<Box<dyn Future<Output = i32> + '_>>;
}

impl MyTrait for i32 {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:28
--> $DIR/async-example-desugared-boxed-in-trait.rs:12: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
--> $DIR/async-example-desugared-boxed-in-trait.rs:8:8
|
LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | trait MyTrait {
LL | fn foo(&self)
LL | -> Pin<Box<dyn Future<Output = i32> + '_>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature `fn(&_) -> Pin<Box<dyn Future<Output = i32>>>`
found signature `fn(&_) -> impl 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 {
...
Comment thread
estebank marked this conversation as resolved.
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
25 changes: 25 additions & 0 deletions tests/ui/compare-method/default-type-parameter.rs
Comment thread
estebank marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Regression test for https://github.com/rust-lang/rust/issues/67991
// The weird indentation is to excercise the span context that shows the enclosing items in the
// diagnostics being emitted.
trait Trait<
T = (),
K = Self,
> {
fn foo()
-> T;
fn bar()
-> K;
}

struct S;

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

fn main() {}
Loading
Loading