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:
commit
d6d09e0b4d
55 changed files with 994 additions and 773 deletions
|
@ -498,9 +498,7 @@ define_dep_nodes!( <'tcx>
|
|||
[] IsAutoImpl(DefId),
|
||||
[] ImplTraitRef(DefId),
|
||||
[] ImplPolarity(DefId),
|
||||
[] ClosureKind(DefId),
|
||||
[] FnSignature(DefId),
|
||||
[] GenSignature(DefId),
|
||||
[] CoerceUnsizedInfo(DefId),
|
||||
|
||||
[] ItemVarianceConstraints(DefId),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -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![]))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!()); }
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(_) => {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(quote)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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;
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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() { }
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
50
src/test/mir-opt/inline-closure-borrows-arg.rs
Normal file
50
src/test/mir-opt/inline-closure-borrows-arg.rs
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
12
src/test/ui/unboxed-closure-no-cyclic-sig.stderr
Normal file
12
src/test/ui/unboxed-closure-no-cyclic-sig.stderr
Normal 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
|
||||
|
Loading…
Reference in a new issue