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),
[] ImplTraitRef(DefId),
[] ImplPolarity(DefId),
[] ClosureKind(DefId),
[] FnSignature(DefId),
[] GenSignature(DefId),
[] CoerceUnsizedInfo(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! {
// E0006 // merged with E0005

View file

@ -236,8 +236,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
ty::Predicate::ObjectSafe(def_id) => {
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);
closure_substs.hash_stable(hcx, hasher);
closure_kind.hash_stable(hcx, hasher);
}
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),
ambient_variance,
needs_wf: false,
root_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> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
/// Span, used when creating new type variables and things.
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,
/// Track the variance as we descend into the type.
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
@ -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-roots are equal, then `for_vid` and
// `vid` are related via subtyping.
return Err(TypeError::CyclicTy);
return Err(TypeError::CyclicTy(self.root_ty));
} else {
match variables.probe_root(vid) {
Some(u) => {

View file

@ -689,9 +689,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
diag: &mut DiagnosticBuilder<'tcx>,
cause: &ObligationCause<'tcx>,
secondary_span: Option<(Span, String)>,
values: Option<ValuePairs<'tcx>>,
mut values: Option<ValuePairs<'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 {
None => (None, None, false),
Some(values) => {
@ -780,17 +787,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
terr);
let span = trace.cause.span;
let failure_str = trace.cause.as_failure_str();
let mut diag = match trace.cause.code {
ObligationCauseCode::IfExpressionWithNoElse => {
let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match failure_code {
FailureCode::Error0317(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)
}
_ => {
FailureCode::Error0308(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);
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> {
fn as_failure_str(&self) -> &'static str {
fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
use self::FailureCode::*;
use traits::ObligationCauseCode::*;
match self.code {
CompareImplMethodObligation { .. } => "method not compatible with trait",
MatchExpressionArm { source, .. } => match source {
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
MatchExpressionArm { source, .. } => Error0308(match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
_ => "match arms have incompatible types",
},
IfExpression => "if and else have incompatible types",
IfExpressionWithNoElse => "if may be missing an else clause",
EquatePredicate => "equality predicate not satisfied",
MainFunctionType => "main function has wrong type",
StartFunctionType => "start function has wrong type",
IntrinsicType => "intrinsic has wrong type",
MethodReceiver => "mismatched method receiver",
_ => "mismatched types",
}),
IfExpression => Error0308("if and else have incompatible types"),
IfExpressionWithNoElse => Error0317("if may be missing an else clause"),
EquatePredicate => Error0308("equality predicate not satisfied"),
MainFunctionType => Error0580("main function has wrong type"),
StartFunctionType => Error0308("start function has wrong type"),
IntrinsicType => Error0308("intrinsic has wrong type"),
MethodReceiver => Error0308("mismatched method receiver"),
// 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.push((pattern.span, format!("consider giving this closure parameter a type")));
}
if let Some(pattern) = local_visitor.found_local_pattern {
} else if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_name) = pattern.simple_name() {
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
} else {

View file

@ -43,9 +43,7 @@
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeFolder;
use ty::subst::Substs;
use util::nodemap::FxHashMap;
use hir::def_id::DefId;
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>,
freshen_count: u32,
freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
closure_set: Vec<DefId>,
}
impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
@ -66,7 +63,6 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
infcx,
freshen_count: 0,
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> {
@ -249,51 +163,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
t
}
ty::TyClosure(def_id, substs) => {
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::TyGenerator(..) |
ty::TyBool |
ty::TyChar |
ty::TyInt(..) |
@ -314,6 +184,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyProjection(..) |
ty::TyForeign(..) |
ty::TyParam(..) |
ty::TyClosure(..) |
ty::TyAnon(..) => {
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)
}
/// 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,
def_id: DefId)
closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>)
-> Option<ty::ClosureKind>
{
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);
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))
let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
closure_kind_ty.to_opt_closure_kind()
}
/// 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
/// return the closure signature in its partially inferred state.
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 {
// Is this a local item?
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().closure_tys().get(hir_id) {
return ty;
// Is it a local *closure*?
if self.tcx.is_closure(def_id) {
let hir_id = self.tcx.hir.node_to_hir_id(id);
// Is this local closure contained within the tables we are inferring?
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)
}
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
/// new obligations that must further be processed.
pub fn partially_normalize_associated_types_in<T>(&self,

View file

@ -56,7 +56,10 @@ pub enum TypeVariableOrigin {
NormalizeProjectionType(Span),
TypeInference(Span),
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),
AutoDeref(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 {
ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
ty::TyClosure(..) => {
match self.tables.closure_kinds().get(fn_hir_id) {
Some(&(kind, _)) => kind,
None => span_bug!(span, "missing closure kind"),
ty::TyClosure(closure_def_id, closure_substs) => {
match self.infcx {
// During upvar inference we may not know the
// 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),

View file

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

View file

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

View file

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

View file

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

View file

@ -356,16 +356,9 @@ pub struct TypeckTables<'tcx> {
/// Borrows
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
/// Records the type of each closure.
closure_tys: ItemLocalMap<ty::PolyFnSig<'tcx>>,
/// 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>>,
/// Records the reasons that we picked the kind of each closure;
/// not all closures are present in the map.
closure_kind_origins: ItemLocalMap<(Span, ast::Name)>,
/// For each fn, records the "liberated" types of its arguments
/// and return type. Liberated means that all bound regions
@ -411,10 +404,7 @@ impl<'tcx> TypeckTables<'tcx> {
pat_binding_modes: ItemLocalMap(),
pat_adjustments: ItemLocalMap(),
upvar_capture_map: FxHashMap(),
generator_sigs: ItemLocalMap(),
generator_interiors: ItemLocalMap(),
closure_tys: ItemLocalMap(),
closure_kinds: ItemLocalMap(),
closure_kind_origins: ItemLocalMap(),
liberated_fn_sigs: ItemLocalMap(),
fru_field_types: ItemLocalMap(),
cast_kinds: ItemLocalMap(),
@ -609,34 +599,17 @@ impl<'tcx> TypeckTables<'tcx> {
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 {
local_id_root: self.local_id_root,
data: &self.closure_tys
data: &self.closure_kind_origins
}
}
pub fn closure_tys_mut(&mut self)
-> LocalTableInContextMut<ty::PolyFnSig<'tcx>> {
pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<(Span, ast::Name)> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.closure_tys
}
}
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
data: &mut self.closure_kind_origins
}
}
@ -681,42 +654,6 @@ impl<'tcx> TypeckTables<'tcx> {
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> {
@ -732,8 +669,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
ref pat_binding_modes,
ref pat_adjustments,
ref upvar_capture_map,
ref closure_tys,
ref closure_kinds,
ref closure_kind_origins,
ref liberated_fn_sigs,
ref fru_field_types,
@ -742,8 +678,6 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
ref used_trait_imports,
tainted_by_errors,
ref free_region_map,
ref generator_sigs,
ref generator_interiors,
} = *self;
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))
});
closure_tys.hash_stable(hcx, hasher);
closure_kinds.hash_stable(hcx, hasher);
closure_kind_origins.hash_stable(hcx, hasher);
liberated_fn_sigs.hash_stable(hcx, hasher);
fru_field_types.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);
tainted_by_errors.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,
closure_id: DefId,
substs: &'tcx Substs<'tcx>)
-> Ty<'tcx> {
self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
substs,
})
substs: ClosureSubsts<'tcx>)
-> Ty<'tcx> {
self.mk_closure_from_closure_substs(closure_id, substs)
}
pub fn mk_closure_from_closure_substs(self,

View file

@ -49,7 +49,11 @@ pub enum TypeError<'tcx> {
FloatMismatch(ExpectedFound<ast::FloatTy>),
Traits(ExpectedFound<DefId>),
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>),
ProjectionBoundsLength(ExpectedFound<usize>),
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
@ -84,7 +88,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
}
match *self {
CyclicTy => write!(f, "cyclic type of infinite size"),
CyclicTy(_) => write!(f, "cyclic type of infinite size"),
Mismatch => write!(f, "types differ"),
UnsafetyMismatch(values) => {
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);
}
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)
-> 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) {
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.
[] 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.
[] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult,
/// The signature of functions and closures.
[] 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.
[] fn coerce_unsized_info: CoerceUnsizedInfo(DefId)
-> 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::ImplTraitRef => { force!(impl_trait_ref, def_id!()); }
DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); }
DepKind::ClosureKind => { force!(closure_kind, 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::ItemVariances => { force!(variances_of, 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<...>`
/// for some substitutions `...` and T being a closure type.
/// Satisfied (or refuted) once we know the closure's kind.
ClosureKind(DefId, ClosureKind),
ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind),
/// `T1 <: T2`
Subtype(PolySubtypePredicate<'tcx>),
@ -999,8 +999,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
Predicate::WellFormed(data.subst(tcx, substs)),
Predicate::ObjectSafe(trait_def_id) =>
Predicate::ObjectSafe(trait_def_id),
Predicate::ClosureKind(closure_def_id, kind) =>
Predicate::ClosureKind(closure_def_id, kind),
Predicate::ClosureKind(closure_def_id, closure_substs, kind) =>
Predicate::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind),
Predicate::ConstEvaluatable(def_id, const_substs) =>
Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)),
}
@ -1182,8 +1182,8 @@ impl<'tcx> Predicate<'tcx> {
ty::Predicate::ObjectSafe(_trait_def_id) => {
vec![]
}
ty::Predicate::ClosureKind(_closure_def_id, _kind) => {
vec![]
ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => {
closure_substs.substs.types().collect()
}
ty::Predicate::ConstEvaluatable(_, substs) => {
substs.types().collect()
@ -1932,6 +1932,9 @@ pub enum 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 {
match *self {
ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem),
@ -1957,6 +1960,16 @@ impl<'a, 'tcx> ClosureKind {
_ => 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> {

View file

@ -211,8 +211,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
ty::Predicate::WellFormed(ty) => {
tcx.lift(&ty).map(ty::Predicate::WellFormed)
}
ty::Predicate::ClosureKind(closure_def_id, kind) => {
Some(ty::Predicate::ClosureKind(closure_def_id, kind))
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
tcx.lift(&closure_substs)
.map(|closure_substs| ty::Predicate::ClosureKind(closure_def_id,
closure_substs,
kind))
}
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),
Traits(x) => Traits(x),
VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy => CyclicTy,
CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)),
ProjectionMismatched(x) => ProjectionMismatched(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::WellFormed(data) =>
ty::Predicate::WellFormed(data.fold_with(folder)),
ty::Predicate::ClosureKind(closure_def_id, kind) =>
ty::Predicate::ClosureKind(closure_def_id, kind),
ty::Predicate::ClosureKind(closure_def_id, closure_substs, 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::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::Projection(ref binder) => binder.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::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),
Traits(x) => Traits(x),
VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy => CyclicTy,
CyclicTy(t) => CyclicTy(t.fold_with(folder)),
ProjectionMismatched(x) => ProjectionMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
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),
TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
ExistentialMismatch(x) => x.visit_with(visitor),
CyclicTy(t) => t.visit_with(visitor),
Mismatch |
Mutability |
TupleSize(_) |
@ -1205,7 +1210,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
FloatMismatch(_) |
Traits(_) |
VariadicMismatch(_) |
CyclicTy |
ProjectionMismatched(_) |
ProjectionBoundsLength(_) => false,
}

View file

@ -174,16 +174,26 @@ pub enum TypeVariants<'tcx> {
/// 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,
/// ...
/// upvark: Uk
/// }
///
/// where 'l0...'li and T0...Tj are the lifetime and type parameters
/// in scope on the function that defined the closure, and U0...Uk are
/// type parameters representing the types of its upvars (borrowed, if
/// appropriate).
/// where:
///
/// - 'l0...'li and T0...Tj are the lifetime and type parameters
/// 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:
///
@ -246,6 +256,17 @@ pub enum TypeVariants<'tcx> {
/// closure C wind up influencing the decisions we ought to make for
/// closure C (which would then require fixed point iteration to
/// 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)]
pub struct ClosureSubsts<'tcx> {
/// Lifetime and type parameters from the enclosing function,
@ -256,14 +277,97 @@ pub struct ClosureSubsts<'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]
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
{
let generics = tcx.generics_of(def_id);
self.substs[self.substs.len()-generics.own_count()..].iter().map(
|t| t.as_type().expect("unexpected region in upvars"))
let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
}
/// 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 {
match self.sty {
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.

View file

@ -336,14 +336,50 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
}
}
ty::TyGenerator(..) | ty::TyClosure(..) => {
// the types in a closure or generator are always the types of
// local variables (or possibly references to local
// variables), we'll walk those.
ty::TyGenerator(..) => {
// Walk ALL the types in the generator: this will
// include the upvar types as well as the yield
// 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
// needed, as they are separately checked w/r/t
// WFedness.)
// The special treatment of closures here really
// ought not to be necessary either; the problem
// 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(_) => {

View file

@ -1261,7 +1261,7 @@ define_print! {
ty::tls::with(|tcx| {
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| {
write!(f, "the closure `{}` implements the trait `{}`",
tcx.item_path_str(closure_def_id), kind)
@ -1285,8 +1285,8 @@ define_print! {
ty::Predicate::ObjectSafe(trait_def_id) => {
write!(f, "ObjectSafe({:?})", trait_def_id)
}
ty::Predicate::ClosureKind(closure_def_id, kind) => {
write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
ty::Predicate::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, _) => {
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) =
self.tables.closure_kinds().get(hir_id)
{
err.span_note(span, &format!(
if let Some((span, name)) = self.tables.closure_kind_origins().get(hir_id) {
err.span_note(*span, &format!(
"closure cannot be invoked more than once because \
it moves the variable `{}` out of its environment",
name

View file

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

View file

@ -136,12 +136,10 @@ provide! { <'tcx> tcx, def_id, other, cdata,
mir
}
generator_sig => { cdata.generator_sig(def_id.index, tcx) }
mir_const_qualif => {
(cdata.mir_const_qualif(def_id.index), Rc::new(IdxSetBuf::new_empty(0)))
}
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) }
inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(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,
id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
@ -1043,23 +1036,6 @@ impl<'a, 'tcx> CrateMetadata {
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]
pub fn def_key(&self, index: DefIndex) -> DefKey {
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);
let tcx = self.tcx;
let kind = if let Some(sig) = self.tcx.generator_sig(def_id) {
let layout = self.tcx.generator_layout(def_id);
let data = GeneratorData {
sig,
layout: layout.clone(),
};
EntryKind::Generator(self.lazy(&data))
} else {
let data = ClosureData {
kind: tcx.closure_kind(def_id),
sig: self.lazy(&tcx.fn_sig(def_id)),
};
EntryKind::Closure(self.lazy(&data))
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 data = GeneratorData {
layout: layout.clone(),
};
EntryKind::Generator(self.lazy(&data))
}
ty::TyClosure(def_id, substs) => {
let sig = substs.closure_sig(def_id, self.tcx);
let data = ClosureData { sig: self.lazy(&sig) };
EntryKind::Closure(self.lazy(&data))
}
_ => bug!("closure that is neither generator nor closure")
};
Entry {

View file

@ -512,14 +512,12 @@ impl_stable_hash_for!(struct MethodData<'tcx> { fn_data, container, has_self });
#[derive(RustcEncodable, RustcDecodable)]
pub struct ClosureData<'tcx> {
pub kind: ty::ClosureKind,
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)]
pub struct GeneratorData<'tcx> {
pub sig: ty::PolyGenSig<'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

@ -103,7 +103,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
Some((closure_self_ty(tcx, id, body_id), None))
}
ty::TyGenerator(..) => {
let gen_ty = tcx.body_tables(body_id).node_id_to_type(fn_hir_id);
let gen_ty = tcx.body_tables(body_id).node_id_to_type(fn_hir_id);
Some((gen_ty, None))
}
_ => None,
@ -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 (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)
} else {
(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_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 {
scope: closure_def_id,
bound_region: ty::BoundRegion::BrEnv,
});
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 =>
tcx.mk_ref(region,
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 self_expr = if let ty::TyClosure(..) = closure_ty.sty {
match cx.tcx.closure_kind(closure_def_id) {
let self_expr = if let ty::TyClosure(_, closure_substs) = closure_ty.sty {
match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() {
ty::ClosureKind::Fn => {
let ref_closure_ty = cx.tcx.mk_ref(region,
ty::TypeAndMut {

View file

@ -767,7 +767,11 @@ impl MirPass for StateTransform {
let hir_id = tcx.hir.node_to_hir_id(node_id);
// 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
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 std::collections::VecDeque;
use std::iter;
use transform::{MirPass, MirSource};
use super::simplify::{remove_dead_blocks, CfgSimplifier};
@ -559,8 +560,29 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
) -> Vec<Operand<'tcx>> {
let tcx = self.tcx;
// A closure is passed its self-type and a tuple like `(arg1, arg2, ...)`,
// hence mappings to tuple fields are needed.
// There is a bit of a mismatch between the *caller* of a closure and the *callee*.
// 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) {
let mut args = args.into_iter();
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");
};
let mut res = Vec::with_capacity(1 + tuple_tys.len());
res.push(Operand::Consume(self_));
res.extend(tuple_tys.iter().enumerate().map(|(i, ty)| {
Operand::Consume(tuple.clone().field(Field::new(i), ty))
}));
res
// The `closure_ref` in our example above.
let closure_ref_arg = iter::once(Operand::Consume(self_));
// The `tmp0`, `tmp1`, and `tmp2` in our example abonve.
let tuple_tmp_args =
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 {
args.into_iter()
.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 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::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), 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, _) => {
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_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)
-> 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) {
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
// haven't yet decided on whether the closure is fn vs
// 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 fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
@ -122,6 +122,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
adjustments,
fn_sig,
closure_def_id: def_id,
closure_substs: substs,
});
return Some(CallStep::DeferredClosure(fn_sig));
}
@ -336,6 +337,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
adjustments: Vec<Adjustment<'tcx>>,
fn_sig: ty::FnSig<'tcx>,
closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'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
// 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.
match fcx.try_overloaded_call_traits(self.call_expr,

View file

@ -10,7 +10,7 @@
//! Code for type-checking closure expressions.
use super::{check_fn, Expectation, FnCtxt};
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use astconv::AstConv;
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);
let interior = check_fn(
let generator_types = check_fn(
self,
self.param_env,
liberated_sig,
@ -100,14 +100,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|_, _| span_bug!(expr.span, "closure has region param"),
|_, _| {
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);
if let Some(interior) = interior {
let closure_substs = ty::ClosureSubsts { substs: substs };
return self.tcx.mk_generator(expr_def_id, closure_substs, interior);
if let Some(GeneratorTypes { yield_ty, interior }) = generator_types {
self.demand_eqtype(expr.span,
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!(
@ -135,15 +141,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
opt_kind
);
{
let mut tables = self.tables.borrow_mut();
tables.closure_tys_mut().insert(expr.hir_id, sig);
match opt_kind {
Some(kind) => {
tables.closure_kinds_mut().insert(expr.hir_id, (kind, None));
}
None => {}
}
let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
self.demand_eqtype(expr.span,
sig_fn_ptr_ty,
substs.closure_sig_ty(expr_def_id, self.tcx));
if let Some(kind) = opt_kind {
self.demand_eqtype(expr.span,
kind.to_ty(self.tcx),
substs.closure_kind_ty(expr_def_id, self.tcx));
}
closure_type

View file

@ -759,30 +759,12 @@ pub fn provide(providers: &mut Providers) {
typeck_item_bodies,
typeck_tables_of,
has_typeck_tables,
closure_kind,
generator_sig,
adt_destructor,
used_trait_imports,
..*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>,
def_id: DefId)
-> Option<ty::Destructor> {
@ -1021,6 +1003,17 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
_: 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
/// 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.
@ -1034,7 +1027,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
body: &'gcx hir::Body,
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();
@ -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 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));
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), witness));
let interior = ty::GeneratorInterior::new(witness);
inherited.tables.borrow_mut().generator_interiors_mut().insert(fn_hir_id, interior);
Some(interior)
Some(GeneratorTypes { yield_ty: fcx.yield_ty.unwrap(), interior: interior })
} else {
inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, None);
None
};
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::mem_categorization as mc;
use middle::mem_categorization::Categorization;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::infer::UpvarRegion;
use syntax::ast;
use syntax_pos::Span;
use rustc::hir;
use rustc::hir::def_id::LocalDefId;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::FxHashMap;
use std::collections::hash_map::Entry;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn closure_analyze(&self, body: &'gcx hir::Body) {
@ -65,7 +63,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
struct InferBorrowKindVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
struct InferBorrowKindVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
}
@ -79,14 +77,11 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
hir::ExprClosure(cc, _, body_id, _, is_generator) => {
let body = self.fcx.tcx.hir.body(body_id);
self.visit_body(body);
self.fcx.analyze_closure((expr.id, expr.hir_id),
expr.span,
body,
cc,
is_generator);
self.fcx
.analyze_closure(expr.id, expr.hir_id, expr.span, body, cc, is_generator);
}
_ => { }
_ => {}
}
intravisit::walk_expr(self, expr);
@ -94,35 +89,43 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn analyze_closure(&self,
(closure_node_id, closure_hir_id): (ast::NodeId, hir::HirId),
span: Span,
body: &hir::Body,
capture_clause: hir::CaptureClause,
gen: bool) {
fn analyze_closure(
&self,
closure_node_id: ast::NodeId,
closure_hir_id: hir::HirId,
span: Span,
body: &hir::Body,
capture_clause: hir::CaptureClause,
is_generator: bool,
) {
/*!
* 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 {
false
} else {
match self.tables
.borrow_mut()
.closure_kinds_mut()
.entry(closure_hir_id) {
Entry::Occupied(_) => false,
Entry::Vacant(entry) => {
debug!("check_closure: adding closure {:?} as Fn", closure_node_id);
entry.insert((ty::ClosureKind::Fn, None));
true
}
// Extract the type of the closure.
let (closure_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
);
}
};
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| {
for freevar in freevars {
@ -133,51 +136,63 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("seed upvar_id {:?}", upvar_id);
let capture_kind = match capture_clause {
hir::CaptureByValue => {
ty::UpvarCapture::ByValue
}
hir::CaptureByValue => ty::UpvarCapture::ByValue,
hir::CaptureByRef => {
let origin = UpvarRegion(upvar_id, span);
let freevar_region = self.next_region_var(origin);
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
region: freevar_region };
let upvar_borrow = ty::UpvarBorrow {
kind: ty::ImmBorrow,
region: freevar_region,
};
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 region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
let mut delegate = InferBorrowKind {
fcx: self,
adjust_closure_kinds: FxHashMap(),
adjust_upvar_captures: ty::UpvarCaptureMap::default(),
};
euv::ExprUseVisitor::with_infer(&mut delegate,
&self.infcx,
self.param_env,
region_scope_tree,
&self.tables.borrow())
.consume_body(body);
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 mut delegate = InferBorrowKind {
fcx: self,
closure_def_id: closure_def_id,
current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
current_origin: None,
adjust_upvar_captures: ty::UpvarCaptureMap::default(),
};
euv::ExprUseVisitor::with_infer(
&mut delegate,
&self.infcx,
self.param_env,
region_scope_tree,
&self.tables.borrow(),
).consume_body(body);
// Write the adjusted values back into the main tables.
if infer_kind {
if let Some(kind) = delegate.adjust_closure_kinds
.remove(&closure_def_id.to_local()) {
self.tables
.borrow_mut()
.closure_kinds_mut()
.insert(closure_hir_id, kind);
}
if infer_kind {
// Unify the (as yet unbound) type variable in the closure
// 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
.borrow_mut()
.closure_kind_origins_mut()
.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
// variable is borrowed, and we know what traits the closure
// implements (Fn vs FnMut etc). We now have some updates to do
@ -190,36 +205,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// C, then the type would have infinite size (and the
// inference algorithm will reject it).
// Extract the type variables UV0...UVn.
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.
// Equate the type variables for the upvars with the actual types.
let final_upvar_tys = self.final_upvar_tys(closure_node_id);
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
closure_node_id, closure_substs, final_upvar_tys);
for (upvar_ty, final_upvar_ty) in
closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys)
debug!(
"analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
closure_node_id,
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);
}
// If we are also inferred the closure kind here,
// process any deferred resolutions.
if infer_kind {
let deferred_call_resolutions =
self.remove_deferred_call_resolutions(closure_def_id);
for deferred_call_resolution in deferred_call_resolutions {
deferred_call_resolution.resolve(self);
}
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
for deferred_call_resolution in deferred_call_resolutions {
deferred_call_resolution.resolve(self);
}
}
@ -234,51 +239,78 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let closure_def_index = tcx.hir.local_def_id(closure_id);
tcx.with_freevars(closure_id, |freevars| {
freevars.iter().map(|freevar| {
let var_node_id = freevar.var_id();
let var_hir_id = tcx.hir.node_to_hir_id(var_node_id);
let freevar_ty = self.node_ty(var_hir_id);
let upvar_id = ty::UpvarId {
var_id: var_hir_id,
closure_expr_id: LocalDefId::from_def_id(closure_def_index),
};
let capture = self.tables.borrow().upvar_capture(upvar_id);
freevars
.iter()
.map(|freevar| {
let var_node_id = freevar.var_id();
let var_hir_id = tcx.hir.node_to_hir_id(var_node_id);
let freevar_ty = self.node_ty(var_hir_id);
let upvar_id = ty::UpvarId {
var_id: var_hir_id,
closure_expr_id: LocalDefId::from_def_id(closure_def_index),
};
let capture = self.tables.borrow().upvar_capture(upvar_id);
debug!("var_id={:?} freevar_ty={:?} capture={:?}",
var_node_id, freevar_ty, capture);
debug!(
"var_id={:?} freevar_ty={:?} capture={:?}",
var_node_id,
freevar_ty,
capture
);
match capture {
ty::UpvarCapture::ByValue => freevar_ty,
ty::UpvarCapture::ByRef(borrow) =>
tcx.mk_ref(borrow.region,
ty::TypeAndMut {
ty: freevar_ty,
mutbl: borrow.kind.to_mutbl_lossy(),
}),
}
}).collect()
match capture {
ty::UpvarCapture::ByValue => freevar_ty,
ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
borrow.region,
ty::TypeAndMut {
ty: freevar_ty,
mutbl: borrow.kind.to_mutbl_lossy(),
},
),
}
})
.collect()
})
}
}
struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
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>,
}
impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
fn adjust_upvar_borrow_kind_for_consume(&mut self,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
debug!("adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
cmt, mode);
fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
debug!(
"adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
cmt,
mode
);
// we only care about moves
match mode {
euv::Copy => { return; }
euv::Move(_) => { }
euv::Copy => {
return;
}
euv::Move(_) => {}
}
let tcx = self.fcx.tcx;
@ -287,28 +319,39 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
// for that to be legal, the upvar would have to be borrowed
// by value instead
let guarantor = cmt.guarantor();
debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
guarantor);
debug!("adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
guarantor.cat);
debug!(
"adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
guarantor
);
debug!(
"adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
guarantor.cat
);
match guarantor.cat {
Categorization::Deref(_, mc::BorrowedPtr(..)) |
Categorization::Deref(_, mc::Implicit(..)) => {
debug!("adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
cmt.note);
debug!(
"adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
cmt.note
);
match guarantor.note {
mc::NoteUpvarRef(upvar_id) => {
debug!("adjust_upvar_borrow_kind_for_consume: \
setting upvar_id={:?} to by value",
upvar_id);
debug!(
"adjust_upvar_borrow_kind_for_consume: \
setting upvar_id={:?} to by value",
upvar_id
);
// to move out of an upvar, this must be a FnOnce closure
self.adjust_closure_kind(upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
guarantor.span,
var_name(tcx, upvar_id.var_id));
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
guarantor.span,
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) => {
// we get just a closureenv ref if this is a
@ -317,16 +360,17 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
// must still adjust the kind of the closure
// to be a FnOnce closure to permit moves out
// of the environment.
self.adjust_closure_kind(upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
guarantor.span,
var_name(tcx, upvar_id.var_id));
}
mc::NoteNone => {
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
guarantor.span,
var_name(tcx, upvar_id.var_id),
);
}
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
/// those upvars must be borrowed using an `&mut` borrow.
fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})",
cmt);
debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt);
match cmt.cat.clone() {
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>) {
debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})",
cmt);
debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt);
match cmt.cat.clone() {
Categorization::Deref(base, mc::Unique) |
@ -393,16 +435,11 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
Categorization::StaticItem |
Categorization::Rvalue(..) |
Categorization::Local(_) |
Categorization::Upvar(..) => {
}
Categorization::Upvar(..) => {}
}
}
fn try_adjust_upvar_deref(&mut self,
cmt: mc::cmt<'tcx>,
borrow_kind: ty::BorrowKind)
-> bool
{
fn try_adjust_upvar_deref(&mut self, cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool {
assert!(match borrow_kind {
ty::MutBorrow => 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);
// also need to be in an FnMut closure since this is not an ImmBorrow
self.adjust_closure_kind(upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
cmt.span,
var_name(tcx, upvar_id.var_id));
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
cmt.span,
var_name(tcx, upvar_id.var_id),
);
true
}
@ -433,16 +472,16 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
// this kind of deref occurs in a `move` closure, or
// for a by-value upvar; in either case, to mutate an
// upvar, we need to be an FnMut closure
self.adjust_closure_kind(upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
cmt.span,
var_name(tcx, upvar_id.var_id));
self.adjust_closure_kind(
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
cmt.span,
var_name(tcx, upvar_id.var_id),
);
true
}
mc::NoteNone => {
false
}
mc::NoteNone => 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).
/// Here the argument `mutbl` is the borrow_kind that is required by
/// some particular use.
fn adjust_upvar_borrow_kind(&mut self,
upvar_id: ty::UpvarId,
kind: ty::BorrowKind) {
let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned()
fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) {
let upvar_capture = self.adjust_upvar_captures
.get(&upvar_id)
.cloned()
.unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
upvar_id, upvar_capture, kind);
debug!(
"adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
upvar_id,
upvar_capture,
kind
);
match upvar_capture {
ty::UpvarCapture::ByValue => {
@ -470,99 +513,107 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
(ty::ImmBorrow, ty::MutBorrow) |
(ty::UniqueImmBorrow, ty::MutBorrow) => {
upvar_borrow.kind = kind;
self.adjust_upvar_captures.insert(upvar_id,
ty::UpvarCapture::ByRef(upvar_borrow));
self.adjust_upvar_captures
.insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow));
}
// Take LHS:
(ty::ImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
(ty::MutBorrow, _) => {
}
(ty::MutBorrow, _) => {}
}
}
}
}
fn adjust_closure_kind(&mut self,
closure_id: LocalDefId,
new_kind: ty::ClosureKind,
upvar_span: Span,
var_name: ast::Name) {
debug!("adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})",
closure_id, new_kind, upvar_span, var_name);
fn adjust_closure_kind(
&mut self,
closure_id: LocalDefId,
new_kind: ty::ClosureKind,
upvar_span: Span,
var_name: ast::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()
.or_else(|| {
let closure_id = self.fcx.tcx.hir.local_def_id_to_hir_id(closure_id);
self.fcx.tables.borrow().closure_kinds().get(closure_id).cloned()
});
// Is this the closure whose kind is currently being inferred?
if closure_id.to_def_id() != self.closure_def_id {
debug!("adjust_closure_kind: not current closure");
return;
}
if let Some((existing_kind, _)) = closure_kind {
debug!("adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}",
closure_id, existing_kind, new_kind);
// closures start out as `Fn`.
let existing_kind = self.current_closure_kind;
match (existing_kind, new_kind) {
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
(ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
(ty::ClosureKind::FnOnce, _) => {
// no change needed
}
debug!(
"adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}",
closure_id,
existing_kind,
new_kind
);
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
// new kind is stronger than the old kind
self.adjust_closure_kinds.insert(
closure_id,
(new_kind, Some((upvar_span, var_name)))
);
}
match (existing_kind, new_kind) {
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
(ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
(ty::ClosureKind::FnOnce, _) => {
// no change needed
}
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
// new kind is stronger than the old kind
self.current_closure_kind = new_kind;
self.current_origin = Some((upvar_span, var_name));
}
}
}
}
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
fn consume(&mut self,
_consume_id: ast::NodeId,
_consume_span: Span,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
fn consume(
&mut self,
_consume_id: ast::NodeId,
_consume_span: Span,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode,
) {
debug!("consume(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
}
fn matched_pat(&mut self,
_matched_pat: &hir::Pat,
_cmt: mc::cmt<'tcx>,
_mode: euv::MatchMode)
{}
fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: mc::cmt<'tcx>, _mode: euv::MatchMode) {
}
fn consume_pat(&mut self,
_consume_pat: &hir::Pat,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
}
fn borrow(&mut self,
borrow_id: ast::NodeId,
_borrow_span: Span,
cmt: mc::cmt<'tcx>,
_loan_region: ty::Region<'tcx>,
bk: ty::BorrowKind,
_loan_cause: euv::LoanCause)
{
debug!("borrow(borrow_id={}, cmt={:?}, bk={:?})",
borrow_id, cmt, bk);
fn borrow(
&mut self,
borrow_id: ast::NodeId,
_borrow_span: Span,
cmt: mc::cmt<'tcx>,
_loan_region: ty::Region<'tcx>,
bk: ty::BorrowKind,
_loan_cause: euv::LoanCause,
) {
debug!(
"borrow(borrow_id={}, cmt={:?}, bk={:?})",
borrow_id,
cmt,
bk
);
match bk {
ty::ImmBorrow => { }
ty::ImmBorrow => {}
ty::UniqueImmBorrow => {
self.adjust_upvar_borrow_kind_for_unique(cmt);
}
@ -572,19 +623,16 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
}
}
fn decl_without_init(&mut self,
_id: ast::NodeId,
_span: Span)
{}
fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {}
fn mutate(&mut self,
_assignment_id: ast::NodeId,
_assignment_span: Span,
assignee_cmt: mc::cmt<'tcx>,
_mode: euv::MutateMode)
{
debug!("mutate(assignee_cmt={:?})",
assignee_cmt);
fn mutate(
&mut self,
_assignment_id: ast::NodeId,
_assignment_span: Span,
assignee_cmt: mc::cmt<'tcx>,
_mode: euv::MutateMode,
) {
debug!("mutate(assignee_cmt={:?})", 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_cast_types();
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,
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);
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 {
owner: common_local_id_root.index,
local_id: id,
};
let closure_ty = self.resolve(closure_ty, &hir_id);
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);
self.tables.closure_kind_origins_mut().insert(hir_id, origin);
}
}
@ -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) {
let fcx_tables = self.fcx.tables.borrow();
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,
// and we don't do that for closures.
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| {
types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
index: type_start + i as u32,
types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef {
index: type_start + i,
name: Symbol::intern("<upvar>"),
def_id,
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);
}
tcx.mk_closure(def_id, Substs::for_item(
tcx, def_id,
|def, _| {
let region = def.to_early_bound_region_data();
tcx.mk_region(ty::ReEarlyBound(region))
},
|def, _| tcx.mk_param_from_def(def)
))
let substs = ty::ClosureSubsts {
substs: Substs::for_item(
tcx,
def_id,
|def, _| {
let region = def.to_early_bound_region_data();
tcx.mk_region(ty::ReEarlyBound(region))
},
|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)) {
@ -1242,7 +1269,14 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
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 => {

View file

@ -13,8 +13,7 @@ fn bar<F>(blk: F) where F: FnOnce() + 'static {
fn foo(x: &()) {
bar(|| {
//~^ ERROR cannot infer
//~| ERROR does not fulfill
//~^ ERROR does not fulfill
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 {
pub fn matches<F: Fn()>(&self, f: &F) {
//~^ ERROR reached the recursion limit while instantiating `A::matches::<[closure
let &A(ref term) = self;
term.matches(f);
}
@ -59,6 +58,7 @@ struct D (Box<A>);
impl D {
pub fn matches<F: Fn()>(&self, f: &F) {
//~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure
let &D(ref a) = self;
a.matches(f)
}

View file

@ -15,5 +15,5 @@ fn fix<F>(f: F) -> i32 where F: Fn(Helper<F>, i32) -> i32 {
}
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;
f = box g;
//~^ ERROR mismatched types
//~| expected type `_`
//~| found type `std::boxed::Box<_>`
//~| cyclic type of infinite size
}

View file

@ -14,7 +14,5 @@ fn main() {
let f;
f = box f;
//~^ ERROR mismatched types
//~| expected type `_`
//~| found type `std::boxed::Box<_>`
//~| 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,9 +34,11 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
// ...
// _7 = _2;
// _5 = (_6, _7);
// _0 = (_5.0: i32);
// _8 = (_5.0: i32);
// _9 = (_5.1: i32);
// _0 = _8;
// ...
// return;
// }
// ...
// END rustc.foo.Inline.after.mir
// END rustc.foo.Inline.after.mir

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`?
error[E0308]: mismatched types
--> $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
error: aborting due to previous error

View file

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

View file

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed
// 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 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