提交 d6d09e0b 编写于 作者: B bors

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
......@@ -498,9 +498,7 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
[] 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 @@ fn hash_stable<W: StableHasherResult>(&self,
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 @@ fn generalize(&self,
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 @@ fn generalize(&self,
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 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
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 @@ pub fn note_type_err(&self,
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 @@ pub fn report_and_explain_type_error(&self,
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 @@ fn report_inference_failure(&self,
}
}
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 @@ pub fn need_type_info(&self, body_id: Option<hir::BodyId>, span: Span, ty: Ty<'t
// ```
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 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
infcx,
freshen_count: 0,
freshen_map: FxHashMap(),
closure_set: vec![],
}
}
......@@ -92,88 +88,6 @@ fn freshen<F>(&mut self,
}
}
}
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 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'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 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
ty::TyProjection(..) |
ty::TyForeign(..) |
ty::TyParam(..) |
ty::TyClosure(..) |
ty::TyAnon(..) => {
t.super_fold_with(self)
}
......
......@@ -1463,26 +1463,17 @@ pub fn type_moves_by_default(&self,
!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 @@ pub fn closure_kind(&self,
/// 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 @@ pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'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 @@ fn cat_upvar(&self,
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 @@ pub fn report_selection_error(&self,
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 @@ pub fn report_selection_error(&self,
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 @@ fn evaluate_predicate_recursively<'o>(&mut self,
}
}
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 @@ fn assemble_closure_candidates(&mut self,
// 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 @@ fn confirm_closure_candidate(&mut self,
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 @@ fn generator_trait_ref_unnormalized(&mut self,
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 @@ pub fn empty(local_id_root: Option<DefId>) -> 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 @@ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
self.upvar_capture_map[&upvar_id]
}
pub fn closure_tys(&self) -> LocalTableInContext<ty::PolyFnSig<'tcx>> {
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.closure_tys
}
}
pub fn closure_tys_mut(&mut self)
-> LocalTableInContextMut<ty::PolyFnSig<'tcx>> {
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)>)> {
pub fn closure_kind_origins(&self) -> LocalTableInContext<(Span, ast::Name)> {
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.closure_kinds
data: &self.closure_kind_origins
}
}
pub fn closure_kinds_mut(&mut self)
-> LocalTableInContextMut<(ty::ClosureKind, Option<(Span, ast::Name)>)> {
pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<(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 @@ pub fn cast_kinds_mut(&mut self) -> LocalTableInContextMut<ty::cast::CastKind> {
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 @@ fn hash_stable<W: StableHasherResult>(&self,
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 @@ fn hash_stable<W: StableHasherResult>(&self,
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 @@ fn hash_stable<W: StableHasherResult>(&self,
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 @@ pub fn mk_projection(self,
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 @@ fn report_maybe_different(f: &mut fmt::Formatter,
}
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 @@ pub fn note_and_explain_type_err(self,
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 @@
/// 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 @@ pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, '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 @@ pub fn walk_tys(&self) -> IntoIter<Ty<'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 @@ pub fn extends(self, other: ty::ClosureKind) -> bool {
_ => 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 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
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 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
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 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
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 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
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 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
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 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
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 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
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 @@ pub fn is_closure(&self) -> bool {
}
}
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 @@ pub fn regions(&self) -> Vec<ty::Region<'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 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
}
}
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).
//
// 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.
//
// (Though, local variables are probably not
// needed, as they are separately checked w/r/t
// WFedness.)
// 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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 @@ pub fn report_use_of_moved_value(&self,
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 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
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 @@ pub fn is_auto_impl(&self, impl_id: DefIndex) -> bool {
}
}
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 @@ pub fn fn_sig(&self,
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 @@ fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'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 @@ pub struct MethodData<'tcx> {
#[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 @@ fn run_pass<'a, 'tcx>(&self,
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::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 @@ fn make_call_args(
) -> 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 @@ fn make_call_args(
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 @@ fn try_overloaded_call_step(&self,
// 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 @@ fn try_overloaded_call_step(&self,
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 @@ pub fn resolve(self, fcx: &FnCtxt<'a, '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 @@ fn check_closure(
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 @@ fn check_closure(
|_, _| 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 @@ fn check_closure(
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 @@ fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
_: 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);
......
此差异已折叠。
......@@ -47,8 +47,6 @@ pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
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 @@ fn visit_closures(&mut self) {
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 @@ fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
}
}
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;
})
}
......
// 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 @@
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 @@ pub fn matches<F: Fn()>(&self, f: &F) {
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
}
// 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
\ No newline at end of file
// 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() {
......
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册