Auto merge of #45879 - nikomatsakis:nll-kill-cyclic-closures, r=arielb1

move closure kind, signature into `ClosureSubsts`

Instead of using side-tables, store the closure-kind and signature in the substitutions themselves. This has two key effects:

- It means that the closure's type changes as inference finds out more things, which is very nice.
    - As a result, it avoids the need for the `freshen_closure_like` code (though we still use it for generators).
- It avoids cyclic closures calls.
    - These were never meant to be supported, precisely because they make a lot of the fancy inference that we do much more complicated. However, due to an oversight, it was previously possible -- if challenging -- to create a setup where a closure *directly* called itself (see e.g. #21410).

We have to see what the effect of this change is, though. Needs a crater run. Marking as [WIP] until that has been assessed.

r? @arielb1
This commit is contained in:
bors 2017-11-21 22:52:19 +00:00
commit d6d09e0b4d
55 changed files with 994 additions and 773 deletions

View File

@ -498,9 +498,7 @@ define_dep_nodes!( <'tcx>
[] IsAutoImpl(DefId), [] IsAutoImpl(DefId),
[] ImplTraitRef(DefId), [] ImplTraitRef(DefId),
[] ImplPolarity(DefId), [] ImplPolarity(DefId),
[] ClosureKind(DefId),
[] FnSignature(DefId), [] FnSignature(DefId),
[] GenSignature(DefId),
[] CoerceUnsizedInfo(DefId), [] CoerceUnsizedInfo(DefId),
[] ItemVarianceConstraints(DefId), [] ItemVarianceConstraints(DefId),

View File

@ -1969,8 +1969,39 @@ fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
``` ```
"##, "##,
E0644: r##"
A closure or generator was constructed that references its own type.
Erroneous example:
```compile-fail,E0644
fn fix<F>(f: &F)
where F: Fn(&F)
{
f(&f);
} }
fn main() {
fix(&|y| {
// Here, when `x` is called, the parameter `y` is equal to `x`.
});
}
```
Rust does not permit a closure to directly reference its own type,
either through an argument (as in the example above) or by capturing
itself through its environment. This restriction helps keep closure
inference tractable.
The easiest fix is to rewrite your closure into a top-level function,
or into a method. In some cases, you may also be able to have your
closure call itself by capturing a `&Fn()` object or `fn()` pointer
that refers to itself. That is permitting, since the closure would be
invoking itself via a virtual call, and hence does not directly
reference its own *type*.
"##, }
register_diagnostics! { register_diagnostics! {
// E0006 // merged with E0005 // E0006 // merged with E0005

View File

@ -236,8 +236,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
ty::Predicate::ObjectSafe(def_id) => { ty::Predicate::ObjectSafe(def_id) => {
def_id.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher);
} }
ty::Predicate::ClosureKind(def_id, closure_kind) => { ty::Predicate::ClosureKind(def_id, closure_substs, closure_kind) => {
def_id.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher);
closure_substs.hash_stable(hcx, hasher);
closure_kind.hash_stable(hcx, hasher); closure_kind.hash_stable(hcx, hasher);
} }
ty::Predicate::ConstEvaluatable(def_id, substs) => { ty::Predicate::ConstEvaluatable(def_id, substs) => {

View File

@ -270,6 +270,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
ambient_variance, ambient_variance,
needs_wf: false, needs_wf: false,
root_ty: ty,
}; };
let ty = generalize.relate(&ty, &ty)?; let ty = generalize.relate(&ty, &ty)?;
@ -280,10 +281,23 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
/// Span, used when creating new type variables and things.
span: Span, span: Span,
/// The vid of the type variable that is in the process of being
/// instantiated; if we find this within the type we are folding,
/// that means we would have created a cyclic type.
for_vid_sub_root: ty::TyVid, for_vid_sub_root: ty::TyVid,
/// Track the variance as we descend into the type.
ambient_variance: ty::Variance, ambient_variance: ty::Variance,
needs_wf: bool, // see the field `needs_wf` in `Generalization`
/// See the field `needs_wf` in `Generalization`.
needs_wf: bool,
/// The root type that we are generalizing. Used when reporting cycles.
root_ty: Ty<'tcx>,
} }
/// Result from a generalization operation. This includes /// Result from a generalization operation. This includes
@ -386,7 +400,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
if sub_vid == self.for_vid_sub_root { if sub_vid == self.for_vid_sub_root {
// If sub-roots are equal, then `for_vid` and // If sub-roots are equal, then `for_vid` and
// `vid` are related via subtyping. // `vid` are related via subtyping.
return Err(TypeError::CyclicTy); return Err(TypeError::CyclicTy(self.root_ty));
} else { } else {
match variables.probe_root(vid) { match variables.probe_root(vid) {
Some(u) => { Some(u) => {

View File

@ -689,9 +689,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
diag: &mut DiagnosticBuilder<'tcx>, diag: &mut DiagnosticBuilder<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
secondary_span: Option<(Span, String)>, secondary_span: Option<(Span, String)>,
values: Option<ValuePairs<'tcx>>, mut values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>) terr: &TypeError<'tcx>)
{ {
// For some types of errors, expected-found does not make
// sense, so just ignore the values we were given.
match terr {
TypeError::CyclicTy(_) => { values = None; }
_ => { }
}
let (expected_found, exp_found, is_simple_error) = match values { let (expected_found, exp_found, is_simple_error) = match values {
None => (None, None, false), None => (None, None, false),
Some(values) => { Some(values) => {
@ -780,17 +787,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
terr); terr);
let span = trace.cause.span; let span = trace.cause.span;
let failure_str = trace.cause.as_failure_str(); let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match trace.cause.code { let mut diag = match failure_code {
ObligationCauseCode::IfExpressionWithNoElse => { FailureCode::Error0317(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
} }
ObligationCauseCode::MainFunctionType => { FailureCode::Error0580(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
} }
_ => { FailureCode::Error0308(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
} }
FailureCode::Error0644(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
}
}; };
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
diag diag
@ -1040,23 +1050,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
} }
enum FailureCode {
Error0317(&'static str),
Error0580(&'static str),
Error0308(&'static str),
Error0644(&'static str),
}
impl<'tcx> ObligationCause<'tcx> { impl<'tcx> ObligationCause<'tcx> {
fn as_failure_str(&self) -> &'static str { fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
use self::FailureCode::*;
use traits::ObligationCauseCode::*; use traits::ObligationCauseCode::*;
match self.code { match self.code {
CompareImplMethodObligation { .. } => "method not compatible with trait", CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
MatchExpressionArm { source, .. } => match source { MatchExpressionArm { source, .. } => Error0308(match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
_ => "match arms have incompatible types", _ => "match arms have incompatible types",
}, }),
IfExpression => "if and else have incompatible types", IfExpression => Error0308("if and else have incompatible types"),
IfExpressionWithNoElse => "if may be missing an else clause", IfExpressionWithNoElse => Error0317("if may be missing an else clause"),
EquatePredicate => "equality predicate not satisfied", EquatePredicate => Error0308("equality predicate not satisfied"),
MainFunctionType => "main function has wrong type", MainFunctionType => Error0580("main function has wrong type"),
StartFunctionType => "start function has wrong type", StartFunctionType => Error0308("start function has wrong type"),
IntrinsicType => "intrinsic has wrong type", IntrinsicType => Error0308("intrinsic has wrong type"),
MethodReceiver => "mismatched method receiver", MethodReceiver => Error0308("mismatched method receiver"),
_ => "mismatched types",
// In the case where we have no more specific thing to
// say, also take a look at the error code, maybe we can
// tailor to that.
_ => match terr {
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() =>
Error0644("closure/generator type that references itself"),
_ =>
Error0308("mismatched types"),
}
} }
} }

View File

@ -125,9 +125,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// ``` // ```
labels.clear(); labels.clear();
labels.push((pattern.span, format!("consider giving this closure parameter a type"))); labels.push((pattern.span, format!("consider giving this closure parameter a type")));
} } else if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_name) = pattern.simple_name() { if let Some(simple_name) = pattern.simple_name() {
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
} else { } else {

View File

@ -43,9 +43,7 @@
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeFolder; use ty::fold::TypeFolder;
use ty::subst::Substs;
use util::nodemap::FxHashMap; use util::nodemap::FxHashMap;
use hir::def_id::DefId;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -56,7 +54,6 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
freshen_count: u32, freshen_count: u32,
freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>, freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
closure_set: Vec<DefId>,
} }
impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
@ -66,7 +63,6 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
infcx, infcx,
freshen_count: 0, freshen_count: 0,
freshen_map: FxHashMap(), freshen_map: FxHashMap(),
closure_set: vec![],
} }
} }
@ -92,88 +88,6 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
} }
} }
} }
fn next_fresh<F>(&mut self,
freshener: F)
-> Ty<'tcx>
where F: FnOnce(u32) -> ty::InferTy,
{
let index = self.freshen_count;
self.freshen_count += 1;
self.infcx.tcx.mk_infer(freshener(index))
}
fn freshen_closure_like<M, C>(&mut self,
def_id: DefId,
substs: ty::ClosureSubsts<'tcx>,
t: Ty<'tcx>,
markers: M,
combine: C)
-> Ty<'tcx>
where M: FnOnce(&mut Self) -> (Ty<'tcx>, Ty<'tcx>),
C: FnOnce(&'tcx Substs<'tcx>) -> Ty<'tcx>
{
let tcx = self.infcx.tcx;
let closure_in_progress = self.infcx.in_progress_tables.map_or(false, |tables| {
tcx.hir.as_local_node_id(def_id).map_or(false, |closure_id| {
tables.borrow().local_id_root ==
Some(DefId::local(tcx.hir.node_to_hir_id(closure_id).owner))
})
});
if !closure_in_progress {
// If this closure belongs to another infcx, its kind etc. were
// fully inferred and its signature/kind are exactly what's listed
// in its infcx. So we don't need to add the markers for them.
return t.super_fold_with(self);
}
// We are encoding a closure in progress. Because we want our freshening
// key to contain all inference information needed to make sense of our
// value, we need to encode the closure signature and kind. The way
// we do that is to add them as 2 variables to the closure substs,
// basically because it's there (and nobody cares about adding extra stuff
// to substs).
//
// This means the "freshened" closure substs ends up looking like
// fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
let (marker_1, marker_2) = if self.closure_set.contains(&def_id) {
// We found the closure def-id within its own signature. Just
// leave a new freshened type - any matching operations would
// have found and compared the exterior closure already to
// get here.
//
// In that case, we already know what the signature would
// be - the parent closure on the stack already contains a
// "copy" of the signature, so there is no reason to encode
// it again for injectivity. Just use a fresh type variable
// to make everything comparable.
//
// For example (closure kinds omitted for clarity)
// t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
// Would get encoded to
// t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
//
// and we can decode by having
// $0=[closure BAR {sig doesn't exist in decode}]
// and get
// t=[closure FOO]
// sig[FOO] = [closure BAR]
// sig[BAR] = [closure FOO]
(self.next_fresh(ty::FreshTy), self.next_fresh(ty::FreshTy))
} else {
self.closure_set.push(def_id);
let markers = markers(self);
self.closure_set.pop();
markers
};
combine(tcx.mk_substs(
substs.substs.iter().map(|k| k.fold_with(self)).chain(
[marker_1, marker_2].iter().cloned().map(From::from)
)))
}
} }
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
@ -249,51 +163,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
t t
} }
ty::TyClosure(def_id, substs) => { ty::TyGenerator(..) |
self.freshen_closure_like(
def_id, substs, t,
|this| {
// HACK: use a "random" integer type to mark the kind. Because
// different closure kinds shouldn't get unified during
// selection, the "subtyping" relationship (where any kind is
// better than no kind) shouldn't matter here, just that the
// types are different.
let closure_kind = this.infcx.closure_kind(def_id);
let closure_kind_marker = match closure_kind {
None => tcx.types.i8,
Some(ty::ClosureKind::Fn) => tcx.types.i16,
Some(ty::ClosureKind::FnMut) => tcx.types.i32,
Some(ty::ClosureKind::FnOnce) => tcx.types.i64,
};
let closure_sig = this.infcx.fn_sig(def_id);
(tcx.mk_fn_ptr(closure_sig.fold_with(this)),
closure_kind_marker)
},
|substs| tcx.mk_closure(def_id, substs)
)
}
ty::TyGenerator(def_id, substs, interior) => {
self.freshen_closure_like(
def_id, substs, t,
|this| {
let gen_sig = this.infcx.generator_sig(def_id).unwrap();
// FIXME: want to revise this strategy when generator
// signatures can actually contain LBRs.
let sig = this.tcx().no_late_bound_regions(&gen_sig)
.unwrap_or_else(|| {
bug!("late-bound regions in signature of {:?}",
def_id)
});
(sig.yield_ty, sig.return_ty).fold_with(this)
},
|substs| {
tcx.mk_generator(def_id, ty::ClosureSubsts { substs }, interior)
}
)
}
ty::TyBool | ty::TyBool |
ty::TyChar | ty::TyChar |
ty::TyInt(..) | ty::TyInt(..) |
@ -314,6 +184,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyProjection(..) | ty::TyProjection(..) |
ty::TyForeign(..) | ty::TyForeign(..) |
ty::TyParam(..) | ty::TyParam(..) |
ty::TyClosure(..) |
ty::TyAnon(..) => { ty::TyAnon(..) => {
t.super_fold_with(self) t.super_fold_with(self)
} }

