Skip to content

Commit 740e8a3

Browse files
committed
Add the actual chain of projections to UserTypeProjection.
Update the existing NLL `patterns.rs` test accordingly. includes changes addressing review feedback: * Added example to docs for `UserTypeProjections` illustrating how we build up multiple projections when descending into a pattern with type ascriptions. * Adapted niko's suggested docs for `UserTypeProjection`. * Factored out `projection_ty` from more general `projection_ty_core` (as a drive-by, made its callback an `FnMut`, as I discovered later that I need that). * Add note to docs that `PlaceTy.field_ty(..)` does not normalize its result. * Normalize as we project out `field_ty`.
1 parent b569caf commit 740e8a3

File tree

13 files changed

+272
-64
lines changed

13 files changed

+272
-64
lines changed

src/librustc/ich/impls_mir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,5 +607,5 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<
607607
}
608608
}
609609

610-
impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base });
610+
impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base, projs });
611611
impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents });

src/librustc/mir/mod.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,6 +2456,31 @@ EnumLiftImpl! {
24562456
///
24572457
/// Its a collection because there can be multiple type ascriptions on
24582458
/// the path from the root of the pattern down to the binding itself.
2459+
///
2460+
/// An example:
2461+
///
2462+
/// ```rust
2463+
/// struct S<'a>((i32, &'a str), String);
2464+
/// let S((_, w): (i32, &'static str), _): S = ...;
2465+
/// // ------ ^^^^^^^^^^^^^^^^^^^ (1)
2466+
/// // --------------------------------- ^ (2)
2467+
/// ```
2468+
///
2469+
/// The highlights labelled `(1)` show the subpattern `(_, w)` being
2470+
/// ascribed the type `(i32, &'static str)`.
2471+
///
2472+
/// The highlights labelled `(2)` show the whole pattern being
2473+
/// ascribed the type `S`.
2474+
///
2475+
/// In this example, when we descend to `w`, we will have built up the
2476+
/// following two projected types:
2477+
///
2478+
/// * base: `S`, projection: `(base.0).1`
2479+
/// * base: `(i32, &'static str)`, projection: `base.1`
2480+
///
2481+
/// The first will lead to the constraint `w: &'1 str` (for some
2482+
/// inferred region `'1`). The second will lead to the constraint `w:
2483+
/// &'static str`.
24592484
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
24602485
pub struct UserTypeProjections<'tcx> {
24612486
pub(crate) contents: Vec<(UserTypeProjection<'tcx>, Span)>,
@@ -2485,14 +2510,49 @@ impl<'tcx> UserTypeProjections<'tcx> {
24852510
}
24862511
}
24872512

2488-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
2513+
/// Encodes the effect of a user-supplied type annotation on the
2514+
/// subcomponents of a pattern. The effect is determined by applying the
2515+
/// given list of proejctions to some underlying base type. Often,
2516+
/// the projection element list `projs` is empty, in which case this
2517+
/// directly encodes a type in `base`. But in the case of complex patterns with
2518+
/// subpatterns and bindings, we want to apply only a *part* of the type to a variable,
2519+
/// in which case the `projs` vector is used.
2520+
///
2521+
/// Examples:
2522+
///
2523+
/// * `let x: T = ...` -- here, the `projs` vector is empty.
2524+
///
2525+
/// * `let (x, _): T = ...` -- here, the `projs` vector would contain
2526+
/// `field[0]` (aka `.0`), indicating that the type of `s` is
2527+
/// determined by finding the type of the `.0` field from `T`.
2528+
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
24892529
pub struct UserTypeProjection<'tcx> {
24902530
pub base: UserTypeAnnotation<'tcx>,
2531+
pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
24912532
}
24922533

2493-
BraceStructTypeFoldableImpl! {
2494-
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> {
2495-
base
2534+
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> {
2535+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
2536+
use mir::ProjectionElem::*;
2537+
2538+
let base = self.base.fold_with(folder);
2539+
let projs: Vec<_> = self.projs
2540+
.iter()
2541+
.map(|elem| {
2542+
match elem {
2543+
Deref => Deref,
2544+
Field(f, ()) => Field(f.clone(), ()),
2545+
Index(()) => Index(()),
2546+
elem => elem.clone(),
2547+
}})
2548+
.collect();
2549+
2550+
UserTypeProjection { base, projs }
2551+
}
2552+
2553+
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
2554+
self.base.visit_with(visitor)
2555+
// Note: there's nothing in `self.proj` to visit.
24962556
}
24972557
}
24982558

src/librustc/mir/tcx.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,59 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
4444
}
4545
}
4646

