Introduce expand_weak_alias_tys
This commit is contained in:
parent
05ce209d20
commit
515d805a0e
13 changed files with 165 additions and 41 deletions
|
@ -181,9 +181,10 @@ impl FlagComputation {
|
||||||
|
|
||||||
&ty::Alias(kind, data) => {
|
&ty::Alias(kind, data) => {
|
||||||
self.add_flags(match kind {
|
self.add_flags(match kind {
|
||||||
ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||||
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
ty::Weak => TypeFlags::HAS_TY_WEAK,
|
||||||
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||||
|
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.add_alias_ty(data);
|
self.add_alias_ty(data);
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::ty::{GenericArgKind, GenericArgsRef};
|
||||||
use rustc_apfloat::Float as _;
|
use rustc_apfloat::Float as _;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
|
||||||
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
|
@ -867,6 +868,30 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
|
||||||
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
|
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expand any [weak alias types][weak] contained within the given `value`.
|
||||||
|
///
|
||||||
|
/// This should be used over other normalization routines in situations where
|
||||||
|
/// it's important not to normalize other alias types and where the predicates
|
||||||
|
/// on the corresponding type alias shouldn't be taken into consideration.
|
||||||
|
///
|
||||||
|
/// Whenever possible **prefer not to use this function**! Instead, use standard
|
||||||
|
/// normalization routines or if feasible don't normalize at all.
|
||||||
|
///
|
||||||
|
/// This function comes in handy if you want to mimic the behavior of eager
|
||||||
|
/// type alias expansion in a localized manner.
|
||||||
|
///
|
||||||
|
/// <div class="warning">
|
||||||
|
/// This delays a bug on overflow! Therefore you need to be certain that the
|
||||||
|
/// contained types get fully normalized at a later stage. Note that even on
|
||||||
|
/// overflow all well-behaved weak alias types get expanded correctly, so the
|
||||||
|
/// result is still useful.
|
||||||
|
/// </div>
|
||||||
|
///
|
||||||
|
/// [weak]: ty::Weak
|
||||||
|
pub fn expand_weak_alias_tys<T: TypeFoldable<TyCtxt<'tcx>>>(self, value: T) -> T {
|
||||||
|
value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OpaqueTypeExpander<'tcx> {
|
struct OpaqueTypeExpander<'tcx> {
|
||||||
|
@ -1002,6 +1027,42 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WeakAliasTypeExpander<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
depth: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
|
||||||
|
fn interner(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
|
||||||
|
return ty;
|
||||||
|
}
|
||||||
|
let ty::Alias(ty::Weak, alias) = ty.kind() else {
|
||||||
|
return ty.super_fold_with(self);
|
||||||
|
};
|
||||||
|
if !self.tcx.recursion_limit().value_within_limit(self.depth) {
|
||||||
|
let guar = self.tcx.dcx().delayed_bug("overflow expanding weak alias type");
|
||||||
|
return Ty::new_error(self.tcx, guar);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.depth += 1;
|
||||||
|
ensure_sufficient_stack(|| {
|
||||||
|
self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||||
|
if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
ct.super_fold_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Ty<'tcx> {
|
impl<'tcx> Ty<'tcx> {
|
||||||
/// Returns the `Size` for primitive types (bool, uint, int, char, float).
|
/// Returns the `Size` for primitive types (bool, uint, int, char, float).
|
||||||
pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size {
|
pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size {
|
||||||
|
|
|
@ -131,12 +131,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
fn collect_late_bound_regions<T>(
|
fn collect_late_bound_regions<T>(
|
||||||
self,
|
self,
|
||||||
value: &Binder<'tcx, T>,
|
value: &Binder<'tcx, T>,
|
||||||
just_constraint: bool,
|
just_constrained: bool,
|
||||||
) -> FxHashSet<ty::BoundRegionKind>
|
) -> FxHashSet<ty::BoundRegionKind>
|
||||||
where
|
where
|
||||||
T: TypeVisitable<TyCtxt<'tcx>>,
|
T: TypeVisitable<TyCtxt<'tcx>>,
|
||||||
{
|
{
|
||||||
let mut collector = LateBoundRegionsCollector::new(just_constraint);
|
let mut collector = LateBoundRegionsCollector::new(self, just_constrained);
|
||||||
|
let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value };
|
||||||
let result = value.as_ref().skip_binder().visit_with(&mut collector);
|
let result = value.as_ref().skip_binder().visit_with(&mut collector);
|
||||||
assert!(result.is_continue()); // should never have stopped early
|
assert!(result.is_continue()); // should never have stopped early
|
||||||
collector.regions
|
collector.regions
|
||||||
|
@ -258,11 +259,7 @@ struct LateBoundRegionsCollector {
|
||||||
|
|
||||||
impl LateBoundRegionsCollector {
|
impl LateBoundRegionsCollector {
|
||||||
fn new(just_constrained: bool) -> Self {
|
fn new(just_constrained: bool) -> Self {
|
||||||
LateBoundRegionsCollector {
|
Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
|
||||||
current_index: ty::INNERMOST,
|
|
||||||
regions: Default::default(),
|
|
||||||
just_constrained,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,12 +275,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
// if we are only looking for "constrained" region, we have to
|
|
||||||
// ignore the inputs to a projection, as they may not appear
|
|
||||||
// in the normalized form
|
|
||||||
if self.just_constrained {
|
if self.just_constrained {
|
||||||
if let ty::Alias(..) = t.kind() {
|
match t.kind() {
|
||||||
return ControlFlow::Continue(());
|
// If we are only looking for "constrained" regions, we have to ignore the
|
||||||
|
// inputs to a projection as they may not appear in the normalized form.
|
||||||
|
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
|
// All weak alias types should've been expanded beforehand.
|
||||||
|
ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,19 +101,17 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||||
value: &T,
|
value: &T,
|
||||||
reveal: Reveal,
|
reveal: Reveal,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let mut flags = ty::TypeFlags::HAS_TY_PROJECTION
|
||||||
|
| ty::TypeFlags::HAS_TY_WEAK
|
||||||
|
| ty::TypeFlags::HAS_TY_INHERENT
|
||||||
|
| ty::TypeFlags::HAS_CT_PROJECTION;
|
||||||
|
|
||||||
match reveal {
|
match reveal {
|
||||||
Reveal::UserFacing => value.has_type_flags(
|
Reveal::UserFacing => {}
|
||||||
ty::TypeFlags::HAS_TY_PROJECTION
|
Reveal::All => flags |= ty::TypeFlags::HAS_TY_OPAQUE,
|
||||||
| ty::TypeFlags::HAS_TY_INHERENT
|
|
||||||
| ty::TypeFlags::HAS_CT_PROJECTION,
|
|
||||||
),
|
|
||||||
Reveal::All => value.has_type_flags(
|
|
||||||
ty::TypeFlags::HAS_TY_PROJECTION
|
|
||||||
| ty::TypeFlags::HAS_TY_INHERENT
|
|
||||||
| ty::TypeFlags::HAS_TY_OPAQUE
|
|
||||||
| ty::TypeFlags::HAS_CT_PROJECTION,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value.has_type_flags(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AssocTypeNormalizer<'a, 'b, 'tcx> {
|
struct AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||||
|
|
|
@ -69,32 +69,35 @@ bitflags! {
|
||||||
|
|
||||||
/// Does this have `Projection`?
|
/// Does this have `Projection`?
|
||||||
const HAS_TY_PROJECTION = 1 << 10;
|
const HAS_TY_PROJECTION = 1 << 10;
|
||||||
/// Does this have `Inherent`?
|
/// Does this have `Weak`?
|
||||||
const HAS_TY_INHERENT = 1 << 11;
|
const HAS_TY_WEAK = 1 << 11;
|
||||||
/// Does this have `Opaque`?
|
/// Does this have `Opaque`?
|
||||||
const HAS_TY_OPAQUE = 1 << 12;
|
const HAS_TY_OPAQUE = 1 << 12;
|
||||||
|
/// Does this have `Inherent`?
|
||||||
|
const HAS_TY_INHERENT = 1 << 13;
|
||||||
/// Does this have `ConstKind::Unevaluated`?
|
/// Does this have `ConstKind::Unevaluated`?
|
||||||
const HAS_CT_PROJECTION = 1 << 13;
|
const HAS_CT_PROJECTION = 1 << 14;
|
||||||
|
|
||||||
/// Could this type be normalized further?
|
/// Could this type be normalized further?
|
||||||
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits()
|
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits()
|
||||||
|
| TypeFlags::HAS_TY_WEAK.bits()
|
||||||
| TypeFlags::HAS_TY_OPAQUE.bits()
|
| TypeFlags::HAS_TY_OPAQUE.bits()
|
||||||
| TypeFlags::HAS_TY_INHERENT.bits()
|
| TypeFlags::HAS_TY_INHERENT.bits()
|
||||||
| TypeFlags::HAS_CT_PROJECTION.bits();
|
| TypeFlags::HAS_CT_PROJECTION.bits();
|
||||||
|
|
||||||
/// Is an error type/const reachable?
|
/// Is an error type/const reachable?
|
||||||
const HAS_ERROR = 1 << 14;
|
const HAS_ERROR = 1 << 15;
|
||||||
|
|
||||||
/// Does this have any region that "appears free" in the type?
|
/// Does this have any region that "appears free" in the type?
|
||||||
/// Basically anything but `ReBound` and `ReErased`.
|
/// Basically anything but `ReBound` and `ReErased`.
|
||||||
const HAS_FREE_REGIONS = 1 << 15;
|
const HAS_FREE_REGIONS = 1 << 16;
|
||||||
|
|
||||||
/// Does this have any `ReBound` regions?
|
/// Does this have any `ReBound` regions?
|
||||||
const HAS_RE_BOUND = 1 << 16;
|
const HAS_RE_BOUND = 1 << 17;
|
||||||
/// Does this have any `Bound` types?
|
/// Does this have any `Bound` types?
|
||||||
const HAS_TY_BOUND = 1 << 17;
|
const HAS_TY_BOUND = 1 << 18;
|
||||||
/// Does this have any `ConstKind::Bound` consts?
|
/// Does this have any `ConstKind::Bound` consts?
|
||||||
const HAS_CT_BOUND = 1 << 18;
|
const HAS_CT_BOUND = 1 << 19;
|
||||||
/// Does this have any bound variables?
|
/// Does this have any bound variables?
|
||||||
/// Used to check if a global bound is safe to evaluate.
|
/// Used to check if a global bound is safe to evaluate.
|
||||||
const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits()
|
const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits()
|
||||||
|
@ -102,22 +105,22 @@ bitflags! {
|
||||||
| TypeFlags::HAS_CT_BOUND.bits();
|
| TypeFlags::HAS_CT_BOUND.bits();
|
||||||
|
|
||||||
/// Does this have any `ReErased` regions?
|
/// Does this have any `ReErased` regions?
|
||||||
const HAS_RE_ERASED = 1 << 19;
|
const HAS_RE_ERASED = 1 << 20;
|
||||||
|
|
||||||
/// Does this value have parameters/placeholders/inference variables which could be
|
/// Does this value have parameters/placeholders/inference variables which could be
|
||||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
|
const STILL_FURTHER_SPECIALIZABLE = 1 << 21;
|
||||||
|
|
||||||
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
||||||
const HAS_TY_FRESH = 1 << 21;
|
const HAS_TY_FRESH = 1 << 22;
|
||||||
|
|
||||||
/// Does this value have `InferConst::Fresh`?
|
/// Does this value have `InferConst::Fresh`?
|
||||||
const HAS_CT_FRESH = 1 << 22;
|
const HAS_CT_FRESH = 1 << 23;
|
||||||
|
|
||||||
/// Does this have `Coroutine` or `CoroutineWitness`?
|
/// Does this have `Coroutine` or `CoroutineWitness`?
|
||||||
const HAS_TY_COROUTINE = 1 << 23;
|
const HAS_TY_COROUTINE = 1 << 24;
|
||||||
|
|
||||||
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
|
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
|
||||||
const HAS_BINDER_VARS = 1 << 24;
|
const HAS_BINDER_VARS = 1 << 25;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
Normal file
15
tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//@ check-pass
|
||||||
|
// Weak alias types constrain late-bound regions if their normalized form constrains them.
|
||||||
|
|
||||||
|
#![feature(lazy_type_alias)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
type Ref<'a> = &'a ();
|
||||||
|
|
||||||
|
type FnPtr = for<'a> fn(Ref<'a>) -> &'a (); // OK
|
||||||
|
type DynCl = dyn for<'a> Fn(Ref<'a>) -> &'a (); // OK
|
||||||
|
|
||||||
|
fn map0(_: Ref) -> Ref { &() } // OK
|
||||||
|
fn map1(_: Ref<'_>) -> Ref<'_> { &() } // OK
|
||||||
|
|
||||||
|
fn main() {}
|
23
tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
Normal file
23
tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Weak alias types only constrain late-bound regions if their normalized form constrains them.
|
||||||
|
|
||||||
|
#![feature(lazy_type_alias)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
type NotInjective<'a> = <() as Discard>::Output<'a>;
|
||||||
|
|
||||||
|
type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a ();
|
||||||
|
//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types
|
||||||
|
type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>;
|
||||||
|
//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types
|
||||||
|
type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a ();
|
||||||
|
//~^ ERROR references lifetime `'a`, which does not appear in the trait input types
|
||||||
|
|
||||||
|
trait Discard { type Output<'a>; }
|
||||||
|
impl Discard for () { type Output<'_a> = (); }
|
||||||
|
|
||||||
|
type NotInjectiveEither<'a, Linchpin> = Linchpin
|
||||||
|
where
|
||||||
|
Linchpin: Fn() -> &'a ();
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
|
||||||
|
--> $DIR/unconstrained-late-bound-regions.rs:8:47
|
||||||
|
|
|
||||||
|
LL | type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a ();
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
|
||||||
|
--> $DIR/unconstrained-late-bound-regions.rs:10:57
|
||||||
|
|
|
||||||
|
LL | type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
|
||||||
|
--> $DIR/unconstrained-late-bound-regions.rs:12:50
|
||||||
|
|
|
||||||
|
LL | type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a ();
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0581, E0582.
|
||||||
|
For more information about an error, try `rustc --explain E0581`.
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
||||||
--> $DIR/unconstrained-param-due-to-overflow.rs:4:6
|
--> $DIR/unconstrained-params-in-impl-due-to-overflow.rs:4:6
|
||||||
|
|
|
|
||||||
LL | impl<T> Loop<T> {}
|
LL | impl<T> Loop<T> {}
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
||||||
--> $DIR/unconstrained-params.rs:4:6
|
--> $DIR/unconstrained-params-in-impl.rs:4:6
|
||||||
|
|
|
|
||||||
LL | impl<T> NotInjective<T> {}
|
LL | impl<T> NotInjective<T> {}
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
Loading…
Add table
Add a link
Reference in a new issue