View File

@ -1463,26 +1463,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span) !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
} }
/// Obtains the latest type of the given closure; this may be a
/// closure in the current function, in which case its
/// `ClosureKind` may not yet be known.
pub fn closure_kind(&self, pub fn closure_kind(&self,
def_id: DefId) closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>)
-> Option<ty::ClosureKind> -> Option<ty::ClosureKind>
{ {
if let Some(tables) = self.in_progress_tables { let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
let hir_id = self.tcx.hir.node_to_hir_id(id); closure_kind_ty.to_opt_closure_kind()
return tables.borrow()
.closure_kinds()
.get(hir_id)
.cloned()
.map(|(kind, _)| kind);
}
}
// During typeck, ALL closures are local. But afterwards,
// during trans, we see closure ids from other traits.
// That may require loading the closure data out of the
// cstore.
Some(self.tcx.closure_kind(def_id))
} }
/// Obtain the signature of a function or closure. /// Obtain the signature of a function or closure.
@ -1490,11 +1481,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// work during the type-checking of the enclosing function and /// work during the type-checking of the enclosing function and
/// return the closure signature in its partially inferred state. /// return the closure signature in its partially inferred state.
pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
// Do we have an in-progress set of tables we are inferring?
if let Some(tables) = self.in_progress_tables { if let Some(tables) = self.in_progress_tables {
// Is this a local item?
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
// Is it a local *closure*?
if self.tcx.is_closure(def_id) {
let hir_id = self.tcx.hir.node_to_hir_id(id); let hir_id = self.tcx.hir.node_to_hir_id(id);
if let Some(&ty) = tables.borrow().closure_tys().get(hir_id) { // Is this local closure contained within the tables we are inferring?
return ty; if tables.borrow().local_id_root == Some(DefId::local(hir_id.owner)) {
// if so, extract signature from there.
let closure_ty = tables.borrow().node_id_to_type(hir_id);
let (closure_def_id, closure_substs) = match closure_ty.sty {
ty::TyClosure(closure_def_id, closure_substs) =>
(closure_def_id, closure_substs),
_ =>
bug!("closure with non-closure type: {:?}", closure_ty),
};
assert_eq!(def_id, closure_def_id);
let closure_sig_ty = closure_substs.closure_sig_ty(def_id, self.tcx);
let closure_sig_ty = self.shallow_resolve(&closure_sig_ty);
return closure_sig_ty.fn_sig(self.tcx);
}
} }
} }
} }
@ -1502,19 +1510,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.fn_sig(def_id) self.tcx.fn_sig(def_id)
} }
pub fn generator_sig(&self, def_id: DefId) -> Option<ty::PolyGenSig<'tcx>> {
if let Some(tables) = self.in_progress_tables {
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
let hir_id = self.tcx.hir.node_to_hir_id(id);
if let Some(&ty) = tables.borrow().generator_sigs().get(hir_id) {
return ty.map(|t| ty::Binder(t));
}
}
}
self.tcx.generator_sig(def_id)
}
/// Normalizes associated types in `value`, potentially returning /// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed. /// new obligations that must further be processed.
pub fn partially_normalize_associated_types_in<T>(&self, pub fn partially_normalize_associated_types_in<T>(&self,

View File

@ -56,7 +56,10 @@ pub enum TypeVariableOrigin {
NormalizeProjectionType(Span), NormalizeProjectionType(Span),
TypeInference(Span), TypeInference(Span),
TypeParameterDefinition(Span, ast::Name), TypeParameterDefinition(Span, ast::Name),
TransformedUpvar(Span),
/// one of the upvars or closure kind parameters in a `ClosureSubsts`
/// (before it has been determined)
ClosureSynthetic(Span),
SubstitutionPlaceholder(Span), SubstitutionPlaceholder(Span),
AutoDeref(Span), AutoDeref(Span),
AdjustmentType(Span), AdjustmentType(Span),

View File

@ -750,10 +750,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
let kind = match self.node_ty(fn_hir_id)?.sty { let kind = match self.node_ty(fn_hir_id)?.sty {
ty::TyGenerator(..) => ty::ClosureKind::FnOnce, ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
ty::TyClosure(..) => { ty::TyClosure(closure_def_id, closure_substs) => {
match self.tables.closure_kinds().get(fn_hir_id) { match self.infcx {
Some(&(kind, _)) => kind, // During upvar inference we may not know the
None => span_bug!(span, "missing closure kind"), // closure kind, just use the LATTICE_BOTTOM value.
Some(infcx) =>
infcx.closure_kind(closure_def_id, closure_substs)
.unwrap_or(ty::ClosureKind::LATTICE_BOTTOM),
None =>
self.tcx.global_tcx()
.lift(&closure_substs)
.expect("no inference cx, but inference variables in closure ty")
.closure_kind(closure_def_id, self.tcx.global_tcx()),
} }
} }
ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t), ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),

View File

@ -643,8 +643,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
violations) violations)
} }
ty::Predicate::ClosureKind(closure_def_id, kind) => { ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
let found_kind = self.closure_kind(closure_def_id).unwrap(); let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap(); let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
let mut err = struct_span_err!( let mut err = struct_span_err!(
@ -663,14 +663,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
if let Some(tables) = self.in_progress_tables { if let Some(tables) = self.in_progress_tables {
let tables = tables.borrow(); let tables = tables.borrow();
let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id); let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id);
match tables.closure_kinds().get(closure_hir_id) { match (found_kind, tables.closure_kind_origins().get(closure_hir_id)) {
Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => { (ty::ClosureKind::FnOnce, Some((span, name))) => {
err.span_note(span, &format!( err.span_note(*span, &format!(
"closure is `FnOnce` because it moves the \ "closure is `FnOnce` because it moves the \
variable `{}` out of its environment", name)); variable `{}` out of its environment", name));
}, },
Some(&(ty::ClosureKind::FnMut, Some((span, name)))) => { (ty::ClosureKind::FnMut, Some((span, name))) => {
err.span_note(span, &format!( err.span_note(*span, &format!(
"closure is `FnMut` because it mutates the \ "closure is `FnMut` because it mutates the \
variable `{}` here", name)); variable `{}` here", name));
}, },

View File

@ -438,8 +438,8 @@ fn process_predicate<'a, 'gcx, 'tcx>(
} }
} }
ty::Predicate::ClosureKind(closure_def_id, kind) => { ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
match selcx.infcx().closure_kind(closure_def_id) { match selcx.infcx().closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => { Some(closure_kind) => {
if closure_kind.extends(kind) { if closure_kind.extends(kind) {
Ok(Some(vec![])) Ok(Some(vec![]))

View File

@ -1264,8 +1264,7 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>(
vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>) vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>)
-> Progress<'tcx> -> Progress<'tcx>
{ {
let gen_sig = selcx.infcx().generator_sig(vtable.closure_def_id).unwrap() let gen_sig = vtable.substs.generator_poly_sig(vtable.closure_def_id, selcx.tcx());
.subst(selcx.tcx(), vtable.substs.substs);
let Normalized { let Normalized {
value: gen_sig, value: gen_sig,
obligations obligations

View File

@ -718,8 +718,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
} }
} }
ty::Predicate::ClosureKind(closure_def_id, kind) => { ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
match self.infcx.closure_kind(closure_def_id) { match self.infcx.closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => { Some(closure_kind) => {
if closure_kind.extends(kind) { if closure_kind.extends(kind) {
EvaluatedToOk EvaluatedToOk
@ -1593,10 +1593,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// touch bound regions, they just capture the in-scope // touch bound regions, they just capture the in-scope
// type/region parameters // type/region parameters
match obligation.self_ty().skip_binder().sty { match obligation.self_ty().skip_binder().sty {
ty::TyClosure(closure_def_id, _) => { ty::TyClosure(closure_def_id, closure_substs) => {
debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}",
kind, obligation); kind, obligation);
match self.infcx.closure_kind(closure_def_id) { match self.infcx.closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => { Some(closure_kind) => {
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
if closure_kind.extends(kind) { if closure_kind.extends(kind) {
@ -2726,7 +2726,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
obligations.push(Obligation::new( obligations.push(Obligation::new(
obligation.cause.clone(), obligation.cause.clone(),
obligation.param_env, obligation.param_env,
ty::Predicate::ClosureKind(closure_def_id, kind))); ty::Predicate::ClosureKind(closure_def_id, substs, kind)));
Ok(VtableClosureData { Ok(VtableClosureData {
closure_def_id, closure_def_id,
@ -3184,8 +3184,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
substs: ty::ClosureSubsts<'tcx>) substs: ty::ClosureSubsts<'tcx>)
-> ty::PolyTraitRef<'tcx> -> ty::PolyTraitRef<'tcx>
{ {
let gen_sig = self.infcx.generator_sig(closure_def_id).unwrap() let gen_sig = substs.generator_poly_sig(closure_def_id, self.tcx());
.subst(self.tcx(), substs.substs);
let ty::Binder((trait_ref, ..)) = let ty::Binder((trait_ref, ..)) =
self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(), self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(),
obligation.predicate.0.self_ty(), // (1) obligation.predicate.0.self_ty(), // (1)

View File

@ -43,8 +43,8 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data) =>
ty::Predicate::ObjectSafe(data), ty::Predicate::ObjectSafe(data),
ty::Predicate::ClosureKind(closure_def_id, kind) => ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) =>
ty::Predicate::ClosureKind(closure_def_id, kind), ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind),
ty::Predicate::Subtype(ref data) => ty::Predicate::Subtype(ref data) =>
ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)),

View File

@ -356,16 +356,9 @@ pub struct TypeckTables<'tcx> {
/// Borrows /// Borrows
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
/// Records the type of each closure. /// Records the reasons that we picked the kind of each closure;
closure_tys: ItemLocalMap<ty::PolyFnSig<'tcx>>, /// not all closures are present in the map.
closure_kind_origins: ItemLocalMap<(Span, ast::Name)>,
/// Records the kind of each closure and the span and name of the variable
/// that caused the closure to be this kind.
closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
generator_sigs: ItemLocalMap<Option<ty::GenSig<'tcx>>>,
generator_interiors: ItemLocalMap<ty::GeneratorInterior<'tcx>>,
/// For each fn, records the "liberated" types of its arguments /// For each fn, records the "liberated" types of its arguments
/// and return type. Liberated means that all bound regions /// and return type. Liberated means that all bound regions
@ -411,10 +404,7 @@ impl<'tcx> TypeckTables<'tcx> {
pat_binding_modes: ItemLocalMap(), pat_binding_modes: ItemLocalMap(),
pat_adjustments: ItemLocalMap(), pat_adjustments: ItemLocalMap(),
upvar_capture_map: FxHashMap(), upvar_capture_map: FxHashMap(),
generator_sigs: ItemLocalMap(), closure_kind_origins: ItemLocalMap(),
generator_interiors: ItemLocalMap(),
closure_tys: ItemLocalMap(),
closure_kinds: ItemLocalMap(),
liberated_fn_sigs: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(),
fru_field_types: ItemLocalMap(), fru_field_types: ItemLocalMap(),
cast_kinds: ItemLocalMap(), cast_kinds: ItemLocalMap(),
@ -609,34 +599,17 @@ impl<'tcx> TypeckTables<'tcx> {
self.upvar_capture_map[&upvar_id] self.upvar_capture_map[&upvar_id]
} }
pub fn closure_tys(&self) -> LocalTableInContext<ty::PolyFnSig<'tcx>> { pub fn closure_kind_origins(&self) -> LocalTableInContext<(Span, ast::Name)> {
LocalTableInContext { LocalTableInContext {
local_id_root: self.local_id_root, local_id_root: self.local_id_root,
data: &self.closure_tys data: &self.closure_kind_origins
} }
} }
pub fn closure_tys_mut(&mut self) pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<(Span, ast::Name)> {
-> LocalTableInContextMut<ty::PolyFnSig<'tcx>> {
LocalTableInContextMut { LocalTableInContextMut {
local_id_root: self.local_id_root, local_id_root: self.local_id_root,
data: &mut self.closure_tys data: &mut self.closure_kind_origins
}
}
pub fn closure_kinds(&self) -> LocalTableInContext<(ty::ClosureKind,
Option<(Span, ast::Name)>)> {
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.closure_kinds
}
}
pub fn closure_kinds_mut(&mut self)
-> LocalTableInContextMut<(ty::ClosureKind, Option<(Span, ast::Name)>)> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.closure_kinds
} }
} }
@ -681,42 +654,6 @@ impl<'tcx> TypeckTables<'tcx> {
data: &mut self.cast_kinds data: &mut self.cast_kinds
} }
} }
pub fn generator_sigs(&self)
-> LocalTableInContext<Option<ty::GenSig<'tcx>>>
{
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.generator_sigs,
}
}
pub fn generator_sigs_mut(&mut self)
-> LocalTableInContextMut<Option<ty::GenSig<'tcx>>>
{
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.generator_sigs,
}
}
pub fn generator_interiors(&self)
-> LocalTableInContext<ty::GeneratorInterior<'tcx>>
{
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.generator_interiors,
}
}
pub fn generator_interiors_mut(&mut self)
-> LocalTableInContextMut<ty::GeneratorInterior<'tcx>>
{
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.generator_interiors,
}
}
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> { impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
@ -732,8 +669,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
ref pat_binding_modes, ref pat_binding_modes,
ref pat_adjustments, ref pat_adjustments,
ref upvar_capture_map, ref upvar_capture_map,
ref closure_tys, ref closure_kind_origins,
ref closure_kinds,
ref liberated_fn_sigs, ref liberated_fn_sigs,
ref fru_field_types, ref fru_field_types,
@ -742,8 +678,6 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
ref used_trait_imports, ref used_trait_imports,
tainted_by_errors, tainted_by_errors,
ref free_region_map, ref free_region_map,
ref generator_sigs,
ref generator_interiors,
} = *self; } = *self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
@ -775,13 +709,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
hcx.def_path_hash(closure_def_id)) hcx.def_path_hash(closure_def_id))
}); });
closure_tys.hash_stable(hcx, hasher); closure_kind_origins.hash_stable(hcx, hasher);
closure_kinds.hash_stable(hcx, hasher);
liberated_fn_sigs.hash_stable(hcx, hasher); liberated_fn_sigs.hash_stable(hcx, hasher);
fru_field_types.hash_stable(hcx, hasher); fru_field_types.hash_stable(hcx, hasher);
cast_kinds.hash_stable(hcx, hasher); cast_kinds.hash_stable(hcx, hasher);
generator_sigs.hash_stable(hcx, hasher);
generator_interiors.hash_stable(hcx, hasher);
used_trait_imports.hash_stable(hcx, hasher); used_trait_imports.hash_stable(hcx, hasher);
tainted_by_errors.hash_stable(hcx, hasher); tainted_by_errors.hash_stable(hcx, hasher);
free_region_map.hash_stable(hcx, hasher); free_region_map.hash_stable(hcx, hasher);
@ -1981,11 +1912,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn mk_closure(self, pub fn mk_closure(self,
closure_id: DefId, closure_id: DefId,
substs: &'tcx Substs<'tcx>) substs: ClosureSubsts<'tcx>)
-> Ty<'tcx> { -> Ty<'tcx> {
self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { self.mk_closure_from_closure_substs(closure_id, substs)
substs,
})
} }
pub fn mk_closure_from_closure_substs(self, pub fn mk_closure_from_closure_substs(self,

View File

@ -49,7 +49,11 @@ pub enum TypeError<'tcx> {
FloatMismatch(ExpectedFound<ast::FloatTy>), FloatMismatch(ExpectedFound<ast::FloatTy>),
Traits(ExpectedFound<DefId>), Traits(ExpectedFound<DefId>),
VariadicMismatch(ExpectedFound<bool>), VariadicMismatch(ExpectedFound<bool>),
CyclicTy,
/// Instantiating a type variable with the given type would have
/// created a cycle (because it appears somewhere within that
/// type).
CyclicTy(Ty<'tcx>),
ProjectionMismatched(ExpectedFound<DefId>), ProjectionMismatched(ExpectedFound<DefId>),
ProjectionBoundsLength(ExpectedFound<usize>), ProjectionBoundsLength(ExpectedFound<usize>),
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>), TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
@ -84,7 +88,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
} }
match *self { match *self {
CyclicTy => write!(f, "cyclic type of infinite size"), CyclicTy(_) => write!(f, "cyclic type of infinite size"),
Mismatch => write!(f, "types differ"), Mismatch => write!(f, "types differ"),
UnsafetyMismatch(values) => { UnsafetyMismatch(values) => {
write!(f, "expected {} fn, found {} fn", write!(f, "expected {} fn, found {} fn",
@ -304,6 +308,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.note_and_explain_type_err(db, &err, sp); self.note_and_explain_type_err(db, &err, sp);
} }
CyclicTy(ty) => {
// Watch out for various cases of cyclic types and try to explain.
if ty.is_closure() || ty.is_generator() {
db.note("closures cannot capture themselves or take themselves as argument;\n\
this error may be the result of a recent compiler bug-fix,\n\
see https://github.com/rust-lang/rust/issues/46062 for more details");
}
}
_ => {} _ => {}
} }
} }

View File

@ -189,7 +189,7 @@ fn resolve_closure<'a, 'tcx>(
requested_kind: ty::ClosureKind) requested_kind: ty::ClosureKind)
-> Instance<'tcx> -> Instance<'tcx>
{ {
let actual_kind = tcx.closure_kind(def_id); let actual_kind = substs.closure_kind(def_id, tcx);
match needs_fn_once_adapter_shim(actual_kind, requested_kind) { match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),

View File

@ -166,20 +166,12 @@ define_maps! { <'tcx>
/// for trans. This is also the only query that can fetch non-local MIR, at present. /// for trans. This is also the only query that can fetch non-local MIR, at present.
[] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>, [] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>,
/// Type of each closure. The def ID is the ID of the
/// expression defining the closure.
[] fn closure_kind: ClosureKind(DefId) -> ty::ClosureKind,
/// The result of unsafety-checking this def-id. /// The result of unsafety-checking this def-id.
[] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult,
/// The signature of functions and closures. /// The signature of functions and closures.
[] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, [] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>,
/// Records the signature of each generator. The def ID is the ID of the
/// expression defining the closure.
[] fn generator_sig: GenSignature(DefId) -> Option<ty::PolyGenSig<'tcx>>,
/// Caches CoerceUnsized kinds for impls on custom types. /// Caches CoerceUnsized kinds for impls on custom types.
[] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId)
-> ty::adjustment::CoerceUnsizedInfo, -> ty::adjustment::CoerceUnsizedInfo,

View File

@ -782,9 +782,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::IsAutoImpl => { force!(is_auto_impl, def_id!()); } DepKind::IsAutoImpl => { force!(is_auto_impl, def_id!()); }
DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); } DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); }
DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); } DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); }
DepKind::ClosureKind => { force!(closure_kind, def_id!()); }
DepKind::FnSignature => { force!(fn_sig, def_id!()); } DepKind::FnSignature => { force!(fn_sig, def_id!()); }
DepKind::GenSignature => { force!(generator_sig, def_id!()); }
DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); } DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); }
DepKind::ItemVariances => { force!(variances_of, def_id!()); } DepKind::ItemVariances => { force!(variances_of, def_id!()); }
DepKind::IsConstFn => { force!(is_const_fn, def_id!()); } DepKind::IsConstFn => { force!(is_const_fn, def_id!()); }

