Tweaks and a test
This commit is contained in:
parent
4ce2123ecc
commit
6d0b6c0d2c
3 changed files with 97 additions and 51 deletions
|
@ -52,7 +52,7 @@ pub trait GeneralizerDelegate<'tcx> {
|
||||||
|
|
||||||
fn forbid_inference_vars() -> bool;
|
fn forbid_inference_vars() -> bool;
|
||||||
|
|
||||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
|
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CombineDelegate<'cx, 'tcx> {
|
pub struct CombineDelegate<'cx, 'tcx> {
|
||||||
|
@ -70,7 +70,9 @@ impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||||
|
// FIXME: This is non-ideal because we don't give a
|
||||||
|
// very descriptive origin for this region variable.
|
||||||
self.infcx
|
self.infcx
|
||||||
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe)
|
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe)
|
||||||
}
|
}
|
||||||
|
@ -88,18 +90,17 @@ where
|
||||||
<Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
|
<Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||||
<Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
|
<Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The "type generalizer" is used when handling inference variables.
|
/// The "generalizer" is used when handling inference variables.
|
||||||
///
|
///
|
||||||
/// The basic strategy for handling a constraint like `?A <: B` is to
|
/// The basic strategy for handling a constraint like `?A <: B` is to
|
||||||
/// apply a "generalization strategy" to the type `B` -- this replaces
|
/// apply a "generalization strategy" to the term `B` -- this replaces
|
||||||
/// all the lifetimes in the type `B` with fresh inference
|
/// all the lifetimes in the term `B` with fresh inference variables.
|
||||||
/// variables. (You can read more about the strategy in this [blog
|
/// (You can read more about the strategy in this [blog post].)
|
||||||
/// post].)
|
|
||||||
///
|
///
|
||||||
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
|
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
|
||||||
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
|
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
|
||||||
|
@ -110,9 +111,11 @@ where
|
||||||
struct Generalizer<'me, 'tcx, D> {
|
struct Generalizer<'me, 'tcx, D> {
|
||||||
infcx: &'me InferCtxt<'tcx>,
|
infcx: &'me InferCtxt<'tcx>,
|
||||||
|
|
||||||
// An delegate used to abstract the behaviors of the three previous
|
/// This is used to abstract the behaviors of the three previous
|
||||||
// generalizer-like implementations.
|
/// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`,
|
||||||
pub delegate: &'me mut D,
|
/// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more
|
||||||
|
/// information.
|
||||||
|
delegate: &'me mut D,
|
||||||
|
|
||||||
/// After we generalize this type, we are going to relate it to
|
/// After we generalize this type, we are going to relate it to
|
||||||
/// some other type. What will be the variance at this point?
|
/// some other type. What will be the variance at this point?
|
||||||
|
@ -138,6 +141,7 @@ struct Generalizer<'me, 'tcx, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, D> Generalizer<'_, 'tcx, D> {
|
impl<'tcx, D> Generalizer<'_, 'tcx, D> {
|
||||||
|
/// Create an error that corresponds to the term kind in `root_term`
|
||||||
fn cyclic_term_error(&self) -> TypeError<'tcx> {
|
fn cyclic_term_error(&self) -> TypeError<'tcx> {
|
||||||
match self.root_term.unpack() {
|
match self.root_term.unpack() {
|
||||||
ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
|
ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
|
||||||
|
@ -183,7 +187,7 @@ where
|
||||||
relate::relate_substs_with_variances(
|
relate::relate_substs_with_variances(
|
||||||
self,
|
self,
|
||||||
item_def_id,
|
item_def_id,
|
||||||
&opt_variances,
|
opt_variances,
|
||||||
a_subst,
|
a_subst,
|
||||||
b_subst,
|
b_subst,
|
||||||
true,
|
true,
|
||||||
|
@ -191,6 +195,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self, variance, b), ret)]
|
||||||
fn relate_with_variance<T: Relate<'tcx>>(
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
variance: ty::Variance,
|
variance: ty::Variance,
|
||||||
|
@ -198,29 +203,21 @@ where
|
||||||
a: T,
|
a: T,
|
||||||
b: T,
|
b: T,
|
||||||
) -> RelateResult<'tcx, T> {
|
) -> RelateResult<'tcx, T> {
|
||||||
debug!("Generalizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b);
|
|
||||||
|
|
||||||
let old_ambient_variance = self.ambient_variance;
|
let old_ambient_variance = self.ambient_variance;
|
||||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||||
|
debug!(?self.ambient_variance, "new ambient variance");
|
||||||
debug!("Generalizer::relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
|
|
||||||
|
|
||||||
let r = self.relate(a, b)?;
|
let r = self.relate(a, b)?;
|
||||||
|
|
||||||
self.ambient_variance = old_ambient_variance;
|
self.ambient_variance = old_ambient_variance;
|
||||||
|
|
||||||
debug!("Generalizer::relate_with_variance: r={:?}", r);
|
|
||||||
|
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self, t2), ret)]
|
||||||
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
||||||
|
|
||||||
if let Some(&result) = self.cache.get(&t) {
|
if let Some(&result) = self.cache.get(&t) {
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
debug!("generalize: t={:?}", t);
|
|
||||||
|
|
||||||
// Check to see whether the type we are generalizing references
|
// Check to see whether the type we are generalizing references
|
||||||
// any other type variable related to `vid` via
|
// any other type variable related to `vid` via
|
||||||
|
@ -241,21 +238,22 @@ where
|
||||||
let mut inner = self.infcx.inner.borrow_mut();
|
let mut inner = self.infcx.inner.borrow_mut();
|
||||||
let vid = inner.type_variables().root_var(vid);
|
let vid = inner.type_variables().root_var(vid);
|
||||||
let sub_vid = inner.type_variables().sub_root_var(vid);
|
let sub_vid = inner.type_variables().sub_root_var(vid);
|
||||||
if TermVid::Ty(sub_vid) == self.root_vid {
|
|
||||||
// If sub-roots are equal, then `for_vid` and
|
if ty::TermVid::Ty(sub_vid) == self.root_vid {
|
||||||
|
// If sub-roots are equal, then `root_vid` and
|
||||||
// `vid` are related via subtyping.
|
// `vid` are related via subtyping.
|
||||||
Err(self.cyclic_term_error())
|
Err(self.cyclic_term_error())
|
||||||
} else {
|
} else {
|
||||||
let probe = inner.type_variables().probe(vid);
|
let probe = inner.type_variables().probe(vid);
|
||||||
match probe {
|
match probe {
|
||||||
TypeVariableValue::Known { value: u } => {
|
TypeVariableValue::Known { value: u } => {
|
||||||
debug!("generalize: known value {:?}", u);
|
|
||||||
drop(inner);
|
drop(inner);
|
||||||
self.relate(u, u)
|
self.relate(u, u)
|
||||||
}
|
}
|
||||||
TypeVariableValue::Unknown { universe } => {
|
TypeVariableValue::Unknown { universe } => {
|
||||||
match self.ambient_variance {
|
match self.ambient_variance {
|
||||||
// Invariant: no need to make a fresh type variable.
|
// Invariant: no need to make a fresh type variable
|
||||||
|
// if we can name the universe.
|
||||||
ty::Invariant => {
|
ty::Invariant => {
|
||||||
if self.for_universe.can_name(universe) {
|
if self.for_universe.can_name(universe) {
|
||||||
return Ok(t);
|
return Ok(t);
|
||||||
|
@ -282,7 +280,7 @@ where
|
||||||
// operation. This is needed to detect cyclic types. To see why, see the
|
// operation. This is needed to detect cyclic types. To see why, see the
|
||||||
// docs in the `type_variables` module.
|
// docs in the `type_variables` module.
|
||||||
inner.type_variables().sub(vid, new_var_id);
|
inner.type_variables().sub(vid, new_var_id);
|
||||||
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
|
debug!("replacing original vid={:?} with new={:?}", vid, u);
|
||||||
Ok(u)
|
Ok(u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,22 +295,17 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Placeholder(placeholder) => {
|
ty::Placeholder(placeholder) => {
|
||||||
if self.for_universe.cannot_name(placeholder.universe) {
|
if self.for_universe.can_name(placeholder.universe) {
|
||||||
|
Ok(t)
|
||||||
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
"Generalizer::tys: root universe {:?} cannot name\
|
"root universe {:?} cannot name placeholder in universe {:?}",
|
||||||
placeholder in universe {:?}",
|
|
||||||
self.for_universe, placeholder.universe
|
self.for_universe, placeholder.universe
|
||||||
);
|
);
|
||||||
Err(TypeError::Mismatch)
|
Err(TypeError::Mismatch)
|
||||||
} else {
|
|
||||||
Ok(t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
|
||||||
let s = self.relate(substs, substs)?;
|
|
||||||
Ok(if s == substs { t } else { self.tcx().mk_opaque(def_id, s) })
|
|
||||||
}
|
|
||||||
_ => relate::super_relate_tys(self, t, t),
|
_ => relate::super_relate_tys(self, t, t),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -320,6 +313,7 @@ where
|
||||||
Ok(g)
|
Ok(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self, r2), ret)]
|
||||||
fn regions(
|
fn regions(
|
||||||
&mut self,
|
&mut self,
|
||||||
r: ty::Region<'tcx>,
|
r: ty::Region<'tcx>,
|
||||||
|
@ -327,8 +321,6 @@ where
|
||||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||||
assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
||||||
|
|
||||||
debug!("generalize: regions r={:?}", r);
|
|
||||||
|
|
||||||
match *r {
|
match *r {
|
||||||
// Never make variables for regions bound within the type itself,
|
// Never make variables for regions bound within the type itself,
|
||||||
// nor for erased regions.
|
// nor for erased regions.
|
||||||
|
@ -336,6 +328,8 @@ where
|
||||||
return Ok(r);
|
return Ok(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It doesn't really matter for correctness if we generalize ReError,
|
||||||
|
// since we're already on a doomed compilation path.
|
||||||
ty::ReError(_) => {
|
ty::ReError(_) => {
|
||||||
return Ok(r);
|
return Ok(r);
|
||||||
}
|
}
|
||||||
|
@ -359,13 +353,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This is non-ideal because we don't give a
|
Ok(self.delegate.generalize_region(self.for_universe))
|
||||||
// very descriptive origin for this region variable.
|
|
||||||
let replacement_region_vid = self.delegate.generalize_existential(self.for_universe);
|
|
||||||
|
|
||||||
Ok(replacement_region_vid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self, c2), ret)]
|
||||||
fn consts(
|
fn consts(
|
||||||
&mut self,
|
&mut self,
|
||||||
c: ty::Const<'tcx>,
|
c: ty::Const<'tcx>,
|
||||||
|
@ -378,13 +369,12 @@ where
|
||||||
bug!("unexpected inference variable encountered in NLL generalization: {:?}", c);
|
bug!("unexpected inference variable encountered in NLL generalization: {:?}", c);
|
||||||
}
|
}
|
||||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||||
// Check if the current unification would end up
|
// If root const vids are equal, then `root_vid` and
|
||||||
// unifying `target_vid` with a const which contains
|
// `vid` are related and we'd be inferring an infinitely
|
||||||
// an inference variable which is unioned with `target_vid`.
|
// deep const.
|
||||||
//
|
if ty::TermVid::Const(
|
||||||
// Not doing so can easily result in stack overflows.
|
self.infcx.inner.borrow_mut().const_unification_table().find(vid),
|
||||||
if TermVid::Const(self.infcx.inner.borrow_mut().const_unification_table().find(vid))
|
) == self.root_vid
|
||||||
== self.root_vid
|
|
||||||
{
|
{
|
||||||
return Err(self.cyclic_term_error());
|
return Err(self.cyclic_term_error());
|
||||||
}
|
}
|
||||||
|
@ -421,10 +411,22 @@ where
|
||||||
)?;
|
)?;
|
||||||
Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
|
Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
|
||||||
}
|
}
|
||||||
|
ty::ConstKind::Placeholder(placeholder) => {
|
||||||
|
if self.for_universe.can_name(placeholder.universe) {
|
||||||
|
Ok(c)
|
||||||
|
} else {
|
||||||
|
debug!(
|
||||||
|
"root universe {:?} cannot name placeholder in universe {:?}",
|
||||||
|
self.for_universe, placeholder.universe
|
||||||
|
);
|
||||||
|
Err(TypeError::Mismatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => relate::super_relate_consts(self, c, c),
|
_ => relate::super_relate_consts(self, c, c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
fn binders<T>(
|
fn binders<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: ty::Binder<'tcx, T>,
|
a: ty::Binder<'tcx, T>,
|
||||||
|
@ -433,7 +435,6 @@ where
|
||||||
where
|
where
|
||||||
T: Relate<'tcx>,
|
T: Relate<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("Generalizer::binders(a={:?})", a);
|
|
||||||
let result = self.relate(a.skip_binder(), a.skip_binder())?;
|
let result = self.relate(a.skip_binder(), a.skip_binder())?;
|
||||||
Ok(a.rebind(result))
|
Ok(a.rebind(result))
|
||||||
}
|
}
|
||||||
|
|
18
tests/ui/traits/non_lifetime_binders/universe-error1.rs
Normal file
18
tests/ui/traits/non_lifetime_binders/universe-error1.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#![feature(non_lifetime_binders)]
|
||||||
|
//~^ WARN the feature `non_lifetime_binders` is incomplete
|
||||||
|
|
||||||
|
trait Other<U: ?Sized> {}
|
||||||
|
|
||||||
|
impl<U: ?Sized> Other<U> for U {}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn foo<U: ?Sized>()
|
||||||
|
where
|
||||||
|
for<T> T: Other<U> {}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
foo::<_>();
|
||||||
|
//~^ ERROR the trait bound `T: Other<_>` is not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
27
tests/ui/traits/non_lifetime_binders/universe-error1.stderr
Normal file
27
tests/ui/traits/non_lifetime_binders/universe-error1.stderr
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/universe-error1.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(non_lifetime_binders)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `T: Other<_>` is not satisfied
|
||||||
|
--> $DIR/universe-error1.rs:14:11
|
||||||
|
|
|
||||||
|
LL | foo::<_>();
|
||||||
|
| ^ the trait `Other<_>` is not implemented for `T`
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/universe-error1.rs:11:15
|
||||||
|
|
|
||||||
|
LL | fn foo<U: ?Sized>()
|
||||||
|
| --- required by a bound in this function
|
||||||
|
LL | where
|
||||||
|
LL | for<T> T: Other<U> {}
|
||||||
|
| ^^^^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue