From 1ad28a6f534d7673664e8f26c632bc71490c33a6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 May 2024 12:40:08 -0400 Subject: [PATCH] Uplift AliasTy --- compiler/rustc_errors/src/diagnostic_impls.rs | 6 + compiler/rustc_middle/src/ty/consts.rs | 18 +- compiler/rustc_middle/src/ty/consts/kind.rs | 30 +- compiler/rustc_middle/src/ty/context.rs | 76 +++- compiler/rustc_middle/src/ty/mod.rs | 16 +- compiler/rustc_middle/src/ty/predicate.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 54 +-- .../rustc_middle/src/ty/structural_impls.rs | 36 +- compiler/rustc_middle/src/ty/sty.rs | 388 +----------------- compiler/rustc_type_ir/src/const_kind.rs | 41 ++ compiler/rustc_type_ir/src/inherent.rs | 29 +- compiler/rustc_type_ir/src/interner.rs | 25 +- compiler/rustc_type_ir/src/ir_print.rs | 6 +- compiler/rustc_type_ir/src/predicate.rs | 234 +++++++++-- compiler/rustc_type_ir/src/ty_kind.rs | 158 ++++++- 15 files changed, 584 insertions(+), 534 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 2cc0167dbaa6e..d9add1c9b3b52 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -106,6 +106,12 @@ impl IntoDiagArg for rustc_type_ir::ExistentialTrait } } +impl IntoDiagArg for rustc_type_ir::UnevaluatedConst { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + format!("{self:?}").into_diag_arg() + } +} + into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagArg for bool { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 329d5f34a2123..27a4abaa0b695 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -7,8 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_type_ir::ConstKind as IrConstKind; -use rustc_type_ir::{TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; mod int; mod kind; @@ -20,7 +19,8 @@ use rustc_span::Span; use rustc_span::DUMMY_SP; pub use valtree::*; -pub type ConstKind<'tcx> = IrConstKind>; +pub type ConstKind<'tcx> = ir::ConstKind>; +pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); @@ -184,9 +184,21 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_bound(tcx, debruijn, var, ty) } + fn new_unevaluated( + interner: TyCtxt<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, + ty: Ty<'tcx>, + ) -> Self { + Const::new_unevaluated(interner, uv, ty) + } + fn ty(self) -> Ty<'tcx> { self.ty() } + + fn into_term(self) -> ty::Term<'tcx> { + self.into() + } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 7e49b0ac915c6..d7ae050ed4d02 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,30 +1,15 @@ use super::Const; use crate::mir; use crate::ty::abstract_const::CastKind; -use crate::ty::GenericArgsRef; use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -/// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct UnevaluatedConst<'tcx> { - pub def: DefId, - pub args: GenericArgsRef<'tcx>, -} - -impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - format!("{self:?}").into_diag_arg() - } -} - -impl<'tcx> UnevaluatedConst<'tcx> { +#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)] +impl<'tcx> ty::UnevaluatedConst<'tcx> { /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this /// hurts performance. #[inline] - pub(crate) fn prepare_for_eval( + fn prepare_for_eval( self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -55,13 +40,6 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -impl<'tcx> UnevaluatedConst<'tcx> { - #[inline] - pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> { - UnevaluatedConst { def, args } - } -} - #[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e831db1a41bf8..d7e185dd5e107 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -76,6 +76,7 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -91,67 +92,124 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type DefiningOpaqueTypes = &'tcx ty::List; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; + type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; - type Term = ty::Term<'tcx>; + type Term = ty::Term<'tcx>; type Binder>> = Binder<'tcx, T>; type BoundVars = &'tcx List; type BoundVar = ty::BoundVariableKind; - type CanonicalVars = CanonicalVarInfos<'tcx>; + type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; type Tys = &'tcx List>; - type AliasTy = ty::AliasTy<'tcx>; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; type PlaceholderTy = ty::PlaceholderType; - type ErrorGuaranteed = ErrorGuaranteed; + type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List>; type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; - type Pat = Pattern<'tcx>; + type Pat = Pattern<'tcx>; type Const = ty::Const<'tcx>; type AliasConst = ty::UnevaluatedConst<'tcx>; type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; - type ExprConst = ty::Expr<'tcx>; + type ExprConst = ty::Expr<'tcx>; type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; type InferRegion = ty::RegionVid; - type PlaceholderRegion = ty::PlaceholderRegion; + type PlaceholderRegion = ty::PlaceholderRegion; type Predicate = Predicate<'tcx>; type TraitPredicate = ty::TraitPredicate<'tcx>; type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>; type ProjectionPredicate = ty::ProjectionPredicate<'tcx>; - type AliasTerm = ty::AliasTerm<'tcx>; type NormalizesTo = ty::NormalizesTo<'tcx>; type SubtypePredicate = ty::SubtypePredicate<'tcx>; type CoercePredicate = ty::CoercePredicate<'tcx>; type ClosureKind = ty::ClosureKind; - type Clauses = ty::Clauses<'tcx>; + type Clauses = ty::Clauses<'tcx>; fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } type GenericsOf = &'tcx ty::Generics; + fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics { self.generics_of(def_id) } + fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> { + self.type_of(def_id).instantiate(self, args) + } + + fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { + match self.def_kind(alias.def_id) { + DefKind::AssocTy => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::Inherent + } else { + ty::Projection + } + } + DefKind::OpaqueTy => ty::Opaque, + DefKind::TyAlias => ty::Weak, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind { + match self.def_kind(alias.def_id) { + DefKind::AssocTy => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::AliasTermKind::InherentTy + } else { + ty::AliasTermKind::ProjectionTy + } + } + DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, + DefKind::TyAlias => ty::AliasTermKind::WeakTy, + DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, + DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { + assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); + let trait_def_id = self.parent(def_id); + assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); + let trait_generics = self.generics_of(trait_def_id); + ( + ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)), + &args[trait_generics.count()..], + ) + } + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { self.mk_args(args) } + fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs { + self.mk_args_from_iter(args) + } + fn check_and_mk_args( self, def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dc5e881843a54..93ccc0a7de420 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -96,9 +96,9 @@ pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ - Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, - ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, - PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, + AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, + ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo, + OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, @@ -110,11 +110,11 @@ pub use self::region::{ }; pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ - AliasTerm, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, - CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, - CoroutineClosureArgs, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, - InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, - UpvarArgs, VarianceDiagInfo, + AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs, + InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index e78856517b217..16ca098853eea 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -13,6 +13,7 @@ use crate::ty::{ }; pub type TraitRef<'tcx> = ir::TraitRef>; +pub type AliasTerm<'tcx> = ir::AliasTerm>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate>; pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8d8ed70a7574d..3577db7234d90 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3038,6 +3038,33 @@ define_print! { p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) } + ty::AliasTy<'tcx> { + let alias_term: ty::AliasTerm<'tcx> = (*self).into(); + p!(print(alias_term)) + } + + ty::AliasTerm<'tcx> { + match self.kind(cx.tcx()) { + ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), + ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::OpaqueTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + // If we're printing verbosely, or don't want to invoke queries + // (`is_impl_trait_in_trait`), then fall back to printing the def path. + // This is likely what you want if you're debugging the compiler anyways. + if !(cx.should_print_verbose() || with_reduced_queries()) + && cx.tcx().is_impl_trait_in_trait(self.def_id) + { + return cx.pretty_print_opaque_impl_type(self.def_id, self.args); + } else { + p!(print_def_path(self.def_id, self.args)); + } + } + } + } + ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); p!(pretty_print_bound_constness(self.trait_ref)); @@ -3205,33 +3232,6 @@ define_print_and_forward_display! { } } - ty::AliasTy<'tcx> { - let alias_term: ty::AliasTerm<'tcx> = (*self).into(); - p!(print(alias_term)) - } - - ty::AliasTerm<'tcx> { - match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - // If we're printing verbosely, or don't want to invoke queries - // (`is_impl_trait_in_trait`), then fall back to printing the def path. - // This is likely what you want if you're debugging the compiler anyways. - if !(cx.should_print_verbose() || with_reduced_queries()) - && cx.tcx().is_impl_trait_in_trait(self.def_id) - { - return cx.pretty_print_opaque_impl_type(self.def_id, self.args); - } else { - p!(print_def_path(self.def_id, self.args)); - } - } - } - } - ty::Predicate<'tcx> { p!(print(self.kind())) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6abd685343b3a..7523cd1532070 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,7 @@ use crate::mir::interpret; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; use rustc_hir::def::Namespace; @@ -164,23 +164,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> { } } -impl<'tcx> fmt::Debug for AliasTy<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for AliasTy<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_struct("AliasTy") - .field("args", &this.map(|data| data.args)) - .field("def_id", &this.data.def_id) - .finish() - } -} - impl<'tcx> DebugWithInfcx> for Pattern<'tcx> { fn fmt>>( this: WithInfcx<'_, Infcx, &Self>, @@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx> for ty::consts::Expr<'tcx> { } } -impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for ty::UnevaluatedConst<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_struct("UnevaluatedConst") - .field("def", &this.data.def) - .field("args", &this.wrap(this.data.args)) - .finish() - } -} - impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { WithInfcx::with_no_infcx(self).fmt(f) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 163016332475e..e4396c6f20ba2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -28,20 +28,17 @@ use std::iter; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; -use rustc_type_ir::BoundVar; -use rustc_type_ir::CollectAndApply; -use rustc_type_ir::DynKind; -use rustc_type_ir::TyKind as IrTyKind; use rustc_type_ir::TyKind::*; -use rustc_type_ir::TypeAndMut as IrTypeAndMut; +use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here #[rustc_diagnostic_item = "TyKind"] -pub type TyKind<'tcx> = IrTyKind>; -pub type TypeAndMut<'tcx> = IrTypeAndMut>; +pub type TyKind<'tcx> = ir::TyKind>; +pub type TypeAndMut<'tcx> = ir::TypeAndMut>; +pub type AliasTy<'tcx> = ir::AliasTy>; pub trait Article { fn article(&self) -> &'static str; @@ -1105,371 +1102,6 @@ where } } -/// Represents the unprojected term of a projection goal. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct AliasTerm<'tcx> { - /// The parameters of the associated or opaque item. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: GenericArgsRef<'tcx>, - - /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether - /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if - /// this is an opaque. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the - /// underlying type if the type is an opaque. - /// - /// Note that if this is an associated type, this is not the `DefId` of the - /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`, - /// aka. `tcx.parent(def_id)`. - pub def_id: DefId, - - /// This field exists to prevent the creation of `AliasTerm` without using - /// [AliasTerm::new]. - _use_alias_term_new_instead: (), -} - -// FIXME: Remove these when we uplift `AliasTerm` -use crate::ty::{DebugWithInfcx, InferCtxtLike, WithInfcx}; -impl<'tcx> std::fmt::Debug for AliasTerm<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for AliasTerm<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { - f.debug_struct("AliasTerm") - .field("args", &this.map(|data| data.args)) - .field("def_id", &this.data.def_id) - .finish() - } -} - -impl<'tcx> rustc_type_ir::inherent::AliasTerm> for AliasTerm<'tcx> { - fn new( - interner: TyCtxt<'tcx>, - trait_def_id: DefId, - args: impl IntoIterator>>, - ) -> Self { - AliasTerm::new(interner, trait_def_id, args) - } - - fn def_id(self) -> DefId { - self.def_id - } - - fn args(self) -> ty::GenericArgsRef<'tcx> { - self.args - } - - fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId { - self.trait_def_id(interner) - } - - fn self_ty(self) -> Ty<'tcx> { - self.self_ty() - } - - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - self.with_self_ty(tcx, self_ty) - } -} - -impl<'tcx> AliasTerm<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: impl IntoIterator>>, - ) -> AliasTerm<'tcx> { - let args = tcx.check_and_mk_args(def_id, args); - AliasTerm { def_id, args, _use_alias_term_new_instead: () } - } - - pub fn expect_ty(self, tcx: TyCtxt<'tcx>) -> AliasTy<'tcx> { - match self.kind(tcx) { - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::WeakTy => {} - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - bug!("Cannot turn `UnevaluatedConst` into `AliasTy`") - } - } - ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } - } - - pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTermKind { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy => { - if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) { - ty::AliasTermKind::InherentTy - } else { - ty::AliasTermKind::ProjectionTy - } - } - DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, - DefKind::TyAlias => ty::AliasTermKind::WeakTy, - DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, - DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), - } - } -} - -/// The following methods work only with (trait) associated item projections. -impl<'tcx> AliasTerm<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.args.type_at(0) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - AliasTerm::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args.iter().skip(1)), - ) - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - kind => bug!("expected a projection AliasTy; found {kind:?}"), - } - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `::Item`, - /// then this function would return a `T: Iterator` trait reference. - /// - /// NOTE: This will drop the args for generic associated types - /// consider calling [Self::trait_ref_and_own_args] to get those - /// as well. - pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = self.trait_def_id(tcx); - ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id))) - } - - /// Extracts the underlying trait reference and own args from this projection. - /// For example, if this is a projection of `::Item<'a>`, - /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args - pub fn trait_ref_and_own_args( - self, - tcx: TyCtxt<'tcx>, - ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - let trait_def_id = self.trait_def_id(tcx); - let trait_generics = tcx.generics_of(trait_def_id); - ( - ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)), - &self.args[trait_generics.count()..], - ) - } - - pub fn to_term(self, tcx: TyCtxt<'tcx>) -> ty::Term<'tcx> { - match self.kind(tcx) { - ty::AliasTermKind::ProjectionTy => Ty::new_alias( - tcx, - ty::Projection, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::InherentTy => Ty::new_alias( - tcx, - ty::Inherent, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::OpaqueTy => Ty::new_alias( - tcx, - ty::Opaque, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::WeakTy => Ty::new_alias( - tcx, - ty::Weak, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst::new(self.def_id, self.args), - tcx.type_of(self.def_id).instantiate(tcx, self.args), - ) - .into() - } - } - } -} - -impl<'tcx> From> for AliasTerm<'tcx> { - fn from(ty: AliasTy<'tcx>) -> Self { - AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } - } -} - -impl<'tcx> From> for AliasTerm<'tcx> { - fn from(ct: ty::UnevaluatedConst<'tcx>) -> Self { - AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } - } -} - -/// Represents the projection of an associated, opaque, or lazy-type-alias type. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct AliasTy<'tcx> { - /// The parameters of the associated or opaque type. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: GenericArgsRef<'tcx>, - - /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether - /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if - /// this is an opaque. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the - /// underlying type if the type is an opaque. - /// - /// Note that if this is an associated type, this is not the `DefId` of the - /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`, - /// aka. `tcx.parent(def_id)`. - pub def_id: DefId, - - /// This field exists to prevent the creation of `AliasT` without using - /// [AliasTy::new]. - _use_alias_ty_new_instead: (), -} - -impl<'tcx> AliasTy<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: impl IntoIterator>>, - ) -> ty::AliasTy<'tcx> { - let args = tcx.check_and_mk_args(def_id, args); - ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () } - } - - pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTyKind { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy - if let DefKind::Impl { of_trait: false } = - tcx.def_kind(tcx.parent(self.def_id)) => - { - ty::Inherent - } - DefKind::AssocTy => ty::Projection, - DefKind::OpaqueTy => ty::Opaque, - DefKind::TyAlias => ty::Weak, - kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), - } - } - - /// Whether this alias type is an opaque. - pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool { - matches!(self.kind(tcx), ty::Opaque) - } - - pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - Ty::new_alias(tcx, self.kind(tcx), self) - } -} - -/// The following methods work only with (trait) associated type projections. -impl<'tcx> AliasTy<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.args.type_at(0) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1))) - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - kind => bug!("expected a projection AliasTy; found {kind:?}"), - } - } - - /// Extracts the underlying trait reference and own args from this projection. - /// For example, if this is a projection of `::Item<'a>`, - /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args - pub fn trait_ref_and_own_args( - self, - tcx: TyCtxt<'tcx>, - ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - let trait_def_id = self.trait_def_id(tcx); - let trait_generics = tcx.generics_of(trait_def_id); - ( - ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)), - &self.args[trait_generics.count()..], - ) - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `::Item`, - /// then this function would return a `T: Iterator` trait reference. - /// - /// WARNING: This will drop the args for generic associated types - /// consider calling [Self::trait_ref_and_own_args] to get those - /// as well. - pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = self.trait_def_id(tcx); - ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id))) - } -} - -/// The following methods work only with inherent associated type projections. -impl<'tcx> AliasTy<'tcx> { - /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. - /// - /// Does the following transformation: - /// - /// ```text - /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] - /// - /// I_i impl args - /// P_j GAT args - /// ``` - pub fn rebase_inherent_args_onto_impl( - self, - impl_args: ty::GenericArgsRef<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> ty::GenericArgsRef<'tcx> { - debug_assert_eq!(self.kind(tcx), ty::Inherent); - - tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1))) - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, @@ -2020,6 +1652,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } + + fn new_alias( + interner: TyCtxt<'tcx>, + kind: ty::AliasTyKind, + alias_ty: ty::AliasTy<'tcx>, + ) -> Self { + Ty::new_alias(interner, kind, alias_ty) + } + + fn into_term(self) -> ty::Term<'tcx> { + self.into() + } } /// Type utilities diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index c748cdf6ed278..af07e9ff96bf8 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -2,6 +2,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; @@ -86,6 +87,46 @@ impl DebugWithInfcx for ConstKind { } } +/// An unevaluated (potentially generic) constant used in the type-system. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct UnevaluatedConst { + pub def: I::DefId, + pub args: I::GenericArgs, +} + +impl UnevaluatedConst { + #[inline] + pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst { + UnevaluatedConst { def, args } + } +} + +impl fmt::Debug for UnevaluatedConst { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for UnevaluatedConst { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("UnevaluatedConst") + .field("def", &this.data.def) + .field("args", &this.wrap(this.data.args)) + .finish() + } +} + rustc_index::newtype_index! { /// A **`const`** **v**ariable **ID**. #[encodable] diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 5e98163643893..0a964801ce7f2 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -5,7 +5,8 @@ use std::ops::Deref; use crate::fold::TypeSuperFoldable; use crate::visit::{Flags, TypeSuperVisitable}; use crate::{ - BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex, + AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, + TyKind, UnevaluatedConst, UniverseIndex, }; pub trait Ty>: @@ -20,6 +21,10 @@ pub trait Ty>: + Flags { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy) -> Self; + + fn into_term(self) -> I::Term; } pub trait Region>: @@ -43,7 +48,11 @@ pub trait Const>: { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; + fn new_unevaluated(interner: I, uv: UnevaluatedConst, ty: I::Ty) -> Self; + fn ty(self) -> I::Ty; + + fn into_term(self) -> I::Term; } pub trait GenericsOf> { @@ -89,21 +98,3 @@ pub trait BoundVars { fn has_no_bound_vars(&self) -> bool; } - -pub trait AliasTerm: Copy + DebugWithInfcx + Hash + Eq + Sized { - fn new( - interner: I, - trait_def_id: I::DefId, - args: impl IntoIterator>, - ) -> Self; - - fn def_id(self) -> I::DefId; - - fn args(self) -> I::GenericArgs; - - fn trait_def_id(self, interner: I) -> I::DefId; - - fn self_ty(self) -> I::Ty; - - fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; -} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index af0e833b9e983..d6680977168ec 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -6,13 +6,16 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ - CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, - NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate, + DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate, + SubtypePredicate, TraitPredicate, TraitRef, }; pub trait Interner: Sized + Copy + + IrPrint> + + IrPrint> + IrPrint> + IrPrint> + IrPrint> @@ -27,6 +30,7 @@ pub trait Interner: type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; + type GenericArgsSlice: Copy + Debug + Hash + Eq; type GenericArg: Copy + DebugWithInfcx + Hash + Eq; type Term: Copy + Debug + Hash + Eq; @@ -39,7 +43,6 @@ pub trait Interner: // Kinds of tys type Ty: Ty; type Tys: Copy + Debug + Hash + Eq + IntoIterator; - type AliasTy: Copy + DebugWithInfcx + Hash + Eq + Sized; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq; type PlaceholderTy: PlaceholderLike; @@ -74,7 +77,6 @@ pub trait Interner: type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; type ProjectionPredicate: Copy + Debug + Hash + Eq; - type AliasTerm: AliasTerm; type NormalizesTo: Copy + Debug + Hash + Eq; type SubtypePredicate: Copy + Debug + Hash + Eq; type CoercePredicate: Copy + Debug + Hash + Eq; @@ -86,8 +88,23 @@ pub trait Interner: type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; + // FIXME: Remove after uplifting `EarlyBinder` + fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty; + + fn alias_ty_kind(self, alias: AliasTy) -> AliasTyKind; + + fn alias_term_kind(self, alias: AliasTerm) -> AliasTermKind; + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (TraitRef, Self::GenericArgsSlice); + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; + fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; + fn check_and_mk_args( self, def_id: Self::DefId, diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 5885139754afe..2a766d0bc09c9 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -1,8 +1,8 @@ use std::fmt; use crate::{ - CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo, - ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, + NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -43,6 +43,8 @@ define_display_via_print!( NormalizesTo, SubtypePredicate, CoercePredicate, + AliasTy, + AliasTerm, ); define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 71f198d2b8e84..1ec237d7cd555 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -6,7 +6,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::inherent::*; use crate::visit::TypeVisitableExt as _; -use crate::{DebugWithInfcx, Interner}; +use crate::{ + AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx, +}; /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: @@ -272,20 +274,20 @@ impl ExistentialProjection { /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait /// reference. - pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef { - let def_id = tcx.parent(self.def_id); - let args_count = tcx.generics_of(def_id).count() - 1; - let args = tcx.mk_args(&self.args[..args_count]); + pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef { + let def_id = interner.parent(self.def_id); + let args_count = interner.generics_of(def_id).count() - 1; + let args = interner.mk_args(&self.args[..args_count]); ExistentialTraitRef { def_id, args } } - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { + pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { // otherwise the escaping regions would be captured by the binders debug_assert!(!self_ty.has_escaping_bound_vars()); ProjectionPredicate { - projection_term: I::AliasTerm::new( - tcx, + projection_term: AliasTerm::new( + interner, self.def_id, [self_ty.into()].into_iter().chain(self.args), ), @@ -293,13 +295,13 @@ impl ExistentialProjection { } } - pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate) -> Self { + pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate) -> Self { // Assert there is a Self. - projection_predicate.projection_term.args().type_at(0); + projection_predicate.projection_term.args.type_at(0); Self { - def_id: projection_predicate.projection_term.def_id(), - args: tcx.mk_args(&projection_predicate.projection_term.args()[1..]), + def_id: projection_predicate.projection_term.def_id, + args: interner.mk_args(&projection_predicate.projection_term.args[1..]), term: projection_predicate.term, } } @@ -339,6 +341,190 @@ impl AliasTermKind { } } +/// Represents the unprojected term of a projection goal. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct AliasTerm { + /// The parameters of the associated or opaque item. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether + /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if + /// this is an opaque. + /// + /// During codegen, `interner.type_of(def_id)` can be used to get the type of the + /// underlying type if the type is an opaque. + /// + /// Note that if this is an associated type, this is not the `DefId` of the + /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`, + /// aka. `interner.parent(def_id)`. + pub def_id: I::DefId, + + /// This field exists to prevent the creation of `AliasTerm` without using + /// [AliasTerm::new]. + _use_alias_term_new_instead: (), +} + +impl std::fmt::Debug for AliasTerm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for AliasTerm { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + f.debug_struct("AliasTerm") + .field("args", &this.map(|data| data.args)) + .field("def_id", &this.data.def_id) + .finish() + } +} + +impl AliasTerm { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> AliasTerm { + let args = interner.check_and_mk_args(def_id, args); + AliasTerm { def_id, args, _use_alias_term_new_instead: () } + } + + pub fn expect_ty(self, interner: I) -> AliasTy { + match self.kind(interner) { + AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::WeakTy => {} + AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") + } + } + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } + } + + pub fn kind(self, interner: I) -> AliasTermKind { + interner.alias_term_kind(self) + } + + pub fn to_term(self, interner: I) -> I::Term { + match self.kind(interner) { + AliasTermKind::ProjectionTy => Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::InherentTy => Ty::new_alias( + interner, + AliasTyKind::Inherent, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::OpaqueTy => Ty::new_alias( + interner, + AliasTyKind::Opaque, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::WeakTy => Ty::new_alias( + interner, + AliasTyKind::Weak, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into_term(), + AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + I::Const::new_unevaluated( + interner, + UnevaluatedConst::new(self.def_id, self.args), + interner.type_of_instantiated(self.def_id, self.args), + ) + .into_term() + } + } + } +} + +/// The following methods work only with (trait) associated type projections. +impl AliasTerm { + pub fn self_ty(self) -> I::Ty { + self.args.type_at(0) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + AliasTerm::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + pub fn trait_def_id(self, interner: I) -> I::DefId { + assert!( + matches!( + self.kind(interner), + AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst + ), + "expected a projection" + ); + interner.parent(self.def_id) + } + + /// Extracts the underlying trait reference and own args from this projection. + /// For example, if this is a projection of `::Item<'a>`, + /// then this function would return a `T: StreamingIterator` trait reference and + /// `['a]` as the own args. + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { + interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) + } + + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the args for generic associated types + /// consider calling [Self::trait_ref_and_own_args] to get those + /// as well. + pub fn trait_ref(self, interner: I) -> TraitRef { + self.trait_ref_and_own_args(interner).0 + } +} + +impl From> for AliasTerm { + fn from(ty: AliasTy) -> Self { + AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } + } +} + +impl From> for AliasTerm { + fn from(ct: UnevaluatedConst) -> Self { + AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -362,7 +548,7 @@ impl AliasTermKind { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct ProjectionPredicate { - pub projection_term: I::AliasTerm, + pub projection_term: AliasTerm, pub term: I::Term, } @@ -371,16 +557,16 @@ impl ProjectionPredicate { self.projection_term.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { - Self { projection_term: self.projection_term.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { + Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self } } - pub fn trait_def_id(self, tcx: I) -> I::DefId { - self.projection_term.trait_def_id(tcx) + pub fn trait_def_id(self, interner: I) -> I::DefId { + self.projection_term.trait_def_id(interner) } pub fn def_id(self) -> I::DefId { - self.projection_term.def_id() + self.projection_term.def_id } } @@ -403,7 +589,7 @@ impl fmt::Debug for ProjectionPredicate { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct NormalizesTo { - pub alias: I::AliasTerm, + pub alias: AliasTerm, pub term: I::Term, } @@ -412,16 +598,16 @@ impl NormalizesTo { self.alias.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo { - Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo { + Self { alias: self.alias.with_self_ty(interner, self_ty), ..self } } - pub fn trait_def_id(self, tcx: I) -> I::DefId { - self.alias.trait_def_id(tcx) + pub fn trait_def_id(self, interner: I) -> I::DefId { + self.alias.trait_def_id(interner) } pub fn def_id(self) -> I::DefId { - self.alias.def_id() + self.alias.def_id } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 6e544d0e6ace4..672c890f94edb 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -4,11 +4,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; -use crate::Interner; -use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; +use crate::inherent::*; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx}; use self::TyKind::*; @@ -88,7 +88,7 @@ pub enum TyKind { /// for `struct List` and the args `[i32]`. /// /// Note that generic parameters in fields only get lazily instantiated - /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`. + /// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`. Adt(I::AdtDef, I::GenericArgs), /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. @@ -201,7 +201,7 @@ pub enum TyKind { /// A projection, opaque type, weak 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, I::AliasTy), + Alias(AliasTyKind, AliasTy), /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(I::ParamTy), @@ -422,6 +422,154 @@ impl fmt::Debug for TyKind { } } +/// Represents the projection of an associated, opaque, or lazy-type-alias type. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct AliasTy { + /// The parameters of the associated or opaque type. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether + /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if + /// this is an opaque. + /// + /// During codegen, `interner.type_of(def_id)` can be used to get the type of the + /// underlying type if the type is an opaque. + /// + /// Note that if this is an associated type, this is not the `DefId` of the + /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`, + /// aka. `interner.parent(def_id)`. + pub def_id: I::DefId, + + /// This field exists to prevent the creation of `AliasTy` without using + /// [AliasTy::new]. + pub(crate) _use_alias_ty_new_instead: (), +} + +impl AliasTy { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> AliasTy { + let args = interner.check_and_mk_args(def_id, args); + AliasTy { def_id, args, _use_alias_ty_new_instead: () } + } + + pub fn kind(self, interner: I) -> AliasTyKind { + interner.alias_ty_kind(self) + } + + /// Whether this alias type is an opaque. + pub fn is_opaque(self, interner: I) -> bool { + matches!(self.kind(interner), AliasTyKind::Opaque) + } + + pub fn to_ty(self, interner: I) -> I::Ty { + Ty::new_alias(interner, self.kind(interner), self) + } +} + +/// The following methods work only with (trait) associated type projections. +impl AliasTy { + pub fn self_ty(self) -> I::Ty { + self.args.type_at(0) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + AliasTy::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + pub fn trait_def_id(self, interner: I) -> I::DefId { + assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection"); + interner.parent(self.def_id) + } + + /// Extracts the underlying trait reference and own args from this projection. + /// For example, if this is a projection of `::Item<'a>`, + /// then this function would return a `T: StreamingIterator` trait reference and + /// `['a]` as the own args. + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { + debug_assert_eq!(self.kind(interner), AliasTyKind::Projection); + interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) + } + + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the args for generic associated types + /// consider calling [Self::trait_ref_and_own_args] to get those + /// as well. + pub fn trait_ref(self, interner: I) -> TraitRef { + self.trait_ref_and_own_args(interner).0 + } +} + +/// The following methods work only with inherent associated type projections. +impl AliasTy { + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. + /// + /// Does the following transformation: + /// + /// ```text + /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] + /// + /// I_i impl args + /// P_j GAT args + /// ``` + pub fn rebase_inherent_args_onto_impl( + self, + impl_args: I::GenericArgs, + interner: I, + ) -> I::GenericArgs { + debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent); + interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1))) + } +} + +impl fmt::Debug for AliasTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for AliasTy { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("AliasTy") + .field("args", &this.map(|data| data.args)) + .field("def_id", &this.data.def_id) + .finish() + } +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum IntTy {