From 28ce5883210da1ed90cda9b7da3d0b16e2794e69 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 20 May 2024 12:57:07 -0400 Subject: [PATCH 1/2] Uplift binder --- compiler/rustc_errors/src/diagnostic_impls.rs | 9 + .../src/hir_ty_lowering/errors.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 1 + compiler/rustc_middle/src/ty/codec.rs | 58 +-- compiler/rustc_middle/src/ty/context.rs | 13 +- compiler/rustc_middle/src/ty/generic_args.rs | 8 + compiler/rustc_middle/src/ty/predicate.rs | 153 +------- compiler/rustc_middle/src/ty/print/pretty.rs | 19 +- compiler/rustc_middle/src/ty/region.rs | 4 + .../rustc_middle/src/ty/structural_impls.rs | 32 -- compiler/rustc_middle/src/ty/sty.rs | 257 +------------ compiler/rustc_middle/src/ty/visit.rs | 98 ----- .../src/canonicalizer.rs | 6 +- .../src/traits/error_reporting/suggestions.rs | 3 +- compiler/rustc_type_ir/src/binder.rs | 340 ++++++++++++++++++ compiler/rustc_type_ir/src/fold.rs | 13 +- compiler/rustc_type_ir/src/inherent.rs | 87 +++-- compiler/rustc_type_ir/src/interner.rs | 42 ++- compiler/rustc_type_ir/src/ir_print.rs | 11 +- compiler/rustc_type_ir/src/lib.rs | 10 + compiler/rustc_type_ir/src/predicate.rs | 147 +++++++- compiler/rustc_type_ir/src/ty_kind.rs | 49 ++- compiler/rustc_type_ir/src/visit.rs | 8 +- 23 files changed, 703 insertions(+), 667 deletions(-) create mode 100644 compiler/rustc_type_ir/src/binder.rs diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 4bf7dccab9238..9614f4e80e17c 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -118,6 +118,15 @@ impl IntoDiagArg for rustc_type_ir::FnSig { } } +impl IntoDiagArg for rustc_type_ir::Binder +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 00356ece58523..168a370bba93e 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 8caeb85204b75..0cd77fe774fb8 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 c0effe9804cd7..07652b4792921 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>> Encodable for Ty<'tcx> { } } -impl<'tcx, E: TyEncoder>> Encodable - 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>> Encodable 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>> Decodable for Ty<'tcx> { } } -impl<'tcx, D: TyDecoder>> Decodable - for ty::Binder<'tcx, ty::PredicateKind<'tcx>> -{ - fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> { +impl<'tcx, D: TyDecoder>> Decodable 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>> Decodable as Decodable>::decode(decoder) }, bound_vars, - ) - } -} - -impl<'tcx, D: TyDecoder>> Decodable 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>> Encodable 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>> Decodable 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::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 8185c99c2fd20..a457319c5f89f 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>> = Binder<'tcx, T>; - type BoundVars = &'tcx List; - type BoundVar = ty::BoundVariableKind; + type BoundVarKinds = &'tcx List; + 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> for abi::Abi { } impl<'tcx> rustc_type_ir::inherent::Safety> 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 3d263e62de66e..cb11bb3ef16d3 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> 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 be91249a25f8d..067d490078d37 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>; @@ -155,6 +155,8 @@ pub struct Clause<'tcx>( pub(super) Interned<'tcx, WithCachedTypeInfo>>>, ); +impl<'tcx> rustc_type_ir::inherent::Clause> 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` (e.g., derived from `dyn PartialEq`), - /// 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`, 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> { /// Returns the "principal `DefId`" of this set of existential predicates. /// @@ -322,49 +296,9 @@ impl<'tcx> ty::List> { } 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: pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, 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, PredicateKind<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom, Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> { - fn upcast_from(from: Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, 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, ClauseKind<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom, Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> { - fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, 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, Clause<'tcx>> for Predicate<'tcx> { impl<'tcx> UpcastFrom, 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, Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> { - fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, 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, TraitRef<'tcx>> for Clause<'tcx> { } } -impl<'tcx> UpcastFrom, Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> { - fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, 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, Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> { - fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, 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, Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> { - fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, 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 0dbb17e9db44e..f0bd071e451f8 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::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::Region<'tcx>>, ty::OutlivesPredicate, ty::Region<'tcx>> } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 551e2ea229561..d7da37385e1fc 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> 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 81d92a2a448e4..af3aa3b56f7bb 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> for ty::AdtDef<'tcx> { } } -impl<'tcx, T: TypeFoldable>> TypeFoldable> for ty::Binder<'tcx, T> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - folder.try_fold_binder(self) - } -} - -impl<'tcx, T: TypeVisitable>> TypeVisitable> for ty::Binder<'tcx, T> { - fn visit_with>>(&self, visitor: &mut V) -> V::Result { - visitor.visit_binder(self) - } -} - -impl<'tcx, T: TypeFoldable>> TypeSuperFoldable> for ty::Binder<'tcx, T> { - fn try_super_fold_with>>( - self, - folder: &mut F, - ) -> Result { - self.try_map_bound(|ty| ty.try_fold_with(folder)) - } -} - -impl<'tcx, T: TypeVisitable>> TypeSuperVisitable> - for ty::Binder<'tcx, T> -{ - fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { - self.as_ref().skip_binder().visit_with(visitor) - } -} - impl<'tcx> TypeFoldable> for &'tcx ty::List> { fn try_fold_with>>( self, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2d9d178449e09..fc9a854c85338 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>; pub type TypeAndMut<'tcx> = ir::TypeAndMut>; pub type AliasTy<'tcx> = ir::AliasTy>; pub type FnSig<'tcx> = ir::FnSig>; +pub type Binder<'tcx, T> = ir::Binder, 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` 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, -} - -impl<'tcx, T> Binder<'tcx, T> -where - T: TypeVisitable>, -{ - /// 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) -> 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> for ty::Binder<'tcx, T> { - fn bound_vars(&self) -> &'tcx List { - 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 { - 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>>(&self, f: F) -> Binder<'tcx, U> - where - F: FnOnce(&T) -> U, - { - self.as_ref().map_bound(f) - } - - pub fn map_bound>>(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>, E>( - self, - f: F, - ) -> Result, E> - where - F: FnOnce(T) -> Result, - { - 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(&self, value: U) -> Binder<'tcx, U> - where - U: TypeVisitable>, - { - 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 - where - T: TypeVisitable>, - { - // `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(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> { - pub fn transpose(self) -> Option> { - 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> { - 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>> { - 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> 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 218567bbd59e8..b1bbfd420e1b1 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, - 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) -> Self { - ValidateBoundVars { - bound_vars, - binder_index: ty::INNERMOST, - visited: SsoHashSet::default(), - } - } -} - -impl<'tcx> TypeVisitor> for ValidateBoundVars<'tcx> { - type Result = ControlFlow<()>; - - fn visit_binder>>( - &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 696639e9c1b65..127ebde5fec3f 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -217,10 +217,9 @@ impl, I: Interner> TypeFolder self.infcx.interner() } - fn fold_binder(&mut self, t: I::Binder) -> I::Binder + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder where T: TypeFoldable, - I::Binder: TypeSuperFoldable, { self.binder_index.shift_in(1); let t = t.super_fold_with(self); @@ -455,10 +454,9 @@ impl TypeFolder for RegionsToStatic { self.interner } - fn fold_binder(&mut self, t: I::Binder) -> I::Binder + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder where T: TypeFoldable, - I::Binder: TypeSuperFoldable, { 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 f9b6b281f9246..6c56ebb62aed1 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 0000000000000..5336b915a1d38 --- /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`). Note that when we instantiate, +/// erase, or otherwise "discharge" these bound vars, we change the +/// type from `Binder` to just `T` (see +/// e.g., `liberate_late_bound_regions`). +/// +/// `Decodable` and `Encodable` are implemented for `Binder` 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 { + 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 Lift for Binder +where + T: Lift, + I::BoundVarKinds: Lift, +{ + type Lifted = Binder; + + fn lift_to_tcx(self, tcx: U) -> Option { + 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> rustc_serialize::Encodable for ty::Binder + where + $t: rustc_serialize::Encodable, + I::BoundVarKinds: rustc_serialize::Encodable, + { + fn encode(&self, e: &mut E) { + self.bound_vars().encode(e); + self.as_ref().skip_binder().encode(e); + } + } + impl> Decodable for ty::Binder + where + $t: TypeVisitable + rustc_serialize::Decodable, + I::BoundVarKinds: rustc_serialize::Decodable, + { + 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, + ty::TraitPredicate, + ty::ExistentialPredicate, + ty::TraitRef, + ty::ExistentialTraitRef, +} + +impl Binder +where + T: TypeVisitable, +{ + /// 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 { + 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 { + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(bound_vars); + value.visit_with(&mut validator); + } + Binder { value, bound_vars } + } +} + +impl> TypeFoldable for Binder { + fn try_fold_with>(self, folder: &mut F) -> Result { + folder.try_fold_binder(self) + } +} + +impl> TypeVisitable for Binder { + fn visit_with>(&self, visitor: &mut V) -> V::Result { + visitor.visit_binder(self) + } +} + +impl> TypeSuperFoldable for Binder { + fn try_super_fold_with>( + self, + folder: &mut F, + ) -> Result { + self.try_map_bound(|ty| ty.try_fold_with(folder)) + } +} + +impl> TypeSuperVisitable for Binder { + fn super_visit_with>(&self, visitor: &mut V) -> V::Result { + self.as_ref().skip_binder().visit_with(visitor) + } +} + +impl Binder { + /// 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 { + Binder { value: &self.value, bound_vars: self.bound_vars } + } + + pub fn as_deref(&self) -> Binder + where + T: Deref, + { + Binder { value: &self.value, bound_vars: self.bound_vars } + } + + pub fn map_bound_ref>(&self, f: F) -> Binder + where + F: FnOnce(&T) -> U, + { + self.as_ref().map_bound(f) + } + + pub fn map_bound>(self, f: F) -> Binder + 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, E>(self, f: F) -> Result, E> + where + F: FnOnce(T) -> Result, + { + 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(&self, value: U) -> Binder + where + U: TypeVisitable, + { + 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 + where + T: TypeVisitable, + { + // `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(self, f: F) -> (Binder, Binder) + 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 Binder> { + pub fn transpose(self) -> Option> { + let Binder { value, bound_vars } = self; + value.map(|value| Binder { value, bound_vars }) + } +} + +impl Binder { + pub fn iter(self) -> impl Iterator> { + let Binder { value, bound_vars } = self; + value.into_iter().map(move |value| Binder { value, bound_vars }) + } +} + +pub struct ValidateBoundVars { + 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 ValidateBoundVars { + pub fn new(bound_vars: I::BoundVarKinds) -> Self { + ValidateBoundVars { + bound_vars, + binder_index: ty::INNERMOST, + visited: SsoHashSet::default(), + } + } +} + +impl TypeVisitor for ValidateBoundVars { + type Result = ControlFlow<()>; + + fn visit_binder>(&mut self, t: &Binder) -> 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 01bb3d73dbdf3..405aba30241b7 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: TypeFoldable { pub trait TypeFolder: FallibleTypeFolder { fn interner(&self) -> I; - fn fold_binder(&mut self, t: I::Binder) -> I::Binder + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder where T: TypeFoldable, - I::Binder: TypeSuperFoldable, { t.super_fold_with(self) } @@ -167,10 +166,9 @@ pub trait FallibleTypeFolder: Sized { fn interner(&self) -> I; - fn try_fold_binder(&mut self, t: I::Binder) -> Result, Self::Error> + fn try_fold_binder(&mut self, t: ty::Binder) -> Result, Self::Error> where T: TypeFoldable, - I::Binder: TypeSuperFoldable, { t.try_super_fold_with(self) } @@ -206,10 +204,9 @@ where TypeFolder::interner(self) } - fn try_fold_binder(&mut self, t: I::Binder) -> Result, Never> + fn try_fold_binder(&mut self, t: ty::Binder) -> Result, Never> where T: TypeFoldable, - I::Binder: TypeSuperFoldable, { Ok(self.fold_binder(t)) } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f66c6e722f7ca..77fe30a466087 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>: Copy @@ -21,24 +18,30 @@ pub trait Ty>: + Eq + Into + Into - + IntoKind> + + IntoKind> + TypeSuperVisitable + TypeSuperFoldable + 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) -> Self; + fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; } pub trait Tys>: - Copy + Debug + Hash + Eq + IntoIterator + Deref> + Copy + + Debug + + Hash + + Eq + + IntoIterator + + Deref> + + TypeVisitable { fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); } @@ -49,13 +52,21 @@ pub trait Abi>: Copy + Debug + Hash + Eq { } pub trait Safety>: Copy + Debug + Hash + Eq { + fn is_safe(self) -> bool; + fn prefix_str(self) -> &'static str; } pub trait Region>: - Copy + DebugWithInfcx + Hash + Eq + Into + IntoKind> + Flags + Copy + + DebugWithInfcx + + Hash + + Eq + + Into + + IntoKind> + + 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>: + Eq + Into + Into - + IntoKind> + + IntoKind> + TypeSuperVisitable + TypeSuperFoldable + 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, ty: I::Ty) -> Self; + fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst, ty: I::Ty) -> Self; fn ty(self) -> I::Ty; } @@ -100,6 +116,12 @@ pub trait GenericArgs>: 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>: @@ -108,14 +130,25 @@ pub trait Predicate>: fn is_coinductive(self, interner: I) -> bool; } +pub trait Clause>: + Copy + + Debug + + Hash + + Eq + // FIXME: Remove these, uplift the `Upcast` impls. + + UpcastFrom>> + + UpcastFrom>> +{ +} + /// 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 { - fn bound_vars(&self) -> I::BoundVars; - - fn has_no_bound_vars(&self) -> bool; -} - pub trait BoundVarLike { - 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 6516d5b164540..2ab81dfff3268 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> + IrPrint> { - type DefId: Copy + Debug + Hash + Eq; + type DefId: Copy + Debug + Hash + Eq + TypeVisitable; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; /// 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 + Hash + Eq + IntoKind>; - type Term: Copy + Debug + Hash + Eq + IntoKind>; - - type Binder>: BoundVars + TypeSuperVisitable; - type BoundVars: IntoIterator; - type BoundVar; + type GenericArg: Copy + + DebugWithInfcx + + Hash + + Eq + + IntoKind> + + TypeVisitable; + type Term: Copy + Debug + Hash + Eq + IntoKind> + TypeVisitable; + + type BoundVarKinds: Copy + + Debug + + Hash + + Eq + + Deref> + + Default; + type BoundVarKind: Copy + Debug + Hash + Eq; type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; type PredefinedOpaques: Copy + Debug + Hash + Eq; @@ -51,7 +60,7 @@ pub trait Interner: // Kinds of tys type Ty: Ty; type Tys: Tys; - type FnInputTys: Copy + Debug + Hash + Eq + Deref; + type FnInputTys: Copy + Debug + Hash + Eq + Deref + TypeVisitable; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike; type PlaceholderTy: PlaceholderLike; @@ -84,14 +93,15 @@ pub trait Interner: // Predicates type ParamEnv: Copy + Debug + Hash + Eq; type Predicate: Predicate; - 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; + type TraitPredicate: Copy + Debug + Hash + Eq + TypeVisitable; + type RegionOutlivesPredicate: Copy + Debug + Hash + Eq + TypeVisitable; + type TypeOutlivesPredicate: Copy + Debug + Hash + Eq + TypeVisitable; + type ProjectionPredicate: Copy + Debug + Hash + Eq + TypeVisitable; + type NormalizesTo: Copy + Debug + Hash + Eq + TypeVisitable; + type SubtypePredicate: Copy + Debug + Hash + Eq + TypeVisitable; + type CoercePredicate: Copy + Debug + Hash + Eq + TypeVisitable; + type ClosureKind: Copy + Debug + Hash + Eq + TypeVisitable; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo]) -> Self::CanonicalVars; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index af4b9eef14b92..6d575b8e44230 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 fmt::Display for Binder +where + I: IrPrint>, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + >>::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 fa9bda9a2f754..4a461b5b5f3c8 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -8,10 +8,14 @@ #[cfg(feature = "nightly")] 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 inherent::BoundVarLike 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 c0619d782c681..b4f3d62f10e3a 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 TraitRef { } } +impl ty::Binder> { + pub fn self_ty(&self) -> ty::Binder { + 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 TraitPredicate { } } +impl ty::Binder> { + 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 { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } + + #[inline] + pub fn polarity(self) -> PredicatePolarity { + self.skip_binder().polarity + } +} + impl fmt::Debug for TraitPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(effects) printing? @@ -204,6 +229,34 @@ impl DebugWithInfcx for ExistentialPredicate { } } +impl ty::Binder> { + /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), + /// 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`, 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 ExistentialTraitRef { } } +impl ty::Binder> { + 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> { + 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 ExistentialProjection { } } +impl ty::Binder> { + pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder> { + 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 AliasTerm { AliasTerm { def_id, args, _use_alias_term_new_instead: () } } - pub fn expect_ty(self, interner: I) -> AliasTy { + pub fn expect_ty(self, interner: I) -> ty::AliasTy { match self.kind(interner) { AliasTermKind::ProjectionTy | AliasTermKind::InherentTy @@ -424,7 +501,7 @@ impl AliasTerm { 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 AliasTerm { 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 AliasTerm { } } -impl From> for AliasTerm { - fn from(ty: AliasTy) -> Self { +impl From> for AliasTerm { + fn from(ty: 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 { +impl From> for AliasTerm { + fn from(ct: ty::UnevaluatedConst) -> Self { AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } } } @@ -571,6 +648,40 @@ impl ProjectionPredicate { } } +impl ty::Binder> { + /// 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> { + // 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 { + 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 fmt::Debug for ProjectionPredicate { 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 629ea9fb839c9..38082bf3c16fb 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 AliasTy { /// 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::OwnItemArgs) { + pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef, 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 AliasTy { /// 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 { + pub fn trait_ref(self, interner: I) -> ty::TraitRef { self.trait_ref_and_own_args(interner).0 } } @@ -982,6 +982,49 @@ impl FnSig { 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 ty::Binder> { + #[inline] + pub fn inputs(self) -> ty::Binder { + self.map_bound(|fn_sig| fn_sig.inputs()) + } + + #[inline] + #[track_caller] + pub fn input(self, index: usize) -> ty::Binder { + self.map_bound(|fn_sig| fn_sig.inputs()[index]) + } + + pub fn inputs_and_output(self) -> ty::Binder { + self.map_bound(|fn_sig| fn_sig.inputs_and_output) + } + + #[inline] + pub fn output(self) -> ty::Binder { + 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 fmt::Debug for FnSig { diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 3d4125f600ef8..6880c7b8cefce 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -90,7 +90,7 @@ pub trait TypeVisitor: Sized { #[cfg(not(feature = "nightly"))] type Result: VisitorResult; - fn visit_binder>(&mut self, t: &I::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { t.super_visit_with(self) } @@ -376,11 +376,11 @@ impl std::fmt::Debug for HasTypeFlagsVisitor { impl TypeVisitor for HasTypeFlagsVisitor { type Result = ControlFlow; - fn visit_binder>(&mut self, t: &I::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> 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 TypeVisitor for HasEscapingVarsVisitor { type Result = ControlFlow; - fn visit_binder>(&mut self, t: &I::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); From 1c8230ea3c54e3f020f1df75d77810e8a5689410 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 21 May 2024 11:07:54 -0400 Subject: [PATCH 2/2] Uplift OutlivesPredicate, remove a bunch of unnecessary associated types from Interner --- .../src/type_check/constraint_conversion.rs | 4 +-- .../rustc_hir_analysis/src/outlives/utils.rs | 2 +- .../rustc_infer/src/infer/outlives/env.rs | 3 +- .../rustc_infer/src/infer/outlives/verify.rs | 6 ++-- compiler/rustc_middle/src/infer/canonical.rs | 4 +-- compiler/rustc_middle/src/ty/context.rs | 10 ------ compiler/rustc_middle/src/ty/predicate.rs | 33 +++++++------------ compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++--- .../rustc_smir/src/rustc_smir/convert/ty.rs | 7 ++-- .../query/type_op/implied_outlives_bounds.rs | 3 +- compiler/rustc_type_ir/src/const_kind.rs | 4 +-- compiler/rustc_type_ir/src/interner.rs | 9 ----- compiler/rustc_type_ir/src/ir_print.rs | 12 ++++++- compiler/rustc_type_ir/src/predicate.rs | 29 ++++++++++++++++ compiler/rustc_type_ir/src/predicate_kind.rs | 20 +++++------ 15 files changed, 79 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 5aa8fe213814d..b23ad2e158425 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -136,7 +136,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { fn convert( &mut self, - predicate: ty::OutlivesPredicate, ty::Region<'tcx>>, + predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, constraint_category: ConstraintCategory<'tcx>, ) { debug!("generate: constraints at: {:#?}", self.locations); @@ -276,7 +276,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &self, ty: Ty<'tcx>, next_outlives_predicates: &mut Vec<( - ty::OutlivesPredicate, ty::Region<'tcx>>, + ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, ConstraintCategory<'tcx>, )>, ) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 95290bbecf2c4..5086c2af3f658 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -9,7 +9,7 @@ use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. pub(crate) type RequiredPredicates<'tcx> = - FxIndexMap, ty::Region<'tcx>>, Span>; + FxIndexMap>, Span>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index c44a5082f68bd..5bcb4f29364d7 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -64,8 +64,7 @@ struct OutlivesEnvironmentBuilder<'tcx> { /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. -pub type RegionBoundPairs<'tcx> = - FxIndexSet, Region<'tcx>>>; +pub type RegionBoundPairs<'tcx> = FxIndexSet>>; impl<'tcx> OutlivesEnvironment<'tcx> { /// Create a builder using `ParamEnv` and add explicit outlives bounds into it. diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index bd981c2056770..7e977b9b95455 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -94,7 +94,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { pub fn approx_declared_bounds_from_env( &self, alias_ty: ty::AliasTy<'tcx>, - ) -> Vec, ty::Region<'tcx>>>> { + ) -> Vec> { let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } @@ -193,7 +193,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn declared_generic_bounds_from_env( &self, generic_ty: Ty<'tcx>, - ) -> Vec, ty::Region<'tcx>>>> { + ) -> Vec> { assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_))); self.declared_generic_bounds_from_env_for_erased_ty(generic_ty) } @@ -213,7 +213,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn declared_generic_bounds_from_env_for_erased_ty( &self, erased_ty: Ty<'tcx>, - ) -> Vec, ty::Region<'tcx>>>> { + ) -> Vec> { let tcx = self.tcx; // To start, collect bounds from user environment. Note that diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 49bf03e9c7544..dba71d88f404b 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -32,7 +32,7 @@ use std::collections::hash_map::Entry; use crate::infer::MemberConstraint; use crate::mir::ConstraintCategory; use crate::ty::GenericArg; -use crate::ty::{self, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; +use crate::ty::{self, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; pub type Canonical<'tcx, V> = ir::Canonical, V>; pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo>; @@ -141,7 +141,7 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } pub type QueryOutlivesConstraint<'tcx> = - (ty::OutlivesPredicate, Region<'tcx>>, ConstraintCategory<'tcx>); + (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>); TrivialTypeTraversalImpls! { crate::infer::canonical::Certainty, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a457319c5f89f..896114e2483c7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -121,7 +121,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Abi = abi::Abi; type Const = ty::Const<'tcx>; - type AliasConst = ty::UnevaluatedConst<'tcx>; type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; @@ -137,15 +136,6 @@ 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>; - type ProjectionPredicate = ty::ProjectionPredicate<'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>; diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 067d490078d37..293cc0a7eca3e 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -1,9 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; -use rustc_macros::{ - extension, HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, -}; +use rustc_macros::{extension, HashStable}; use rustc_type_ir as ir; use std::cmp::Ordering; @@ -24,6 +22,15 @@ pub type PredicateKind<'tcx> = ir::PredicateKind>; pub type NormalizesTo<'tcx> = ir::NormalizesTo>; pub type CoercePredicate<'tcx> = ir::CoercePredicate>; pub type SubtypePredicate<'tcx> = ir::SubtypePredicate>; +pub type OutlivesPredicate<'tcx, T> = ir::OutlivesPredicate, T>; +pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::Region<'tcx>>; +pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, Ty<'tcx>>; +pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'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> = ty::Binder<'tcx, ProjectionPredicate<'tcx>>; /// A statement that can be proven by a trait solver. This includes things that may /// show up in where clauses, such as trait predicates and projection predicates, @@ -405,20 +412,6 @@ impl<'tcx> Clause<'tcx> { } } -pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; - -/// `A: B` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct OutlivesPredicate(pub A, pub B); -pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; -pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, 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>>; - pub trait ToPolyTraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } @@ -545,10 +538,8 @@ impl<'tcx> UpcastFrom, PolyRegionOutlivesPredicate<'tcx>> for Predi } } -impl<'tcx> UpcastFrom, OutlivesPredicate, ty::Region<'tcx>>> - for Predicate<'tcx> -{ - fn upcast_from(from: OutlivesPredicate, ty::Region<'tcx>>, tcx: TyCtxt<'tcx>) -> Self { +impl<'tcx> UpcastFrom, TypeOutlivesPredicate<'tcx>> for Predicate<'tcx> { + fn upcast_from(from: TypeOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(from))).upcast(tcx) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f0bd071e451f8..a1ead1bb59f54 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2860,10 +2860,9 @@ where } } -impl<'tcx, T, U, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate +impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<'tcx, T> where T: Print<'tcx, P>, - U: Print<'tcx, P>, { fn print(&self, cx: &mut P) -> Result<(), PrintError> { define_scoped_cx!(cx); @@ -3016,10 +3015,7 @@ forward_display_to_print! { ty::Region<'tcx>, Ty<'tcx>, &'tcx ty::List>, - ty::Const<'tcx>, - - ty::OutlivesPredicate, ty::Region<'tcx>>, - ty::OutlivesPredicate, ty::Region<'tcx>> + ty::Const<'tcx> } define_print! { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 15447983abbc2..be20924670c37 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -707,12 +707,11 @@ impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> { } } -impl<'tcx, A, B, U, V> Stable<'tcx> for ty::OutlivesPredicate +impl<'tcx, T> Stable<'tcx> for ty::OutlivesPredicate<'tcx, T> where - A: Stable<'tcx, T = U>, - B: Stable<'tcx, T = V>, + T: Stable<'tcx>, { - type T = stable_mir::ty::OutlivesPredicate; + type T = stable_mir::ty::OutlivesPredicate; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let ty::OutlivesPredicate(a, b) = self; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index f7e84a46639d4..00cc77e71e72a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -162,8 +162,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); let mut wf_args = vec![ty.into()]; - let mut outlives_bounds: Vec, ty::Region<'tcx>>> = - vec![]; + let mut outlives_bounds: Vec>> = vec![]; while let Some(arg) = wf_args.pop() { if !checked_wf_args.insert(arg) { diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index af07e9ff96bf8..7076df2893feb 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -5,7 +5,7 @@ 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}; +use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use self::ConstKind::*; @@ -29,7 +29,7 @@ pub enum ConstKind { /// An unnormalized const item such as an anon const or assoc const or free const item. /// Right now anything other than anon consts does not actually work properly but this /// should - Unevaluated(I::AliasConst), + Unevaluated(ty::UnevaluatedConst), /// Used to hold computed value. Value(I::ValueConst), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 2ab81dfff3268..9b8bb210ff424 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -76,7 +76,6 @@ pub trait Interner: // Kinds of consts type Const: Const; - type AliasConst: Copy + DebugWithInfcx + Hash + Eq; type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike; @@ -94,14 +93,6 @@ pub trait Interner: type ParamEnv: Copy + Debug + Hash + Eq; type Predicate: Predicate; type Clause: Clause; - type TraitPredicate: Copy + Debug + Hash + Eq + TypeVisitable; - type RegionOutlivesPredicate: Copy + Debug + Hash + Eq + TypeVisitable; - type TypeOutlivesPredicate: Copy + Debug + Hash + Eq + TypeVisitable; - type ProjectionPredicate: Copy + Debug + Hash + Eq + TypeVisitable; - type NormalizesTo: Copy + Debug + Hash + Eq + TypeVisitable; - type SubtypePredicate: Copy + Debug + Hash + Eq + TypeVisitable; - type CoercePredicate: Copy + Debug + Hash + Eq + TypeVisitable; - type ClosureKind: Copy + Debug + Hash + Eq + TypeVisitable; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo]) -> Self::CanonicalVars; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 6d575b8e44230..d57d0816680bf 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -2,7 +2,8 @@ use std::fmt; use crate::{ AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, - Interner, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate, + TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -58,3 +59,12 @@ define_display_via_print!( ); define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); + +impl fmt::Display for OutlivesPredicate +where + I: IrPrint>, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + >>::print(self, fmt) + } +} diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index b4f3d62f10e3a..4e12c6b3d6713 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -6,10 +6,39 @@ 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::lift::Lift; use crate::upcast::Upcast; use crate::visit::TypeVisitableExt as _; use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; +/// `A: 'region` +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "A: Clone"), + Copy(bound = "A: Copy"), + Hash(bound = "A: Hash"), + PartialEq(bound = "A: PartialEq"), + Eq(bound = "A: Eq"), + Debug(bound = "A: fmt::Debug") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct OutlivesPredicate(pub A, pub I::Region); + +// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't +// understand how to turn `A` to `A::Lifted` in the output `type Lifted`. +impl Lift for OutlivesPredicate +where + A: Lift, + I::Region: Lift, +{ + type Lifted = OutlivesPredicate; + + fn lift_to_tcx(self, tcx: U) -> Option { + Some(OutlivesPredicate(self.0.lift_to_tcx(tcx)?, self.1.lift_to_tcx(tcx)?)) + } +} + /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: /// ```ignore (illustrative) diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index c477ab14153e2..efe270ed60836 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -3,7 +3,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEn use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; -use crate::Interner; +use crate::{self as ty, Interner}; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. @@ -15,17 +15,17 @@ pub enum ClauseKind { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. - Trait(I::TraitPredicate), + Trait(ty::TraitPredicate), - /// `where 'a: 'b` - RegionOutlives(I::RegionOutlivesPredicate), + /// `where 'a: 'r` + RegionOutlives(ty::OutlivesPredicate), - /// `where T: 'a` - TypeOutlives(I::TypeOutlivesPredicate), + /// `where T: 'r` + TypeOutlives(ty::OutlivesPredicate), /// `where ::Name == X`, approximately. /// See the `ProjectionPredicate` struct for details. - Projection(I::ProjectionPredicate), + Projection(ty::ProjectionPredicate), /// Ensures that a const generic argument to a parameter `const N: u8` /// is of type `u8`. @@ -75,7 +75,7 @@ pub enum PredicateKind { /// This obligation is created most often when we have two /// unresolved type variables and hence don't have enough /// information to process the subtyping obligation yet. - Subtype(I::SubtypePredicate), + Subtype(ty::SubtypePredicate), /// `T1` coerced to `T2` /// @@ -85,7 +85,7 @@ pub enum PredicateKind { /// obligation yet. At the moment, we actually process coercions /// very much like subtyping and don't handle the full coercion /// logic. - Coerce(I::CoercePredicate), + Coerce(ty::CoercePredicate), /// Constants must be equal. The first component is the const that is expected. ConstEquate(I::Const, I::Const), @@ -102,7 +102,7 @@ pub enum PredicateKind { /// `T as Trait>::Assoc`, `Projection(::Assoc, ?x)` constrains `?x` /// to `::Assoc` while `NormalizesTo(::Assoc, ?x)` /// results in `NoSolution`. - NormalizesTo(I::NormalizesTo), + NormalizesTo(ty::NormalizesTo), /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. /// This predicate requires two terms to be equal to eachother.