Skip to content

Commit d95f078

Browse files
committed
Auto merge of rust-lang#53225 - nikomatsakis:nll-type-annot, r=pnkfelix
MIR: support user-given type annotations on fns, structs, and enums This branch adds tooling to track user-given type annotations on functions, structs, and enum variant expressions. The user-given types are passed onto NLL which then enforces them. cc rust-lang#47184 — not a complete fix, as there are more cases to cover r? @eddyb cc @rust-lang/wg-compiler-nll
2 parents d41f21f + ed73a32 commit d95f078

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1757
-79
lines changed

src/librustc/hir/def.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub enum Def {
6868
Const(DefId),
6969
Static(DefId, bool /* is_mutbl */),
7070
StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
71-
VariantCtor(DefId, CtorKind),
71+
VariantCtor(DefId, CtorKind), // DefId refers to the enum variant
7272
Method(DefId),
7373
AssociatedConst(DefId),
7474

src/librustc/ich/impls_mir.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,11 @@ for mir::AggregateKind<'gcx> {
479479
mir::AggregateKind::Array(t) => {
480480
t.hash_stable(hcx, hasher);
481481
}
482-
mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
482+
mir::AggregateKind::Adt(adt_def, idx, substs, user_substs, active_field) => {
483483
adt_def.hash_stable(hcx, hasher);
484484
idx.hash_stable(hcx, hasher);
485485
substs.hash_stable(hcx, hasher);
486+
user_substs.hash_stable(hcx, hasher);
486487
active_field.hash_stable(hcx, hasher);
487488
}
488489
mir::AggregateKind::Closure(def_id, ref substs) => {
@@ -528,7 +529,7 @@ impl_stable_hash_for!(enum mir::NullOp {
528529
SizeOf
529530
});
530531

531-
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
532+
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, user_ty, literal });
532533

533534
impl_stable_hash_for!(struct mir::Location { block, statement_index });
534535

src/librustc/infer/canonical/mod.rs

+30
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,36 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
188188
}
189189
}
190190

191+
impl<'gcx, V> Canonical<'gcx, V> {
192+
/// Allows you to map the `value` of a canonical while keeping the
193+
/// same set of bound variables.
194+
///
195+
/// **WARNING:** This function is very easy to mis-use, hence the
196+
/// name! In particular, the new value `W` must use all **the
197+
/// same type/region variables** in **precisely the same order**
198+
/// as the original! (The ordering is defined by the
199+
/// `TypeFoldable` implementation of the type in question.)
200+
///
201+
/// An example of a **correct** use of this:
202+
///
203+
/// ```rust,ignore (not real code)
204+
/// let a: Canonical<'_, T> = ...;
205+
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
206+
/// ```
207+
///
208+
/// An example of an **incorrect** use of this:
209+
///
210+
/// ```rust,ignore (not real code)
211+
/// let a: Canonical<'tcx, T> = ...;
212+
/// let ty: Ty<'tcx> = ...;
213+
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
214+
/// ```
215+
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
216+
let Canonical { variables, value } = self;
217+
Canonical { variables, value: map_op(value) }
218+
}
219+
}
220+
191221
pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
192222