47+
/// `place_ty.field_ty(tcx, f)` computes the type at a given field
48+
/// of a record or enum-variant. (Most clients of `PlaceTy` can
49+
/// instead just extract the relevant type directly from their
50+
/// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
51+
/// not carry a `Ty` for `T`.)
52+
///
53+
/// Note that the resulting type has not been normalized.
54+
pub fn field_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, f: &Field) -> Ty<'tcx>
55+
{
56+
// Pass `0` here so it can be used as a "default" variant_index in first arm below
57+
let answer = match (self, 0) {
58+
(PlaceTy::Ty {
59+
ty: &ty::TyS { sty: ty::TyKind::Adt(adt_def, substs), .. } }, variant_index) |
60+
(PlaceTy::Downcast { adt_def, substs, variant_index }, _) => {
61+
let variant_def = &adt_def.variants[variant_index];
62+
let field_def = &variant_def.fields[f.index()];
63+
field_def.ty(tcx, substs)
64+
}
65+
(PlaceTy::Ty { ty }, _) => {
66+
match ty.sty {
67+
ty::Tuple(ref tys) => tys[f.index()],
68+
_ => bug!("extracting field of non-tuple non-adt: {:?}", self),
69+
}
70+
}
71+
};
72+
debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
73+
answer
74+
}
75+
76+
/// Convenience wrapper around `projection_ty_core` for
77+
/// `PlaceElem`, where we can just use the `Ty` that is already
78+
/// stored inline on field projection elems.
4779
pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
4880
elem: &PlaceElem<'tcx>)
4981
-> PlaceTy<'tcx>
5082
{
51-
match *elem {
83+
self.projection_ty_core(tcx, elem, |_, _, ty| ty)
84+
}
85+
86+
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
87+
/// projects `place_ty` onto `elem`, returning the appropriate
88+
/// `Ty` or downcast variant corresponding to that projection.
89+
/// The `handle_field` callback must map a `Field` to its `Ty`,
90+
/// (which should be trivial when `T` = `Ty`).
91+
pub fn projection_ty_core<V, T>(self,
92+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
93+
elem: &ProjectionElem<'tcx, V, T>,
94+
mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
95+
-> PlaceTy<'tcx>
96+
where
97+
V: ::std::fmt::Debug, T: ::std::fmt::Debug
98+
{
99+
let answer = match *elem {
52100
ProjectionElem::Deref => {
53101
let ty = self.to_ty(tcx)
54102
.builtin_deref(true)
@@ -94,8 +142,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
94142
bug!("cannot downcast non-ADT type: `{:?}`", self)
95143
}
96144
},
97-
ProjectionElem::Field(_, fty) => PlaceTy::Ty { ty: fty }
98-
}
145+
ProjectionElem::Field(ref f, ref fty) => PlaceTy::Ty { ty: handle_field(&self, f, fty) }
146+
};
147+
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
148+
answer
99149
}
100150
}
101151

src/librustc/mir/visit.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,9 @@ macro_rules! make_mir_visitor {
797797
) {
798798
let UserTypeProjection {
799799
ref $($mutability)* base,
800+
projs: _, // Note: Does not visit projection elems!
800801
} = *ty;
801-
self.visit_user_type_annotation(base)
802+
self.visit_user_type_annotation(base);
802803
}
803804

804805
fn super_user_type_annotation(

src/librustc_codegen_llvm/mir/analyze.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
168168
let base_ty = self.fx.monomorphize(&base_ty);
169169

170170
// ZSTs don't require any actual memory access.
171-
let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx);
171+
let elem_ty = base_ty
172+
.projection_ty(cx.tcx, &proj.elem)
173+
.to_ty(cx.tcx);
172174
let elem_ty = self.fx.monomorphize(&elem_ty);
173175
if cx.layout_of(elem_ty).is_zst() {
174176
return;

src/librustc_codegen_llvm/mir/place.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
517517
let mut subslice = cg_base.project_index(bx,
518518
C_usize(bx.cx, from as u64));
519519
let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty }
520-
.projection_ty(tcx, &projection.elem).to_ty(bx.tcx());
520+
.projection_ty(tcx, &projection.elem)
521+
.to_ty(bx.tcx());
521522
subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty));
522523

523524
if subslice.layout.is_unsized() {

src/librustc_mir/borrow_check/nll/type_check/mod.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
284284
if let Err(terr) = self.cx.relate_type_and_user_type(
285285
constant.ty,
286286
ty::Variance::Invariant,
287-
&UserTypeProjection { base: user_ty },
287+
&UserTypeProjection { base: user_ty, projs: vec![], },
288288
location.to_locations(),
289289
ConstraintCategory::Boring,
290290
) {
@@ -980,7 +980,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
980980
a, v, user_ty, locations,
981981
);
982982

983-
// FIXME
984983
match user_ty.base {
985984
UserTypeAnnotation::Ty(canonical_ty) => {
986985
let (ty, _) = self.infcx
@@ -991,6 +990,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
991990
// ambient variance to get the right relationship.
992991
let v1 = ty::Contravariant.xform(v);
993992

993+
let tcx = self.infcx.tcx;
994+
let mut projected_ty = PlaceTy::from_ty(ty);
995+
for proj in &user_ty.projs {
996+
projected_ty = projected_ty.projection_ty_core(
997+
tcx, proj, |this, field, &()| {
998+
let ty = this.field_ty(tcx, field);
999+
self.normalize(ty, locations)
1000+
});
1001+
}
1002+
debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
1003+
user_ty.base, ty, user_ty.projs, projected_ty);
1004+
1005+
let ty = projected_ty.to_ty(tcx);
1006+
9941007
self.relate_types(ty, v1, a, locations, category)?;
9951008
}
9961009
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
@@ -1000,6 +1013,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
10001013
) = self.infcx
10011014
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
10021015

