Skip to content

Commit 299bd12

Browse files
committed
Point at associated types when they have a default type
Associated types with a default type in a trait can't be relied upon to remain of that default type when in use, so literals of that type can't be used in the trait's items. Point at the associated type and state that information. Reduce verbosity for associated consts of the wrong type.
1 parent ee96b8b commit 299bd12

File tree

10 files changed

+96
-25
lines changed

10 files changed

+96
-25
lines changed

src/librustc_middle/traits/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ pub enum ObligationCauseCode<'tcx> {
193193

194194
DerivedObligation(DerivedObligationCause<'tcx>),
195195

196+
/// Error derived when matching traits/impls; see ObligationCause for more details
197+
CompareImplConstObligation,
198+
196199
/// Error derived when matching traits/impls; see ObligationCause for more details
197200
CompareImplMethodObligation {
198201
item_name: ast::Name,

src/librustc_middle/traits/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
164164
tcx.lift(cause).map(super::ImplDerivedObligation)
165165
}
166166
super::DerivedObligation(ref cause) => tcx.lift(cause).map(super::DerivedObligation),
167+
super::CompareImplConstObligation => Some(super::CompareImplConstObligation),
167168
super::CompareImplMethodObligation {
168169
item_name,
169170
impl_item_def_id,

src/librustc_middle/ty/error.rs

+64-6
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ impl<'tcx> TyCtxt<'tcx> {
339339
body_owner_def_id: DefId,
340340
) {
341341
use self::TypeError::*;
342-
342+
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
343343
match err {
344344
Sorts(values) => {
345345
let expected_str = values.expected.sort_string(self);
@@ -623,8 +623,12 @@ impl<T> Trait<T> for X {
623623
) => false,
624624
_ => true,
625625
};
626-
let impl_comparison =
627-
matches!(cause_code, ObligationCauseCode::CompareImplMethodObligation { .. });
626+
let impl_comparison = matches!(
627+
cause_code,
628+
ObligationCauseCode::CompareImplMethodObligation { .. }
629+
| ObligationCauseCode::CompareImplTypeObligation { .. }
630+
| ObligationCauseCode::CompareImplConstObligation
631+
);
628632
if !callable_scope || impl_comparison {
629633
// We do not want to suggest calling functions when the reason of the
630634
// type error is a comparison of an `impl` with its `trait` or when the
@@ -679,12 +683,66 @@ impl<T> Trait<T> for X {
679683
suggested |=
680684
self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found);
681685
}
686+
if let (Some(hir_id), false) = (self.hir().as_local_hir_id(body_owner_def_id), suggested) {
687+
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
688+
// `expected` and point at it.
689+
let parent_id = self.hir().get_parent_item(hir_id);
690+
let item = self.hir().find(parent_id);
691+
debug!("expected_projection parent item {:?}", item);
692+
match item {
693+
Some(hir::Node::Item(hir::Item {
694+
kind: hir::ItemKind::Trait(.., items), ..
695+
})) => {
696+
// FIXME: account for `#![feature(specialization)]`
697+
for item in &items[..] {
698+
match item.kind {
699+
hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
700+
if self.type_of(self.hir().local_def_id(item.id.hir_id))
701+
== values.found
702+
{
703+
if let hir::Defaultness::Default { has_value: true } =
704+
item.defaultness
705+
{
706+
db.span_label(
707+
item.span,
708+
"associated type defaults can't be assumed inside the \
709+
trait defining them",
710+
);
711+
} else {
712+
db.span_label(item.span, "expected this associated type");
713+
}
714+
suggested = true;
715+
}
716+
}
717+
_ => {}
718+
}
719+
}
720+
}
721+
Some(hir::Node::Item(hir::Item {
722+
kind: hir::ItemKind::Impl { items, .. },
723+
..
724+
})) => {
725+
for item in &items[..] {
726+
match item.kind {
727+
hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
728+
if self.type_of(self.hir().local_def_id(item.id.hir_id))
729+
== values.found
730+
{
731+
db.span_label(item.span, "expected this associated type");
732+
suggested = true;
733+
}
734+
}
735+
_ => {}
736+
}
737+
}
738+
}
739+
_ => {}
740+
}
741+
}
682742
if !suggested && !impl_comparison {
683743
// Generic suggestion when we can't be more specific.
684744
if callable_scope {
685-
db.help(
686-
&format!("{} or calling a method that returns `{}`", msg, values.expected,),
687-
);
745+
db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected));
688746
} else {
689747
db.help(&msg);
690748
}

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
17381738
predicate
17391739
));
17401740
}
1741+
ObligationCauseCode::CompareImplConstObligation => {
1742+
err.note(&format!(
1743+
"the requirement `{}` appears on the associated impl constant \
1744+
but not on the corresponding associated trait constant",
1745+
predicate
1746+
));
1747+
}
17411748
ObligationCauseCode::ReturnType
17421749
| ObligationCauseCode::ReturnValue(_)
17431750
| ObligationCauseCode::BlockTailExpression(_) => (),

src/librustc_typeck/check/compare_method.rs

+1
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ crate fn compare_const_impl<'tcx>(
966966
let impl_ty = tcx.type_of(impl_c.def_id);
967967
let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
968968
let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id);
969+
cause.code = ObligationCauseCode::CompareImplConstObligation;
969970

970971
// There is no "body" here, so just pass dummy id.
971972
let impl_ty =

src/test/ui/associated-const/associated-const-generic-obligations.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ LL | const FROM: &'static str = "foo";
99
|
1010
= note: expected associated type `<T as Foo>::Out`
1111
found reference `&'static str`
12-
= help: consider constraining the associated type `<T as Foo>::Out` to `&'static str`
13-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
1412