View File

@ -896,7 +896,7 @@ pub enum Predicate<'tcx> {
/// No direct syntax. May be thought of as `where T : FnFoo<...>` /// No direct syntax. May be thought of as `where T : FnFoo<...>`
/// for some substitutions `...` and T being a closure type. /// for some substitutions `...` and T being a closure type.
/// Satisfied (or refuted) once we know the closure's kind. /// Satisfied (or refuted) once we know the closure's kind.
ClosureKind(DefId, ClosureKind), ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind),
/// `T1 <: T2` /// `T1 <: T2`
Subtype(PolySubtypePredicate<'tcx>), Subtype(PolySubtypePredicate<'tcx>),
@ -999,8 +999,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
Predicate::WellFormed(data.subst(tcx, substs)), Predicate::WellFormed(data.subst(tcx, substs)),
Predicate::ObjectSafe(trait_def_id) => Predicate::ObjectSafe(trait_def_id) =>
Predicate::ObjectSafe(trait_def_id), Predicate::ObjectSafe(trait_def_id),
Predicate::ClosureKind(closure_def_id, kind) => Predicate::ClosureKind(closure_def_id, closure_substs, kind) =>
Predicate::ClosureKind(closure_def_id, kind), Predicate::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind),
Predicate::ConstEvaluatable(def_id, const_substs) => Predicate::ConstEvaluatable(def_id, const_substs) =>
Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)), Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)),
} }
@ -1182,8 +1182,8 @@ impl<'tcx> Predicate<'tcx> {
ty::Predicate::ObjectSafe(_trait_def_id) => { ty::Predicate::ObjectSafe(_trait_def_id) => {
vec![] vec![]
} }
ty::Predicate::ClosureKind(_closure_def_id, _kind) => { ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => {
vec![] closure_substs.substs.types().collect()
} }
ty::Predicate::ConstEvaluatable(_, substs) => { ty::Predicate::ConstEvaluatable(_, substs) => {
substs.types().collect() substs.types().collect()
@ -1932,6 +1932,9 @@ pub enum ClosureKind {
} }
impl<'a, 'tcx> ClosureKind { impl<'a, 'tcx> ClosureKind {
// This is the initial value used when doing upvar inference.
pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
pub fn trait_did(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefId { pub fn trait_did(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefId {
match *self { match *self {
ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem), ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem),
@ -1957,6 +1960,16 @@ impl<'a, 'tcx> ClosureKind {
_ => false, _ => false,
} }
} }
/// Returns the representative scalar type for this closure kind.
/// See `TyS::to_opt_closure_kind` for more details.
pub fn to_ty(self, tcx: TyCtxt<'_, '_, 'tcx>) -> Ty<'tcx> {
match self {
ty::ClosureKind::Fn => tcx.types.i8,
ty::ClosureKind::FnMut => tcx.types.i16,
ty::ClosureKind::FnOnce => tcx.types.i32,
}
}
} }
impl<'tcx> TyS<'tcx> { impl<'tcx> TyS<'tcx> {

View File

@ -211,8 +211,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
ty::Predicate::WellFormed(ty) => { ty::Predicate::WellFormed(ty) => {
tcx.lift(&ty).map(ty::Predicate::WellFormed) tcx.lift(&ty).map(ty::Predicate::WellFormed)
} }
ty::Predicate::ClosureKind(closure_def_id, kind) => { ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
Some(ty::Predicate::ClosureKind(closure_def_id, kind)) tcx.lift(&closure_substs)
.map(|closure_substs| ty::Predicate::ClosureKind(closure_def_id,
closure_substs,
kind))
} }
ty::Predicate::ObjectSafe(trait_def_id) => { ty::Predicate::ObjectSafe(trait_def_id) => {
Some(ty::Predicate::ObjectSafe(trait_def_id)) Some(ty::Predicate::ObjectSafe(trait_def_id))
@ -420,7 +423,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
FloatMismatch(x) => FloatMismatch(x), FloatMismatch(x) => FloatMismatch(x),
Traits(x) => Traits(x), Traits(x) => Traits(x),
VariadicMismatch(x) => VariadicMismatch(x), VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy => CyclicTy, CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)),
ProjectionMismatched(x) => ProjectionMismatched(x), ProjectionMismatched(x) => ProjectionMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
@ -966,8 +969,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
ty::Predicate::Projection(binder.fold_with(folder)), ty::Predicate::Projection(binder.fold_with(folder)),
ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data) =>
ty::Predicate::WellFormed(data.fold_with(folder)), ty::Predicate::WellFormed(data.fold_with(folder)),
ty::Predicate::ClosureKind(closure_def_id, kind) => ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) =>
ty::Predicate::ClosureKind(closure_def_id, kind), ty::Predicate::ClosureKind(closure_def_id, closure_substs.fold_with(folder), kind),
ty::Predicate::ObjectSafe(trait_def_id) => ty::Predicate::ObjectSafe(trait_def_id) =>
ty::Predicate::ObjectSafe(trait_def_id), ty::Predicate::ObjectSafe(trait_def_id),
ty::Predicate::ConstEvaluatable(def_id, substs) => ty::Predicate::ConstEvaluatable(def_id, substs) =>
@ -984,7 +987,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), ty::Predicate::Projection(ref binder) => binder.visit_with(visitor),
ty::Predicate::WellFormed(data) => data.visit_with(visitor), ty::Predicate::WellFormed(data) => data.visit_with(visitor),
ty::Predicate::ClosureKind(_closure_def_id, _kind) => false, ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) =>
closure_substs.visit_with(visitor),
ty::Predicate::ObjectSafe(_trait_def_id) => false, ty::Predicate::ObjectSafe(_trait_def_id) => false,
ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor), ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor),
} }
@ -1169,7 +1173,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
FloatMismatch(x) => FloatMismatch(x), FloatMismatch(x) => FloatMismatch(x),
Traits(x) => Traits(x), Traits(x) => Traits(x),
VariadicMismatch(x) => VariadicMismatch(x), VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy => CyclicTy, CyclicTy(t) => CyclicTy(t.fold_with(folder)),
ProjectionMismatched(x) => ProjectionMismatched(x), ProjectionMismatched(x) => ProjectionMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
Sorts(x) => Sorts(x.fold_with(folder)), Sorts(x) => Sorts(x.fold_with(folder)),
@ -1196,6 +1200,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
OldStyleLUB(ref x) => x.visit_with(visitor), OldStyleLUB(ref x) => x.visit_with(visitor),
TyParamDefaultMismatch(ref x) => x.visit_with(visitor), TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
ExistentialMismatch(x) => x.visit_with(visitor), ExistentialMismatch(x) => x.visit_with(visitor),
CyclicTy(t) => t.visit_with(visitor),
Mismatch | Mismatch |
Mutability | Mutability |
TupleSize(_) | TupleSize(_) |
@ -1205,7 +1210,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
FloatMismatch(_) | FloatMismatch(_) |
Traits(_) | Traits(_) |
VariadicMismatch(_) | VariadicMismatch(_) |
CyclicTy |
ProjectionMismatched(_) | ProjectionMismatched(_) |
ProjectionBoundsLength(_) => false, ProjectionBoundsLength(_) => false,
} }

