Rollup merge of #88336 - jackh726:gats-where-constraints, r=estebank
Detect stricter constraints on gats where clauses in impls vs trait I might try to see if I can do a bit more to improve these diagnostics, but any initial feedback is appreciated. I can also do any additional work in a followup PR. r? `@estebank`
This commit is contained in:
commit
6d4f27ebc7
8 changed files with 130 additions and 47 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||||
use crate::infer::{Subtype, ValuePairs};
|
use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
|
||||||
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
|
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -11,44 +11,53 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::{MultiSpan, Span};
|
use rustc_span::{MultiSpan, Span, Symbol};
|
||||||
|
|
||||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
|
/// 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<ErrorReported> {
|
pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
|
||||||
if let Some(ref error) = self.error {
|
let error = self.error.as_ref()?;
|
||||||
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
|
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
|
||||||
if let RegionResolutionError::SubSupConflict(
|
if let RegionResolutionError::SubSupConflict(
|
||||||
_,
|
_,
|
||||||
var_origin,
|
var_origin,
|
||||||
sub_origin,
|
sub_origin,
|
||||||
_sub,
|
_sub,
|
||||||
sup_origin,
|
sup_origin,
|
||||||
_sup,
|
_sup,
|
||||||
) = error.clone()
|
) = error.clone()
|
||||||
{
|
{
|
||||||
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) =
|
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
|
||||||
(&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 (
|
if sup_expected_found == sub_expected_found {
|
||||||
ValuePairs::Types(sub_expected_found),
|
self.emit_err(
|
||||||
ValuePairs::Types(sup_expected_found),
|
var_origin.span(),
|
||||||
CompareImplMethodObligation { trait_item_def_id, .. },
|
sub_expected_found.expected,
|
||||||
) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code)
|
sub_expected_found.found,
|
||||||
{
|
*trait_item_def_id,
|
||||||
if sup_expected_found == sub_expected_found {
|
);
|
||||||
self.emit_err(
|
return Some(ErrorReported);
|
||||||
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);
|
||||||
|
return Some(ErrorReported);
|
||||||
|
}
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +116,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
err.emit();
|
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> {
|
struct TypeParamSpanVisitor<'tcx> {
|
||||||
|
|
|
@ -99,6 +99,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
"...so that the definition in impl matches the definition from the trait",
|
"...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,
|
trait_item_def_id,
|
||||||
&format!("`{}: {}`", sup, sub),
|
&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),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -427,6 +427,15 @@ pub enum SubregionOrigin<'tcx> {
|
||||||
impl_item_def_id: DefId,
|
impl_item_def_id: DefId,
|
||||||
trait_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.
|
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
|
@ -1810,6 +1819,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
||||||
ReferenceOutlivesReferent(_, a) => a,
|
ReferenceOutlivesReferent(_, a) => a,
|
||||||
CallReturn(a) => a,
|
CallReturn(a) => a,
|
||||||
CompareImplMethodObligation { span, .. } => span,
|
CompareImplMethodObligation { span, .. } => span,
|
||||||
|
CompareImplTypeObligation { span, .. } => span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1833,6 +1843,17 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
||||||
trait_item_def_id,
|
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(),
|
_ => default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ impl<T> Foo for Fooy<T> {
|
||||||
type A<'a> where Self: 'static = (&'a ());
|
type A<'a> where Self: 'static = (&'a ());
|
||||||
//~^ ERROR the parameter type `T` may not live long enough
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
||||||
//~^ ERROR lifetime bound not satisfied
|
//~^ ERROR `impl` associated type
|
||||||
//~| ERROR lifetime bound not satisfied
|
//~| ERROR lifetime bound not satisfied
|
||||||
type C where Self: Copy = String;
|
type C where Self: Copy = String;
|
||||||
//~^ ERROR the trait bound `T: Copy` is not satisfied
|
//~^ ERROR the trait bound `T: Copy` is not satisfied
|
||||||
|
|
|
@ -5,24 +5,16 @@ LL | type A<'a> where Self: 'static = (&'a ());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider adding an explicit lifetime bound `T: 'static`...
|
= help: consider adding an explicit lifetime bound `T: 'static`...
|
||||||
= note: ...so that the type `Fooy<T>` 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
|
--> $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 ());
|
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
|
||||||
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error[E0478]: lifetime bound not satisfied
|
error[E0478]: lifetime bound not satisfied
|
||||||
--> $DIR/impl_bounds.rs:17:5
|
--> $DIR/impl_bounds.rs:17:5
|
||||||
|
|
|
@ -9,7 +9,7 @@ LL | | <Left as HasChildrenOf>::T: 'a,
|
||||||
LL | | <Right as HasChildrenOf>::T: 'a
|
LL | | <Right as HasChildrenOf>::T: 'a
|
||||||
| | - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
|
| | - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
|
||||||
LL | | = Either<&'a Left::T, &'a Right::T>;
|
LL | | = Either<&'a Left::T, &'a Right::T>;
|
||||||
| |________________________________________^ ...so that the type `<Left as HasChildrenOf>::T` will meet its required lifetime bounds
|
| |________________________________________^ ...so that the definition in impl matches the definition from the trait
|
||||||
|
|
||||||
error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
|
error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
|
||||||
--> $DIR/issue-86787.rs:23:5
|
--> $DIR/issue-86787.rs:23:5
|
||||||
|
@ -22,7 +22,7 @@ LL | | <Left as HasChildrenOf>::T: 'a,
|
||||||
LL | | <Right as HasChildrenOf>::T: 'a
|
LL | | <Right as HasChildrenOf>::T: 'a
|
||||||
| | - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
|
| | - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
|
||||||
LL | | = Either<&'a Left::T, &'a Right::T>;
|
LL | | = Either<&'a Left::T, &'a Right::T>;
|
||||||
| |________________________________________^ ...so that the type `<Right as HasChildrenOf>::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
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
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: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue