From af9de99f1262ae0b42e9e4a7d0cf56fa1e429827 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 25 Aug 2021 13:43:00 -0400 Subject: [PATCH 1/2] Detect stricter constraints on gats where clauses in impls vs trait --- .../trait_impl_difference.rs | 87 ++++++++++++------- .../src/infer/error_reporting/note.rs | 18 ++++ compiler/rustc_infer/src/infer/mod.rs | 21 +++++ .../generic-associated-types/impl_bounds.rs | 3 +- .../impl_bounds.stderr | 35 ++++---- .../issue-86787.stderr | 4 +- .../missing-where-clause-on-trait.rs | 14 +++ .../missing-where-clause-on-trait.stderr | 21 +++++ 8 files changed, 153 insertions(+), 50 deletions(-) create mode 100644 src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs create mode 100644 src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 61c8113d05287..4d789d2309136 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -2,7 +2,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; +use crate::infer::{SubregionOrigin, Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_errors::ErrorReported; use rustc_hir as hir; @@ -11,44 +11,52 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{MultiSpan, Span}; +use rustc_span::{MultiSpan, Span, Symbol}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option { - if let Some(ref error) = self.error { - debug!("try_report_impl_not_conforming_to_trait {:?}", error); - if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - _sub, - sup_origin, - _sup, - ) = error.clone() - { - if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = - (&sup_origin, &sub_origin) + let error = self.error.as_ref()?; + debug!("try_report_impl_not_conforming_to_trait {:?}", error); + if let RegionResolutionError::SubSupConflict( + _, + var_origin, + sub_origin, + _sub, + sup_origin, + _sup, + ) = error.clone() + { + if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) { + if let ( + ValuePairs::Types(sub_expected_found), + ValuePairs::Types(sup_expected_found), + CompareImplMethodObligation { trait_item_def_id, .. }, + ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) { - if let ( - ValuePairs::Types(sub_expected_found), - ValuePairs::Types(sup_expected_found), - CompareImplMethodObligation { trait_item_def_id, .. }, - ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) - { - if sup_expected_found == sub_expected_found { - self.emit_err( - var_origin.span(), - sub_expected_found.expected, - sub_expected_found.found, - *trait_item_def_id, - ); - return Some(ErrorReported); - } + if sup_expected_found == sub_expected_found { + self.emit_err( + var_origin.span(), + sub_expected_found.expected, + sub_expected_found.found, + *trait_item_def_id, + ); + return Some(ErrorReported); } } } } + if let RegionResolutionError::ConcreteFailure(origin, _, _) = error.clone() { + if let SubregionOrigin::CompareImplTypeObligation { + span, + item_name, + impl_item_def_id, + trait_item_def_id, + } = origin + { + self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id); + } + } None } @@ -107,6 +115,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } err.emit(); } + + fn emit_associated_type_err( + &self, + span: Span, + item_name: Symbol, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + ) { + let impl_sp = self.tcx().def_span(impl_item_def_id); + let trait_sp = self.tcx().def_span(trait_item_def_id); + let mut err = self + .tcx() + .sess + .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name)); + err.span_label(impl_sp, &format!("found")); + err.span_label(trait_sp, &format!("expected")); + + err.emit(); + } } struct TypeParamSpanVisitor<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 4bc59a4baf5ca..5f99a23f86e88 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -99,6 +99,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...so that the definition in impl matches the definition from the trait", ); } + infer::CompareImplTypeObligation { span, .. } => { + label_or_note( + span, + "...so that the definition in impl matches the definition from the trait", + ); + } } } @@ -356,6 +362,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_item_def_id, &format!("`{}: {}`", sup, sub), ), + infer::CompareImplTypeObligation { + span, + item_name, + impl_item_def_id, + trait_item_def_id, + } => self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + ), } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index bc98a3aa3f95e..354b8e26d53d5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -427,6 +427,15 @@ pub enum SubregionOrigin<'tcx> { impl_item_def_id: DefId, trait_item_def_id: DefId, }, + + /// Comparing the signature and requirements of an impl associated type + /// against the containing trait + CompareImplTypeObligation { + span: Span, + item_name: Symbol, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -1810,6 +1819,7 @@ impl<'tcx> SubregionOrigin<'tcx> { ReferenceOutlivesReferent(_, a) => a, CallReturn(a) => a, CompareImplMethodObligation { span, .. } => span, + CompareImplTypeObligation { span, .. } => span, } } @@ -1833,6 +1843,17 @@ impl<'tcx> SubregionOrigin<'tcx> { trait_item_def_id, }, + traits::ObligationCauseCode::CompareImplTypeObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CompareImplTypeObligation { + span: cause.span, + item_name, + impl_item_def_id, + trait_item_def_id, + }, + _ => default(), } } diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index 01edad00a89f1..2b52483d1d6a1 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -15,7 +15,8 @@ impl Foo for Fooy { type A<'a> where Self: 'static = (&'a ()); //~^ ERROR the parameter type `T` may not live long enough type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - //~^ ERROR lifetime bound not satisfied + //~^ ERROR `impl` associated type + //~| ERROR impl has stricter //~| ERROR lifetime bound not satisfied type C where Self: Copy = String; //~^ ERROR the trait bound `T: Copy` is not satisfied diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 8cf923ca3ac0c..38c7ca7a1a195 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -5,24 +5,25 @@ LL | type A<'a> where Self: 'static = (&'a ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `Fooy` will meet its required lifetime bounds + = note: ...so that the definition in impl matches the definition from the trait -error[E0478]: lifetime bound not satisfied +error: `impl` associated type signature for `B` doesn't match `trait` associated type signature --> $DIR/impl_bounds.rs:17:5 | +LL | type B<'a, 'b> where 'a: 'b; + | ---------------------------- expected +... LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the associated item at 17:16 - --> $DIR/impl_bounds.rs:17:16 - | -LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the associated item at 17:12 - --> $DIR/impl_bounds.rs:17:12 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + +error[E0276]: impl has stricter requirements than trait + --> $DIR/impl_bounds.rs:17:5 | +LL | type B<'a, 'b> where 'a: 'b; + | ---------------------------- definition of `B` from trait +... LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'b: 'a` error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:5 @@ -42,7 +43,7 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:20:5 + --> $DIR/impl_bounds.rs:21:5 | LL | type C where Self: Copy = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -67,7 +68,7 @@ LL | impl Foo for Fooy { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:22:5 + --> $DIR/impl_bounds.rs:23:5 | LL | fn d() where Self: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -91,7 +92,7 @@ help: consider restricting type parameter `T` LL | impl Foo for Fooy { | +++++++++++++++++++ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0277, E0310, E0478. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277, E0310, E0478. +For more information about an error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 04cd84b08011c..e1ff772921104 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -9,7 +9,7 @@ LL | | ::T: 'a, LL | | ::T: 'a | | - help: consider adding a where clause: `, ::T: 'a` LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ ...so that the type `::T` will meet its required lifetime bounds + | |________________________________________^ ...so that the definition in impl matches the definition from the trait error[E0309]: the associated type `::T` may not live long enough --> $DIR/issue-86787.rs:23:5 @@ -22,7 +22,7 @@ LL | | ::T: 'a, LL | | ::T: 'a | | - help: consider adding a where clause: `, ::T: 'a` LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ ...so that the type `::T` will meet its required lifetime bounds + | |________________________________________^ ...so that the definition in impl matches the definition from the trait error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs new file mode 100644 index 0000000000000..fa846516040f3 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -0,0 +1,14 @@ +// check-fail + +#![feature(generic_associated_types)] + +trait Foo { + type Assoc<'a, 'b>; +} +impl Foo for () { + type Assoc<'a, 'b> where 'a: 'b = (); + //~^ `impl` associated type + //~| impl has stricter +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr new file mode 100644 index 0000000000000..d582099500256 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -0,0 +1,21 @@ +error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature + --> $DIR/missing-where-clause-on-trait.rs:9:5 + | +LL | type Assoc<'a, 'b>; + | ------------------- expected +... +LL | type Assoc<'a, 'b> where 'a: 'b = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + +error[E0276]: impl has stricter requirements than trait + --> $DIR/missing-where-clause-on-trait.rs:9:5 + | +LL | type Assoc<'a, 'b>; + | ------------------- definition of `Assoc` from trait +... +LL | type Assoc<'a, 'b> where 'a: 'b = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0276`. From 890de33e4f92c449ca6f142eeb7a7ab945ae5e27 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 7 Sep 2021 18:51:24 -0400 Subject: [PATCH 2/2] Fix duplicate error --- .../trait_impl_difference.rs | 1 + .../generic-associated-types/impl_bounds.rs | 1 - .../impl_bounds.stderr | 19 +++++-------------- .../missing-where-clause-on-trait.rs | 1 - .../missing-where-clause-on-trait.stderr | 12 +----------- 5 files changed, 7 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4d789d2309136..43aa8a6efcec4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } = origin { self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id); + return Some(ErrorReported); } } None diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index 2b52483d1d6a1..27c135cb7cf82 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -16,7 +16,6 @@ impl Foo for Fooy { //~^ ERROR the parameter type `T` may not live long enough type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); //~^ ERROR `impl` associated type - //~| ERROR impl has stricter //~| ERROR lifetime bound not satisfied type C where Self: Copy = String; //~^ ERROR the trait bound `T: Copy` is not satisfied diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 38c7ca7a1a195..73415e0faac88 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -16,15 +16,6 @@ LL | type B<'a, 'b> where 'a: 'b; LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found -error[E0276]: impl has stricter requirements than trait - --> $DIR/impl_bounds.rs:17:5 - | -LL | type B<'a, 'b> where 'a: 'b; - | ---------------------------- definition of `B` from trait -... -LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'b: 'a` - error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:5 | @@ -43,7 +34,7 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:21:5 + --> $DIR/impl_bounds.rs:20:5 | LL | type C where Self: Copy = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -68,7 +59,7 @@ LL | impl Foo for Fooy { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:23:5 + --> $DIR/impl_bounds.rs:22:5 | LL | fn d() where Self: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -92,7 +83,7 @@ help: consider restricting type parameter `T` LL | impl Foo for Fooy { | +++++++++++++++++++ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0276, E0277, E0310, E0478. -For more information about an error, try `rustc --explain E0276`. +Some errors have detailed explanations: E0277, E0310, E0478. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs index fa846516040f3..ad9f2e3e4ec4a 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -8,7 +8,6 @@ trait Foo { impl Foo for () { type Assoc<'a, 'b> where 'a: 'b = (); //~^ `impl` associated type - //~| impl has stricter } fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr index d582099500256..0e183c8d69a4c 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -7,15 +7,5 @@ LL | type Assoc<'a, 'b>; LL | type Assoc<'a, 'b> where 'a: 'b = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found -error[E0276]: impl has stricter requirements than trait - --> $DIR/missing-where-clause-on-trait.rs:9:5 - | -LL | type Assoc<'a, 'b>; - | ------------------- definition of `Assoc` from trait -... -LL | type Assoc<'a, 'b> where 'a: 'b = (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0276`.