View File

@ -174,16 +174,26 @@ pub enum TypeVariants<'tcx> {
/// A closure can be modeled as a struct that looks like: /// A closure can be modeled as a struct that looks like:
/// ///
/// struct Closure<'l0...'li, T0...Tj, U0...Uk> { /// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> {
/// upvar0: U0, /// upvar0: U0,
/// ... /// ...
/// upvark: Uk /// upvark: Uk
/// } /// }
/// ///
/// where 'l0...'li and T0...Tj are the lifetime and type parameters /// where:
/// in scope on the function that defined the closure, and U0...Uk are ///
/// type parameters representing the types of its upvars (borrowed, if /// - 'l0...'li and T0...Tj are the lifetime and type parameters
/// appropriate). /// in scope on the function that defined the closure,
/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
/// is rather hackily encoded via a scalar type. See
/// `TyS::to_opt_closure_kind` for details.
/// - CS represents the *closure signature*, representing as a `fn()`
/// type. For example, `fn(u32, u32) -> u32` would mean that the closure
/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
/// specified above.
/// - U0...Uk are type parameters representing the types of its upvars
/// (borrowed, if appropriate; that is, if Ui represents a by-ref upvar,
/// and the up-var has the type `Foo`, then `Ui = &Foo`).
/// ///
/// So, for example, given this function: /// So, for example, given this function:
/// ///
@ -246,6 +256,17 @@ pub enum TypeVariants<'tcx> {
/// closure C wind up influencing the decisions we ought to make for /// closure C wind up influencing the decisions we ought to make for
/// closure C (which would then require fixed point iteration to /// closure C (which would then require fixed point iteration to
/// handle). Plus it fixes an ICE. :P /// handle). Plus it fixes an ICE. :P
///
/// ## Generators
///
/// Perhaps surprisingly, `ClosureSubsts` are also used for
/// generators. In that case, what is written above is only half-true
/// -- the set of type parameters is similar, but the role of CK and
/// CS are different. CK represents the "yield type" and CS
/// represents the "return type" of the generator.
///
/// It'd be nice to split this struct into ClosureSubsts and
/// GeneratorSubsts, I believe. -nmatsakis
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct ClosureSubsts<'tcx> { pub struct ClosureSubsts<'tcx> {
/// Lifetime and type parameters from the enclosing function, /// Lifetime and type parameters from the enclosing function,
@ -256,14 +277,97 @@ pub struct ClosureSubsts<'tcx> {
pub substs: &'tcx Substs<'tcx>, pub substs: &'tcx Substs<'tcx>,
} }
impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { /// Struct returned by `split()`. Note that these are subslices of the
/// parent slice and not canonical substs themselves.
struct SplitClosureSubsts<'tcx> {
closure_kind_ty: Ty<'tcx>,
closure_sig_ty: Ty<'tcx>,
upvar_kinds: &'tcx [Kind<'tcx>],
}
impl<'tcx> ClosureSubsts<'tcx> {
/// Divides the closure substs into their respective
/// components. Single source of truth with respect to the
/// ordering.
fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitClosureSubsts<'tcx> {
let generics = tcx.generics_of(def_id);
let parent_len = generics.parent_count();
SplitClosureSubsts {
closure_kind_ty: self.substs[parent_len].as_type().expect("CK should be a type"),
closure_sig_ty: self.substs[parent_len + 1].as_type().expect("CS should be a type"),
upvar_kinds: &self.substs[parent_len + 2..],
}
}
#[inline] #[inline]
pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) ->
impl Iterator<Item=Ty<'tcx>> + 'tcx impl Iterator<Item=Ty<'tcx>> + 'tcx
{ {
let generics = tcx.generics_of(def_id); let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
self.substs[self.substs.len()-generics.own_count()..].iter().map( upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
|t| t.as_type().expect("unexpected region in upvars")) }
/// Returns the closure kind for this closure; may return a type
/// variable during inference. To get the closure kind during
/// inference, use `infcx.closure_kind(def_id, substs)`.
pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.split(def_id, tcx).closure_kind_ty
}
/// Returns the type representing the closure signature for this
/// closure; may contain type variables during inference. To get
/// the closure signature during inference, use
/// `infcx.fn_sig(def_id)`.
pub fn closure_sig_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.split(def_id, tcx).closure_sig_ty
}
/// Returns the type representing the yield type of the generator.
pub fn generator_yield_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.closure_kind_ty(def_id, tcx)
}
/// Returns the type representing the return type of the generator.
pub fn generator_return_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.closure_sig_ty(def_id, tcx)
}
/// Return the "generator signature", which consists of its yield
/// and return types.
///
/// NB. Some bits of the code prefers to see this wrapped in a
/// binder, but it never contains bound regions. Probably this
/// function should be removed.
pub fn generator_poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> {
ty::Binder(self.generator_sig(def_id, tcx))
}
/// Return the "generator signature", which consists of its yield
/// and return types.
pub fn generator_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> GenSig<'tcx> {
ty::GenSig {
yield_ty: self.generator_yield_ty(def_id, tcx),
return_ty: self.generator_return_ty(def_id, tcx),
}
}
}
impl<'tcx> ClosureSubsts<'tcx> {
/// Returns the closure kind for this closure; only usable outside
/// of an inference context, because in that context we know that
/// there are no type variables.
pub fn closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::ClosureKind {
self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap()
}
/// Extracts the signature from the closure; only usable outside
/// of an inference context, because in that context we know that
/// there are no type variables.
pub fn closure_sig(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::PolyFnSig<'tcx> {
match self.closure_sig_ty(def_id, tcx).sty {
ty::TyFnPtr(sig) => sig,
ref t => bug!("closure_sig_ty is not a fn-ptr: {:?}", t),
}
} }
} }
@ -1268,6 +1372,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
} }
} }
pub fn is_generator(&self) -> bool {
match self.sty {
TyGenerator(..) => true,
_ => false,
}
}
pub fn is_integral(&self) -> bool { pub fn is_integral(&self) -> bool {
match self.sty { match self.sty {
TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
@ -1442,6 +1553,37 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
} }
} }
} }
/// When we create a closure, we record its kind (i.e., what trait
/// it implements) into its `ClosureSubsts` using a type
/// parameter. This is kind of a phantom type, except that the
/// most convenient thing for us to are the integral types. This
/// function converts such a special type into the closure
/// kind. To go the other way, use
/// `tcx.closure_kind_ty(closure_kind)`.
///
/// Note that during type checking, we use an inference variable
/// to represent the closure kind, because it has not yet been
/// inferred. Once [upvar inference] is complete, that type varibale
/// will be unified.
///
/// [upvar inference]: src/librustc_typeck/check/upvar.rs
pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
match self.sty {
TyInt(int_ty) => match int_ty {
ast::IntTy::I8 => Some(ty::ClosureKind::Fn),
ast::IntTy::I16 => Some(ty::ClosureKind::FnMut),
ast::IntTy::I32 => Some(ty::ClosureKind::FnOnce),
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
},
TyInfer(_) => None,
TyError => Some(ty::ClosureKind::Fn),
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
}
}
} }
/// Typed constant value. /// Typed constant value.

View File