193223
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {

src/librustc/mir/mod.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -1888,12 +1888,15 @@ pub enum Operand<'tcx> {
18881888
/// This implies that the type of the place must be `Copy`; this is true
18891889
/// by construction during build, but also checked by the MIR type checker.
18901890
Copy(Place<'tcx>),
1891+
18911892
/// Move: The value (including old borrows of it) will not be used again.
18921893
///
18931894
/// Safe for values of all types (modulo future developments towards `?Move`).
18941895
/// Correct usage patterns are enforced by the borrow checker for safe code.
18951896
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
18961897
Move(Place<'tcx>),
1898+
1899+
/// Synthesizes a constant value.
18971900
Constant(Box<Constant<'tcx>>),
18981901
}
18991902

@@ -1909,6 +1912,9 @@ impl<'tcx> Debug for Operand<'tcx> {
19091912
}
19101913

19111914
impl<'tcx> Operand<'tcx> {
1915+
/// Convenience helper to make a constant that refers to the fn
1916+
/// with given def-id and substs. Since this is used to synthesize
1917+
/// MIR, assumes `user_ty` is None.
19121918
pub fn function_handle<'a>(
19131919
tcx: TyCtxt<'a, 'tcx, 'tcx>,
19141920
def_id: DefId,
@@ -1919,6 +1925,7 @@ impl<'tcx> Operand<'tcx> {
19191925
Operand::Constant(box Constant {
19201926
span,
19211927
ty,
1928+
user_ty: None,
19221929
literal: ty::Const::zero_sized(tcx, ty),
19231930
})
19241931
}
@@ -2002,7 +2009,7 @@ pub enum AggregateKind<'tcx> {
20022009
/// active field number and is present only for union expressions
20032010
/// -- e.g. for a union expression `SomeUnion { c: .. }`, the
20042011
/// active field index would identity the field `c`
2005-
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<usize>),
2012+
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<CanonicalTy<'tcx>>, Option<usize>),
20062013

20072014
Closure(DefId, ClosureSubsts<'tcx>),
20082015
Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
@@ -2128,7 +2135,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
21282135
_ => fmt_tuple(fmt, places),
21292136
},
21302137

2131-
AggregateKind::Adt(adt_def, variant, substs, _) => {
2138+
AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
21322139
let variant_def = &adt_def.variants[variant];
21332140

21342141
ppaux::parameterized(fmt, substs, variant_def.did, &[])?;
@@ -2207,6 +2214,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
22072214
pub struct Constant<'tcx> {
22082215
pub span: Span,
22092216
pub ty: Ty<'tcx>,
2217+
2218+
/// Optional user-given type: for something like
2219+
/// `collect::<Vec<_>>`, this would be present and would
2220+
/// indicate that `Vec<_>` was explicitly specified.
2221+
///
2222+
/// Needed for NLL to impose user-given type constraints.
2223+
pub user_ty: Option<CanonicalTy<'tcx>>,
2224+
22102225
pub literal: &'tcx ty::Const<'tcx>,
22112226
}
22122227

@@ -2798,8 +2813,14 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
27982813
let kind = box match **kind {
27992814
AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
28002815
AggregateKind::Tuple => AggregateKind::Tuple,
2801-
AggregateKind::Adt(def, v, substs, n) => {
2802-
AggregateKind::Adt(def, v, substs.fold_with(folder), n)
2816+
AggregateKind::Adt(def, v, substs, user_ty, n) => {
2817+
AggregateKind::Adt(
2818+
def,
2819+
v,
2820+
substs.fold_with(folder),
2821+
user_ty.fold_with(folder),
2822+
n,
2823+
)
28032824
}
28042825
AggregateKind::Closure(id, substs) => {
28052826
AggregateKind::Closure(id, substs.fold_with(folder))
@@ -2831,7 +2852,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
28312852
(match **kind {
28322853
AggregateKind::Array(ty) => ty.visit_with(visitor),
28332854
AggregateKind::Tuple => false,
2834-
AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
2855+
AggregateKind::Adt(_, _, substs, user_ty, _) =>
2856+
substs.visit_with(visitor) || user_ty.visit_with(visitor),
28352857
AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
28362858
AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
28372859
}) || fields.visit_with(visitor)
@@ -2902,6 +2924,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
29022924
Constant {
29032925
span: self.span.clone(),
29042926
ty: self.ty.fold_with(folder),
2927+
user_ty: self.user_ty.fold_with(folder),
29052928
literal: self.literal.fold_with(folder),
29062929
}
29072930
}

src/librustc/mir/tcx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl<'tcx> Rvalue<'tcx> {
216216
AggregateKind::Tuple => {
217217
tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
218218
}
219-
AggregateKind::Adt(def, _, substs, _) => {
219+
AggregateKind::Adt(def, _, substs, _, _) => {
220220
tcx.type_of(def.did).subst(tcx, substs)
221221
}
222222
AggregateKind::Closure(did, substs) => {

src/librustc/mir/visit.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ macro_rules! make_mir_visitor {
213213
self.super_ty(ty);
214214
}
215215

216+
fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
217+
self.super_canonical_ty(ty);
218+
}
219+
216220
fn visit_region(&mut self,
217221
region: & $($mutability)* ty::Region<'tcx>,
218222
_: Location) {
@@ -585,6 +589,7 @@ macro_rules! make_mir_visitor {
585589
AggregateKind::Adt(_adt_def,
586590
_variant_index,
587591
ref $($mutability)* substs,
592+
_user_substs,
588593
_active_field_index) => {
589594
self.visit_substs(substs, location);
590595
}
@@ -625,9 +630,10 @@ macro_rules! make_mir_visitor {
625630
}
626631

627632
fn super_user_assert_ty(&mut self,
628-
_c_ty: & $($mutability)* CanonicalTy<'tcx>,
633+
c_ty: & $($mutability)* CanonicalTy<'tcx>,
629634
local: & $($mutability)* Local,
630635
location: Location) {
636+
self.visit_canonical_ty(c_ty);
631637
self.visit_local(local, PlaceContext::Validate, location);
632638
}
633639

@@ -740,11 +746,13 @@ macro_rules! make_mir_visitor {
740746
let Constant {
741747
ref $($mutability)* span,
742748
ref $($mutability)* ty,
749+
ref $($mutability)* user_ty,
743750
ref $($mutability)* literal,
744751
} = *constant;
745752

746753
self.visit_span(span);
747754
self.visit_ty(ty, TyContext::Location(location));
755+
drop(user_ty); // no visit method for this
748756
self.visit_const(literal, location);
749757
}
750758

@@ -764,6 +772,9 @@ macro_rules! make_mir_visitor {
764772
self.visit_source_scope(scope);
765773
}
766774

775+
fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) {
776+
}
777+
767778
fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
768779
}
769780

src/librustc/ty/context.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
3333
use middle::stability;
3434
use mir::{self, Mir, interpret};
3535
use mir::interpret::Allocation;
36-
use ty::subst::{Kind, Substs, Subst};
36+
use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
3737
use ty::ReprOptions;
3838
use traits;
3939
use traits::{Clause, Clauses, Goal, Goals};
@@ -371,6 +371,18 @@ pub struct TypeckTables<'tcx> {
371371
/// other items.
372372
node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
373373

374+
/// Stores the substitutions that the user explicitly gave (if any)
375+
/// attached to `id`. These will not include any inferred
376+
/// values. The canonical form is used to capture things like `_`
377+
/// or other unspecified values.
378+
///
379+
/// Example:
380+
///
381+
/// If the user wrote `foo.collect::<Vec<_>>()`, then the
382+
/// canonical substitutions would include only `for<X> { Vec<X>
383+
/// }`.
384+
user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,
385+
374386
adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
375387

376388
/// Stores the actual binding mode for all instances of hir::BindingAnnotation.
@@ -444,6 +456,7 @@ impl<'tcx> TypeckTables<'tcx> {
444456
user_provided_tys: ItemLocalMap(),
445457
node_types: ItemLocalMap(),
446458
node_substs: ItemLocalMap(),
459+
user_substs: ItemLocalMap(),
447460
adjustments: ItemLocalMap(),
448461
pat_binding_modes: ItemLocalMap(),
449462
pat_adjustments: ItemLocalMap(),
@@ -561,6 +574,18 @@ impl<'tcx> TypeckTables<'tcx> {
561574
self.node_substs.get(&id.local_id).cloned()
562575
}
563576

577+
pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<CanonicalSubsts<'tcx>> {
578+
LocalTableInContextMut {
579+
local_id_root: self.local_id_root,
580+
data: &mut self.user_substs
581+
}
582+
}
583+
584+
pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalSubsts<'tcx>> {
585+
validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
586+
self.user_substs.get(&id.local_id).cloned()
587+
}
588+
564589
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
565590
// doesn't provide type parameter substitutions.
566591
pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> {
@@ -740,6 +765,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
740765
ref user_provided_tys,
741766
ref node_types,
742767
ref node_substs,
768+
ref user_substs,
743769
ref adjustments,
744770
ref pat_binding_modes,
745771
ref pat_adjustments,
@@ -762,6 +788,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
762788
user_provided_tys.hash_stable(hcx, hasher);
763789
node_types.hash_stable(hcx, hasher);
764790
node_substs.hash_stable(hcx, hasher);
791+
user_substs.hash_stable(hcx, hasher);
765792
adjustments.hash_stable(hcx, hasher);
766793
pat_binding_modes.hash_stable(hcx, hasher);
767794
pat_adjustments.hash_stable(hcx, hasher);

src/librustc/ty/subst.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
// Type substitutions.
1212

1313
use hir::def_id::DefId;
14-
use ty::{self, Lift, List, Ty, TyCtxt};
14+
use infer::canonical::Canonical;
15+
use ty::{self, CanonicalVar, Lift, List, Ty, TyCtxt};
1516
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
1617

1718
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
1819
use syntax_pos::{Span, DUMMY_SP};
1920
use rustc_data_structures::accumulate_vec::AccumulateVec;
2021
use rustc_data_structures::array_vec::ArrayVec;
22+
use rustc_data_structures::indexed_vec::Idx;
2123

2224
use core::intrinsics;
2325
use std::cmp::Ordering;
@@ -339,6 +341,33 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
339341
}
340342
}
341343

344+
pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>;
345+
346+
impl<'gcx> CanonicalSubsts<'gcx> {
347+
/// True if this represents a substitution like
348+
///
349+
/// ```text
350+
/// [?0, ?1, ?2]
351+
/// ```
352+
///
353+
/// i.e., each thing is mapped to a canonical variable with the same index.
354+
pub fn is_identity(&self) -> bool {
355+
self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
356+
match kind.unpack() {
357+
UnpackedKind::Type(ty) => match ty.sty {
358+
ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
359+
_ => false,
360+
},
361+
362+
UnpackedKind::Lifetime(r) => match r {
363+
ty::ReCanonical(cvar1) => cvar == *cvar1,
364+
_ => false,
365+
},
366+
}
367+
})
368+
}
369+
}
370+
342371
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
343372

344373
///////////////////////////////////////////////////////////////////////////

src/librustc_codegen_llvm/mir/rvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
148148

149149
mir::Rvalue::Aggregate(ref kind, ref operands) => {
150150
let (dest, active_field_index) = match **kind {
151-
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
151+
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
152152
dest.codegen_set_discr(&bx, variant_index);
153153
if adt_def.is_enum() {
154154
(dest.project_downcast(&bx, variant_index), active_field_index)

0 commit comments

Comments
 (0)