diff options
| author | bors <bors@rust-lang.org> | 2018-10-16 23:27:43 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-10-16 23:27:43 +0000 |
| commit | 01ca85becd45a4115bd5a1b367a1667c06f0906b (patch) | |
| tree | d5ccbfbaf741308c228752047d8088ff87a0b7cc /src/librustc/ty | |
| parent | bef62ccddb911b9cd7677717a69348a62cf61f96 (diff) | |
| parent | b70b4a6814d420222f28684f9286a21ddb980bcf (diff) | |
| download | rust-01ca85becd45a4115bd5a1b367a1667c06f0906b.tar.gz rust-01ca85becd45a4115bd5a1b367a1667c06f0906b.zip | |
Auto merge of #55093 - nikomatsakis:nll-issue-54574-multisegment-path, r=pnkfelix
nll type annotations in multisegment path This turned out to be sort of tricky. The problem is that if you have a path like ``` <Foo<&'static u32>>::bar ``` and it comes from an impl like `impl<T> Foo<T>` then the self-type the user gave doesn't *directly* map to the substitutions that the impl wants. To handle this, then, we have to preserve not just the "user-given substs" we used to do, but also a "user-given self-ty", which we have to apply later. This PR makes those changes. It also removes the code from NLL relate-ops that handled canonical variables and moves to use normal inference variables instead. This simplifies a few things and gives us a bit more flexibility (for example, I predict we are going to have to start normalizing at some point, and it would be easy now). r? @matthewjasper -- you were just touching this code, do you feel comfortable reviewing this? Fixes #54574
Diffstat (limited to 'src/librustc/ty')
| -rw-r--r-- | src/librustc/ty/context.rs | 8 | ||||
| -rw-r--r-- | src/librustc/ty/subst.rs | 122 |
2 files changed, 99 insertions, 31 deletions
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::<Vec<_>>()`, then the /// canonical substitutions would include only `for<X> { Vec<X> /// }`. - user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>, + user_substs: ItemLocalMap<CanonicalUserSubsts<'tcx>>, adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>, @@ -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<CanonicalSubsts<'tcx>> { + pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalUserSubsts<'tcx>> { 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..64cfba7df6e 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., `<T>::Item` or `<T as Trait>::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 `<T>::Item` path (when applied + /// to an inherent impl). See `UserSelfTy` below. + pub user_self_ty: Option<UserSelfTy<'tcx>>, +} + +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<T> { } +/// impl<A> Foo<A> { fn method() { } } +/// ``` +/// +/// when you then have a path like `<Foo<&'static u32>>::method`, +/// this struct would carry the def-id of the impl along with the +/// self-type `Foo<u32>`. Then we can instantiate the parameters of +/// the impl (with the substs from `UserSubsts`) and apply those to +/// the self-type, giving `Foo<?A>`. 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, + } +} |