@ -336,14 +336,50 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
} }
} }
ty::TyGenerator(..) | ty::TyClosure(..) => { ty::TyGenerator(..) => {
// the types in a closure or generator are always the types of // Walk ALL the types in the generator: this will
// local variables (or possibly references to local // include the upvar types as well as the yield
// variables), we'll walk those. // type. Note that this is mildly distinct from
// the closure case, where we have to be careful
// about the signature of the closure. We don't
// have the problem of implied bounds here since
// generators don't take arguments.
}
ty::TyClosure(def_id, substs) => {
// Only check the upvar types for WF, not the rest
// of the types within. This is needed because we
// capture the signature and it may not be WF
// without the implied bounds. Consider a closure
// like `|x: &'a T|` -- it may be that `T: 'a` is
// not known to hold in the creator's context (and
// indeed the closure may not be invoked by its
// creator, but rather turned to someone who *can*
// verify that).
// //
// (Though, local variables are probably not // The special treatment of closures here really
// needed, as they are separately checked w/r/t // ought not to be necessary either; the problem
// WFedness.) // is related to #25860 -- there is no way for us
// to express a fn type complete with the implied
// bounds that it is assuming. I think in reality
// the WF rules around fn are a bit messed up, and
// that is the rot problem: `fn(&'a T)` should
// probably always be WF, because it should be
// shorthand for something like `where(T: 'a) {
// fn(&'a T) }`, as discussed in #25860.
//
// Note that we are also skipping the generic
// types. This is consistent with the `outlives`
// code, but anyway doesn't matter: within the fn
// body where they are created, the generics will
// always be WF, and outside of that fn body we
// are not directly inspecting closure types
// anyway, except via auto trait matching (which
// only inspects the upvar types).
subtys.skip_current_subtree(); // subtree handled by compute_projection
for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) {
self.compute(upvar_ty);
}
} }
ty::TyFnDef(..) | ty::TyFnPtr(_) => { ty::TyFnDef(..) | ty::TyFnPtr(_) => {

View File

@ -1261,7 +1261,7 @@ define_print! {
ty::tls::with(|tcx| { ty::tls::with(|tcx| {
write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id))
}), }),
ty::Predicate::ClosureKind(closure_def_id, kind) => ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) =>
ty::tls::with(|tcx| { ty::tls::with(|tcx| {
write!(f, "the closure `{}` implements the trait `{}`", write!(f, "the closure `{}` implements the trait `{}`",
tcx.item_path_str(closure_def_id), kind) tcx.item_path_str(closure_def_id), kind)
@ -1285,8 +1285,8 @@ define_print! {
ty::Predicate::ObjectSafe(trait_def_id) => { ty::Predicate::ObjectSafe(trait_def_id) => {
write!(f, "ObjectSafe({:?})", trait_def_id) write!(f, "ObjectSafe({:?})", trait_def_id)
} }
ty::Predicate::ClosureKind(closure_def_id, kind) => { ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind) write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
} }
ty::Predicate::ConstEvaluatable(def_id, substs) => { ty::Predicate::ConstEvaluatable(def_id, substs) => {
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)

View File

@ -655,10 +655,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
ty::TypeVariants::TyClosure(id, _) => { ty::TypeVariants::TyClosure(id, _) => {
let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
let hir_id = self.tcx.hir.node_to_hir_id(node_id); let hir_id = self.tcx.hir.node_to_hir_id(node_id);
if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = if let Some((span, name)) = self.tables.closure_kind_origins().get(hir_id) {
self.tables.closure_kinds().get(hir_id) err.span_note(*span, &format!(
{
err.span_note(span, &format!(
"closure cannot be invoked more than once because \ "closure cannot be invoked more than once because \
it moves the variable `{}` out of its environment", it moves the variable `{}` out of its environment",
name name

View File

@ -15,6 +15,7 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![feature(match_default_bindings)]
#![feature(quote)] #![feature(quote)]
#[macro_use] extern crate log; #[macro_use] extern crate log;

View File

@ -136,12 +136,10 @@ provide! { <'tcx> tcx, def_id, other, cdata,
mir mir
} }
generator_sig => { cdata.generator_sig(def_id.index, tcx) }
mir_const_qualif => { mir_const_qualif => {
(cdata.mir_const_qualif(def_id.index), Rc::new(IdxSetBuf::new_empty(0))) (cdata.mir_const_qualif(def_id.index), Rc::new(IdxSetBuf::new_empty(0)))
} }
typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) } typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) }
closure_kind => { cdata.closure_kind(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) } fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
is_const_fn => { cdata.is_const_fn(def_id.index) } is_const_fn => { cdata.is_const_fn(def_id.index) }

View File

@ -1020,13 +1020,6 @@ impl<'a, 'tcx> CrateMetadata {
} }
} }
pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind {
match self.entry(closure_id).kind {
EntryKind::Closure(data) => data.decode(self).kind,
_ => bug!(),
}
}
pub fn fn_sig(&self, pub fn fn_sig(&self,
id: DefIndex, id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>) tcx: TyCtxt<'a, 'tcx, 'tcx>)
@ -1043,23 +1036,6 @@ impl<'a, 'tcx> CrateMetadata {
sig.decode((self, tcx)) sig.decode((self, tcx))
} }
fn get_generator_data(&self,
id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Option<GeneratorData<'tcx>> {
match self.entry(id).kind {
EntryKind::Generator(data) => Some(data.decode((self, tcx))),
_ => None,
}
}
pub fn generator_sig(&self,
id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Option<ty::PolyGenSig<'tcx>> {
self.get_generator_data(id, tcx).map(|d| d.sig)
}
#[inline] #[inline]
pub fn def_key(&self, index: DefIndex) -> DefKey { pub fn def_key(&self, index: DefIndex) -> DefKey {
self.def_path_table.def_key(index) self.def_path_table.def_key(index)

View File

@ -1205,19 +1205,25 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
debug!("IsolatedEncoder::encode_info_for_closure({:?})", def_id); debug!("IsolatedEncoder::encode_info_for_closure({:?})", def_id);
let tcx = self.tcx; let tcx = self.tcx;
let kind = if let Some(sig) = self.tcx.generator_sig(def_id) { let tables = self.tcx.typeck_tables_of(def_id);
let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
let kind = match tables.node_id_to_type(hir_id).sty {
ty::TyGenerator(def_id, ..) => {
let layout = self.tcx.generator_layout(def_id); let layout = self.tcx.generator_layout(def_id);
let data = GeneratorData { let data = GeneratorData {
sig,
layout: layout.clone(), layout: layout.clone(),
}; };
EntryKind::Generator(self.lazy(&data)) EntryKind::Generator(self.lazy(&data))
} else { }
let data = ClosureData {
kind: tcx.closure_kind(def_id), ty::TyClosure(def_id, substs) => {
sig: self.lazy(&tcx.fn_sig(def_id)), let sig = substs.closure_sig(def_id, self.tcx);
}; let data = ClosureData { sig: self.lazy(&sig) };
EntryKind::Closure(self.lazy(&data)) EntryKind::Closure(self.lazy(&data))
}
_ => bug!("closure that is neither generator nor closure")
}; };
Entry { Entry {

View File

@ -512,14 +512,12 @@ impl_stable_hash_for!(struct MethodData<'tcx> { fn_data, container, has_self });
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct ClosureData<'tcx> { pub struct ClosureData<'tcx> {
pub kind: ty::ClosureKind,
pub sig: Lazy<ty::PolyFnSig<'tcx>>, pub sig: Lazy<ty::PolyFnSig<'tcx>>,
} }
impl_stable_hash_for!(struct ClosureData<'tcx> { kind, sig }); impl_stable_hash_for!(struct ClosureData<'tcx> { sig });
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct GeneratorData<'tcx> { pub struct GeneratorData<'tcx> {
pub sig: ty::PolyGenSig<'tcx>,
pub layout: mir::GeneratorLayout<'tcx>, pub layout: mir::GeneratorLayout<'tcx>,
} }
impl_stable_hash_for!(struct GeneratorData<'tcx> { sig, layout }); impl_stable_hash_for!(struct GeneratorData<'tcx> { layout });

View File

@ -127,7 +127,12 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
let arguments = implicit_argument.into_iter().chain(explicit_arguments); let arguments = implicit_argument.into_iter().chain(explicit_arguments);
let (yield_ty, return_ty) = if body.is_generator { let (yield_ty, return_ty) = if body.is_generator {
let gen_sig = cx.tables().generator_sigs()[fn_hir_id].clone().unwrap(); let gen_sig = match ty.sty {
ty::TyGenerator(gen_def_id, gen_substs, ..) =>
gen_substs.generator_sig(gen_def_id, tcx),
_ =>
span_bug!(tcx.hir.span(id), "generator w/o generator type: {:?}", ty),
};
(Some(gen_sig.yield_ty), gen_sig.return_ty) (Some(gen_sig.yield_ty), gen_sig.return_ty)
} else { } else {
(None, fn_sig.output()) (None, fn_sig.output())
@ -248,14 +253,18 @@ pub fn closure_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id); let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id);
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id); let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id);
let closure_def_id = tcx.hir.local_def_id(closure_expr_id); let (closure_def_id, closure_substs) = match closure_ty.sty {
ty::TyClosure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
_ => bug!("closure expr does not have closure type: {:?}", closure_ty)
};
let region = ty::ReFree(ty::FreeRegion { let region = ty::ReFree(ty::FreeRegion {
scope: closure_def_id, scope: closure_def_id,
bound_region: ty::BoundRegion::BrEnv, bound_region: ty::BoundRegion::BrEnv,
}); });
let region = tcx.mk_region(region); let region = tcx.mk_region(region);
match tcx.closure_kind(closure_def_id) { match closure_substs.closure_kind_ty(closure_def_id, tcx).to_opt_closure_kind().unwrap() {
ty::ClosureKind::Fn => ty::ClosureKind::Fn =>
tcx.mk_ref(region, tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty, ty::TypeAndMut { ty: closure_ty,

View File

@ -713,8 +713,8 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}); });
let region = cx.tcx.mk_region(region); let region = cx.tcx.mk_region(region);
let self_expr = if let ty::TyClosure(..) = closure_ty.sty { let self_expr = if let ty::TyClosure(_, closure_substs) = closure_ty.sty {
match cx.tcx.closure_kind(closure_def_id) { match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() {
ty::ClosureKind::Fn => { ty::ClosureKind::Fn => {
let ref_closure_ty = cx.tcx.mk_ref(region, let ref_closure_ty = cx.tcx.mk_ref(region,
ty::TypeAndMut { ty::TypeAndMut {

View File

@ -767,7 +767,11 @@ impl MirPass for StateTransform {
let hir_id = tcx.hir.node_to_hir_id(node_id); let hir_id = tcx.hir.node_to_hir_id(node_id);
// Get the interior types which typeck computed // Get the interior types which typeck computed
let interior = *tcx.typeck_tables_of(def_id).generator_interiors().get(hir_id).unwrap(); let tables = tcx.typeck_tables_of(def_id);
let interior = match tables.node_id_to_type(hir_id).sty {
ty::TyGenerator(_, _, interior) => interior,
ref t => bug!("type of generator not a generator: {:?}", t),
};
// The first argument is the generator type passed by value // The first argument is the generator type passed by value
let gen_ty = mir.local_decls.raw[1].ty; let gen_ty = mir.local_decls.raw[1].ty;

View File

@ -23,6 +23,7 @@ use rustc::ty::layout::LayoutOf;
use rustc::ty::subst::{Subst,Substs}; use rustc::ty::subst::{Subst,Substs};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::iter;
use transform::{MirPass, MirSource}; use transform::{MirPass, MirSource};
use super::simplify::{remove_dead_blocks, CfgSimplifier}; use super::simplify::{remove_dead_blocks, CfgSimplifier};
@ -559,8 +560,29 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
) -> Vec<Operand<'tcx>> { ) -> Vec<Operand<'tcx>> {
let tcx = self.tcx; let tcx = self.tcx;
// A closure is passed its self-type and a tuple like `(arg1, arg2, ...)`, // There is a bit of a mismatch between the *caller* of a closure and the *callee*.
// hence mappings to tuple fields are needed. // The caller provides the arguments wrapped up in a tuple:
//
// tuple_tmp = (a, b, c)
// Fn::call(closure_ref, tuple_tmp)
//
// meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`)
// as distinct arguments. (This is the "rust-call" ABI hack.) Normally, trans has
// the job of unpacking this tuple. But here, we are trans. =) So we want to create
// a vector like
//
// [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2]
//
// Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient
// if we "spill" that into *another* temporary, so that we can map the argument
// variable in the callee MIR directly to an argument variable on our side.
// So we introduce temporaries like:
//
// tmp0 = tuple_tmp.0
// tmp1 = tuple_tmp.1
// tmp2 = tuple_tmp.2
//
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
if tcx.is_closure(callsite.callee) { if tcx.is_closure(callsite.callee) {
let mut args = args.into_iter(); let mut args = args.into_iter();
let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_mir); let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_mir);
@ -573,12 +595,21 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
bug!("Closure arguments are not passed as a tuple"); bug!("Closure arguments are not passed as a tuple");
}; };
let mut res = Vec::with_capacity(1 + tuple_tys.len()); // The `closure_ref` in our example above.
res.push(Operand::Consume(self_)); let closure_ref_arg = iter::once(Operand::Consume(self_));
res.extend(tuple_tys.iter().enumerate().map(|(i, ty)| {
Operand::Consume(tuple.clone().field(Field::new(i), ty)) // The `tmp0`, `tmp1`, and `tmp2` in our example abonve.
})); let tuple_tmp_args =
res tuple_tys.iter().enumerate().map(|(i, ty)| {
// This is e.g. `tuple_tmp.0` in our example above.
let tuple_field = Operand::Consume(tuple.clone().field(Field::new(i), ty));
// Spill to a local to make e.g. `tmp0`.
let tmp = self.create_temp_if_necessary(tuple_field, callsite, caller_mir);
Operand::Consume(tmp)
});
closure_ref_arg.chain(tuple_tmp_args).collect()
} else { } else {
args.into_iter() args.into_iter()
.map(|a| Operand::Consume(self.create_temp_if_necessary(a, callsite, caller_mir))) .map(|a| Operand::Consume(self.create_temp_if_necessary(a, callsite, caller_mir)))

View File

@ -396,7 +396,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs); let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs);
let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
let env_ty = match tcx.closure_kind(def_id) { let env_ty = match substs.closure_kind(def_id, tcx) {
ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty), ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty),
ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty), ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty),
ty::ClosureKind::FnOnce => ty, ty::ClosureKind::FnOnce => ty,
@ -412,7 +412,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
} }
ty::TyGenerator(def_id, substs, _) => { ty::TyGenerator(def_id, substs, _) => {
let tcx = ccx.tcx(); let tcx = ccx.tcx();
let sig = tcx.generator_sig(def_id).unwrap().subst(tcx, substs.substs); let sig = substs.generator_poly_sig(def_id, ccx.tcx());
let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);

View File

@ -86,7 +86,7 @@ pub fn resolve_closure<'a, 'tcx> (
requested_kind: ty::ClosureKind) requested_kind: ty::ClosureKind)
-> Instance<'tcx> -> Instance<'tcx>
{ {
let actual_kind = tcx.closure_kind(def_id); let actual_kind = substs.closure_kind(def_id, tcx);
match needs_fn_once_adapter_shim(actual_kind, requested_kind) { match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),

View File

@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Check whether this is a call to a closure where we // Check whether this is a call to a closure where we
// haven't yet decided on whether the closure is fn vs // haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing. // fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(def_id).is_none() { if self.closure_kind(def_id, substs).is_none() {
let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs); let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs);
let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span, let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall, infer::FnCall,
@ -122,6 +122,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
adjustments, adjustments,
fn_sig, fn_sig,
closure_def_id: def_id, closure_def_id: def_id,
closure_substs: substs,
}); });
return Some(CallStep::DeferredClosure(fn_sig)); return Some(CallStep::DeferredClosure(fn_sig));
} }
@ -336,6 +337,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
adjustments: Vec<Adjustment<'tcx>>, adjustments: Vec<Adjustment<'tcx>>,
fn_sig: ty::FnSig<'tcx>, fn_sig: ty::FnSig<'tcx>,
closure_def_id: DefId, closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>,
} }
impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
@ -344,7 +346,7 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
// we should not be invoked until the closure kind has been // we should not be invoked until the closure kind has been
// determined by upvar inference // determined by upvar inference
assert!(fcx.closure_kind(self.closure_def_id).is_some()); assert!(fcx.closure_kind(self.closure_def_id, self.closure_substs).is_some());
// We may now know enough to figure out fn vs fnmut etc. // We may now know enough to figure out fn vs fnmut etc.
match fcx.try_overloaded_call_traits(self.call_expr, match fcx.try_overloaded_call_traits(self.call_expr,

View File

@ -10,7 +10,7 @@
//! Code for type-checking closure expressions. //! Code for type-checking closure expressions.
use super::{check_fn, Expectation, FnCtxt}; use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use astconv::AstConv; use astconv::AstConv;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("check_closure: ty_of_closure returns {:?}", liberated_sig); debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
let interior = check_fn( let generator_types = check_fn(
self, self,
self.param_env, self.param_env,
liberated_sig, liberated_sig,
@ -100,14 +100,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|_, _| span_bug!(expr.span, "closure has region param"), |_, _| span_bug!(expr.span, "closure has region param"),
|_, _| { |_, _| {
self.infcx self.infcx
.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
}, },
); );
let substs = ty::ClosureSubsts { substs };
let closure_type = self.tcx.mk_closure(expr_def_id, substs); let closure_type = self.tcx.mk_closure(expr_def_id, substs);
if let Some(interior) = interior { if let Some(GeneratorTypes { yield_ty, interior }) = generator_types {
let closure_substs = ty::ClosureSubsts { substs: substs }; self.demand_eqtype(expr.span,
return self.tcx.mk_generator(expr_def_id, closure_substs, interior); yield_ty,
substs.generator_yield_ty(expr_def_id, self.tcx));
self.demand_eqtype(expr.span,
liberated_sig.output(),
substs.generator_return_ty(expr_def_id, self.tcx));
return self.tcx.mk_generator(expr_def_id, substs, interior);
} }
debug!( debug!(
@ -135,15 +141,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
opt_kind opt_kind
); );
{ let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
let mut tables = self.tables.borrow_mut(); self.demand_eqtype(expr.span,
tables.closure_tys_mut().insert(expr.hir_id, sig); sig_fn_ptr_ty,
match opt_kind { substs.closure_sig_ty(expr_def_id, self.tcx));
Some(kind) => {
tables.closure_kinds_mut().insert(expr.hir_id, (kind, None)); if let Some(kind) = opt_kind {
} self.demand_eqtype(expr.span,
None => {} kind.to_ty(self.tcx),
} substs.closure_kind_ty(expr_def_id, self.tcx));
} }
closure_type closure_type

View File

@ -759,30 +759,12 @@ pub fn provide(providers: &mut Providers) {
typeck_item_bodies, typeck_item_bodies,
typeck_tables_of, typeck_tables_of,
has_typeck_tables, has_typeck_tables,
closure_kind,
generator_sig,
adt_destructor, adt_destructor,
used_trait_imports, used_trait_imports,
..*providers ..*providers
}; };
} }
fn generator_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<ty::PolyGenSig<'tcx>> {
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let hir_id = tcx.hir.node_to_hir_id(node_id);
tcx.typeck_tables_of(def_id).generator_sigs()[hir_id].map(|s| ty::Binder(s))
}
fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::ClosureKind {
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let hir_id = tcx.hir.node_to_hir_id(node_id);
tcx.typeck_tables_of(def_id).closure_kinds()[hir_id].0
}
fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId) def_id: DefId)
-> Option<ty::Destructor> { -> Option<ty::Destructor> {
@ -1021,6 +1003,17 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
_: hir::BodyId, _: Span, _: ast::NodeId) { } _: hir::BodyId, _: Span, _: ast::NodeId) { }
} }
/// When `check_fn` is invoked on a generator (i.e., a body that
/// includes yield), it returns back some information about the yield
/// points.
struct GeneratorTypes<'tcx> {
/// Type of value that is yielded.
yield_ty: ty::Ty<'tcx>,
/// Types that are captured (see `GeneratorInterior` for more).
interior: ty::GeneratorInterior<'tcx>
}
/// Helper used for fns and closures. Does the grungy work of checking a function /// Helper used for fns and closures. Does the grungy work of checking a function
/// body and returns the function context used for that purpose, since in the case of a fn item /// body and returns the function context used for that purpose, since in the case of a fn item
/// there is still a bit more to do. /// there is still a bit more to do.
@ -1034,7 +1027,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId, fn_id: ast::NodeId,
body: &'gcx hir::Body, body: &'gcx hir::Body,
can_be_generator: bool) can_be_generator: bool)
-> (FnCtxt<'a, 'gcx, 'tcx>, Option<ty::GeneratorInterior<'tcx>>) -> (FnCtxt<'a, 'gcx, 'tcx>, Option<GeneratorTypes<'tcx>>)
{ {
let mut fn_sig = fn_sig.clone(); let mut fn_sig = fn_sig.clone();
@ -1084,21 +1077,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id); let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id);
let gen_ty = if can_be_generator && body.is_generator { let gen_ty = if can_be_generator && body.is_generator {
let gen_sig = ty::GenSig {
yield_ty: fcx.yield_ty.unwrap(),
return_ty: ret_ty,
};
inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, Some(gen_sig));
let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)); let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span));
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), witness)); fcx.deferred_generator_interiors.borrow_mut().push((body.id(), witness));
let interior = ty::GeneratorInterior::new(witness); let interior = ty::GeneratorInterior::new(witness);
Some(GeneratorTypes { yield_ty: fcx.yield_ty.unwrap(), interior: interior })
inherited.tables.borrow_mut().generator_interiors_mut().insert(fn_hir_id, interior);
Some(interior)
} else { } else {
inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, None);
None None
}; };
inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_hir_id, fn_sig); inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_hir_id, fn_sig);

