diff options
23 files changed, 703 insertions, 667 deletions
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 4bf7dccab92..9614f4e80e1 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -118,6 +118,15 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> { } } +impl<I: rustc_type_ir::Interner, T> IntoDiagArg for rustc_type_ir::Binder<I, T> +where + T: IntoDiagArg, +{ + fn into_diag_arg(self) -> DiagArgValue { + self.skip_binder().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_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 00356ece585..168a370bba9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; use rustc_middle::bug; use rustc_middle::query::Key; -use rustc_middle::ty::print::PrintTraitRefExt as _; +use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, suggest_constraining_type_param}; use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt}; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 8caeb85204b..0cd77fe774f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -40,6 +40,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, TypeVisitableExt, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index c0effe9804c..07652b47929 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -115,18 +115,11 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Ty<'tcx> { } } -impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> - for ty::Binder<'tcx, ty::PredicateKind<'tcx>> -{ - fn encode(&self, e: &mut E) { - self.bound_vars().encode(e); - encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands); - } -} - impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> { fn encode(&self, e: &mut E) { - self.kind().encode(e); + let kind = self.kind(); + kind.bound_vars().encode(e); + encode_with_shorthand(e, &kind.skip_binder(), TyEncoder::predicate_shorthands); } } @@ -233,13 +226,11 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> { } } -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> - for ty::Binder<'tcx, ty::PredicateKind<'tcx>> -{ - fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> { +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> { + fn decode(decoder: &mut D) -> ty::Predicate<'tcx> { let bound_vars = Decodable::decode(decoder); // Handle shorthands first, if we have a usize > 0x80. - ty::Binder::bind_with_vars( + let predicate_kind = ty::Binder::bind_with_vars( if decoder.positioned_at_shorthand() { let pos = decoder.read_usize(); assert!(pos >= SHORTHAND_OFFSET); @@ -250,13 +241,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> <ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder) }, bound_vars, - ) - } -} - -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> { - fn decode(decoder: &mut D) -> ty::Predicate<'tcx> { - let predicate_kind = Decodable::decode(decoder); + ); decoder.interner().mk_predicate(predicate_kind) } } @@ -599,32 +584,3 @@ macro_rules! implement_ty_decoder { } } } - -macro_rules! impl_binder_encode_decode { - ($($t:ty),+ $(,)?) => { - $( - impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Binder<'tcx, $t> { - fn encode(&self, e: &mut E) { - self.bound_vars().encode(e); - self.as_ref().skip_binder().encode(e); - } - } - impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Binder<'tcx, $t> { - fn decode(decoder: &mut D) -> Self { - let bound_vars = Decodable::decode(decoder); - ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars) - } - } - )* - } -} - -impl_binder_encode_decode! { - &'tcx ty::List<Ty<'tcx>>, - ty::FnSig<'tcx>, - ty::Predicate<'tcx>, - ty::TraitPredicate<'tcx>, - ty::ExistentialPredicate<'tcx>, - ty::TraitRef<'tcx>, - ty::ExistentialTraitRef<'tcx>, -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8185c99c2fd..a457319c5f8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -31,8 +31,7 @@ use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, - Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, - Visibility, + Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -96,9 +95,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; - type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>; - type BoundVars = &'tcx List<ty::BoundVariableKind>; - type BoundVar = ty::BoundVariableKind; + type BoundVarKinds = &'tcx List<ty::BoundVariableKind>; + type BoundVarKind = ty::BoundVariableKind; type CanonicalVars = CanonicalVarInfos<'tcx>; type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; @@ -138,6 +136,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; + type Clause = Clause<'tcx>; type TraitPredicate = ty::TraitPredicate<'tcx>; type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>; @@ -245,6 +244,10 @@ impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi { } impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety { + fn is_safe(self) -> bool { + matches!(self, hir::Safety::Safe) + } + fn prefix_str(self) -> &'static str { self.prefix_str() } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 3d263e62de6..cb11bb3ef16 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -51,6 +51,14 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> { GenericArgs::identity_for_item(tcx, def_id) } + + fn extend_with_error( + tcx: TyCtxt<'tcx>, + def_id: DefId, + original_args: &[ty::GenericArg<'tcx>], + ) -> ty::GenericArgsRef<'tcx> { + ty::GenericArgs::extend_with_error(tcx, def_id, original_args) + } } impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index be91249a25f..067d490078d 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -8,8 +8,8 @@ use rustc_type_ir as ir; use std::cmp::Ordering; use crate::ty::{ - self, Binder, DebruijnIndex, EarlyBinder, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags, - Upcast, UpcastFrom, WithCachedTypeInfo, + self, DebruijnIndex, EarlyBinder, PredicatePolarity, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom, + WithCachedTypeInfo, }; pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>; @@ -155,6 +155,8 @@ pub struct Clause<'tcx>( pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, ); +impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {} + impl<'tcx> Clause<'tcx> { pub fn as_predicate(self) -> Predicate<'tcx> { Predicate(self.0) @@ -231,34 +233,6 @@ impl<'tcx> ExistentialPredicate<'tcx> { pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>; -impl<'tcx> PolyExistentialPredicate<'tcx> { - /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`), - /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` - /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example). - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> { - match self.skip_binder() { - ExistentialPredicate::Trait(tr) => { - self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx) - } - ExistentialPredicate::Projection(p) => { - self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx) - } - ExistentialPredicate::AutoTrait(did) => { - let generics = tcx.generics_of(did); - let trait_ref = if generics.own_params.len() == 1 { - ty::TraitRef::new(tcx, did, [self_ty]) - } else { - // If this is an ill-formed auto trait, then synthesize - // new error args for the missing generics. - let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]); - ty::TraitRef::new(tcx, did, err_args) - }; - self.rebind(trait_ref).upcast(tcx) - } - } - } -} - impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> { /// Returns the "principal `DefId`" of this set of existential predicates. /// @@ -322,49 +296,9 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> { } pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>; - -impl<'tcx> PolyTraitRef<'tcx> { - pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> { - self.map_bound_ref(|tr| tr.self_ty()) - } - - pub fn def_id(&self) -> DefId { - self.skip_binder().def_id - } -} - pub type PolyExistentialTraitRef<'tcx> = ty::Binder<'tcx, ExistentialTraitRef<'tcx>>; - -impl<'tcx> PolyExistentialTraitRef<'tcx> { - pub fn def_id(&self) -> DefId { - self.skip_binder().def_id - } - - /// Object types don't have a self type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self type. A common choice is `mk_err()` - /// or some placeholder type. - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> { - self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) - } -} - pub type PolyExistentialProjection<'tcx> = ty::Binder<'tcx, ExistentialProjection<'tcx>>; -impl<'tcx> PolyExistentialProjection<'tcx> { - pub fn with_self_ty( - &self, - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - ) -> ty::PolyProjectionPredicate<'tcx> { - self.map_bound(|p| p.with_self_ty(tcx, self_ty)) - } - - pub fn item_def_id(&self) -> DefId { - self.skip_binder().def_id - } -} - impl<'tcx> Clause<'tcx> { /// Performs a instantiation suitable for going from a /// poly-trait-ref to supertraits that must hold if that @@ -473,22 +407,6 @@ impl<'tcx> Clause<'tcx> { pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; -impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(self) -> DefId { - // Ok to skip binder since trait `DefId` does not care about regions. - self.skip_binder().def_id() - } - - pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> { - self.map_bound(|trait_ref| trait_ref.self_ty()) - } - - #[inline] - pub fn polarity(self) -> PredicatePolarity { - self.skip_binder().polarity - } -} - /// `A: B` #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -497,47 +415,10 @@ pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty: pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; - pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; - pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; - pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>; -impl<'tcx> PolyProjectionPredicate<'tcx> { - /// Returns the `DefId` of the trait of the associated item being projected. - #[inline] - pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { - self.skip_binder().projection_term.trait_def_id(tcx) - } - - /// Get the [PolyTraitRef] required for this projection to be well formed. - /// Note that for generic associated types the predicates of the associated - /// type also need to be checked. - #[inline] - pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { - // Note: unlike with `TraitRef::to_poly_trait_ref()`, - // `self.0.trait_ref` is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx)) - } - - pub fn term(&self) -> Binder<'tcx, Term<'tcx>> { - self.map_bound(|predicate| predicate.term) - } - - /// The `DefId` of the `TraitItem` for the associated type. - /// - /// Note that this is not the `DefId` of the `TraitRef` containing this - /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. - pub fn projection_def_id(&self) -> DefId { - // Ok to skip binder since trait `DefId` does not care about regions. - self.skip_binder().projection_term.def_id - } -} - pub trait ToPolyTraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } @@ -554,8 +435,8 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> { - fn upcast_from(from: Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> { + fn upcast_from(from: ty::Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { tcx.mk_predicate(from) } } @@ -566,8 +447,8 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> { - fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> { + fn upcast_from(from: ty::Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { tcx.mk_predicate(from.map_bound(PredicateKind::Clause)) } } @@ -580,12 +461,12 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Clause<'tcx>> for Predicate<'tcx> { impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Clause<'tcx> { fn upcast_from(from: ClauseKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self { - tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(from))).expect_clause() + tcx.mk_predicate(ty::Binder::dummy(PredicateKind::Clause(from))).expect_clause() } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> { - fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> { + fn upcast_from(from: ty::Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { tcx.mk_predicate(from.map_bound(|clause| PredicateKind::Clause(clause))).expect_clause() } } @@ -609,22 +490,22 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> { } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> { - fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> { + fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx); pred.upcast(tcx) } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> { - fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> { + fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx); pred.upcast(tcx) } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> { - fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> { + fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self { from.map_bound(|trait_ref| TraitPredicate { trait_ref, polarity: PredicatePolarity::Positive, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0dbb17e9db4..f0bd071e451 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2934,12 +2934,13 @@ impl<'tcx> ty::TraitRef<'tcx> { } } +#[extension(pub trait PrintPolyTraitRefExt<'tcx>)] impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { - pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { + fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { self.map_bound(|tr| tr.print_only_trait_path()) } - pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> { + fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> { self.map_bound(|tr| tr.print_trait_sugared()) } } @@ -2960,8 +2961,9 @@ impl<'tcx> ty::TraitPredicate<'tcx> { } } +#[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)] impl<'tcx> ty::PolyTraitPredicate<'tcx> { - pub fn print_modifiers_and_trait_path( + fn print_modifiers_and_trait_path( self, ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> { self.map_bound(TraitPredPrintModifiersAndPath) @@ -3016,17 +3018,6 @@ forward_display_to_print! { &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, ty::Const<'tcx>, - // HACK(eddyb) these are exhaustive instead of generic, - // because `for<'tcx>` isn't possible yet. - ty::PolyExistentialProjection<'tcx>, - ty::PolyExistentialTraitRef<'tcx>, - ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>, - ty::Binder<'tcx, ty::FnSig<'tcx>>, - ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, - ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 551e2ea2295..d7da37385e1 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -384,6 +384,10 @@ impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion { fn var(self) -> BoundVar { self.var } + + fn assert_eq(self, var: ty::BoundVariableKind) { + assert_eq!(self.kind, var.expect_region()) + } } impl core::fmt::Debug for BoundRegion { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 81d92a2a448..af3aa3b56f7 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -387,38 +387,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> { } } -impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - folder.try_fold_binder(self) - } -} - -impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { - fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { - visitor.visit_binder(self) - } -} - -impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { - fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - self.try_map_bound(|ty| ty.try_fold_with(folder)) - } -} - -impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeSuperVisitable<TyCtxt<'tcx>> - for ty::Binder<'tcx, T> -{ - fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { - self.as_ref().skip_binder().visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2d9d178449e..fc9a854c853 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -3,17 +3,16 @@ #![allow(rustc::usage_of_ty_tykind)] use crate::infer::canonical::Canonical; -use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; use crate::ty::{ self, AdtDef, BoundRegionKind, Discr, Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + TypeVisitable, TypeVisitor, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use crate::ty::{List, ParamEnv}; use hir::def::{CtorKind, DefKind}; use rustc_data_structures::captures::Captures; -use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan}; +use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; @@ -21,11 +20,11 @@ use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; -use rustc_target::spec::abi::{self, Abi}; +use rustc_target::spec::abi; use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; -use std::ops::{ControlFlow, Deref, Range}; +use std::ops::{ControlFlow, Range}; use ty::util::IntTypeExt; use rustc_type_ir::TyKind::*; @@ -40,6 +39,7 @@ pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>; pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>; pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>; pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>; +pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>; pub trait Article { fn article(&self) -> &'static str; @@ -373,7 +373,7 @@ impl<'tcx> CoroutineClosureArgs<'tcx> { self.split().signature_parts_ty } - pub fn coroutine_closure_sig(self) -> ty::Binder<'tcx, CoroutineClosureSignature<'tcx>> { + pub fn coroutine_closure_sig(self) -> Binder<'tcx, CoroutineClosureSignature<'tcx>> { let interior = self.coroutine_witness_ty(); let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() }; sig.map_bound(|sig| { @@ -898,203 +898,6 @@ impl BoundVariableKind { } } -/// Binder is a binder for higher-ranked lifetimes or types. It is part of the -/// compiler's representation for things like `for<'a> Fn(&'a isize)` -/// (which would be represented by the type `PolyTraitRef == -/// Binder<'tcx, TraitRef>`). Note that when we instantiate, -/// erase, or otherwise "discharge" these bound vars, we change the -/// type from `Binder<'tcx, T>` to just `T` (see -/// e.g., `liberate_late_bound_regions`). -/// -/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[derive(HashStable, Lift)] -pub struct Binder<'tcx, T> { - value: T, - bound_vars: &'tcx List<BoundVariableKind>, -} - -impl<'tcx, T> Binder<'tcx, T> -where - T: TypeVisitable<TyCtxt<'tcx>>, -{ - /// Wraps `value` in a binder, asserting that `value` does not - /// contain any bound vars that would be bound by the - /// binder. This is commonly used to 'inject' a value T into a - /// different binding level. - #[track_caller] - pub fn dummy(value: T) -> Binder<'tcx, T> { - assert!( - !value.has_escaping_bound_vars(), - "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder." - ); - Binder { value, bound_vars: ty::List::empty() } - } - - pub fn bind_with_vars(value: T, bound_vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> { - if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(bound_vars); - value.visit_with(&mut validator); - } - Binder { value, bound_vars } - } -} - -impl<'tcx, T> rustc_type_ir::inherent::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { - fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> { - self.bound_vars - } - - fn has_no_bound_vars(&self) -> bool { - self.bound_vars.is_empty() - } -} - -impl<'tcx, T> Binder<'tcx, T> { - /// Skips the binder and returns the "bound" value. This is a - /// risky thing to do because it's easy to get confused about - /// De Bruijn indices and the like. It is usually better to - /// discharge the binder using `no_bound_vars` or - /// `instantiate_bound_regions` or something like - /// that. `skip_binder` is only valid when you are either - /// extracting data that has nothing to do with bound vars, you - /// are doing some sort of test that does not involve bound - /// regions, or you are being very careful about your depth - /// accounting. - /// - /// Some examples where `skip_binder` is reasonable: - /// - /// - extracting the `DefId` from a PolyTraitRef; - /// - comparing the self type of a PolyTraitRef to see if it is equal to - /// a type parameter `X`, since the type `X` does not reference any regions - pub fn skip_binder(self) -> T { - self.value - } - - pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> { - self.bound_vars - } - - pub fn as_ref(&self) -> Binder<'tcx, &T> { - Binder { value: &self.value, bound_vars: self.bound_vars } - } - - pub fn as_deref(&self) -> Binder<'tcx, &T::Target> - where - T: Deref, - { - Binder { value: &self.value, bound_vars: self.bound_vars } - } - - pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U> - where - F: FnOnce(&T) -> U, - { - self.as_ref().map_bound(f) - } - - pub fn map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>>(self, f: F) -> Binder<'tcx, U> - where - F: FnOnce(T) -> U, - { - let Binder { value, bound_vars } = self; - let value = f(value); - if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(bound_vars); - value.visit_with(&mut validator); - } - Binder { value, bound_vars } - } - - pub fn try_map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>, E>( - self, - f: F, - ) -> Result<Binder<'tcx, U>, E> - where - F: FnOnce(T) -> Result<U, E>, - { - let Binder { value, bound_vars } = self; - let value = f(value)?; - if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(bound_vars); - value.visit_with(&mut validator); - } - Ok(Binder { value, bound_vars }) - } - - /// Wraps a `value` in a binder, using the same bound variables as the - /// current `Binder`. This should not be used if the new value *changes* - /// the bound variables. Note: the (old or new) value itself does not - /// necessarily need to *name* all the bound variables. - /// - /// This currently doesn't do anything different than `bind`, because we - /// don't actually track bound vars. However, semantically, it is different - /// because bound vars aren't allowed to change here, whereas they are - /// in `bind`. This may be (debug) asserted in the future. - pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U> - where - U: TypeVisitable<TyCtxt<'tcx>>, - { - Binder::bind_with_vars(value, self.bound_vars) - } - - /// Unwraps and returns the value within, but only if it contains - /// no bound vars at all. (In other words, if this binder -- - /// and indeed any enclosing binder -- doesn't bind anything at - /// all.) Otherwise, returns `None`. - /// - /// (One could imagine having a method that just unwraps a single - /// binder, but permits late-bound vars bound by enclosing - /// binders, but that would require adjusting the debruijn - /// indices, and given the shallow binding structure we often use, - /// would not be that useful.) - pub fn no_bound_vars(self) -> Option<T> - where - T: TypeVisitable<TyCtxt<'tcx>>, - { - // `self.value` is equivalent to `self.skip_binder()` - if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } - } - - /// Splits the contents into two things that share the same binder - /// level as the original, returning two distinct binders. - /// - /// `f` should consider bound regions at depth 1 to be free, and - /// anything it produces with bound regions at depth 1 will be - /// bound in the resulting return values. - pub fn split<U, V, F>(self, f: F) -> (Binder<'tcx, U>, Binder<'tcx, V>) - where - F: FnOnce(T) -> (U, V), - { - let Binder { value, bound_vars } = self; - let (u, v) = f(value); - (Binder { value: u, bound_vars }, Binder { value: v, bound_vars }) - } -} - -impl<'tcx, T> Binder<'tcx, Option<T>> { - pub fn transpose(self) -> Option<Binder<'tcx, T>> { - let Binder { value, bound_vars } = self; - value.map(|value| Binder { value, bound_vars }) - } -} - -impl<'tcx, T: IntoIterator> Binder<'tcx, T> { - pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> { - let Binder { value, bound_vars } = self; - value.into_iter().map(|value| Binder { value, bound_vars }) - } -} - -impl<'tcx, T> IntoDiagArg for Binder<'tcx, T> -where - T: IntoDiagArg, -{ - fn into_diag_arg(self) -> DiagArgValue { - self.value.into_diag_arg() - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, @@ -1103,48 +906,6 @@ pub struct GenSig<'tcx> { } pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; - -impl<'tcx> PolyFnSig<'tcx> { - #[inline] - pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> { - self.map_bound_ref(|fn_sig| fn_sig.inputs()) - } - - #[inline] - #[track_caller] - pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) - } - - pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output) - } - - #[inline] - pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> { - self.map_bound_ref(|fn_sig| fn_sig.output()) - } - - pub fn c_variadic(&self) -> bool { - self.skip_binder().c_variadic - } - - pub fn safety(&self) -> hir::Safety { - self.skip_binder().safety - } - - pub fn abi(&self) -> abi::Abi { - self.skip_binder().abi - } - - pub fn is_fn_trait_compatible(&self) -> bool { - matches!( - self.skip_binder(), - ty::FnSig { safety: rustc_hir::Safety::Safe, abi: Abi::Rust, c_variadic: false, .. } - ) - } -} - pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] @@ -1203,6 +964,10 @@ impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundTy { fn var(self) -> BoundVar { self.var } + + fn assert_eq(self, var: ty::BoundVariableKind) { + assert_eq!(self.kind, var.expect_ty()) + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] @@ -2001,7 +1766,7 @@ impl<'tcx> Ty<'tcx> { FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) - ty::Binder::dummy(ty::FnSig { + Binder::dummy(ty::FnSig { inputs_and_output: ty::List::empty(), c_variadic: false, safety: hir::Safety::Safe, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 218567bbd59..b1bbfd420e1 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,7 +1,6 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sso::SsoHashSet; use rustc_type_ir::fold::TypeFoldable; use std::ops::ControlFlow; @@ -145,103 +144,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -pub struct ValidateBoundVars<'tcx> { - bound_vars: &'tcx ty::List<ty::BoundVariableKind>, - binder_index: ty::DebruijnIndex, - // We may encounter the same variable at different levels of binding, so - // this can't just be `Ty` - visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, -} - -impl<'tcx> ValidateBoundVars<'tcx> { - pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self { - ValidateBoundVars { - bound_vars, - binder_index: ty::INNERMOST, - visited: SsoHashSet::default(), - } - } -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> { - type Result = ControlFlow<()>; - - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> Self::Result { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - if t.outer_exclusive_binder() < self.binder_index - || !self.visited.insert((self.binder_index, t)) - { - return ControlFlow::Break(()); - } - match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - if self.bound_vars.len() <= bound_ty.var.as_usize() { - bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); - } - let list_var = self.bound_vars[bound_ty.var.as_usize()]; - match list_var { - ty::BoundVariableKind::Ty(kind) => { - if kind != bound_ty.kind { - bug!( - "Mismatched type kinds: {:?} doesn't var in list {:?}", - bound_ty.kind, - list_var - ); - } - } - _ => { - bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var) - } - } - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { - match *r { - ty::ReBound(index, br) if index == self.binder_index => { - if self.bound_vars.len() <= br.var.as_usize() { - bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars); - } - let list_var = self.bound_vars[br.var.as_usize()]; - match list_var { - ty::BoundVariableKind::Region(kind) => { - if kind != br.kind { - bug!( - "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})", - br.kind, - list_var, - self.bound_vars - ); - } - } - _ => bug!( - "Mismatched bound variable kinds! Expected region, found {:?}", - list_var - ), - } - } - - _ => (), - }; - - ControlFlow::Continue(()) - } -} - /// Collects all the late-bound regions at the innermost binding level /// into a hash set. struct LateBoundRegionsCollector { diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 696639e9c1b..127ebde5fec 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -217,10 +217,9 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> self.infcx.interner() } - fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> where T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, { self.binder_index.shift_in(1); let t = t.super_fold_with(self); @@ -455,10 +454,9 @@ impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> { self.interner } - fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> where T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, { self.binder.shift_in(1); let t = t.super_fold_with(self); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index f9b6b281f92..6c56ebb62ae 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -47,7 +47,8 @@ use crate::infer::InferCtxtExt as _; use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_middle::ty::print::{ - with_forced_trimmed_paths, with_no_trimmed_paths, PrintTraitPredicateExt as _, + with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _, + PrintTraitPredicateExt as _, }; use itertools::EitherOrBoth; diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs new file mode 100644 index 00000000000..5336b915a1d --- /dev/null +++ b/compiler/rustc_type_ir/src/binder.rs @@ -0,0 +1,340 @@ +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::{ControlFlow, Deref}; + +#[cfg(feature = "nightly")] +use rustc_macros::HashStable_NoContext; +use rustc_serialize::Decodable; + +use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; +use crate::inherent::*; +use crate::lift::Lift; +use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +use crate::{self as ty, Interner, SsoHashSet}; + +/// Binder is a binder for higher-ranked lifetimes or types. It is part of the +/// compiler's representation for things like `for<'a> Fn(&'a isize)` +/// (which would be represented by the type `PolyTraitRef == +/// Binder<I, TraitRef>`). Note that when we instantiate, +/// erase, or otherwise "discharge" these bound vars, we change the +/// type from `Binder<I, T>` to just `T` (see +/// e.g., `liberate_late_bound_regions`). +/// +/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "T: Clone"), + Copy(bound = "T: Copy"), + Hash(bound = "T: Hash"), + PartialEq(bound = "T: PartialEq"), + Eq(bound = "T: Eq"), + Debug(bound = "T: Debug") +)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct Binder<I: Interner, T> { + value: T, + bound_vars: I::BoundVarKinds, +} + +// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't +// understand how to turn `T` to `T::Lifted` in the output `type Lifted`. +impl<I: Interner, U: Interner, T> Lift<U> for Binder<I, T> +where + T: Lift<U>, + I::BoundVarKinds: Lift<U, Lifted = U::BoundVarKinds>, +{ + type Lifted = Binder<U, T::Lifted>; + + fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> { + Some(Binder { + value: self.value.lift_to_tcx(tcx)?, + bound_vars: self.bound_vars.lift_to_tcx(tcx)?, + }) + } +} + +macro_rules! impl_binder_encode_decode { + ($($t:ty),+ $(,)?) => { + $( + impl<I: Interner, E: crate::TyEncoder<I = I>> rustc_serialize::Encodable<E> for ty::Binder<I, $t> + where + $t: rustc_serialize::Encodable<E>, + I::BoundVarKinds: rustc_serialize::Encodable<E>, + { + fn encode(&self, e: &mut E) { + self.bound_vars().encode(e); + self.as_ref().skip_binder().encode(e); + } + } + impl<I: Interner, D: crate::TyDecoder<I = I>> Decodable<D> for ty::Binder<I, $t> + where + $t: TypeVisitable<I> + rustc_serialize::Decodable<D>, + I::BoundVarKinds: rustc_serialize::Decodable<D>, + { + fn decode(decoder: &mut D) -> Self { + let bound_vars = Decodable::decode(decoder); + ty::Binder::bind_with_vars(<$t>::decode(decoder), bound_vars) + } + } + )* + } +} + +impl_binder_encode_decode! { + ty::FnSig<I>, + ty::TraitPredicate<I>, + ty::ExistentialPredicate<I>, + ty::TraitRef<I>, + ty::ExistentialTraitRef<I>, +} + +impl<I: Interner, T> Binder<I, T> +where + T: TypeVisitable<I>, +{ + /// Wraps `value` in a binder, asserting that `value` does not + /// contain any bound vars that would be bound by the + /// binder. This is commonly used to 'inject' a value T into a + /// different binding level. + #[track_caller] + pub fn dummy(value: T) -> Binder<I, T> { + assert!( + !value.has_escaping_bound_vars(), + "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder." + ); + Binder { value, bound_vars: Default::default() } + } + + pub fn bind_with_vars(value: T, bound_vars: I::BoundVarKinds) -> Binder<I, T> { + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(bound_vars); + value.visit_with(&mut validator); + } + Binder { value, bound_vars } + } +} + +impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Binder<I, T> { + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + folder.try_fold_binder(self) + } +} + +impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { + visitor.visit_binder(self) + } +} + +impl<I: Interner, T: TypeFoldable<I>> TypeSuperFoldable<I> for Binder<I, T> { + fn try_super_fold_with<F: FallibleTypeFolder<I>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + self.try_map_bound(|ty| ty.try_fold_with(folder)) + } +} + +impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> { + fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { + self.as_ref().skip_binder().visit_with(visitor) + } +} + +impl<I: Interner, T> Binder<I, T> { + /// Skips the binder and returns the "bound" value. This is a + /// risky thing to do because it's easy to get confused about + /// De Bruijn indices and the like. It is usually better to + /// discharge the binder using `no_bound_vars` or + /// `instantiate_bound_regions` or something like + /// that. `skip_binder` is only valid when you are either + /// extracting data that has nothing to do with bound vars, you + /// are doing some sort of test that does not involve bound + /// regions, or you are being very careful about your depth + /// accounting. + /// + /// Some examples where `skip_binder` is reasonable: + /// + /// - extracting the `DefId` from a PolyTraitRef; + /// - comparing the self type of a PolyTraitRef to see if it is equal to + /// a type parameter `X`, since the type `X` does not reference any regions + pub fn skip_binder(self) -> T { + self.value + } + + pub fn bound_vars(&self) -> I::BoundVarKinds { + self.bound_vars + } + + pub fn as_ref(&self) -> Binder<I, &T> { + Binder { value: &self.value, bound_vars: self.bound_vars } + } + + pub fn as_deref(&self) -> Binder<I, &T::Target> + where + T: Deref, + { + Binder { value: &self.value, bound_vars: self.bound_vars } + } + + pub fn map_bound_ref<F, U: TypeVisitable<I>>(&self, f: F) -> Binder<I, U> + where + F: FnOnce(&T) -> U, + { + self.as_ref().map_bound(f) + } + + pub fn map_bound<F, U: TypeVisitable<I>>(self, f: F) -> Binder<I, U> + where + F: FnOnce(T) -> U, + { + let Binder { value, bound_vars } = self; + let value = f(value); + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(bound_vars); + value.visit_with(&mut validator); + } + Binder { value, bound_vars } + } + + pub fn try_map_bound<F, U: TypeVisitable<I>, E>(self, f: F) -> Result<Binder<I, U>, E> + where + F: FnOnce(T) -> Result<U, E>, + { + let Binder { value, bound_vars } = self; + let value = f(value)?; + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(bound_vars); + value.visit_with(&mut validator); + } + Ok(Binder { value, bound_vars }) + } + + /// Wraps a `value` in a binder, using the same bound variables as the + /// current `Binder`. This should not be used if the new value *changes* + /// the bound variables. Note: the (old or new) value itself does not + /// necessarily need to *name* all the bound variables. + /// + /// This currently doesn't do anything different than `bind`, because we + /// don't actually track bound vars. However, semantically, it is different + /// because bound vars aren't allowed to change here, whereas they are + /// in `bind`. This may be (debug) asserted in the future. + pub fn rebind<U>(&self, value: U) -> Binder<I, U> + where + U: TypeVisitable<I>, + { + Binder::bind_with_vars(value, self.bound_vars) + } + + /// Unwraps and returns the value within, but only if it contains + /// no bound vars at all. (In other words, if this binder -- + /// and indeed any enclosing binder -- doesn't bind anything at + /// all.) Otherwise, returns `None`. + /// + /// (One could imagine having a method that just unwraps a single + /// binder, but permits late-bound vars bound by enclosing + /// binders, but that would require adjusting the debruijn + /// indices, and given the shallow binding structure we often use, + /// would not be that useful.) + pub fn no_bound_vars(self) -> Option<T> + where + T: TypeVisitable<I>, + { + // `self.value` is equivalent to `self.skip_binder()` + if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } + } + + /// Splits the contents into two things that share the same binder + /// level as the original, returning two distinct binders. + /// + /// `f` should consider bound regions at depth 1 to be free, and + /// anything it produces with bound regions at depth 1 will be + /// bound in the resulting return values. + pub fn split<U, V, F>(self, f: F) -> (Binder<I, U>, Binder<I, V>) + where + F: FnOnce(T) -> (U, V), + { + let Binder { value, bound_vars } = self; + let (u, v) = f(value); + (Binder { value: u, bound_vars }, Binder { value: v, bound_vars }) + } +} + +impl<I: Interner, T> Binder<I, Option<T>> { + pub fn transpose(self) -> Option<Binder<I, T>> { + let Binder { value, bound_vars } = self; + value.map(|value| Binder { value, bound_vars }) + } +} + +impl<I: Interner, T: IntoIterator> Binder<I, T> { + pub fn iter(self) -> impl Iterator<Item = Binder<I, T::Item>> { + let Binder { value, bound_vars } = self; + value.into_iter().map(move |value| Binder { value, bound_vars }) + } +} + +pub struct ValidateBoundVars<I: Interner> { + bound_vars: I::BoundVarKinds, + binder_index: ty::DebruijnIndex, + // We may encounter the same variable at different levels of binding, so + // this can't just be `Ty` + visited: SsoHashSet<(ty::DebruijnIndex, I::Ty)>, +} + +impl<I: Interner> ValidateBoundVars<I> { + pub fn new(bound_vars: I::BoundVarKinds) -> Self { + ValidateBoundVars { + bound_vars, + binder_index: ty::INNERMOST, + visited: SsoHashSet::default(), + } + } +} + +impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { + type Result = ControlFlow<()>; + + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result { + self.binder_index.shift_in(1); + let result = t.super_visit_with(self); + self.binder_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + if t.outer_exclusive_binder() < self.binder_index + || !self.visited.insert((self.binder_index, t)) + { + return ControlFlow::Break(()); + } + match t.kind() { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + let idx = bound_ty.var().as_usize(); + if self.bound_vars.len() <= idx { + panic!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); + } + bound_ty.assert_eq(self.bound_vars[idx]); + } + _ => {} + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: I::Region) -> Self::Result { + match r.kind() { + ty::ReBound(index, br) if index == self.binder_index => { + let idx = br.var().as_usize(); + if self.bound_vars.len() <= idx { + panic!("Not enough bound vars: {:?} not found in {:?}", r, self.bound_vars); + } + br.assert_eq(self.bound_vars[idx]); + } + + _ => (), + }; + + ControlFlow::Continue(()) + } +} diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 01bb3d73dbd..405aba30241 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -48,8 +48,8 @@ use rustc_index::{Idx, IndexVec}; use std::mem; -use crate::Lrc; -use crate::{visit::TypeVisitable, Interner}; +use crate::visit::TypeVisitable; +use crate::{self as ty, Interner, Lrc}; #[cfg(feature = "nightly")] type Never = !; @@ -128,10 +128,9 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> { pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> { fn interner(&self) -> I; - fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> where T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, { t.super_fold_with(self) } @@ -167,10 +166,9 @@ pub trait FallibleTypeFolder<I: Interner>: Sized { fn interner(&self) -> I; - fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error> + fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Self::Error> where T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, { t.try_super_fold_with(self) } @@ -206,10 +204,9 @@ where TypeFolder::interner(self) } - fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Never> + fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Never> where T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, { Ok(self.fold_binder(t)) } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f66c6e722f7..77fe30a4660 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -8,11 +8,8 @@ use std::hash::Hash; use std::ops::Deref; use crate::fold::{TypeFoldable, TypeSuperFoldable}; -use crate::visit::{Flags, TypeSuperVisitable}; -use crate::{ - AliasTy, AliasTyKind, BoundVar, ConstKind, ConstVid, DebruijnIndex, DebugWithInfcx, InferConst, - InferTy, Interner, RegionKind, TyKind, TyVid, UnevaluatedConst, UniverseIndex, -}; +use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; +use crate::{self as ty, DebugWithInfcx, Interner, UpcastFrom}; pub trait Ty<I: Interner<Ty = Self>>: Copy @@ -21,24 +18,30 @@ pub trait Ty<I: Interner<Ty = Self>>: + Eq + Into<I::GenericArg> + Into<I::Term> - + IntoKind<Kind = TyKind<I>> + + IntoKind<Kind = ty::TyKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags { fn new_bool(interner: I) -> Self; - fn new_infer(interner: I, var: InferTy) -> Self; + fn new_infer(interner: I, var: ty::InferTy) -> Self; - fn new_var(interner: I, var: TyVid) -> Self; + fn new_var(interner: I, var: ty::TyVid) -> Self; - fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; - fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self; + fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self; } pub trait Tys<I: Interner<Tys = Self>>: - Copy + Debug + Hash + Eq + IntoIterator<Item = I::Ty> + Deref<Target: Deref<Target = [I::Ty]>> + Copy + + Debug + + Hash + + Eq + + IntoIterator<Item = I::Ty> + + Deref<Target: Deref<Target = [I::Ty]>> + + TypeVisitable<I> { fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); } @@ -49,13 +52,21 @@ pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq { } pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq { + fn is_safe(self) -> bool; + fn prefix_str(self) -> &'static str; } pub trait Region<I: Interner<Region = Self>>: - Copy + DebugWithInfcx<I> + Hash + Eq + Into<I::GenericArg> + IntoKind<Kind = RegionKind<I>> + Flags + Copy + + DebugWithInfcx<I> + + Hash + + Eq + + Into<I::GenericArg> + + IntoKind<Kind = ty::RegionKind<I>> + + Flags { - fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_static(interner: I) -> Self; } @@ -67,18 +78,23 @@ pub trait Const<I: Interner<Const = Self>>: + Eq + Into<I::GenericArg> + Into<I::Term> - + IntoKind<Kind = ConstKind<I>> + + IntoKind<Kind = ty::ConstKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags { - fn new_infer(interner: I, var: InferConst, ty: I::Ty) -> Self; + fn new_infer(interner: I, var: ty::InferConst, ty: I::Ty) -> Self; - fn new_var(interner: I, var: ConstVid, ty: I::Ty) -> Self; + fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self; - fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; + fn new_anon_bound( + interner: I, + debruijn: ty::DebruijnIndex, + var: ty::BoundVar, + ty: I::Ty, + ) -> Self; - fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self; + fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>, ty: I::Ty) -> Self; fn ty(self) -> I::Ty; } @@ -100,6 +116,12 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>: fn type_at(self, i: usize) -> I::Ty; fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; + + fn extend_with_error( + tcx: I, + def_id: I::DefId, + original_args: &[I::GenericArg], + ) -> I::GenericArgs; } pub trait Predicate<I: Interner<Predicate = Self>>: @@ -108,14 +130,25 @@ pub trait Predicate<I: Interner<Predicate = Self>>: fn is_coinductive(self, interner: I) -> bool; } +pub trait Clause<I: Interner<Clause = Self>>: + Copy + + Debug + + Hash + + Eq + // FIXME: Remove these, uplift the `Upcast` impls. + + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>> + + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>> +{ +} + /// Common capabilities of placeholder kinds pub trait PlaceholderLike: Copy + Debug + Hash + Eq { - fn universe(self) -> UniverseIndex; - fn var(self) -> BoundVar; + fn universe(self) -> ty::UniverseIndex; + fn var(self) -> ty::BoundVar; - fn with_updated_universe(self, ui: UniverseIndex) -> Self; + fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self; - fn new(ui: UniverseIndex, var: BoundVar) -> Self; + fn new(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self; } pub trait IntoKind { @@ -124,12 +157,8 @@ pub trait IntoKind { fn kind(self) -> Self::Kind; } -pub trait BoundVars<I: Interner> { - fn bound_vars(&self) -> I::BoundVars; - - fn has_no_bound_vars(&self) -> bool; -} - pub trait BoundVarLike<I: Interner> { - fn var(self) -> BoundVar; + fn var(self) -> ty::BoundVar; + + fn assert_eq(self, var: I::BoundVarKind); } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6516d5b1645..2ab81dfff32 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -28,19 +28,28 @@ pub trait Interner: + IrPrint<CoercePredicate<Self>> + IrPrint<FnSig<Self>> { - type DefId: Copy + Debug + Hash + Eq; + type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs<Self>; /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`, /// not including the args from the parent item (trait or impl). type OwnItemArgs: Copy + Debug + Hash + Eq; - type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq + IntoKind<Kind = GenericArgKind<Self>>; - type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>>; - - type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>; - type BoundVars: IntoIterator<Item = Self::BoundVar>; - type BoundVar; + type GenericArg: Copy + + DebugWithInfcx<Self> + + Hash + + Eq + + IntoKind<Kind = GenericArgKind<Self>> + + TypeVisitable<Self>; + type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>> + TypeVisitable<Self>; + + type BoundVarKinds: Copy + + Debug + + Hash + + Eq + + Deref<Target: Deref<Target = [Self::BoundVarKind]>> + + Default; + type BoundVarKind: Copy + Debug + Hash + Eq; type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>; type PredefinedOpaques: Copy + Debug + Hash + Eq; @@ -51,7 +60,7 @@ pub trait Interner: // Kinds of tys type Ty: Ty<Self>; type Tys: Tys<Self>; - type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]>; + type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]> + TypeVisitable<Self>; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type PlaceholderTy: PlaceholderLike; @@ -84,14 +93,15 @@ pub trait Interner: // Predicates type ParamEnv: Copy + Debug + Hash + Eq; type Predicate: Predicate<Self>; - type TraitPredicate: Copy + Debug + Hash + Eq; - type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; - type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; - type ProjectionPredicate: Copy + Debug + Hash + Eq; - type NormalizesTo: Copy + Debug + Hash + Eq; - type SubtypePredicate: Copy + Debug + Hash + Eq; - type CoercePredicate: Copy + Debug + Hash + Eq; - type ClosureKind: Copy + Debug + Hash + Eq; + type Clause: Clause<Self>; + type TraitPredicate: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type RegionOutlivesPredicate: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type TypeOutlivesPredicate: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type ProjectionPredicate: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type NormalizesTo: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type SubtypePredicate: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type CoercePredicate: Copy + Debug + Hash + Eq + TypeVisitable<Self>; + type ClosureKind: Copy + Debug + Hash + Eq + TypeVisitable<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index af4b9eef14b..6d575b8e442 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -1,7 +1,7 @@ use std::fmt; use crate::{ - AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, + AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, Interner, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; @@ -22,6 +22,15 @@ macro_rules! define_display_via_print { } } +impl<I: Interner, T> fmt::Display for Binder<I, T> +where + I: IrPrint<Binder<I, T>>, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + <I as IrPrint<Binder<I, T>>>::print(self, fmt) + } +} + macro_rules! define_debug_via_print { ($($ty:ident),+ $(,)?) => { $( diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index fa9bda9a2f7..4a461b5b5f3 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -9,9 +9,13 @@ extern crate self as rustc_type_ir; #[cfg(feature = "nightly")] +use rustc_data_structures::sso::SsoHashSet; +#[cfg(feature = "nightly")] use rustc_data_structures::sync::Lrc; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext}; +#[cfg(not(feature = "nightly"))] +use std::collections::HashSet as SsoHashSet; use std::fmt; use std::hash::Hash; #[cfg(not(feature = "nightly"))] @@ -31,6 +35,7 @@ pub mod ty_kind; #[macro_use] mod macros; +mod binder; mod canonical; mod const_kind; mod debug; @@ -43,6 +48,7 @@ mod predicate_kind; mod region_kind; mod upcast; +pub use binder::*; pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; @@ -374,6 +380,10 @@ impl<I: Interner> inherent::BoundVarLike<I> for BoundVar { fn var(self) -> BoundVar { self } + + fn assert_eq(self, _var: I::BoundVarKind) { + unreachable!("FIXME: We really should have a separate `BoundConst` for consts") + } } /// Represents the various closure traits in the language. This diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c0619d782c6..b4f3d62f10e 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -6,10 +6,9 @@ use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEn use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; +use crate::upcast::Upcast; use crate::visit::TypeVisitableExt as _; -use crate::{ - AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx, -}; +use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: @@ -75,6 +74,16 @@ impl<I: Interner> TraitRef<I> { } } +impl<I: Interner> ty::Binder<I, TraitRef<I>> { + pub fn self_ty(&self) -> ty::Binder<I, I::Ty> { + self.map_bound_ref(|tr| tr.self_ty()) + } + + pub fn def_id(&self) -> I::DefId { + self.skip_binder().def_id + } +} + #[derive(derivative::Derivative)] #[derivative( Clone(bound = ""), @@ -112,6 +121,22 @@ impl<I: Interner> TraitPredicate<I> { } } +impl<I: Interner> ty::Binder<I, TraitPredicate<I>> { + pub fn def_id(self) -> I::DefId { + // Ok to skip binder since trait `DefId` does not care about regions. + self.skip_binder().def_id() + } + + pub fn self_ty(self) -> ty::Binder<I, I::Ty> { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } + + #[inline] + pub fn polarity(self) -> PredicatePolarity { + self.skip_binder().polarity + } +} + impl<I: Interner> fmt::Debug for TraitPredicate<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(effects) printing? @@ -204,6 +229,34 @@ impl<I: Interner> DebugWithInfcx<I> for ExistentialPredicate<I> { } } +impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> { + /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`), + /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` + /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example). + pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> I::Clause { + match self.skip_binder() { + ExistentialPredicate::Trait(tr) => { + self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx) + } + ExistentialPredicate::Projection(p) => { + self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx) + } + ExistentialPredicate::AutoTrait(did) => { + let generics = tcx.generics_of(did); + let trait_ref = if generics.count() == 1 { + ty::TraitRef::new(tcx, did, [self_ty]) + } else { + // If this is an ill-formed auto trait, then synthesize + // new error args for the missing generics. + let err_args = GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]); + ty::TraitRef::new(tcx, did, err_args) + }; + self.rebind(trait_ref).upcast(tcx) + } + } + } +} + /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) @@ -253,6 +306,20 @@ impl<I: Interner> ExistentialTraitRef<I> { } } +impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> { + pub fn def_id(&self) -> I::DefId { + self.skip_binder().def_id + } + + /// Object types don't have a self type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self type. A common choice is `mk_err()` + /// or some placeholder type. + pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> { + self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) + } +} + /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(derivative::Derivative)] #[derivative( @@ -308,6 +375,16 @@ impl<I: Interner> ExistentialProjection<I> { } } +impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> { + pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, ProjectionPredicate<I>> { + self.map_bound(|p| p.with_self_ty(tcx, self_ty)) + } + + pub fn item_def_id(&self) -> I::DefId { + self.skip_binder().def_id + } +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum AliasTermKind { @@ -414,7 +491,7 @@ impl<I: Interner> AliasTerm<I> { AliasTerm { def_id, args, _use_alias_term_new_instead: () } } - pub fn expect_ty(self, interner: I) -> AliasTy<I> { + pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> { match self.kind(interner) { AliasTermKind::ProjectionTy | AliasTermKind::InherentTy @@ -424,7 +501,7 @@ impl<I: Interner> AliasTerm<I> { panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") } } - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } + ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } } pub fn kind(self, interner: I) -> AliasTermKind { @@ -435,32 +512,32 @@ impl<I: Interner> AliasTerm<I> { 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: () }, + ty::AliasTyKind::Projection, + ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), AliasTermKind::InherentTy => Ty::new_alias( interner, - AliasTyKind::Inherent, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ty::AliasTyKind::Inherent, + ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), AliasTermKind::OpaqueTy => Ty::new_alias( interner, - AliasTyKind::Opaque, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ty::AliasTyKind::Opaque, + ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), AliasTermKind::WeakTy => Ty::new_alias( interner, - AliasTyKind::Weak, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ty::AliasTyKind::Weak, + ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { I::Const::new_unevaluated( interner, - UnevaluatedConst::new(self.def_id, self.args), + ty::UnevaluatedConst::new(self.def_id, self.args), interner.type_of_instantiated(self.def_id, self.args), ) .into() @@ -514,14 +591,14 @@ impl<I: Interner> AliasTerm<I> { } } -impl<I: Interner> From<AliasTy<I>> for AliasTerm<I> { - fn from(ty: AliasTy<I>) -> Self { +impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> { + fn from(ty: ty::AliasTy<I>) -> Self { AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } } } -impl<I: Interner> From<UnevaluatedConst<I>> for AliasTerm<I> { - fn from(ct: UnevaluatedConst<I>) -> Self { +impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> { + fn from(ct: ty::UnevaluatedConst<I>) -> Self { AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } } } @@ -571,6 +648,40 @@ impl<I: Interner> ProjectionPredicate<I> { } } +impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> { + /// Returns the `DefId` of the trait of the associated item being projected. + #[inline] + pub fn trait_def_id(&self, tcx: I) -> I::DefId { + self.skip_binder().projection_term.trait_def_id(tcx) + } + + /// Get the trait ref required for this projection to be well formed. + /// Note that for generic associated types the predicates of the associated + /// type also need to be checked. + #[inline] + pub fn required_poly_trait_ref(&self, tcx: I) -> ty::Binder<I, TraitRef<I>> { + // Note: unlike with `TraitRef::to_poly_trait_ref()`, + // `self.0.trait_ref` is permitted to have escaping regions. + // This is because here `self` has a `Binder` and so does our + // return value, so we are preserving the number of binding + // levels. + self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx)) + } + + pub fn term(&self) -> ty::Binder<I, I::Term> { + self.map_bound(|predicate| predicate.term) + } + + /// The `DefId` of the `TraitItem` for the associated type. + /// + /// Note that this is not the `DefId` of the `TraitRef` containing this + /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. + pub fn projection_def_id(&self) -> I::DefId { + // Ok to skip binder since trait `DefId` does not care about regions. + self.skip_binder().projection_term.def_id + } +} + impl<I: Interner> fmt::Debug for ProjectionPredicate<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_term, self.term) diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 629ea9fb839..38082bf3c16 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -8,7 +8,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use std::fmt; use crate::inherent::*; -use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx}; +use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use self::TyKind::*; @@ -514,7 +514,7 @@ impl<I: Interner> AliasTy<I> { /// For example, if this is a projection of `<T as StreamingIterator>::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>, I::OwnItemArgs) { + pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::OwnItemArgs) { debug_assert_eq!(self.kind(interner), AliasTyKind::Projection); interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) } @@ -526,7 +526,7 @@ impl<I: Interner> AliasTy<I> { /// 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<I> { + pub fn trait_ref(self, interner: I) -> ty::TraitRef<I> { self.trait_ref_and_own_args(interner).0 } } @@ -982,6 +982,49 @@ impl<I: Interner> FnSig<I> { pub fn output(self) -> I::Ty { self.split_inputs_and_output().1 } + + pub fn is_fn_trait_compatible(self) -> bool { + let FnSig { safety, abi, c_variadic, .. } = self; + !c_variadic && safety.is_safe() && abi.is_rust() + } +} + +impl<I: Interner> ty::Binder<I, FnSig<I>> { + #[inline] + pub fn inputs(self) -> ty::Binder<I, I::FnInputTys> { + self.map_bound(|fn_sig| fn_sig.inputs()) + } + + #[inline] + #[track_caller] + pub fn input(self, index: usize) -> ty::Binder<I, I::Ty> { + self.map_bound(|fn_sig| fn_sig.inputs()[index]) + } + + pub fn inputs_and_output(self) -> ty::Binder<I, I::Tys> { + self.map_bound(|fn_sig| fn_sig.inputs_and_output) + } + + #[inline] + pub fn output(self) -> ty::Binder<I, I::Ty> { + self.map_bound(|fn_sig| fn_sig.output()) + } + + pub fn c_variadic(self) -> bool { + self.skip_binder().c_variadic + } + + pub fn safety(self) -> I::Safety { + self.skip_binder().safety + } + + pub fn abi(self) -> I::Abi { + self.skip_binder().abi + } + + pub fn is_fn_trait_compatible(&self) -> bool { + self.skip_binder().is_fn_trait_compatible() + } } impl<I: Interner> fmt::Debug for FnSig<I> { diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 3d4125f600e..6880c7b8cef 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -90,7 +90,7 @@ pub trait TypeVisitor<I: Interner>: Sized { #[cfg(not(feature = "nightly"))] type Result: VisitorResult; - fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { t.super_visit_with(self) } @@ -376,11 +376,11 @@ impl std::fmt::Debug for HasTypeFlagsVisitor { impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { type Result = ControlFlow<FoundFlags>; - fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { // If we're looking for the HAS_BINDER_VARS flag, check if the // binder has vars. This won't be present in the binder's bound // value, so we need to check here too. - if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.has_no_bound_vars() { + if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() { return ControlFlow::Break(FoundFlags); } @@ -476,7 +476,7 @@ struct HasEscapingVarsVisitor { impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor { type Result = ControlFlow<FoundEscapingVars>; - fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); |
