Remove weak alias terminology
This commit is contained in:
parent
7f695232a8
commit
bdfeb8f36b
47 changed files with 106 additions and 106 deletions
|
|
@ -56,7 +56,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
|||
| ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
|
||||
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
|
||||
|
||||
ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
|
||||
ty::Alias(ty::Free, _) => bug!("type_name: unexpected free alias"),
|
||||
ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
|
||||
ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1991,7 +1991,7 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
ItemKind::TyAlias(..) => {
|
||||
assert!(
|
||||
tcx.type_alias_is_lazy(item.owner_id),
|
||||
"should not be computing variance of non-weak type alias"
|
||||
"should not be computing variance of non-free type alias"
|
||||
);
|
||||
}
|
||||
kind => span_bug!(item.span, "cannot compute the variances of {kind:?}"),
|
||||
|
|
@ -2223,7 +2223,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> {
|
|||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
let def_id = match ty.kind() {
|
||||
ty::Adt(adt_def, _) => Some(adt_def.did()),
|
||||
ty::Alias(ty::Weak, alias_ty) => Some(alias_ty.def_id),
|
||||
ty::Alias(ty::Free, alias_ty) => Some(alias_ty.def_id),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(def_id) = def_id {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
let id = id.owner_id.def_id;
|
||||
let item_span = self.tcx.def_span(id);
|
||||
let self_ty = self.tcx.type_of(id).instantiate_identity();
|
||||
let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
|
||||
let mut self_ty = self.tcx.peel_off_free_alias_tys(self_ty);
|
||||
// We allow impls on pattern types exactly when we allow impls on the base type.
|
||||
// FIXME(pattern_types): Figure out the exact coherence rules we want here.
|
||||
while let ty::Pat(base, _) = *self_ty.kind() {
|
||||
|
|
@ -188,7 +188,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Alias(ty::Weak, _)
|
||||
| ty::Alias(ty::Free, _)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ pub(crate) fn orphan_check_impl(
|
|||
ty::Projection => "associated type",
|
||||
// type Foo = (impl Sized, bool)
|
||||
// impl AutoTrait for Foo {}
|
||||
ty::Weak => "type alias",
|
||||
ty::Free => "type alias",
|
||||
// type Opaque = impl Trait;
|
||||
// impl AutoTrait for Opaque {}
|
||||
ty::Opaque => "opaque type",
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub(crate) fn parameters_for<'tcx>(
|
|||
include_nonconstraining: bool,
|
||||
) -> Vec<Parameter> {
|
||||
let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
|
||||
let value = if !include_nonconstraining { tcx.expand_weak_alias_tys(value) } else { value };
|
||||
let value = if !include_nonconstraining { tcx.expand_free_alias_tys(value) } else { value };
|
||||
value.visit_with(&mut collector);
|
||||
collector.parameters
|
||||
}
|
||||
|
|
@ -68,9 +68,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
|||
{
|
||||
return;
|
||||
}
|
||||
// All weak alias types should've been expanded beforehand.
|
||||
ty::Alias(ty::Weak, _) if !self.include_nonconstraining => {
|
||||
bug!("unexpected weak alias type")
|
||||
// All free alias types should've been expanded beforehand.
|
||||
ty::Alias(ty::Free, _) if !self.include_nonconstraining => {
|
||||
bug!("unexpected free alias type")
|
||||
}
|
||||
ty::Param(param) => self.parameters.push(Parameter::from(param)),
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -958,7 +958,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
|
||||
// then actually instantiate the where bounds of.
|
||||
let alias_ty = ty::AliasTy::new_from_args(tcx, did, args);
|
||||
Ty::new_alias(tcx, ty::Weak, alias_ty)
|
||||
Ty::new_alias(tcx, ty::Free, alias_ty)
|
||||
} else {
|
||||
tcx.at(span).type_of(did).instantiate(tcx, args)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,10 +157,10 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, alias) => {
|
||||
ty::Alias(ty::Free, alias) => {
|
||||
// This corresponds to a type like `Type<'a, T>`.
|
||||
// We check inferred and explicit predicates.
|
||||
debug!("Weak");
|
||||
debug!("Free");
|
||||
check_inferred_predicates(
|
||||
tcx,
|
||||
alias.def_id,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
let current_item = &CurrentItem { inferred_start };
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
|
||||
// The type as returned by `type_of` is the underlying type and generally not a weak projection.
|
||||
// The type as returned by `type_of` is the underlying type and generally not a free alias.
|
||||
// Therefore we need to check the `DefKind` first.
|
||||
if let DefKind::TyAlias = tcx.def_kind(def_id)
|
||||
&& tcx.type_alias_is_lazy(def_id)
|
||||
|
|
@ -282,7 +282,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
self.add_constraints_from_invariant_args(current, data.args, variance);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, ref data) => {
|
||||
ty::Alias(ty::Free, ref data) => {
|
||||
self.add_constraints_from_args(current, data.def_id, data.args, variance);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
|||
match ty.kind() {
|
||||
ty::Adt(adt_def, _) => Some(*adt_def),
|
||||
// FIXME(#104767): Should we handle bound regions here?
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _)
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Free, _)
|
||||
if !ty.has_escaping_bound_vars() =>
|
||||
{
|
||||
if self.next_trait_solver() {
|
||||
|
|
@ -357,7 +357,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
|||
// WF obligations that are registered elsewhere, but they have a
|
||||
// better cause code assigned to them in `add_required_obligations_for_hir`.
|
||||
// This means that they should shadow obligations with worse spans.
|
||||
if let ty::Alias(ty::Projection | ty::Weak, ty::AliasTy { args, def_id, .. }) =
|
||||
if let ty::Alias(ty::Projection | ty::Free, ty::AliasTy { args, def_id, .. }) =
|
||||
ty.kind()
|
||||
{
|
||||
self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}]);
|
||||
}
|
||||
// The old solver only accepts projection predicates for associated types.
|
||||
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
|
||||
ty::Alias(ty::Inherent | ty::Free | ty::Opaque, _) => {
|
||||
return Err(TypeError::CyclicTy(source_ty));
|
||||
}
|
||||
_ => bug!("generalized `{source_ty:?} to infer, not an alias"),
|
||||
|
|
|
|||
|
|
@ -1371,7 +1371,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
|
||||
|
||||
ty::Param(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
||||
| ty::Infer(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Error(_)
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ rustc_queries! {
|
|||
|
||||
/// Returns whether the type alias given by `DefId` is lazy.
|
||||
///
|
||||
/// I.e., if the type alias expands / ought to expand to a [weak] [alias type]
|
||||
/// I.e., if the type alias expands / ought to expand to a [free] [alias type]
|
||||
/// instead of the underyling aliased type.
|
||||
///
|
||||
/// Relevant for features `lazy_type_alias` and `type_alias_impl_trait`.
|
||||
|
|
@ -298,7 +298,7 @@ rustc_queries! {
|
|||
///
|
||||
/// This query *may* panic if the given definition is not a type alias.
|
||||
///
|
||||
/// [weak]: rustc_middle::ty::Weak
|
||||
/// [free]: rustc_middle::ty::Free
|
||||
/// [alias type]: rustc_middle::ty::AliasTy
|
||||
query type_alias_is_lazy(key: DefId) -> bool {
|
||||
desc { |tcx|
|
||||
|
|
@ -2280,7 +2280,7 @@ rustc_queries! {
|
|||
/// Do not call this query directly: Invoke `normalize` instead.
|
||||
///
|
||||
/// </div>
|
||||
query normalize_canonicalized_weak_ty(
|
||||
query normalize_canonicalized_free_alias(
|
||||
goal: CanonicalAliasGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
/// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy`
|
||||
ConstParam(Ty<'tcx>),
|
||||
|
||||
/// Obligations emitted during the normalization of a weak type alias.
|
||||
/// Obligations emitted during the normalization of a free type alias.
|
||||
TypeAlias(ObligationCauseCodeHandle<'tcx>, Span, DefId),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
|
|||
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
}
|
||||
|
||||
/// Result of the `normalize_canonicalized_{{,inherent_}projection,weak}_ty` queries.
|
||||
/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}_ty` queries.
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct NormalizationResult<'tcx> {
|
||||
/// Result of the normalization.
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::Opaque,
|
||||
DefKind::TyAlias => ty::Weak,
|
||||
DefKind::TyAlias => ty::Free,
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -242,7 +242,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
||||
DefKind::TyAlias => ty::AliasTermKind::WeakTy,
|
||||
DefKind::TyAlias => ty::AliasTermKind::FreeTy,
|
||||
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
|
||||
DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => {
|
||||
ty::AliasTermKind::UnevaluatedConst
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
ty::Placeholder(..) => "higher-ranked type".into(),
|
||||
ty::Bound(..) => "bound type variable".into(),
|
||||
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
|
||||
ty::Alias(ty::Weak, _) => "type alias".into(),
|
||||
ty::Alias(ty::Free, _) => "type alias".into(),
|
||||
ty::Param(_) => "type parameter".into(),
|
||||
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
InhabitedPredicate::True
|
||||
}
|
||||
Never => InhabitedPredicate::False,
|
||||
Param(_) | Alias(ty::Projection | ty::Weak, _) => InhabitedPredicate::GenericType(self),
|
||||
Param(_) | Alias(ty::Projection | ty::Free, _) => InhabitedPredicate::GenericType(self),
|
||||
Alias(ty::Opaque, alias_ty) => {
|
||||
match alias_ty.def_id.as_local() {
|
||||
// Foreign opaque is considered inhabited.
|
||||
|
|
|
|||
|
|
@ -820,7 +820,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
ty::Foreign(def_id) => {
|
||||
p!(print_def_path(def_id, &[]));
|
||||
}
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ref data) => {
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Free, ref data) => {
|
||||
p!(print(data))
|
||||
}
|
||||
ty::Placeholder(placeholder) => match placeholder.bound.kind {
|
||||
|
|
@ -3205,7 +3205,7 @@ define_print! {
|
|||
p!(print_def_path(self.def_id, self.args));
|
||||
}
|
||||
}
|
||||
| ty::AliasTermKind::WeakTy
|
||||
| ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::OpaqueTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
(kind, tcx.def_kind(alias_ty.def_id)),
|
||||
(ty::Opaque, DefKind::OpaqueTy)
|
||||
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
|
||||
| (ty::Weak, DefKind::TyAlias)
|
||||
| (ty::Free, DefKind::TyAlias)
|
||||
);
|
||||
Ty::new(tcx, Alias(kind, alias_ty))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -911,7 +911,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|| self.extern_crate(key).is_some_and(|e| e.is_direct())
|
||||
}
|
||||
|
||||
/// Expand any [weak alias types][weak] contained within the given `value`.
|
||||
/// Expand any [free alias types][free] 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
|
||||
|
|
@ -926,19 +926,19 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// <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
|
||||
/// overflow all well-behaved free 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 })
|
||||
/// [free]: ty::Free
|
||||
pub fn expand_free_alias_tys<T: TypeFoldable<TyCtxt<'tcx>>>(self, value: T) -> T {
|
||||
value.fold_with(&mut FreeAliasTypeExpander { tcx: self, depth: 0 })
|
||||
}
|
||||
|
||||
/// Peel off all [weak alias types] in this type until there are none left.
|
||||
/// Peel off all [free alias types] in this type until there are none left.
|
||||
///
|
||||
/// This only expands weak alias types in “head” / outermost positions. It can
|
||||
/// be used over [expand_weak_alias_tys] as an optimization in situations where
|
||||
/// This only expands free alias types in “head” / outermost positions. It can
|
||||
/// be used over [expand_free_alias_tys] as an optimization in situations where
|
||||
/// one only really cares about the *kind* of the final aliased type but not
|
||||
/// the types the other constituent types alias.
|
||||
///
|
||||
|
|
@ -947,17 +947,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// type gets fully normalized at a later stage.
|
||||
/// </div>
|
||||
///
|
||||
/// [weak]: ty::Weak
|
||||
/// [expand_weak_alias_tys]: Self::expand_weak_alias_tys
|
||||
pub fn peel_off_weak_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
|
||||
/// [free]: ty::Free
|
||||
/// [expand_free_alias_tys]: Self::expand_free_alias_tys
|
||||
pub fn peel_off_free_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty::Alias(ty::Free, _) = ty.kind() else { return ty };
|
||||
|
||||
let limit = self.recursion_limit();
|
||||
let mut depth = 0;
|
||||
|
||||
while let ty::Alias(ty::Weak, alias) = ty.kind() {
|
||||
while let ty::Alias(ty::Free, alias) = ty.kind() {
|
||||
if !limit.value_within_limit(depth) {
|
||||
let guar = self.dcx().delayed_bug("overflow expanding weak alias type");
|
||||
let guar = self.dcx().delayed_bug("overflow expanding free alias type");
|
||||
return Ty::new_error(self, guar);
|
||||
}
|
||||
|
||||
|
|
@ -985,7 +985,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)),
|
||||
ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::WeakTy
|
||||
| ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => None,
|
||||
}
|
||||
|
|
@ -1078,25 +1078,25 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct WeakAliasTypeExpander<'tcx> {
|
||||
struct FreeAliasTypeExpander<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for FreeAliasTypeExpander<'tcx> {
|
||||
fn cx(&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) {
|
||||
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_FREE_ALIAS) {
|
||||
return ty;
|
||||
}
|
||||
let ty::Alias(ty::Weak, alias) = ty.kind() else {
|
||||
let ty::Alias(ty::Free, 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");
|
||||
let guar = self.tcx.dcx().delayed_bug("overflow expanding free alias type");
|
||||
return Ty::new_error(self.tcx, guar);
|
||||
}
|
||||
|
||||
|
|
@ -1107,7 +1107,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
|
|||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if !ct.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
|
||||
if !ct.has_type_flags(ty::TypeFlags::HAS_TY_FREE_ALIAS) {
|
||||
return ct;
|
||||
}
|
||||
ct.super_fold_with(self)
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
{
|
||||
let mut collector = LateBoundRegionsCollector::new(just_constrained);
|
||||
let value = value.skip_binder();
|
||||
let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value };
|
||||
let value = if just_constrained { self.expand_free_alias_tys(value) } else { value };
|
||||
value.visit_with(&mut collector);
|
||||
collector.regions
|
||||
}
|
||||
|
|
@ -182,8 +182,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
|
|||
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
|
||||
return;
|
||||
}
|
||||
// All weak alias types should've been expanded beforehand.
|
||||
ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"),
|
||||
// All free alias types should've been expanded beforehand.
|
||||
ty::Alias(ty::Free, _) => bug!("unexpected free alias type"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ where
|
|||
}
|
||||
|
||||
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
|
||||
ty::Alias(ty::Inherent | ty::Weak, _) => {
|
||||
ty::Alias(ty::Inherent | ty::Free, _) => {
|
||||
self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ where
|
|||
|
||||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(_) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Computes a normalizes-to (projection) goal for inherent associated types,
|
||||
//! `#![feature(lazy_type_alias)]` and `#![feature(type_alias_impl_trait)]`.
|
||||
//!
|
||||
//! Since a weak alias is never ambiguous, this just computes the `type_of` of
|
||||
//! Since a free alias is never ambiguous, this just computes the `type_of` of
|
||||
//! the alias and registers the where-clauses of the type alias.
|
||||
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
|
@ -14,22 +14,22 @@ where
|
|||
D: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn normalize_weak_type(
|
||||
pub(super) fn normalize_free_alias(
|
||||
&mut self,
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let cx = self.cx();
|
||||
let weak_ty = goal.predicate.alias;
|
||||
let free_ty = goal.predicate.alias;
|
||||
|
||||
// Check where clauses
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
cx.predicates_of(weak_ty.def_id)
|
||||
.iter_instantiated(cx, weak_ty.args)
|
||||
cx.predicates_of(free_ty.def_id)
|
||||
.iter_instantiated(cx, free_ty.args)
|
||||
.map(|pred| goal.with(cx, pred)),
|
||||
);
|
||||
|
||||
let actual = cx.type_of(weak_ty.def_id).instantiate(cx, weak_ty.args);
|
||||
let actual = cx.type_of(free_ty.def_id).instantiate(cx, free_ty.args);
|
||||
self.instantiate_normalizes_to_term(goal, actual.into());
|
||||
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
mod anon_const;
|
||||
mod free_alias;
|
||||
mod inherent;
|
||||
mod opaque_types;
|
||||
mod weak_types;
|
||||
|
||||
use rustc_type_ir::fast_reject::DeepRejectCtxt;
|
||||
use rustc_type_ir::inherent::*;
|
||||
|
|
@ -50,7 +50,7 @@ where
|
|||
}
|
||||
ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal),
|
||||
ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
|
||||
ty::AliasTermKind::WeakTy => self.normalize_weak_type(goal),
|
||||
ty::AliasTermKind::FreeTy => self.normalize_free_alias(goal),
|
||||
ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1153,7 +1153,7 @@ where
|
|||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
|
||||
| ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
|
||||
| ty::Placeholder(..) => Some(Err(NoSolution)),
|
||||
|
||||
ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => {
|
||||
ty::Alias(kind @ (ty::Inherent | ty::Free | ty::Projection), data) => {
|
||||
if self.def_id_visitor.skip_assoc_tys() {
|
||||
// Visitors searching for minimal visibility/reachability want to
|
||||
// conservatively approximate associated types like `Type::Alias`
|
||||
|
|
@ -227,7 +227,7 @@ where
|
|||
data.def_id,
|
||||
match kind {
|
||||
ty::Inherent | ty::Projection => "associated type",
|
||||
ty::Weak => "type alias",
|
||||
ty::Free => "type alias",
|
||||
ty::Opaque => unreachable!(),
|
||||
},
|
||||
&LazyDefPathStr { def_id: data.def_id, tcx },
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl<'tcx> Stable<'tcx> for ty::AliasTyKind {
|
|||
ty::Projection => stable_mir::ty::AliasKind::Projection,
|
||||
ty::Inherent => stable_mir::ty::AliasKind::Inherent,
|
||||
ty::Opaque => stable_mir::ty::AliasKind::Opaque,
|
||||
ty::Weak => stable_mir::ty::AliasKind::Weak,
|
||||
ty::Free => stable_mir::ty::AliasKind::Free,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1026,7 +1026,7 @@ pub enum AliasKind {
|
|||
Projection,
|
||||
Inherent,
|
||||
Opaque,
|
||||
Weak,
|
||||
Free,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
|
|
|
|||
|
|
@ -707,7 +707,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
ty::Projection | ty::Inherent => {
|
||||
format!("the associated type `{p}`")
|
||||
}
|
||||
ty::Weak => format!("the type alias `{p}`"),
|
||||
ty::Free => format!("the type alias `{p}`"),
|
||||
ty::Opaque => format!("the opaque type `{p}`"),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1682,7 +1682,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
ty::Alias(ty::Projection, ..) => Some(12),
|
||||
ty::Alias(ty::Inherent, ..) => Some(13),
|
||||
ty::Alias(ty::Opaque, ..) => Some(14),
|
||||
ty::Alias(ty::Weak, ..) => Some(15),
|
||||
ty::Alias(ty::Free, ..) => Some(15),
|
||||
ty::Never => Some(16),
|
||||
ty::Adt(..) => Some(17),
|
||||
ty::Coroutine(..) => Some(18),
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
|||
);
|
||||
normalized_ty
|
||||
}
|
||||
ty::Weak => {
|
||||
ty::Free => {
|
||||
let recursion_limit = self.cx().recursion_limit();
|
||||
if !recursion_limit.value_within_limit(self.depth) {
|
||||
self.selcx.infcx.err_ctxt().report_overflow_error(
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ fn normalize_to_error<'a, 'tcx>(
|
|||
ty::AliasTermKind::ProjectionTy
|
||||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::OpaqueTy
|
||||
| ty::AliasTermKind::WeakTy => selcx.infcx.next_ty_var(cause.span).into(),
|
||||
| ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(),
|
||||
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
|
||||
selcx.infcx.next_const_var(cause.span).into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
ty::Projection | ty::Inherent | ty::Weak => {
|
||||
ty::Projection | ty::Inherent | ty::Free => {
|
||||
// See note in `rustc_trait_selection::traits::project`
|
||||
|
||||
let infcx = self.infcx;
|
||||
|
|
@ -275,7 +275,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
let result = match kind {
|
||||
ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
|
||||
ty::Weak => tcx.normalize_canonicalized_weak_ty(c_data),
|
||||
ty::Free => tcx.normalize_canonicalized_free_alias(c_data),
|
||||
ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
|
||||
kind => unreachable!("did not expect {kind:?} due to match arm above"),
|
||||
}?;
|
||||
|
|
@ -313,10 +313,10 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
};
|
||||
// `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
|
||||
// still has unevaluated consts, so keep normalizing here if that's the case.
|
||||
// Similarly, `tcx.normalize_canonicalized_weak_ty` will only unwrap one layer
|
||||
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
|
||||
// of type and we need to continue folding it to reveal the TAIT behind it.
|
||||
if res != ty
|
||||
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak)
|
||||
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free)
|
||||
{
|
||||
res.try_fold_with(self)?
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -730,7 +730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
ty::Param(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..) => {
|
||||
// In these cases, we don't know what the actual
|
||||
|
|
|
|||
|
|
@ -2323,7 +2323,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
ty::Placeholder(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
|
||||
|
|
|
|||
|
|
@ -756,7 +756,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
// Simple cases that are WF if their type args are WF.
|
||||
}
|
||||
|
||||
ty::Alias(ty::Projection | ty::Opaque | ty::Weak, data) => {
|
||||
ty::Alias(ty::Projection | ty::Opaque | ty::Free, data) => {
|
||||
let obligations = self.nominal_obligations(data.def_id, data.args);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use tracing::debug;
|
|||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers {
|
||||
normalize_canonicalized_projection_ty,
|
||||
normalize_canonicalized_weak_ty,
|
||||
normalize_canonicalized_free_alias,
|
||||
normalize_canonicalized_inherent_projection_ty,
|
||||
..*p
|
||||
};
|
||||
|
|
@ -63,11 +63,11 @@ fn normalize_canonicalized_projection_ty<'tcx>(
|
|||
)
|
||||
}
|
||||
|
||||
fn normalize_canonicalized_weak_ty<'tcx>(
|
||||
fn normalize_canonicalized_free_alias<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalAliasGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
|
||||
debug!("normalize_canonicalized_weak_ty(goal={:#?})", goal);
|
||||
debug!("normalize_canonicalized_free_alias(goal={:#?})", goal);
|
||||
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(
|
||||
&goal,
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||
}
|
||||
// Skips type aliases, as they are meant to be transparent.
|
||||
// FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly?
|
||||
ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
ty::Alias(ty::Free, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
self.tcx
|
||||
.type_of(alias_ty.def_id)
|
||||
.instantiate(self.tcx, alias_ty.args)
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ bitflags::bitflags! {
|
|||
|
||||
/// Does this have `Projection`?
|
||||
const HAS_TY_PROJECTION = 1 << 10;
|
||||
/// Does this have `Weak`?
|
||||
const HAS_TY_WEAK = 1 << 11;
|
||||
/// Does this have `Free` aliases?
|
||||
const HAS_TY_FREE_ALIAS = 1 << 11;
|
||||
/// Does this have `Opaque`?
|
||||
const HAS_TY_OPAQUE = 1 << 12;
|
||||
/// Does this have `Inherent`?
|
||||
|
|
@ -88,7 +88,7 @@ bitflags::bitflags! {
|
|||
///
|
||||
/// Rephrased, could this term be normalized further?
|
||||
const HAS_ALIAS = TypeFlags::HAS_TY_PROJECTION.bits()
|
||||
| TypeFlags::HAS_TY_WEAK.bits()
|
||||
| TypeFlags::HAS_TY_FREE_ALIAS.bits()
|
||||
| TypeFlags::HAS_TY_OPAQUE.bits()
|
||||
| TypeFlags::HAS_TY_INHERENT.bits()
|
||||
| TypeFlags::HAS_CT_PROJECTION.bits();
|
||||
|
|
@ -275,7 +275,7 @@ impl<I: Interner> FlagComputation<I> {
|
|||
ty::Alias(kind, data) => {
|
||||
self.add_flags(match kind {
|
||||
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||
ty::Weak => TypeFlags::HAS_TY_WEAK,
|
||||
ty::Free => TypeFlags::HAS_TY_FREE_ALIAS,
|
||||
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -470,10 +470,10 @@ pub enum AliasTermKind {
|
|||
/// An opaque type (usually from `impl Trait` in type aliases or function return types)
|
||||
/// Can only be normalized away in PostAnalysis mode or its defining scope.
|
||||
OpaqueTy,
|
||||
/// A type alias that actually checks its trait bounds.
|
||||
/// A free type alias that actually checks its trait bounds.
|
||||
/// Currently only used if the type alias references opaque types.
|
||||
/// Can always be normalized away.
|
||||
WeakTy,
|
||||
FreeTy,
|
||||
/// An unevaluated const coming from a generic const expression.
|
||||
UnevaluatedConst,
|
||||
/// An unevaluated const coming from an associated const.
|
||||
|
|
@ -487,7 +487,7 @@ impl AliasTermKind {
|
|||
AliasTermKind::ProjectionConst => "associated const",
|
||||
AliasTermKind::InherentTy => "inherent associated type",
|
||||
AliasTermKind::OpaqueTy => "opaque type",
|
||||
AliasTermKind::WeakTy => "type alias",
|
||||
AliasTermKind::FreeTy => "type alias",
|
||||
AliasTermKind::UnevaluatedConst => "unevaluated constant",
|
||||
}
|
||||
}
|
||||
|
|
@ -498,7 +498,7 @@ impl From<ty::AliasTyKind> for AliasTermKind {
|
|||
match value {
|
||||
ty::Projection => AliasTermKind::ProjectionTy,
|
||||
ty::Opaque => AliasTermKind::OpaqueTy,
|
||||
ty::Weak => AliasTermKind::WeakTy,
|
||||
ty::Free => AliasTermKind::FreeTy,
|
||||
ty::Inherent => AliasTermKind::InherentTy,
|
||||
}
|
||||
}
|
||||
|
|
@ -565,7 +565,7 @@ impl<I: Interner> AliasTerm<I> {
|
|||
AliasTermKind::ProjectionTy
|
||||
| AliasTermKind::InherentTy
|
||||
| AliasTermKind::OpaqueTy
|
||||
| AliasTermKind::WeakTy => {}
|
||||
| AliasTermKind::FreeTy => {}
|
||||
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
|
||||
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
|
||||
}
|
||||
|
|
@ -597,9 +597,9 @@ impl<I: Interner> AliasTerm<I> {
|
|||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
AliasTermKind::WeakTy => Ty::new_alias(
|
||||
AliasTermKind::FreeTy => Ty::new_alias(
|
||||
interner,
|
||||
ty::AliasTyKind::Weak,
|
||||
ty::AliasTyKind::Free,
|
||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
|
|||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
| ty::AliasTermKind::WeakTy
|
||||
| ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub enum AliasTyKind {
|
|||
/// A type alias that actually checks its trait bounds.
|
||||
/// Currently only used if the type alias references opaque types.
|
||||
/// Can always be normalized away.
|
||||
Weak,
|
||||
Free,
|
||||
}
|
||||
|
||||
impl AliasTyKind {
|
||||
|
|
@ -63,7 +63,7 @@ impl AliasTyKind {
|
|||
AliasTyKind::Projection => "associated type",
|
||||
AliasTyKind::Inherent => "inherent associated type",
|
||||
AliasTyKind::Opaque => "opaque type",
|
||||
AliasTyKind::Weak => "type alias",
|
||||
AliasTyKind::Free => "type alias",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ pub enum TyKind<I: Interner> {
|
|||
/// A tuple type. For example, `(i32, bool)`.
|
||||
Tuple(I::Tys),
|
||||
|
||||
/// A projection, opaque type, weak type alias, or inherent associated type.
|
||||
/// A projection, opaque type, free type alias, or inherent associated type.
|
||||
/// All of these types are represented as pairs of def-id and args, and can
|
||||
/// be normalized, so they are grouped conceptually.
|
||||
Alias(AliasTyKind, AliasTy<I>),
|
||||
|
|
|
|||
|
|
@ -2213,9 +2213,9 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
}))
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, data) => {
|
||||
ty::Alias(ty::Free, data) => {
|
||||
if cx.tcx.features().lazy_type_alias() {
|
||||
// Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
|
||||
// Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
|
||||
// we need to use `type_of`.
|
||||
let path = clean_middle_path(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -853,7 +853,7 @@ impl TyCoercionStability {
|
|||
continue;
|
||||
},
|
||||
ty::Param(_) if for_return => Self::Deref,
|
||||
ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"),
|
||||
ty::Alias(ty::Free | ty::Inherent, _) => unreachable!("should have been normalized away above"),
|
||||
ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow,
|
||||
ty::Infer(_)
|
||||
| ty::Error(_)
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool
|
|||
inputs.iter().any(|input| {
|
||||
matches!(
|
||||
input.kind(),
|
||||
ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait()
|
||||
ty::Alias(ty::AliasTyKind::Free, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
#![allow(incomplete_features)]
|
||||
|
||||
// This used to crash when we were computing the variances of `Struct` since we would convert
|
||||
// `eager::Alias<T>` to a weak projection due to the presence of `#![feature(lazy_type_alias)]` in
|
||||
// `eager::Alias<T>` to a weak alias due to the presence of `#![feature(lazy_type_alias)]` in
|
||||
// this (!) crate and subsequently attempt to obtain the variances of the type alias associated with
|
||||
// the weak projection which would panic because we don't compute this information for eager type
|
||||
// the weak alias which would panic because we don't compute this information for eager type
|
||||
// aliases at all.
|
||||
struct Struct<T>(eager::Alias<T>);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue