Skip to content

Commit 901bde1

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 02bdbc2 commit 901bde1

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
@@ -191,6 +191,9 @@ pub enum ObligationCauseCode<'tcx> {
191191

192192
ImplDerivedObligation(DerivedObligationCause<'tcx>),
193193

194+
/// Error derived when matching traits/impls; see ObligationCause for more details
195+
CompareImplConstObligation,
196+
194197
/// Error derived when matching traits/impls; see ObligationCause for more details
195198
CompareImplMethodObligation {
196199
item_name: ast::Name,

src/librustc_middle/traits/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
456456
super::ImplDerivedObligation(ref cause) => {
457457
tcx.lift(cause).map(super::ImplDerivedObligation)
458458
}
459+
super::CompareImplConstObligation => Some(super::CompareImplConstObligation),
459460
super::CompareImplMethodObligation {
460461
item_name,
461462
impl_item_def_id,

src/librustc_middle/ty/error.rs

+64-6
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ impl<'tcx> TyCtxt<'tcx> {
330330
body_owner_def_id: DefId,
331331
) {
332332
use self::TypeError::*;
333-
333+
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
334334
match err {
335335
Sorts(values) => {
336336
let expected_str = values.expected.sort_string(self);
@@ -602,8 +602,12 @@ impl<T> Trait<T> for X {
602602
) => false,
603603
_ => true,
604604
};
605-
let impl_comparison =
606-
matches!(cause_code, ObligationCauseCode::CompareImplMethodObligation { .. });
605+
let impl_comparison = matches!(
606+
cause_code,
607+
ObligationCauseCode::CompareImplMethodObligation { .. }
608+
| ObligationCauseCode::CompareImplTypeObligation { .. }
609+
| ObligationCauseCode::CompareImplConstObligation
610+
);
607611
if !callable_scope || impl_comparison {
608612
// We do not want to suggest calling functions when the reason of the
609613
// type error is a comparison of an `impl` with its `trait` or when the
@@ -658,12 +662,66 @@ impl<T> Trait<T> for X {
658662
suggested |=
659663
self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found);
660664
}
665+
if let (Some(hir_id), false) = (self.hir().as_local_hir_id(body_owner_def_id), suggested) {
666+
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
667+
// `expected` and point at it.
668+
let parent_id = self.hir().get_parent_item(hir_id);
669+
let item = self.hir().find(parent_id);
670+
debug!("expected_projection parent item {:?}", item);
671+
match item {
672+
Some(hir::Node::Item(hir::Item {
673+
kind: hir::ItemKind::Trait(.., items), ..
674+
})) => {
675+
// FIXME: account for `#![feature(specialization)]`
676+
for item in &items[..] {
677+
match item.kind {
678+
hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
679+
if self.type_of(self.hir().local_def_id(item.id.hir_id))
680+
== values.found
681+
{
682+
if let hir::Defaultness::Default { has_value: true } =
683+
item.defaultness
684+
{
685+
db.span_label(
686+
item.span,
687+
"associated type defaults can't be assumed inside the \
688+
trait defining them",
689+
);
690+
} else {
691+
db.span_label(item.span, "expected this associated type");
692+
}
693+
suggested = true;
694+
}
695+
}
696+
_ => {}
697+
}
698+
}
699+
}
700+
Some(hir::Node::Item(hir::Item {
701+
kind: hir::ItemKind::Impl { items, .. },
702+
..
703+
})) => {
704+
for item in &items[..] {
705+
match item.kind {
706+
hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => {
707+
if self.type_of(self.hir().local_def_id(item.id.hir_id))
708+
== values.found
709+
{
710+
db.span_label(item.span, "expected this associated type");
711+
suggested = true;
712+
}
713+
}
714+
_ => {}
715+
}
716+
}
717+
}
718+
_ => {}
719+
}
720+
}
661721
if !suggested && !impl_comparison {
662722
// Generic suggestion when we can't be more specific.
663723
if callable_scope {
664-
db.help(
665-
&format!("{} or calling a method that returns `{}`", msg, values.expected,),
666-
);
724+
db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected));
667725
} else {
668726
db.help(&msg);
669727
}

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
16751675
predicate
16761676
));
16771677
}
1678+
ObligationCauseCode::CompareImplConstObligation => {
1679+
err.note(&format!(
1680+
"the requirement `{}` appears on the associated impl constant \
1681+
but not on the corresponding associated trait constant",
1682+
predicate
1683+
));
1684+
}
16781685
ObligationCauseCode::ReturnType
16791686
| ObligationCauseCode::ReturnValue(_)
16801687
| ObligationCauseCode::BlockTailExpression(_) => (),

src/librustc_typeck/check/compare_method.rs

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

971972
// There is no "body" here, so just pass dummy id.
972973
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)