Skip to content

Commit 7d018a2

Browse files
committed
thread the closure-kind through in the closure substs
Similar to how freshen handled things, but "always happening"; we can thus remove the corresponding code from `freshen`.
1 parent 0391ab3 commit 7d018a2

File tree

8 files changed

+122
-28
lines changed

8 files changed

+122
-28
lines changed

src/librustc/infer/freshen.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -253,22 +253,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
253253
self.freshen_closure_like(
254254
def_id, substs, t,
255255
|this| {
256-
// HACK: use a "random" integer type to mark the kind. Because
257-
// different closure kinds shouldn't get unified during
258-
// selection, the "subtyping" relationship (where any kind is
259-
// better than no kind) shouldn't matter here, just that the
260-
// types are different.
261-
let closure_kind = this.infcx.closure_kind(def_id);
262-
let closure_kind_marker = match closure_kind {
263-
None => tcx.types.i8,
264-
Some(ty::ClosureKind::Fn) => tcx.types.i16,
265-
Some(ty::ClosureKind::FnMut) => tcx.types.i32,
266-
Some(ty::ClosureKind::FnOnce) => tcx.types.i64,
267-
};
268-
269256
let closure_sig = this.infcx.fn_sig(def_id);
270-
(tcx.mk_fn_ptr(closure_sig.fold_with(this)),
271-
closure_kind_marker)
257+
(tcx.mk_fn_ptr(closure_sig.fold_with(this)), tcx.types.char)
272258
},
273259
|substs| tcx.mk_closure(def_id, substs)
274260
)

src/librustc/infer/type_variable.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ pub enum TypeVariableOrigin {
5656
NormalizeProjectionType(Span),
5757
TypeInference(Span),
5858
TypeParameterDefinition(Span, ast::Name),
59-
TransformedUpvar(Span),
59+
60+
/// one of the upvars or closure kind parameters in a `ClosureSubsts`
61+
/// (before it has been determined)
62+
ClosureSynthetic(Span),
6063
SubstitutionPlaceholder(Span),
6164
AutoDeref(Span),
6265
AdjustmentType(Span),

src/librustc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#![feature(slice_patterns)]
5757
#![feature(specialization)]
5858
#![feature(unboxed_closures)]
59+
#![feature(underscore_lifetimes)]
5960
#![feature(trace_macros)]
6061
#![feature(test)]
6162
#![feature(const_atomic_bool_new)]

src/librustc/ty/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,16 @@ impl<'a, 'tcx> ClosureKind {
19271927
_ => false,
19281928
}
19291929
}
1930+
1931+
/// Returns the representative scalar type for this closure kind.
1932+
/// See `TyS::to_opt_closure_kind` for more details.
1933+
pub fn to_ty(self, tcx: TyCtxt<'_, '_, 'tcx>) -> Ty<'tcx> {
1934+
match self {
1935+
ty::ClosureKind::Fn => tcx.types.i8,
1936+
ty::ClosureKind::FnMut => tcx.types.i16,
1937+
ty::ClosureKind::FnOnce => tcx.types.i32,
1938+
}
1939+
}
19301940
}
19311941

19321942
impl<'tcx> TyS<'tcx> {

src/librustc/ty/sty.rs

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,22 @@ pub enum TypeVariants<'tcx> {
173173

174174
/// A closure can be modeled as a struct that looks like:
175175
///
176-
/// struct Closure<'l0...'li, T0...Tj, U0...Uk> {
176+
/// struct Closure<'l0...'li, T0...Tj, CK, U0...Uk> {
177177
/// upvar0: U0,
178178
/// ...
179179
/// upvark: Uk
180180
/// }
181181
///
182-
/// where 'l0...'li and T0...Tj are the lifetime and type parameters
183-
/// in scope on the function that defined the closure, and U0...Uk are
184-
/// type parameters representing the types of its upvars (borrowed, if
185-
/// appropriate).
182+
/// where:
183+
///
184+
/// - 'l0...'li and T0...Tj are the lifetime and type parameters
185+
/// in scope on the function that defined the closure,
186+
/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
187+
/// is rather hackily encoded via a scalar type. See
188+
/// `TyS::to_opt_closure_kind` for details.
189+
/// - U0...Uk are type parameters representing the types of its upvars
190+
/// (borrowed, if appropriate; that is, if Ui represents a by-ref upvar,
191+
/// and the up-var has the type `Foo`, then `Ui = &Foo`).
186192
///
187193
/// So, for example, given this function:
188194
///
@@ -255,14 +261,54 @@ pub struct ClosureSubsts<'tcx> {
255261
pub substs: &'tcx Substs<'tcx>,
256262
}
257263