View File

@ -45,16 +45,14 @@ use super::FnCtxt;
use middle::expr_use_visitor as euv; use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc; use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization; use middle::mem_categorization::Categorization;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::infer::UpvarRegion; use rustc::infer::UpvarRegion;
use syntax::ast; use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::LocalDefId; use rustc::hir::def_id::LocalDefId;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::util::nodemap::FxHashMap;
use std::collections::hash_map::Entry;
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn closure_analyze(&self, body: &'gcx hir::Body) { pub fn closure_analyze(&self, body: &'gcx hir::Body) {
@ -79,11 +77,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
hir::ExprClosure(cc, _, body_id, _, is_generator) => { hir::ExprClosure(cc, _, body_id, _, is_generator) => {
let body = self.fcx.tcx.hir.body(body_id); let body = self.fcx.tcx.hir.body(body_id);
self.visit_body(body); self.visit_body(body);
self.fcx.analyze_closure((expr.id, expr.hir_id), self.fcx
expr.span, .analyze_closure(expr.id, expr.hir_id, expr.span, body, cc, is_generator);
body,
cc,
is_generator);
} }
_ => {} _ => {}
@ -94,35 +89,43 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
} }
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn analyze_closure(&self, fn analyze_closure(
(closure_node_id, closure_hir_id): (ast::NodeId, hir::HirId), &self,
closure_node_id: ast::NodeId,
closure_hir_id: hir::HirId,
span: Span, span: Span,
body: &hir::Body, body: &hir::Body,
capture_clause: hir::CaptureClause, capture_clause: hir::CaptureClause,
gen: bool) { is_generator: bool,
) {
/*! /*!
* Analysis starting point. * Analysis starting point.
*/ */
debug!("analyze_closure(id={:?}, body.id={:?})", closure_node_id, body.id()); debug!(
"analyze_closure(id={:?}, body.id={:?})",
closure_node_id,
body.id()
);
let infer_kind = if gen { // Extract the type of the closure.
false let (closure_def_id, closure_substs) = match self.node_ty(closure_hir_id).sty {
} else { ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => (def_id, substs),
match self.tables ref t => {
.borrow_mut() span_bug!(
.closure_kinds_mut() span,
.entry(closure_hir_id) { "type of closure expr {:?} is not a closure {:?}",
Entry::Occupied(_) => false, closure_node_id,
Entry::Vacant(entry) => { t
debug!("check_closure: adding closure {:?} as Fn", closure_node_id); );
entry.insert((ty::ClosureKind::Fn, None));
true
}
} }
}; };
let closure_def_id = self.tcx.hir.local_def_id(closure_node_id); let infer_kind = if is_generator {
false
} else {
self.closure_kind(closure_def_id, closure_substs).is_none()
};
self.tcx.with_freevars(closure_node_id, |freevars| { self.tcx.with_freevars(closure_node_id, |freevars| {
for freevar in freevars { for freevar in freevars {
@ -133,50 +136,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("seed upvar_id {:?}", upvar_id); debug!("seed upvar_id {:?}", upvar_id);
let capture_kind = match capture_clause { let capture_kind = match capture_clause {
hir::CaptureByValue => { hir::CaptureByValue => ty::UpvarCapture::ByValue,
ty::UpvarCapture::ByValue
}
hir::CaptureByRef => { hir::CaptureByRef => {
let origin = UpvarRegion(upvar_id, span); let origin = UpvarRegion(upvar_id, span);
let freevar_region = self.next_region_var(origin); let freevar_region = self.next_region_var(origin);
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, let upvar_borrow = ty::UpvarBorrow {
region: freevar_region }; kind: ty::ImmBorrow,
region: freevar_region,
};
ty::UpvarCapture::ByRef(upvar_borrow) ty::UpvarCapture::ByRef(upvar_borrow)
} }
}; };
self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); self.tables
.borrow_mut()
.upvar_capture_map
.insert(upvar_id, capture_kind);
} }
}); });
{
let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id()); let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id); let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
let mut delegate = InferBorrowKind { let mut delegate = InferBorrowKind {
fcx: self, fcx: self,
adjust_closure_kinds: FxHashMap(), closure_def_id: closure_def_id,
current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
current_origin: None,
adjust_upvar_captures: ty::UpvarCaptureMap::default(), adjust_upvar_captures: ty::UpvarCaptureMap::default(),
}; };
euv::ExprUseVisitor::with_infer(&mut delegate, euv::ExprUseVisitor::with_infer(
&mut delegate,
&self.infcx, &self.infcx,
self.param_env, self.param_env,
region_scope_tree, region_scope_tree,
&self.tables.borrow()) &self.tables.borrow(),
.consume_body(body); ).consume_body(body);
// Write the adjusted values back into the main tables.
if infer_kind { if infer_kind {
if let Some(kind) = delegate.adjust_closure_kinds // Unify the (as yet unbound) type variable in the closure
.remove(&closure_def_id.to_local()) { // substs with the kind we inferred.
let inferred_kind = delegate.current_closure_kind;
let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
// If we have an origin, store it.
if let Some(origin) = delegate.current_origin {
self.tables self.tables
.borrow_mut() .borrow_mut()
.closure_kinds_mut() .closure_kind_origins_mut()
.insert(closure_hir_id, kind); .insert(closure_hir_id, origin);
} }
} }
self.tables.borrow_mut().upvar_capture_map.extend(
delegate.adjust_upvar_captures); self.tables
} .borrow_mut()
.upvar_capture_map
.extend(delegate.adjust_upvar_captures);
// Now that we've analyzed the closure, we know how each // Now that we've analyzed the closure, we know how each
// variable is borrowed, and we know what traits the closure // variable is borrowed, and we know what traits the closure
@ -190,38 +205,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// C, then the type would have infinite size (and the // C, then the type would have infinite size (and the
// inference algorithm will reject it). // inference algorithm will reject it).
// Extract the type variables UV0...UVn. // Equate the type variables for the upvars with the actual types.
let (def_id, closure_substs) = match self.node_ty(closure_hir_id).sty {
ty::TyClosure(def_id, substs) |
ty::TyGenerator(def_id, substs, _) => (def_id, substs),
ref t => {
span_bug!(
span,
"type of closure expr {:?} is not a closure {:?}",
closure_node_id, t);
}
};
// Equate the type variables with the actual types.
let final_upvar_tys = self.final_upvar_tys(closure_node_id); let final_upvar_tys = self.final_upvar_tys(closure_node_id);
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", debug!(
closure_node_id, closure_substs, final_upvar_tys); "analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
for (upvar_ty, final_upvar_ty) in closure_node_id,
closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys) closure_substs,
final_upvar_tys
);
for (upvar_ty, final_upvar_ty) in closure_substs
.upvar_tys(closure_def_id, self.tcx)
.zip(final_upvar_tys)
{ {
self.demand_eqtype(span, final_upvar_ty, upvar_ty); self.demand_eqtype(span, final_upvar_ty, upvar_ty);
} }
// If we are also inferred the closure kind here, // If we are also inferred the closure kind here,
// process any deferred resolutions. // process any deferred resolutions.
if infer_kind { let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
let deferred_call_resolutions =
self.remove_deferred_call_resolutions(closure_def_id);
for deferred_call_resolution in deferred_call_resolutions { for deferred_call_resolution in deferred_call_resolutions {
deferred_call_resolution.resolve(self); deferred_call_resolution.resolve(self);
} }
} }
}
// Returns a list of `ClosureUpvar`s for each upvar. // Returns a list of `ClosureUpvar`s for each upvar.
fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> { fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
@ -234,7 +239,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let closure_def_index = tcx.hir.local_def_id(closure_id); let closure_def_index = tcx.hir.local_def_id(closure_id);
tcx.with_freevars(closure_id, |freevars| { tcx.with_freevars(closure_id, |freevars| {
freevars.iter().map(|freevar| { freevars
.iter()
.map(|freevar| {
let var_node_id = freevar.var_id(); let var_node_id = freevar.var_id();
let var_hir_id = tcx.hir.node_to_hir_id(var_node_id); let var_hir_id = tcx.hir.node_to_hir_id(var_node_id);
let freevar_ty = self.node_ty(var_hir_id); let freevar_ty = self.node_ty(var_hir_id);
@ -244,40 +251,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}; };
let capture = self.tables.borrow().upvar_capture(upvar_id); let capture = self.tables.borrow().upvar_capture(upvar_id);
debug!("var_id={:?} freevar_ty={:?} capture={:?}", debug!(
var_node_id, freevar_ty, capture); "var_id={:?} freevar_ty={:?} capture={:?}",
var_node_id,
freevar_ty,
capture
);
match capture { match capture {
ty::UpvarCapture::ByValue => freevar_ty, ty::UpvarCapture::ByValue => freevar_ty,
ty::UpvarCapture::ByRef(borrow) => ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
tcx.mk_ref(borrow.region, borrow.region,
ty::TypeAndMut { ty::TypeAndMut {
ty: freevar_ty, ty: freevar_ty,
mutbl: borrow.kind.to_mutbl_lossy(), mutbl: borrow.kind.to_mutbl_lossy(),
}), },
),
} }
}).collect() })
.collect()
}) })
} }
} }
struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
adjust_closure_kinds: FxHashMap<LocalDefId, (ty::ClosureKind, Option<(Span, ast::Name)>)>,
// The def-id of the closure whose kind and upvar accesses are being inferred.
closure_def_id: DefId,
// The kind that we have inferred that the current closure
// requires. Note that we *always* infer a minimal kind, even if
// we don't always *use* that in the final result (i.e., sometimes
// we've taken the closure kind from the expectations instead, and
// for generators we don't even implement the closure traits
// really).
current_closure_kind: ty::ClosureKind,
// If we modified `current_closure_kind`, this field contains a `Some()` with the
// variable access that caused us to do so.
current_origin: Option<(Span, ast::Name)>,
// For each upvar that we access, we track the minimal kind of
// access we need (ref, ref mut, move, etc).
adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>,
} }
impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
fn adjust_upvar_borrow_kind_for_consume(&mut self, fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
cmt: mc::cmt<'tcx>, debug!(
mode: euv::ConsumeMode) "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
{ cmt,
debug!("adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", mode
cmt, mode); );
// we only care about moves // we only care about moves
match mode { match mode {
euv::Copy => { return; } euv::Copy => {
return;
}
euv::Move(_) => {} euv::Move(_) => {}
} }
@ -287,28 +319,39 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
// for that to be legal, the upvar would have to be borrowed // for that to be legal, the upvar would have to be borrowed
// by value instead // by value instead
let guarantor = cmt.guarantor(); let guarantor = cmt.guarantor();
debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", debug!(
guarantor); "adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
debug!("adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}", guarantor
guarantor.cat); );
debug!(
"adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
guarantor.cat
);
match guarantor.cat { match guarantor.cat {
Categorization::Deref(_, mc::BorrowedPtr(..)) | Categorization::Deref(_, mc::BorrowedPtr(..)) |
Categorization::Deref(_, mc::Implicit(..)) => { Categorization::Deref(_, mc::Implicit(..)) => {
debug!("adjust_upvar_borrow_kind_for_consume: found deref with note {:?}", debug!(
cmt.note); "adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
cmt.note
);
match guarantor.note { match guarantor.note {
mc::NoteUpvarRef(upvar_id) => { mc::NoteUpvarRef(upvar_id) => {
debug!("adjust_upvar_borrow_kind_for_consume: \ debug!(
"adjust_upvar_borrow_kind_for_consume: \
setting upvar_id={:?} to by value", setting upvar_id={:?} to by value",
upvar_id); upvar_id
);
// to move out of an upvar, this must be a FnOnce closure // to move out of an upvar, this must be a FnOnce closure
self.adjust_closure_kind(upvar_id.closure_expr_id, self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce,
guarantor.span, guarantor.span,
var_name(tcx, upvar_id.var_id)); var_name(tcx, upvar_id.var_id),
);
self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); self.adjust_upvar_captures
.insert(upvar_id, ty::UpvarCapture::ByValue);
} }
mc::NoteClosureEnv(upvar_id) => { mc::NoteClosureEnv(upvar_id) => {
// we get just a closureenv ref if this is a // we get just a closureenv ref if this is a
@ -317,13 +360,14 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
// must still adjust the kind of the closure // must still adjust the kind of the closure
// to be a FnOnce closure to permit moves out // to be a FnOnce closure to permit moves out
// of the environment. // of the environment.
self.adjust_closure_kind(upvar_id.closure_expr_id, self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce,
guarantor.span, guarantor.span,
var_name(tcx, upvar_id.var_id)); var_name(tcx, upvar_id.var_id),
} );
mc::NoteNone => {
} }
mc::NoteNone => {}
} }
} }
_ => {} _ => {}
@ -334,8 +378,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
/// to). If cmt contains any by-ref upvars, this implies that /// to). If cmt contains any by-ref upvars, this implies that
/// those upvars must be borrowed using an `&mut` borrow. /// those upvars must be borrowed using an `&mut` borrow.
fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt);
cmt);
match cmt.cat.clone() { match cmt.cat.clone() {
Categorization::Deref(base, mc::Unique) | Categorization::Deref(base, mc::Unique) |
@ -368,8 +411,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
} }
fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt);
cmt);
match cmt.cat.clone() { match cmt.cat.clone() {
Categorization::Deref(base, mc::Unique) | Categorization::Deref(base, mc::Unique) |
@ -393,16 +435,11 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
Categorization::StaticItem | Categorization::StaticItem |
Categorization::Rvalue(..) | Categorization::Rvalue(..) |
Categorization::Local(_) | Categorization::Local(_) |
Categorization::Upvar(..) => { Categorization::Upvar(..) => {}
}
} }
} }
fn try_adjust_upvar_deref(&mut self, fn try_adjust_upvar_deref(&mut self, cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool {
cmt: mc::cmt<'tcx>,
borrow_kind: ty::BorrowKind)
-> bool
{
assert!(match borrow_kind { assert!(match borrow_kind {
ty::MutBorrow => true, ty::MutBorrow => true,
ty::UniqueImmBorrow => true, ty::UniqueImmBorrow => true,
@ -422,10 +459,12 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
self.adjust_upvar_borrow_kind(upvar_id, borrow_kind); self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
// also need to be in an FnMut closure since this is not an ImmBorrow // also need to be in an FnMut closure since this is not an ImmBorrow
self.adjust_closure_kind(upvar_id.closure_expr_id, self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut, ty::ClosureKind::FnMut,
cmt.span, cmt.span,
var_name(tcx, upvar_id.var_id)); var_name(tcx, upvar_id.var_id),
);
true true
} }
@ -433,16 +472,16 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
// this kind of deref occurs in a `move` closure, or // this kind of deref occurs in a `move` closure, or
// for a by-value upvar; in either case, to mutate an // for a by-value upvar; in either case, to mutate an
// upvar, we need to be an FnMut closure // upvar, we need to be an FnMut closure
self.adjust_closure_kind(upvar_id.closure_expr_id, self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut, ty::ClosureKind::FnMut,
cmt.span, cmt.span,
var_name(tcx, upvar_id.var_id)); var_name(tcx, upvar_id.var_id),
);
true true
} }
mc::NoteNone => { mc::NoteNone => false,
false
}
} }
} }
@ -451,13 +490,17 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
/// moving from left to right as needed (but never right to left). /// moving from left to right as needed (but never right to left).
/// Here the argument `mutbl` is the borrow_kind that is required by /// Here the argument `mutbl` is the borrow_kind that is required by
/// some particular use. /// some particular use.
fn adjust_upvar_borrow_kind(&mut self, fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) {
upvar_id: ty::UpvarId, let upvar_capture = self.adjust_upvar_captures
kind: ty::BorrowKind) { .get(&upvar_id)
let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned() .cloned()
.unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", debug!(
upvar_id, upvar_capture, kind); "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
upvar_id,
upvar_capture,
kind
);
match upvar_capture { match upvar_capture {
ty::UpvarCapture::ByValue => { ty::UpvarCapture::ByValue => {
@ -470,37 +513,49 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
(ty::ImmBorrow, ty::MutBorrow) | (ty::ImmBorrow, ty::MutBorrow) |
(ty::UniqueImmBorrow, ty::MutBorrow) => { (ty::UniqueImmBorrow, ty::MutBorrow) => {
upvar_borrow.kind = kind; upvar_borrow.kind = kind;
self.adjust_upvar_captures.insert(upvar_id, self.adjust_upvar_captures
ty::UpvarCapture::ByRef(upvar_borrow)); .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow));
} }
// Take LHS: // Take LHS:
(ty::ImmBorrow, ty::ImmBorrow) | (ty::ImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::ImmBorrow) | (ty::UniqueImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
(ty::MutBorrow, _) => { (ty::MutBorrow, _) => {}
}
} }
} }
} }
} }
fn adjust_closure_kind(&mut self, fn adjust_closure_kind(
&mut self,
closure_id: LocalDefId, closure_id: LocalDefId,
new_kind: ty::ClosureKind, new_kind: ty::ClosureKind,
upvar_span: Span, upvar_span: Span,
var_name: ast::Name) { var_name: ast::Name,
debug!("adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", ) {
closure_id, new_kind, upvar_span, var_name); debug!(
"adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})",
closure_id,
new_kind,
upvar_span,
var_name
);
let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned() // Is this the closure whose kind is currently being inferred?
.or_else(|| { if closure_id.to_def_id() != self.closure_def_id {
let closure_id = self.fcx.tcx.hir.local_def_id_to_hir_id(closure_id); debug!("adjust_closure_kind: not current closure");
self.fcx.tables.borrow().closure_kinds().get(closure_id).cloned() return;
}); }
if let Some((existing_kind, _)) = closure_kind { // closures start out as `Fn`.
debug!("adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", let existing_kind = self.current_closure_kind;
closure_id, existing_kind, new_kind);
debug!(
"adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}",
closure_id,
existing_kind,
new_kind
);
match (existing_kind, new_kind) { match (existing_kind, new_kind) {
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) | (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
@ -514,52 +569,48 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
// new kind is stronger than the old kind // new kind is stronger than the old kind
self.adjust_closure_kinds.insert( self.current_closure_kind = new_kind;
closure_id, self.current_origin = Some((upvar_span, var_name));
(new_kind, Some((upvar_span, var_name)))
);
}
} }
} }
} }
} }
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
fn consume(&mut self, fn consume(
&mut self,
_consume_id: ast::NodeId, _consume_id: ast::NodeId,
_consume_span: Span, _consume_span: Span,
cmt: mc::cmt<'tcx>, cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) mode: euv::ConsumeMode,
{ ) {
debug!("consume(cmt={:?},mode={:?})", cmt, mode); debug!("consume(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
} }
fn matched_pat(&mut self, fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: mc::cmt<'tcx>, _mode: euv::MatchMode) {
_matched_pat: &hir::Pat, }
_cmt: mc::cmt<'tcx>,
_mode: euv::MatchMode)
{}
fn consume_pat(&mut self, fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
_consume_pat: &hir::Pat,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
} }
fn borrow(&mut self, fn borrow(
&mut self,
borrow_id: ast::NodeId, borrow_id: ast::NodeId,
_borrow_span: Span, _borrow_span: Span,
cmt: mc::cmt<'tcx>, cmt: mc::cmt<'tcx>,
_loan_region: ty::Region<'tcx>, _loan_region: ty::Region<'tcx>,
bk: ty::BorrowKind, bk: ty::BorrowKind,
_loan_cause: euv::LoanCause) _loan_cause: euv::LoanCause,
{ ) {
debug!("borrow(borrow_id={}, cmt={:?}, bk={:?})", debug!(
borrow_id, cmt, bk); "borrow(borrow_id={}, cmt={:?}, bk={:?})",
borrow_id,
cmt,
bk
);
match bk { match bk {
ty::ImmBorrow => {} ty::ImmBorrow => {}
@ -572,19 +623,16 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
} }
} }
fn decl_without_init(&mut self, fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {}
_id: ast::NodeId,
_span: Span)
{}
fn mutate(&mut self, fn mutate(
&mut self,
_assignment_id: ast::NodeId, _assignment_id: ast::NodeId,
_assignment_span: Span, _assignment_span: Span,
assignee_cmt: mc::cmt<'tcx>, assignee_cmt: mc::cmt<'tcx>,
_mode: euv::MutateMode) _mode: euv::MutateMode,
{ ) {
debug!("mutate(assignee_cmt={:?})", debug!("mutate(assignee_cmt={:?})", assignee_cmt);
assignee_cmt);
self.adjust_upvar_borrow_kind_for_mut(assignee_cmt); self.adjust_upvar_borrow_kind_for_mut(assignee_cmt);
} }

