ignore implied bounds with placeholders
This commit is contained in:
parent
492e57c6ad
commit
af79fd109b
4 changed files with 81 additions and 3 deletions
|
@ -7,7 +7,7 @@ use rustc_infer::infer::region_constraints::GenericKind;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::traits::query::OutlivesBound;
|
use rustc_middle::traits::query::OutlivesBound;
|
||||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
|
||||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -321,6 +321,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||||
.ok()?;
|
.ok()?;
|
||||||
debug!(?bounds, ?constraints);
|
debug!(?bounds, ?constraints);
|
||||||
|
// Because of #109628, we may have unexpected placeholders. Ignore them!
|
||||||
|
// FIXME(#109628): panic in this case once the issue is fixed.
|
||||||
|
let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
|
||||||
self.add_outlives_bounds(bounds);
|
self.add_outlives_bounds(bounds);
|
||||||
constraints
|
constraints
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut constraints = QueryRegionConstraints::default();
|
let mut constraints = QueryRegionConstraints::default();
|
||||||
let Ok(InferOk { value, obligations }) = self
|
let Ok(InferOk { value: mut bounds, obligations }) = self
|
||||||
.instantiate_nll_query_response_and_region_obligations(
|
.instantiate_nll_query_response_and_region_obligations(
|
||||||
&ObligationCause::dummy(),
|
&ObligationCause::dummy(),
|
||||||
param_env,
|
param_env,
|
||||||
|
@ -85,6 +85,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||||
};
|
};
|
||||||
assert_eq!(&obligations, &[]);
|
assert_eq!(&obligations, &[]);
|
||||||
|
|
||||||
|
// Because of #109628, we may have unexpected placeholders. Ignore them!
|
||||||
|
// FIXME(#109628): panic in this case once the issue is fixed.
|
||||||
|
bounds.retain(|bound| !bound.has_placeholders());
|
||||||
|
|
||||||
if !constraints.is_empty() {
|
if !constraints.is_empty() {
|
||||||
let span = self.tcx.def_span(body_id);
|
let span = self.tcx.def_span(body_id);
|
||||||
|
|
||||||
|
@ -114,7 +118,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
value
|
bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implied_bounds_tys(
|
fn implied_bounds_tys(
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0477]: the type `&'lt u8` does not fulfill the required lifetime
|
||||||
|
--> $DIR/normalization-placeholder-leak.rs:31:40
|
||||||
|
|
|
||||||
|
LL | fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0477]: the type `<T as AnotherTrait>::Ty2<'lt>` does not fulfill the required lifetime
|
||||||
|
--> $DIR/normalization-placeholder-leak.rs:36:44
|
||||||
|
|
|
||||||
|
LL | fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0477`.
|
56
tests/ui/implied-bounds/normalization-placeholder-leak.rs
Normal file
56
tests/ui/implied-bounds/normalization-placeholder-leak.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// Because of #109628, when we compute the implied bounds from `Foo<X>`,
|
||||||
|
// we incorrectly get `X: placeholder('x)`.
|
||||||
|
// Make sure we ignore these bogus bounds and not use them for anything useful.
|
||||||
|
//
|
||||||
|
// revisions: fail pass
|
||||||
|
// [fail] check-fail
|
||||||
|
// [pass] check-pass
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Ty<'a> where Self: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Trait for T {
|
||||||
|
type Ty<'a> = () where Self: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo<T: Trait>(T)
|
||||||
|
where
|
||||||
|
for<'x> T::Ty<'x>: Sized;
|
||||||
|
|
||||||
|
trait AnotherTrait {
|
||||||
|
type Ty2<'a>: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(fail)]
|
||||||
|
mod fail {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// implied_bound: `'lt: placeholder('x)`.
|
||||||
|
// don't use the bound to prove `'lt: 'static`.
|
||||||
|
fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
|
||||||
|
//[fail]~^ ERROR `&'lt u8` does not fulfill the required lifetime
|
||||||
|
|
||||||
|
// implied bound: `T::Ty2<'lt>: placeholder('x)`.
|
||||||
|
// don't use the bound to prove `T::Ty2<'lt>: 'static`.
|
||||||
|
fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
|
||||||
|
//[fail]~^ ERROR `<T as AnotherTrait>::Ty2<'lt>` does not fulfill the required lifetime
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mod pass {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// implied_bound: 'static: placeholder('x).
|
||||||
|
// don't ice.
|
||||||
|
fn test_lifetime<T: Trait>(_: Foo<&'static u8>) {}
|
||||||
|
|
||||||
|
// implied bound: T::Ty2<'static>: placeholder('x).
|
||||||
|
// don't add the bound to the environment,
|
||||||
|
// otherwise we would fail to infer a value for `'_`.
|
||||||
|
fn test_alias<T: AnotherTrait>(_: Foo<T::Ty2::<'static>>) {
|
||||||
|
None::<&'static T::Ty2<'_>>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue