Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIR: support user-given type annotations on fns, structs, and enums #53225

Merged
merged 16 commits into from
Aug 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub enum Def {
Const(DefId),
Static(DefId, bool /* is_mutbl */),
StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
VariantCtor(DefId, CtorKind),
VariantCtor(DefId, CtorKind), // DefId refers to the enum variant
Method(DefId),
AssociatedConst(DefId),

Expand Down
5 changes: 3 additions & 2 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,11 @@ for mir::AggregateKind<'gcx> {
mir::AggregateKind::Array(t) => {
t.hash_stable(hcx, hasher);
}
mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
mir::AggregateKind::Adt(adt_def, idx, substs, user_substs, active_field) => {
adt_def.hash_stable(hcx, hasher);
idx.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
user_substs.hash_stable(hcx, hasher);
active_field.hash_stable(hcx, hasher);
}
mir::AggregateKind::Closure(def_id, ref substs) => {
Expand Down Expand Up @@ -528,7 +529,7 @@ impl_stable_hash_for!(enum mir::NullOp {
SizeOf
});

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

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

Expand Down
30 changes: 30 additions & 0 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,36 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
}
}

impl<'gcx, V> Canonical<'gcx, V> {
/// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables.
///
/// **WARNING:** This function is very easy to mis-use, hence the
/// name! In particular, the new value `W` must use all **the
/// same type/region variables** in **precisely the same order**
/// as the original! (The ordering is defined by the
/// `TypeFoldable` implementation of the type in question.)
///
/// An example of a **correct** use of this:
///
/// ```rust,ignore (not real code)
/// let a: Canonical<'_, T> = ...;
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
/// ```
///
/// An example of an **incorrect** use of this:
///
/// ```rust,ignore (not real code)
/// let a: Canonical<'tcx, T> = ...;
/// let ty: Ty<'tcx> = ...;
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
/// ```
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
let Canonical { variables, value } = self;
Canonical { variables, value: map_op(value) }
}
}

pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
Expand Down
33 changes: 28 additions & 5 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1888,12 +1888,15 @@ pub enum Operand<'tcx> {
/// This implies that the type of the place must be `Copy`; this is true
/// by construction during build, but also checked by the MIR type checker.
Copy(Place<'tcx>),

/// Move: The value (including old borrows of it) will not be used again.
///
/// Safe for values of all types (modulo future developments towards `?Move`).
/// Correct usage patterns are enforced by the borrow checker for safe code.
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
Move(Place<'tcx>),

/// Synthesizes a constant value.
Constant(Box<Constant<'tcx>>),
}

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

impl<'tcx> Operand<'tcx> {
/// Convenience helper to make a constant that refers to the fn
/// with given def-id and substs. Since this is used to synthesize
/// MIR, assumes `user_ty` is None.
pub fn function_handle<'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
Expand All @@ -1919,6 +1925,7 @@ impl<'tcx> Operand<'tcx> {
Operand::Constant(box Constant {
span,
ty,
user_ty: None,
literal: ty::Const::zero_sized(tcx, ty),
})
}
Expand Down Expand Up @@ -2002,7 +2009,7 @@ pub enum AggregateKind<'tcx> {
/// active field number and is present only for union expressions
/// -- e.g. for a union expression `SomeUnion { c: .. }`, the
/// active field index would identity the field `c`
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<usize>),
Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<CanonicalTy<'tcx>>, Option<usize>),

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

AggregateKind::Adt(adt_def, variant, substs, _) => {
AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
let variant_def = &adt_def.variants[variant];

ppaux::parameterized(fmt, substs, variant_def.did, &[])?;
Expand Down Expand Up @@ -2207,6 +2214,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
pub struct Constant<'tcx> {
pub span: Span,
pub ty: Ty<'tcx>,

/// Optional user-given type: for something like
/// `collect::<Vec<_>>`, this would be present and would
/// indicate that `Vec<_>` was explicitly specified.
///
/// Needed for NLL to impose user-given type constraints.
pub user_ty: Option<CanonicalTy<'tcx>>,

pub literal: &'tcx ty::Const<'tcx>,
}

Expand Down Expand Up @@ -2798,8 +2813,14 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
let kind = box match **kind {
AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
AggregateKind::Tuple => AggregateKind::Tuple,
AggregateKind::Adt(def, v, substs, n) => {
AggregateKind::Adt(def, v, substs.fold_with(folder), n)
AggregateKind::Adt(def, v, substs, user_ty, n) => {
AggregateKind::Adt(
def,
v,
substs.fold_with(folder),
user_ty.fold_with(folder),
n,
)
}
AggregateKind::Closure(id, substs) => {
AggregateKind::Closure(id, substs.fold_with(folder))
Expand Down Expand Up @@ -2831,7 +2852,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
(match **kind {
AggregateKind::Array(ty) => ty.visit_with(visitor),
AggregateKind::Tuple => false,
AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
AggregateKind::Adt(_, _, substs, user_ty, _) =>
substs.visit_with(visitor) || user_ty.visit_with(visitor),
AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
}) || fields.visit_with(visitor)
Expand Down Expand Up @@ -2902,6 +2924,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
Constant {
span: self.span.clone(),
ty: self.ty.fold_with(folder),
user_ty: self.user_ty.fold_with(folder),
literal: self.literal.fold_with(folder),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ impl<'tcx> Rvalue<'tcx> {
AggregateKind::Tuple => {
tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
}
AggregateKind::Adt(def, _, substs, _) => {
AggregateKind::Adt(def, _, substs, _, _) => {
tcx.type_of(def.did).subst(tcx, substs)
}
AggregateKind::Closure(did, substs) => {
Expand Down
13 changes: 12 additions & 1 deletion src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ macro_rules! make_mir_visitor {
self.super_ty(ty);
}

fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
self.super_canonical_ty(ty);
}

fn visit_region(&mut self,
region: & $($mutability)* ty::Region<'tcx>,
_: Location) {
Expand Down Expand Up @@ -585,6 +589,7 @@ macro_rules! make_mir_visitor {
AggregateKind::Adt(_adt_def,
_variant_index,
ref $($mutability)* substs,
_user_substs,
_active_field_index) => {
self.visit_substs(substs, location);
}
Expand Down Expand Up @@ -625,9 +630,10 @@ macro_rules! make_mir_visitor {
}

fn super_user_assert_ty(&mut self,
_c_ty: & $($mutability)* CanonicalTy<'tcx>,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
local: & $($mutability)* Local,
location: Location) {
self.visit_canonical_ty(c_ty);
self.visit_local(local, PlaceContext::Validate, location);
}

Expand Down Expand Up @@ -740,11 +746,13 @@ macro_rules! make_mir_visitor {
let Constant {
ref $($mutability)* span,
ref $($mutability)* ty,
ref $($mutability)* user_ty,
ref $($mutability)* literal,
} = *constant;

self.visit_span(span);
self.visit_ty(ty, TyContext::Location(location));
drop(user_ty); // no visit method for this
self.visit_const(literal, location);
}

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

fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) {
}

fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
}

Expand Down
29 changes: 28 additions & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{Kind, Substs, Subst};
use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
use ty::ReprOptions;
use traits;
use traits::{Clause, Clauses, Goal, Goals};
Expand Down Expand Up @@ -371,6 +371,18 @@ pub struct TypeckTables<'tcx> {
/// other items.
node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,

/// Stores the substitutions that the user explicitly gave (if any)
/// attached to `id`. These will not include any inferred
/// values. The canonical form is used to capture things like `_`
/// or other unspecified values.
///
/// Example:
///
/// If the user wrote `foo.collect::<Vec<_>>()`, then the
/// canonical substitutions would include only `for<X> { Vec<X>
/// }`.
user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,

adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,

/// Stores the actual binding mode for all instances of hir::BindingAnnotation.
Expand Down Expand Up @@ -444,6 +456,7 @@ impl<'tcx> TypeckTables<'tcx> {
user_provided_tys: ItemLocalMap(),
node_types: ItemLocalMap(),
node_substs: ItemLocalMap(),
user_substs: ItemLocalMap(),
adjustments: ItemLocalMap(),
pat_binding_modes: ItemLocalMap(),
pat_adjustments: ItemLocalMap(),
Expand Down Expand Up @@ -561,6 +574,18 @@ impl<'tcx> TypeckTables<'tcx> {
self.node_substs.get(&id.local_id).cloned()
}

pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<CanonicalSubsts<'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>> {
validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
self.user_substs.get(&id.local_id).cloned()
}

// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> {
Expand Down Expand Up @@ -740,6 +765,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
ref user_provided_tys,
ref node_types,
ref node_substs,
ref user_substs,
ref adjustments,
ref pat_binding_modes,
ref pat_adjustments,
Expand All @@ -762,6 +788,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
user_provided_tys.hash_stable(hcx, hasher);
node_types.hash_stable(hcx, hasher);
node_substs.hash_stable(hcx, hasher);
user_substs.hash_stable(hcx, hasher);
adjustments.hash_stable(hcx, hasher);
pat_binding_modes.hash_stable(hcx, hasher);
pat_adjustments.hash_stable(hcx, hasher);
Expand Down
31 changes: 30 additions & 1 deletion src/librustc/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
// Type substitutions.

use hir::def_id::DefId;
use ty::{self, Lift, List, Ty, TyCtxt};
use infer::canonical::Canonical;
use ty::{self, CanonicalVar, Lift, List, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};

use serialize::{self, Encodable, Encoder, Decodable, Decoder};
use syntax_pos::{Span, DUMMY_SP};
use rustc_data_structures::accumulate_vec::AccumulateVec;
use rustc_data_structures::array_vec::ArrayVec;
use rustc_data_structures::indexed_vec::Idx;

use core::intrinsics;
use std::cmp::Ordering;
Expand Down Expand Up @@ -339,6 +341,33 @@ 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> {}

///////////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl FunctionCx<'a, 'll, 'tcx> {

mir::Rvalue::Aggregate(ref kind, ref operands) => {
let (dest, active_field_index) = match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
dest.codegen_set_discr(&bx, variant_index);
if adt_def.is_enum() {
(dest.project_downcast(&bx, variant_index), active_field_index)
Expand Down
Loading