258-
impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
264+
/// Struct returned by `split()`. Note that these are subslices of the
265+
/// parent slice and not canonical substs themselves.
266+
struct SplitClosureSubsts<'tcx> {
267+
closure_kind_ty: Ty<'tcx>,
268+
upvar_kinds: &'tcx [Kind<'tcx>],
269+
}
270+
271+
impl<'tcx> ClosureSubsts<'tcx> {
272+
/// Divides the closure substs into their respective
273+
/// components. Single source of truth with respect to the
274+
/// ordering.
275+
fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitClosureSubsts<'tcx> {
276+
let generics = tcx.generics_of(def_id);
277+
let parent_len = generics.parent_count();
278+
SplitClosureSubsts {
279+
closure_kind_ty: self.substs[parent_len].as_type().expect("closure-kind should be type"),
280+
upvar_kinds: &self.substs[parent_len + 1..],
281+
}
282+
}
283+
259284
#[inline]
260-
pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) ->
285+
pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) ->
261286
impl Iterator<Item=Ty<'tcx>> + 'tcx
262287
{
263-
let generics = tcx.generics_of(def_id);
264-
self.substs[self.substs.len()-generics.own_count()..].iter().map(
265-
|t| t.as_type().expect("unexpected region in upvars"))
288+
let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
289+
upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
290+
}
291+
292+
/// Returns the closure kind for this closure; may return `None`
293+
/// if inference has not yet completed.
294+
pub fn opt_closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>)
295+
-> Option<ty::ClosureKind> {
296+
let closure_kind_ty = self.closure_kind_ty(def_id, tcx);
297+
closure_kind_ty.to_opt_closure_kind()
298+
}
299+
300+
/// Returns the closure kind for this closure; may return `None`
301+
/// if inference has not yet completed.
302+
pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
303+
self.split(def_id, tcx).closure_kind_ty
304+
}
305+
}
306+
307+
impl<'tcx> ClosureSubsts<'tcx> {
308+
/// Returns the closure kind for this closure; only usable outside
309+
/// of an inference context.
310+
pub fn closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::ClosureKind {
311+
self.opt_closure_kind(def_id, tcx).unwrap()
266312
}
267313
}
268314

@@ -1400,6 +1446,35 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
14001446
}
14011447
}
14021448
}
1449+
1450+
/// When we create a closure, we record its kind (i.e., what trait
1451+
/// it implements) into its `ClosureSubsts` using a type
1452+
/// parameter. This is kind of a phantom type, except that the
1453+
/// most convenient thing for us to are the integral types. This
1454+
/// function converts such a special type into the closure
1455+
/// kind. To go the other way, use
1456+
/// `tcx.closure_kind_ty(closure_kind)`.
1457+
///
1458+
/// Note that during type checking, we use an inference variable
1459+
/// to represent the closure kind, because it has not yet been
1460+
/// inferred. Once [upvar inference] is complete, that type varibale
1461+
/// will be unified.
1462+
///
1463+
/// [upvar inference]: src/librustc_typeck/check/upvar.rs
1464+
pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
1465+
match self.sty {
1466+
TyInt(int_ty) => match int_ty {
1467+
ast::IntTy::I8 => Some(ty::ClosureKind::Fn),
1468+
ast::IntTy::I16 => Some(ty::ClosureKind::FnMut),
1469+
ast::IntTy::I32 => Some(ty::ClosureKind::FnOnce),
1470+
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
1471+
},
1472+
1473+
TyInfer(_) => None,
1474+
1475+
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
1476+
}
1477+
}
14031478
}
14041479

14051480
/// Typed constant value.

src/librustc_typeck/check/closure.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
100100
|_, _| span_bug!(expr.span, "closure has region param"),
101101
|_, _| {
102102
self.infcx
103-
.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
103+
.next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
104104
},
105105
);
106106
let closure_type = self.tcx.mk_closure(expr_def_id, substs);

src/librustc_typeck/check/upvar.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use middle::expr_use_visitor as euv;
4646
use middle::mem_categorization as mc;
4747
use middle::mem_categorization::Categorization;
4848
use rustc::ty::{self, Ty, TyCtxt};
49+
use rustc::ty::TypeFoldable;
4950
use rustc::infer::UpvarRegion;
5051
use syntax::ast;
5152
use syntax_pos::Span;
@@ -213,6 +214,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
213214
}
214215
};
215216

217+
// Equate the type variable representing the closure kind.
218+
let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx);
219+
if closure_kind_ty.needs_infer() {
220+
let final_closure_kind = self.tables.borrow().closure_kinds()[closure_hir_id].0;
221+
self.demand_eqtype(span, final_closure_kind.to_ty(self.tcx), closure_kind_ty);
222+
}
223+
216224
// Equate the type variables with the actual types.
217225
let final_upvar_tys = self.final_upvar_tys(closure_node_id);
218226
debug!(

src/librustc_typeck/collect.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,8 +987,19 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
987987
// cares about anything but the length is instantiation,
988988
// and we don't do that for closures.
989989
if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
990+
// add a dummy parameter for the closure kind
991+
types.push(ty::TypeParameterDef {
992+
index: type_start as u32,
993+
name: Symbol::intern("<closure_kind>"),
994+
def_id,
995+
has_default: false,
996+
object_lifetime_default: rl::Set1::Empty,
997+
pure_wrt_drop: false,
998+
synthetic: None,
999+
});
1000+
9901001
tcx.with_freevars(node_id, |fv| {
991-
types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
1002+
types.extend(fv.iter().zip(1..).map(|(_, i)| ty::TypeParameterDef {
9921003
index: type_start + i as u32,
9931004
name: Symbol::intern("<upvar>"),
9941005
def_id,

0 commit comments

Comments
 (0)