diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2020-04-14 15:12:11 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2020-05-02 18:24:07 -0700 |
| commit | 299bd12fe5edb4a99f85b1a94b9f9e7ce5365654 (patch) | |
| tree | b2bd331ba3db485963edbf6dbebe535500cf509c | |
| parent | ee96b8b11945f8bee1bcfa8f39ed06097c1dc9c8 (diff) | |
| download | rust-299bd12fe5edb4a99f85b1a94b9f9e7ce5365654.tar.gz rust-299bd12fe5edb4a99f85b1a94b9f9e7ce5365654.zip | |
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.
10 files changed, 96 insertions, 25 deletions
diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index d6989fd8e4e..3a05d577bfa 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> { DerivedObligation(DerivedObligationCause<'tcx>), /// Error derived when matching traits/impls; see ObligationCause for more details + CompareImplConstObligation, + + /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplMethodObligation { item_name: ast::Name, impl_item_def_id: DefId, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 69a5213d3e4..668c84ad5e6 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -164,6 +164,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { tcx.lift(cause).map(super::ImplDerivedObligation) } super::DerivedObligation(ref cause) => tcx.lift(cause).map(super::DerivedObligation), + super::CompareImplConstObligation => Some(super::CompareImplConstObligation), super::CompareImplMethodObligation { item_name, impl_item_def_id, diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index 5720a2a02cb..14909fff1ce 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -339,7 +339,7 @@ impl<'tcx> TyCtxt<'tcx> { body_owner_def_id: DefId, ) { use self::TypeError::*; - + debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); match err { Sorts(values) => { let expected_str = values.expected.sort_string(self); @@ -623,8 +623,12 @@ impl<T> Trait<T> for X { ) => false, _ => true, }; - let impl_comparison = - matches!(cause_code, ObligationCauseCode::CompareImplMethodObligation { .. }); + let impl_comparison = matches!( + cause_code, + ObligationCauseCode::CompareImplMethodObligation { .. } + | ObligationCauseCode::CompareImplTypeObligation { .. } + | ObligationCauseCode::CompareImplConstObligation + ); if !callable_scope || impl_comparison { // We do not want to suggest calling functions when the reason of the // type error is a comparison of an `impl` with its `trait` or when the @@ -679,12 +683,66 @@ impl<T> Trait<T> for X { suggested |= self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found); } + if let (Some(hir_id), false) = (self.hir().as_local_hir_id(body_owner_def_id), suggested) { + // When `body_owner` is an `impl` or `trait` item, look in its associated types for + // `expected` and point at it. + let parent_id = self.hir().get_parent_item(hir_id); + let item = self.hir().find(parent_id); + debug!("expected_projection parent item {:?}", item); + match item { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(.., items), .. + })) => { + // FIXME: account for `#![feature(specialization)]` + for item in &items[..] { + match item.kind { + hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) + == values.found + { + if let hir::Defaultness::Default { has_value: true } = + item.defaultness + { + db.span_label( + item.span, + "associated type defaults can't be assumed inside the \ + trait defining them", + ); + } else { + db.span_label(item.span, "expected this associated type"); + } + suggested = true; + } + } + _ => {} + } + } + } + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl { items, .. }, + .. + })) => { + for item in &items[..] { + match item.kind { + hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) + == values.found + { + db.span_label(item.span, "expected this associated type"); + suggested = true; + } + } + _ => {} + } + } + } + _ => {} + } + } if !suggested && !impl_comparison { // Generic suggestion when we can't be more specific. if callable_scope { - db.help( - &format!("{} or calling a method that returns `{}`", msg, values.expected,), - ); + db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected)); } else { db.help(&msg); } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5ec2d68ab2a..ce7b1390d46 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1738,6 +1738,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate )); } + ObligationCauseCode::CompareImplConstObligation => { + err.note(&format!( + "the requirement `{}` appears on the associated impl constant \ + but not on the corresponding associated trait constant", + predicate + )); + } ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) => (), diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6e4af6d769a..29cd9681295 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -966,6 +966,7 @@ crate fn compare_const_impl<'tcx>( let impl_ty = tcx.type_of(impl_c.def_id); let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs); let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id); + cause.code = ObligationCauseCode::CompareImplConstObligation; // There is no "body" here, so just pass dummy id. let impl_ty = diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-const/associated-const-generic-obligations.stderr index 6e3ec4ed155..d8bac07e058 100644 --- a/src/test/ui/associated-const/associated-const-generic-obligations.stderr +++ b/src/test/ui/associated-const/associated-const-generic-obligations.stderr @@ -9,8 +9,6 @@ LL | const FROM: &'static str = "foo"; | = note: expected associated type `<T as Foo>::Out` found reference `&'static str` - = help: consider constraining the associated type `<T as Foo>::Out` to `&'static str` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to previous error diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.rs b/src/test/ui/associated-types/defaults-in-other-trait-items.rs index 41dc67d6f47..4014f46285d 100644 --- a/src/test/ui/associated-types/defaults-in-other-trait-items.rs +++ b/src/test/ui/associated-types/defaults-in-other-trait-items.rs @@ -3,15 +3,13 @@ // Associated type defaults may not be assumed inside the trait defining them. // ie. they only resolve to `<Self as Tr>::A`, not the actual type `()` trait Tr { - type A = (); + type A = (); //~ NOTE associated type defaults can't be assumed inside the trait defining them fn f(p: Self::A) { let () = p; //~^ ERROR mismatched types //~| NOTE expected associated type, found `()` //~| NOTE expected associated type `<Self as Tr>::A` - //~| HELP consider constraining the associated type - //~| NOTE for more information, visit } } @@ -31,15 +29,13 @@ impl Tr for u8 { } trait AssocConst { - type Ty = u8; + type Ty = u8; //~ NOTE associated type defaults can't be assumed inside the trait defining them // Assoc. consts also cannot assume that default types hold const C: Self::Ty = 0u8; //~^ ERROR mismatched types //~| NOTE expected associated type, found `u8` //~| NOTE expected associated type `<Self as AssocConst>::Ty` - //~| HELP consider constraining the associated type - //~| NOTE for more information, visit } // An impl can, however diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr index a5b170d05c4..493df30a64d 100644 --- a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr +++ b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr @@ -1,24 +1,26 @@ error[E0308]: mismatched types --> $DIR/defaults-in-other-trait-items.rs:9:13 | +LL | type A = (); + | ------------ associated type defaults can't be assumed inside the trait defining them +... LL | let () = p; | ^^ expected associated type, found `()` | = note: expected associated type `<Self as Tr>::A` found unit type `()` - = help: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types - --> $DIR/defaults-in-other-trait-items.rs:37:25 + --> $DIR/defaults-in-other-trait-items.rs:35:25 | +LL | type Ty = u8; + | ------------- associated type defaults can't be assumed inside the trait defining them +... LL | const C: Self::Ty = 0u8; | ^^^ expected associated type, found `u8` | = note: expected associated type `<Self as AssocConst>::Ty` found type `u8` - = help: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 2f3ce832725..37a4d9b60fd 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -16,6 +16,9 @@ error[E0053]: method `make` has an incompatible type for trait LL | fn make() -> Self::Ty { | -------- type in trait ... +LL | default type Ty = bool; + | ----------------------- expected this associated type +LL | LL | fn make() -> bool { true } | ^^^^ expected associated type, found `bool` | @@ -25,6 +28,9 @@ LL | fn make() -> bool { true } error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:9:9 | +LL | type Ty = u8; + | ------------- associated type defaults can't be assumed inside the trait defining them +LL | LL | fn make() -> Self::Ty { | -------- expected `<Self as Tr>::Ty` because of return type LL | 0u8 @@ -32,8 +38,6 @@ LL | 0u8 | = note: expected associated type `<Self as Tr>::Ty` found type `u8` - = help: consider constraining the associated type `<Self as Tr>::Ty` to `u8` or calling a method that returns `<Self as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:25:29 @@ -51,6 +55,9 @@ LL | fn make() -> Self::Ty { 0u8 } error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:43:29 | +LL | default type Ty = bool; + | ----------------------- expected this associated type +LL | LL | fn make() -> Self::Ty { true } | -------- ^^^^ expected associated type, found `bool` | | @@ -58,8 +65,6 @@ LL | fn make() -> Self::Ty { true } | = note: expected associated type `<B2<T> as Tr>::Ty` found type `bool` - = help: consider constraining the associated type `<B2<T> as Tr>::Ty` to `bool` or calling a method that returns `<B2<T> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:86:32 diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 4dccf9ad9ab..7233387eba1 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:15:9 | +LL | default type Output = Box<T>; + | ----------------------------- expected this associated type LL | default fn generate(self) -> Self::Output { | ------------ expected `<T as Example>::Output` because of return type LL | Box::new(self) @@ -8,8 +10,6 @@ LL | Box::new(self) | = note: expected associated type `<T as Example>::Output` found struct `std::boxed::Box<T>` - = 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` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:25:5 |