1513
error: aborting due to previous error
1614

src/test/ui/associated-types/defaults-in-other-trait-items.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
// Associated type defaults may not be assumed inside the trait defining them.
44
// ie. they only resolve to `<Self as Tr>::A`, not the actual type `()`
55
trait Tr {
6-
type A = ();
6+
type A = (); //~ NOTE associated type defaults can't be assumed inside the trait defining them
77

88
fn f(p: Self::A) {
99
let () = p;
1010
//~^ ERROR mismatched types
1111
//~| NOTE expected associated type, found `()`
1212
//~| NOTE expected associated type `<Self as Tr>::A`
13-
//~| HELP consider constraining the associated type
14-
//~| NOTE for more information, visit
1513
}
1614
}
1715

@@ -31,15 +29,13 @@ impl Tr for u8 {
3129
}
3230

3331
trait AssocConst {
34-
type Ty = u8;
32+
type Ty = u8; //~ NOTE associated type defaults can't be assumed inside the trait defining them
3533

3634
// Assoc. consts also cannot assume that default types hold
3735
const C: Self::Ty = 0u8;
3836
//~^ ERROR mismatched types
3937
//~| NOTE expected associated type, found `u8`
4038
//~| NOTE expected associated type `<Self as AssocConst>::Ty`
41-
//~| HELP consider constraining the associated type
42-
//~| NOTE for more information, visit
4339
}
4440

4541
// An impl can, however

src/test/ui/associated-types/defaults-in-other-trait-items.stderr

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
error[E0308]: mismatched types
22
--> $DIR/defaults-in-other-trait-items.rs:9:13
33
|
4+
LL | type A = ();
5+
| ------------ associated type defaults can't be assumed inside the trait defining them
6+
...
47
LL | let () = p;
58
| ^^ expected associated type, found `()`
69
|
710
= note: expected associated type `<Self as Tr>::A`
811
found unit type `()`
9-
= help: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A`
10-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
1112

1213
error[E0308]: mismatched types
13-
--> $DIR/defaults-in-other-trait-items.rs:37:25
14+
--> $DIR/defaults-in-other-trait-items.rs:35:25
1415
|
16+
LL | type Ty = u8;
17+
| ------------- associated type defaults can't be assumed inside the trait defining them
18+
...
1519
LL | const C: Self::Ty = 0u8;
1620
| ^^^ expected associated type, found `u8`
1721
|
1822
= note: expected associated type `<Self as AssocConst>::Ty`
1923
found type `u8`
20-
= help: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8`
21-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
2224

2325
error: aborting due to 2 previous errors
2426

src/test/ui/associated-types/defaults-specialization.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ error[E0053]: method `make` has an incompatible type for trait
1616
LL | fn make() -> Self::Ty {
1717
| -------- type in trait
1818
...
19+
LL | default type Ty = bool;
20+
| ----------------------- expected this associated type
21+
LL |
1922
LL | fn make() -> bool { true }
2023
| ^^^^ expected associated type, found `bool`
2124
|
@@ -25,15 +28,16 @@ LL | fn make() -> bool { true }
2528
error[E0308]: mismatched types
2629
--> $DIR/defaults-specialization.rs:9:9
2730
|
31+
LL | type Ty = u8;
32+
| ------------- associated type defaults can't be assumed inside the trait defining them
33+
LL |
2834
LL | fn make() -> Self::Ty {
2935
| -------- expected `<Self as Tr>::Ty` because of return type
3036
LL | 0u8
3137
| ^^^ expected associated type, found `u8`
3238
|
3339
= note: expected associated type `<Self as Tr>::Ty`
3440
found type `u8`
35-
= help: consider constraining the associated type `<Self as Tr>::Ty` to `u8` or calling a method that returns `<Self as Tr>::Ty`
36-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
3741

3842
error[E0308]: mismatched types
3943
--> $DIR/defaults-specialization.rs:25:29
@@ -51,15 +55,16 @@ LL | fn make() -> Self::Ty { 0u8 }
5155
error[E0308]: mismatched types
5256
--> $DIR/defaults-specialization.rs:43:29
5357
|
58+
LL | default type Ty = bool;
59+
| ----------------------- expected this associated type
60+
LL |
5461
LL | fn make() -> Self::Ty { true }
5562
| -------- ^^^^ expected associated type, found `bool`
5663
| |
5764
| expected `<B2<T> as Tr>::Ty` because of return type
5865
|
5966
= note: expected associated type `<B2<T> as Tr>::Ty`
6067
found type `bool`
61-
= help: consider constraining the associated type `<B2<T> as Tr>::Ty` to `bool` or calling a method that returns `<B2<T> as Tr>::Ty`
62-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
6368

6469
error[E0308]: mismatched types
6570
--> $DIR/defaults-specialization.rs:86:32

src/test/ui/specialization/specialization-default-types.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
error[E0308]: mismatched types
22
--> $DIR/specialization-default-types.rs:15:9
33
|
4+
LL | default type Output = Box<T>;
5+
| ----------------------------- expected this associated type
46
LL | default fn generate(self) -> Self::Output {
57
| ------------ expected `<T as Example>::Output` because of return type
68
LL | Box::new(self)
79
| ^^^^^^^^^^^^^^ expected associated type, found struct `std::boxed::Box`
810
|
911
= note: expected associated type `<T as Example>::Output`
1012
found struct `std::boxed::Box<T>`
11-
= help: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>` or calling a method that returns `<T as Example>::Output`
12-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
1313

1414
error[E0308]: mismatched types
1515
--> $DIR/specialization-default-types.rs:25:5

0 commit comments

Comments
 (0)