From 1443ac0aa7d9c877b8fdbefbbd99092a517802d2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Oct 2018 17:18:51 -0400 Subject: introduce a more expressive `UserSubsts` --- src/librustc/ich/impls_ty.rs | 5 ++ src/librustc/mir/mod.rs | 6 +-- src/librustc/ty/context.rs | 8 +-- src/librustc/ty/subst.rs | 122 +++++++++++++++++++++++++++++++++---------- 4 files changed, 107 insertions(+), 34 deletions(-) (limited to 'src/librustc') diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index dd2c41dda64..e54968c5274 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1417,3 +1417,8 @@ impl_stable_hash_for!(enum traits::QuantifierKind { Universal, Existential }); + +impl_stable_hash_for!(struct ty::subst::UserSubsts<'tcx> { substs, user_self_ty }); + +impl_stable_hash_for!(struct ty::subst::UserSelfTy<'tcx> { impl_def_id, self_ty }); + diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 278a9bba178..48b2ccbcf87 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -37,7 +37,7 @@ use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use ty::subst::{CanonicalSubsts, Subst, Substs}; +use ty::subst::{CanonicalUserSubsts, Subst, Substs}; use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt}; use util::ppaux; @@ -2413,8 +2413,8 @@ pub struct Constant<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UserTypeAnnotation<'tcx> { Ty(CanonicalTy<'tcx>), - FnDef(DefId, CanonicalSubsts<'tcx>), - AdtDef(&'tcx AdtDef, CanonicalSubsts<'tcx>), + FnDef(DefId, CanonicalUserSubsts<'tcx>), + AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>), } EnumTypeFoldableImpl! { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ab1df2d4c3b..6f0f258a217 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; use mir::interpret::Allocation; -use ty::subst::{CanonicalSubsts, Kind, Substs, Subst}; +use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst}; use ty::ReprOptions; use traits; use traits::{Clause, Clauses, GoalKind, Goal, Goals}; @@ -383,7 +383,7 @@ pub struct TypeckTables<'tcx> { /// If the user wrote `foo.collect::>()`, then the /// canonical substitutions would include only `for { Vec /// }`. - user_substs: ItemLocalMap>, + user_substs: ItemLocalMap>, adjustments: ItemLocalMap>>, @@ -573,14 +573,14 @@ impl<'tcx> TypeckTables<'tcx> { self.node_substs.get(&id.local_id).cloned() } - pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalSubsts<'tcx>> { + pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> { LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.user_substs } } - pub fn user_substs(&self, id: hir::HirId) -> Option> { + pub fn user_substs(&self, id: hir::HirId) -> Option> { validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.user_substs.get(&id.local_id).cloned() } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index c0a42fd5854..bea5ba04f7c 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -323,33 +323,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } -pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>; - -impl<'gcx> CanonicalSubsts<'gcx> { - /// True if this represents a substitution like - /// - /// ```text - /// [?0, ?1, ?2] - /// ``` - /// - /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { - self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| { - match kind.unpack() { - UnpackedKind::Type(ty) => match ty.sty { - ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1, - _ => false, - }, - - UnpackedKind::Lifetime(r) => match r { - ty::ReCanonical(cvar1) => cvar == *cvar1, - _ => false, - }, - } - }) - } -} - impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {} /////////////////////////////////////////////////////////////////////////// @@ -564,3 +537,98 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } + +pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>; + +impl CanonicalUserSubsts<'tcx> { + /// True if this represents a substitution like + /// + /// ```text + /// [?0, ?1, ?2] + /// ``` + /// + /// i.e., each thing is mapped to a canonical variable with the same index. + pub fn is_identity(&self) -> bool { + if self.value.user_self_ty.is_some() { + return false; + } + + self.value.substs.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| { + match kind.unpack() { + UnpackedKind::Type(ty) => match ty.sty { + ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1, + _ => false, + }, + + UnpackedKind::Lifetime(r) => match r { + ty::ReCanonical(cvar1) => cvar == *cvar1, + _ => false, + }, + } + }) + } +} + +/// Stores the user-given substs to reach some fully qualified path +/// (e.g., `::Item` or `::Item`). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UserSubsts<'tcx> { + /// The substitutions for the item as given by the user. + pub substs: &'tcx Substs<'tcx>, + + /// The self-type, in the case of a `::Item` path (when applied + /// to an inherent impl). See `UserSubsts` below. + pub user_self_ty: Option>, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserSubsts<'tcx> { + substs, + user_self_ty, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserSubsts<'a> { + type Lifted = UserSubsts<'tcx>; + substs, + user_self_ty, + } +} + +/// Specifies the user-given self-type. In the case of a path that +/// refers to a member in an inherent impl, this self-type is +/// sometimes needed to constrain the type parameters on the impl. For +/// example, in this code: +/// +/// ``` +/// struct Foo { } +/// impl Foo { fn method() { } } +/// ``` +/// +/// when you then have a path like `>::method`, +/// this struct would carry the def-id of the impl along with the +/// self-type `Foo`. Then we can instantiate the parameters of +/// the impl (with the substs from `UserSubsts`) and apply those to +/// the self-type, giving `Foo`. Finally, we unify that with +/// the self-type here, which contains `?A` to be `&'static u32` +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UserSelfTy<'tcx> { + pub impl_def_id: DefId, + pub self_ty: Ty<'tcx>, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserSelfTy<'tcx> { + impl_def_id, + self_ty, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserSelfTy<'a> { + type Lifted = UserSelfTy<'tcx>; + impl_def_id, + self_ty, + } +} -- cgit 1.4.1-3-g733a5