1016+
// FIXME: add user_ty.projs support to `AscribeUserType`.
10031017
self.fully_perform_op(
10041018
locations,
10051019
category,
@@ -1173,7 +1187,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11731187
if let Err(terr) = self.relate_type_and_user_type(
11741188
rv_ty,
11751189
ty::Variance::Invariant,
1176-
&UserTypeProjection { base: user_ty },
1190+
&UserTypeProjection { base: user_ty, projs: vec![], },
11771191
location.to_locations(),
11781192
ConstraintCategory::Boring,
11791193
) {

src/librustc_mir/build/expr/as_place.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
147147
kind: StatementKind::AscribeUserType(
148148
place.clone(),
149149
Variance::Invariant,
150-
box UserTypeProjection { base: user_ty },
150+
box UserTypeProjection { base: user_ty, projs: vec![], },
151151
),
152152
},
153153
);
@@ -167,7 +167,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
167167
kind: StatementKind::AscribeUserType(
168168
Place::Local(temp.clone()),
169169
Variance::Invariant,
170-
box UserTypeProjection { base: user_ty },
170+
box UserTypeProjection { base: user_ty, projs: vec![], },
171171
),
172172
},
173173
);

src/librustc_mir/build/matches/mod.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ mod simplify;
3232
mod test;
3333
mod util;
3434

35+
use std::convert::TryFrom;
36+
3537
/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
3638
/// a match arm has a guard expression attached to it.
3739
#[derive(Copy, Clone, Debug)]
@@ -541,11 +543,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
541543
ref slice,
542544
ref suffix,
543545
} => {
546+
let from = u32::try_from(prefix.len()).unwrap();
547+
let to = u32::try_from(suffix.len()).unwrap();
544548
for subpattern in prefix {
545549
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
546550
}
547551
for subpattern in slice {
548-
self.visit_bindings(subpattern, &pattern_user_ty.subslice(), f);
552+
self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f);
549553
}
550554
for subpattern in suffix {
551555
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
@@ -555,25 +559,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
555559
PatternKind::Deref { ref subpattern } => {
556560
self.visit_bindings(subpattern, &pattern_user_ty.deref(), f);
557561
}
558-
PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
562+
PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
559563
// This corresponds to something like
560564
//
561565
// ```
562566
// let A::<'a>(_): A<'static> = ...;
563567
// ```
564-
let pattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span);
565-
self.visit_bindings(subpattern, &pattern_user_ty, f)
568+
let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span);
569+
self.visit_bindings(subpattern, &subpattern_user_ty, f)
566570
}
567571

568572
PatternKind::Leaf { ref subpatterns } => {
569-
for (j, subpattern) in subpatterns.iter().enumerate() {
570-
self.visit_bindings(&subpattern.pattern, &pattern_user_ty.leaf(j), f);
573+
for subpattern in subpatterns {
574+
let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
575+
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
571576
}
572577
}
573578

574-
PatternKind::Variant { ref subpatterns, .. } => {
575-
for (j, subpattern) in subpatterns.iter().enumerate() {
576-
self.visit_bindings(&subpattern.pattern, &pattern_user_ty.variant(j), f);
579+
PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => {
580+
for subpattern in subpatterns {
581+
let subpattern_user_ty = pattern_user_ty.variant(
582+
adt_def, variant_index, subpattern.field);
583+
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
577584
}
578585
}
579586
}
@@ -1329,7 +1336,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13291336
kind: StatementKind::AscribeUserType(
13301337
ascription.source.clone(),
13311338
ty::Variance::Covariant,
1332-
box ascription.user_ty.user_ty(),
1339+
box ascription.user_ty.clone().user_ty(),
13331340
),
13341341
},
13351342
);

src/librustc_mir/build/matches/simplify.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
6363
candidate: &mut Candidate<'pat, 'tcx>)
6464
-> Result<(), MatchPair<'pat, 'tcx>> {
6565
match *match_pair.pattern.kind {
66-
PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
66+
PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
6767
candidate.ascriptions.push(Ascription {
6868
span: user_ty_span,
69-
user_ty,
69+
user_ty: user_ty.clone(),
7070
source: match_pair.place.clone(),
7171
});
7272

0 commit comments

Comments
 (0)