View File

@ -47,8 +47,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
wbcx.visit_anon_types(); wbcx.visit_anon_types();
wbcx.visit_cast_types(); wbcx.visit_cast_types();
wbcx.visit_free_region_map(); wbcx.visit_free_region_map();
wbcx.visit_generator_sigs();
wbcx.visit_generator_interiors();
let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports, let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
Rc::new(DefIdSet())); Rc::new(DefIdSet()));
@ -244,21 +242,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
let common_local_id_root = fcx_tables.local_id_root.unwrap(); let common_local_id_root = fcx_tables.local_id_root.unwrap();
for (&id, closure_ty) in fcx_tables.closure_tys().iter() { for (&id, &origin) in fcx_tables.closure_kind_origins().iter() {
let hir_id = hir::HirId { let hir_id = hir::HirId {
owner: common_local_id_root.index, owner: common_local_id_root.index,
local_id: id, local_id: id,
}; };
let closure_ty = self.resolve(closure_ty, &hir_id); self.tables.closure_kind_origins_mut().insert(hir_id, origin);
self.tables.closure_tys_mut().insert(hir_id, closure_ty);
}
for (&id, &closure_kind) in fcx_tables.closure_kinds().iter() {
let hir_id = hir::HirId {
owner: common_local_id_root.index,
local_id: id,
};
self.tables.closure_kinds_mut().insert(hir_id, closure_kind);
} }
} }
@ -418,33 +407,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
} }
} }
fn visit_generator_interiors(&mut self) {
let common_local_id_root = self.fcx.tables.borrow().local_id_root.unwrap();
for (&id, interior) in self.fcx.tables.borrow().generator_interiors().iter() {
let hir_id = hir::HirId {
owner: common_local_id_root.index,
local_id: id,
};
let interior = self.resolve(interior, &hir_id);
self.tables.generator_interiors_mut().insert(hir_id, interior);
}
}
fn visit_generator_sigs(&mut self) {
let common_local_id_root = self.fcx.tables.borrow().local_id_root.unwrap();
for (&id, gen_sig) in self.fcx.tables.borrow().generator_sigs().iter() {
let hir_id = hir::HirId {
owner: common_local_id_root.index,
local_id: id,
};
let gen_sig = gen_sig.map(|s| ty::GenSig {
yield_ty: self.resolve(&s.yield_ty, &hir_id),
return_ty: self.resolve(&s.return_ty, &hir_id),
});
self.tables.generator_sigs_mut().insert(hir_id, gen_sig);
}
}
fn visit_liberated_fn_sigs(&mut self) { fn visit_liberated_fn_sigs(&mut self) {
let fcx_tables = self.fcx.tables.borrow(); let fcx_tables = self.fcx.tables.borrow();
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);

View File

@ -1019,9 +1019,31 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// cares about anything but the length is instantiation, // cares about anything but the length is instantiation,
// and we don't do that for closures. // and we don't do that for closures.
if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node { if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
// add a dummy parameter for the closure kind
types.push(ty::TypeParameterDef {
index: type_start,
name: Symbol::intern("<closure_kind>"),
def_id,
has_default: false,
object_lifetime_default: rl::Set1::Empty,
pure_wrt_drop: false,
synthetic: None,
});
// add a dummy parameter for the closure signature
types.push(ty::TypeParameterDef {
index: type_start + 1,
name: Symbol::intern("<closure_signature>"),
def_id,
has_default: false,
object_lifetime_default: rl::Set1::Empty,
pure_wrt_drop: false,
synthetic: None,
});
tcx.with_freevars(node_id, |fv| { tcx.with_freevars(node_id, |fv| {
types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef {
index: type_start + i as u32, index: type_start + i,
name: Symbol::intern("<upvar>"), name: Symbol::intern("<upvar>"),
def_id, def_id,
has_default: false, has_default: false,
@ -1156,14 +1178,19 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return tcx.typeck_tables_of(def_id).node_id_to_type(hir_id); return tcx.typeck_tables_of(def_id).node_id_to_type(hir_id);
} }
tcx.mk_closure(def_id, Substs::for_item( let substs = ty::ClosureSubsts {
tcx, def_id, substs: Substs::for_item(
tcx,
def_id,
|def, _| { |def, _| {
let region = def.to_early_bound_region_data(); let region = def.to_early_bound_region_data();
tcx.mk_region(ty::ReEarlyBound(region)) tcx.mk_region(ty::ReEarlyBound(region))
}, },
|def, _| tcx.mk_param_from_def(def) |def, _| tcx.mk_param_from_def(def)
)) )
};
tcx.mk_closure(def_id, substs)
} }
NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) { NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
@ -1242,7 +1269,14 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
NodeExpr(&hir::Expr { node: hir::ExprClosure(..), hir_id, .. }) => { NodeExpr(&hir::Expr { node: hir::ExprClosure(..), hir_id, .. }) => {
tcx.typeck_tables_of(def_id).closure_tys()[hir_id] let tables = tcx.typeck_tables_of(def_id);
match tables.node_id_to_type(hir_id).sty {
ty::TyClosure(closure_def_id, closure_substs) => {
assert_eq!(def_id, closure_def_id);
return closure_substs.closure_sig(closure_def_id, tcx);
}
ref t => bug!("closure with non-closure type: {:?}", t),
}
} }
x => { x => {

View File

@ -13,8 +13,7 @@ fn bar<F>(blk: F) where F: FnOnce() + 'static {
fn foo(x: &()) { fn foo(x: &()) {
bar(|| { bar(|| {
//~^ ERROR cannot infer //~^ ERROR does not fulfill
//~| ERROR does not fulfill
let _ = x; let _ = x;
}) })
} }

View File

@ -0,0 +1,45 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generator_trait)]
#![feature(generators)]
// Test that we cannot create a generator that returns a value of its
// own type.
use std::ops::Generator;
pub fn want_cyclic_generator_return<T>(_: T)
where T: Generator<Yield = (), Return = T>
{
}
fn supply_cyclic_generator_return() {
want_cyclic_generator_return(|| {
//~^ ERROR type mismatch
if false { yield None.unwrap(); }
None.unwrap()
})
}
pub fn want_cyclic_generator_yield<T>(_: T)
where T: Generator<Yield = T, Return = ()>
{
}
fn supply_cyclic_generator_yield() {
want_cyclic_generator_yield(|| {
//~^ ERROR type mismatch
if false { yield None.unwrap(); }
None.unwrap()
})
}
fn main() { }

View File

@ -19,7 +19,6 @@ struct A (B);
impl A { impl A {
pub fn matches<F: Fn()>(&self, f: &F) { pub fn matches<F: Fn()>(&self, f: &F) {
//~^ ERROR reached the recursion limit while instantiating `A::matches::<[closure
let &A(ref term) = self; let &A(ref term) = self;
term.matches(f); term.matches(f);
} }
@ -59,6 +58,7 @@ struct D (Box<A>);
impl D { impl D {
pub fn matches<F: Fn()>(&self, f: &F) { pub fn matches<F: Fn()>(&self, f: &F) {
//~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure
let &D(ref a) = self; let &D(ref a) = self;
a.matches(f) a.matches(f)
} }

View File

@ -15,5 +15,5 @@ fn fix<F>(f: F) -> i32 where F: Fn(Helper<F>, i32) -> i32 {
} }
fn main() { fn main() {
fix(|_, x| x); fix(|_, x| x); //~ ERROR closure/generator type that references itself [E0644]
} }

View File

@ -16,7 +16,5 @@ fn main() {
g = f; g = f;
f = box g; f = box g;
//~^ ERROR mismatched types //~^ ERROR mismatched types
//~| expected type `_`
//~| found type `std::boxed::Box<_>`
//~| cyclic type of infinite size //~| cyclic type of infinite size
} }

View File

@ -14,7 +14,5 @@ fn main() {
let f; let f;
f = box f; f = box f;
//~^ ERROR mismatched types //~^ ERROR mismatched types
//~| expected type `_`
//~| found type `std::boxed::Box<_>`
//~| cyclic type of infinite size //~| cyclic type of infinite size
} }

View File

@ -0,0 +1,50 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z span_free_formats
// Tests that MIR inliner can handle closure arguments,
// even when (#45894)
fn main() {
println!("{}", foo(0, &14));
}
fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
let x = |r: &i32, _s: &i32| {
let variable = &*r;
*variable
};
x(q, q)
}
// END RUST SOURCE
// START rustc.foo.Inline.after.mir
// ...
// bb0: {
// ...
// _3 = [closure@NodeId(39)];
// ...
// _4 = &_3;
// ...
// _6 = &(*_2);
// ...
// _7 = &(*_2);
// _5 = (_6, _7);
// _9 = (_5.0: &i32);
// _10 = (_5.1: &i32);
// StorageLive(_8);
// _8 = (*_9);
// _0 = _8;
// ...
// return;
// }
// ...
// END rustc.foo.Inline.after.mir

View File

@ -34,7 +34,9 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
// ... // ...
// _7 = _2; // _7 = _2;
// _5 = (_6, _7); // _5 = (_6, _7);
// _0 = (_5.0: i32); // _8 = (_5.0: i32);
// _9 = (_5.1: i32);
// _0 = _8;
// ... // ...
// return; // return;
// } // }

View File

@ -6,16 +6,5 @@ error[E0599]: no method named `b` found for type `&Self` in the current scope
| |
= help: did you mean `a`? = help: did you mean `a`?
error[E0308]: mismatched types error: aborting due to previous error
--> $DIR/issue-3563.rs:13:9
|
12 | fn a(&self) {
| - possibly return type missing here?
13 | || self.b()
| ^^^^^^^^^^^ expected (), found closure
|
= note: expected type `()`
found type `[closure@$DIR/issue-3563.rs:13:9: 13:20 self:_]`
error: aborting due to 2 previous errors

View File

@ -43,9 +43,6 @@ error[E0308]: mismatched types
| |
41 | f = box f; 41 | f = box f;
| ^^^^^ cyclic type of infinite size | ^^^^^ cyclic type of infinite size
|
= note: expected type `_`
found type `std::boxed::Box<_>`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:48:9 --> $DIR/coerce-suggestions.rs:48:9

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Test that unboxed closures cannot capture their own type.
//
// Also regression test for issue #21410.
fn g<F>(_: F) where F: FnOnce(Option<F>) {} fn g<F>(_: F) where F: FnOnce(Option<F>) {}
fn main() { fn main() {

View File

@ -0,0 +1,12 @@
error[E0644]: closure/generator type that references itself
--> $DIR/unboxed-closure-no-cyclic-sig.rs:18:7
|
18 | g(|_| { });
| ^^^^^^^^ cyclic type of infinite size
|
= note: closures cannot capture themselves or take themselves as argument;
this error may be the result of a recent compiler bug-fix,
see https://github.com/rust-lang/rust/issues/46062 for more details
error: aborting due to previous error