diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 523a244c8361b..db3aa9a1efa4b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -498,9 +498,7 @@ define_dep_nodes!( <'tcx> [] IsAutoImpl(DefId), [] ImplTraitRef(DefId), [] ImplPolarity(DefId), - [] ClosureKind(DefId), [] FnSignature(DefId), - [] GenSignature(DefId), [] CoerceUnsizedInfo(DefId), [] ItemVarianceConstraints(DefId), diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index bab3bded77b09..130266e627363 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -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) + 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 diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e7627b110fae4..8f2ad98f85885 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -236,8 +236,9 @@ impl<'gcx> HashStable> 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) => { diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 40e933b26a257..50a37e12531a7 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -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) => { diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 4f36193e197d9..6fadafc7b97ae 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -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>, + mut values: Option>, 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"), + } } } diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 22d9a9e313b77..ea3c0a8ddb450 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -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 { diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 41e7dffe54dc1..426c61e9ac083 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -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>, - closure_set: Vec, } 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(&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(&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) } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4f923f0b249d6..7302bad0ca166 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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 { - 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> { - 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(&self, diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index cc91a637b8931..6aa094d2cd6d7 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -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), diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 5e9019c92c5b7..36286a3ac883c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -51,6 +51,7 @@ #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] #![feature(macro_vis_matcher)] +#![feature(match_default_bindings)] #![feature(never_type)] #![feature(nonzero)] #![feature(quote)] diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2c6bcc654a532..1636ab40d39ea 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7c38cf75b8d5a..46ec2be4a1f9b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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)); }, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 297feead61760..6b681322c9bf5 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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![])) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 9c56df058c3dd..0cc755dc42727 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -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 diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7716770d318ba..4bc3e2dd4d8d4 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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) diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 42e0834e8e43b..898accb902159 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -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)), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 22a3edd200c4f..dbcdd17480eac 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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>, - - /// 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>>, - - generator_interiors: ItemLocalMap>, + /// 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> { - LocalTableInContext { - local_id_root: self.local_id_root, - data: &self.closure_tys - } - } - - pub fn closure_tys_mut(&mut self) - -> LocalTableInContextMut> { - 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 @@ impl<'tcx> TypeckTables<'tcx> { data: &mut self.cast_kinds } } - - pub fn generator_sigs(&self) - -> LocalTableInContext>> - { - LocalTableInContext { - local_id_root: self.local_id_root, - data: &self.generator_sigs, - } - } - - pub fn generator_sigs_mut(&mut self) - -> LocalTableInContextMut>> - { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.generator_sigs, - } - } - - pub fn generator_interiors(&self) - -> LocalTableInContext> - { - LocalTableInContext { - local_id_root: self.local_id_root, - data: &self.generator_interiors, - } - } - - pub fn generator_interiors_mut(&mut self) - -> LocalTableInContextMut> - { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.generator_interiors, - } - } } impl<'gcx> HashStable> for TypeckTables<'gcx> { @@ -732,8 +669,7 @@ impl<'gcx> HashStable> 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> 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> 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, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 228ca76ed9a7a..cb68e576e5af9 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -49,7 +49,11 @@ pub enum TypeError<'tcx> { FloatMismatch(ExpectedFound), Traits(ExpectedFound), VariadicMismatch(ExpectedFound), - 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), ProjectionBoundsLength(ExpectedFound), TyParamDefaultMismatch(ExpectedFound>), @@ -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"); + } + } _ => {} } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 6ea953c3f7375..70636f8b6fe9b 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -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), diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 320f651484987..228503b1a3f31 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -167,20 +167,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>, - /// Caches CoerceUnsized kinds for impls on custom types. [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) -> ty::adjustment::CoerceUnsizedInfo, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 1ca8fc6eb480f..739537c7c3a71 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -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!()); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a584f2ce1919a..450e48f5fdcc7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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() @@ -1937,6 +1937,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), @@ -1962,6 +1965,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> { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e5c24b4fcf921..83207fbe3c346 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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, } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 65406c3d16cc5..7406fbf820893 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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> + '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 { + 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. diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c631e2c4db51b..a851ccc34bfd6 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -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). + // + // 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(_) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index acb929981fbf2..f130f28153e3b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1257,7 +1257,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) @@ -1281,8 +1281,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) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 7b09e45fe96e3..36b397bbbe546 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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 diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 78aacd49f807d..c8b71be86f862 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -15,6 +15,7 @@ #![allow(non_camel_case_types)] +#![feature(match_default_bindings)] #![feature(quote)] #[macro_use] extern crate log; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index b26ebfd6121b4..1f671adf4f8a4 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -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) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0dd1b9e500c08..633806d5ef568 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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> { - 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> { - 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) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 23e86b2d35a51..80b68022fe2ac 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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 { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 3efe74bfecc92..8ff327463917a 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -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>, } -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 }); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index e722a589b66bf..65abbe8a081d3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 798928e7ae7a5..00d7cdc0ff7a4 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -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 { diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 7d12d50355b59..d46aa1c7aef2b 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -768,7 +768,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; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 628a8161615e3..0ad29f99accf4 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -22,6 +22,7 @@ use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::{Subst,Substs}; use std::collections::VecDeque; +use std::iter; use transform::{MirPass, MirSource}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; @@ -558,8 +559,29 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { ) -> Vec> { 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); @@ -572,12 +594,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))) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index e3856cabcf910..07bbd9b8c3dc1 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -511,7 +511,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, @@ -527,7 +527,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); diff --git a/src/librustc_trans_utils/monomorphize.rs b/src/librustc_trans_utils/monomorphize.rs index ab61dacf010ae..1f8d273d8fbcd 100644 --- a/src/librustc_trans_utils/monomorphize.rs +++ b/src/librustc_trans_utils/monomorphize.rs @@ -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), diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 91ce4511a31cb..8f409b687526b 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -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>, 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, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d475fb0cf1a14..5b5d697bcf435 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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 diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b3a07027fb032..b70c62cd73339 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -722,30 +722,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> { - 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 { @@ -981,6 +963,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. @@ -994,7 +987,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>) + -> (FnCtxt<'a, 'gcx, 'tcx>, Option>) { let mut fn_sig = fn_sig.clone(); @@ -1044,21 +1037,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); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 9a70a8699aa5c..2e0d0ddfc3936 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -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); - - // 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); - } + 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); + + 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); - - 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() + 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 + ); + + 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)>, + + // 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_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); + 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); } 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); - - 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() - }); - - if let Some((existing_kind, _)) = closure_kind { - debug!("adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", - closure_id, existing_kind, new_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 - } + 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 + ); + + // 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; + } - (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))) - ); - } + // closures start out as `Fn`. + let existing_kind = self.current_closure_kind; + + debug!( + "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", + closure_id, + existing_kind, + new_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 + } + + (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 consume_pat(&mut self, - _consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, - mode: euv::ConsumeMode) - { + 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) { 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 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 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); self.adjust_upvar_borrow_kind_for_mut(assignee_cmt); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ce2ac73a27e0c..d399185012170 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -46,8 +46,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())); @@ -243,21 +241,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); } } @@ -388,33 +377,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); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b5fbbeb1692e6..90a3ab75751b0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1015,9 +1015,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(""), + 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(""), + 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(""), def_id, has_default: false, @@ -1152,14 +1174,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)) { @@ -1238,7 +1265,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 => { diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs index 16ed73e9095e4..513a17e2ef2f4 100644 --- a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -13,8 +13,7 @@ fn bar(blk: F) where F: FnOnce() + 'static { fn foo(x: &()) { bar(|| { - //~^ ERROR cannot infer - //~| ERROR does not fulfill + //~^ ERROR does not fulfill let _ = x; }) } diff --git a/src/test/compile-fail/generator-yielding-or-returning-itself.rs b/src/test/compile-fail/generator-yielding-or-returning-itself.rs new file mode 100644 index 0000000000000..13abdf616b29b --- /dev/null +++ b/src/test/compile-fail/generator-yielding-or-returning-itself.rs @@ -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 or the MIT license +// , 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) + where T: Generator +{ +} + +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) + where T: Generator +{ +} + +fn supply_cyclic_generator_yield() { + want_cyclic_generator_yield(|| { + //~^ ERROR type mismatch + if false { yield None.unwrap(); } + None.unwrap() + }) +} + +fn main() { } diff --git a/src/test/compile-fail/issue-22638.rs b/src/test/compile-fail/issue-22638.rs index 53b0d9f4e9f0c..1c534ebbd4350 100644 --- a/src/test/compile-fail/issue-22638.rs +++ b/src/test/compile-fail/issue-22638.rs @@ -19,7 +19,6 @@ struct A (B); impl A { pub fn matches(&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); impl D { pub fn matches(&self, f: &F) { + //~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure let &D(ref a) = self; a.matches(f) } diff --git a/src/test/run-pass/issue-25439.rs b/src/test/compile-fail/issue-25439.rs similarity index 87% rename from src/test/run-pass/issue-25439.rs rename to src/test/compile-fail/issue-25439.rs index 88c48f42c513c..6e33fd5ae71a6 100644 --- a/src/test/run-pass/issue-25439.rs +++ b/src/test/compile-fail/issue-25439.rs @@ -15,5 +15,5 @@ fn fix(f: F) -> i32 where F: Fn(Helper, i32) -> i32 { } fn main() { - fix(|_, x| x); + fix(|_, x| x); //~ ERROR closure/generator type that references itself [E0644] } diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs index a276af83dee25..5d162fe944ec8 100644 --- a/src/test/compile-fail/occurs-check-2.rs +++ b/src/test/compile-fail/occurs-check-2.rs @@ -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 } diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs index 5b6a11e58c27c..2c784365ea989 100644 --- a/src/test/compile-fail/occurs-check.rs +++ b/src/test/compile-fail/occurs-check.rs @@ -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 } diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs new file mode 100644 index 0000000000000..de7b38d551956 --- /dev/null +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -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 or the MIT license +// , 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: 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 diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index 3f3428714d15c..9d3fb923f5b3a 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -34,9 +34,11 @@ fn foo(_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 diff --git a/src/test/ui/block-result/issue-3563.stderr b/src/test/ui/block-result/issue-3563.stderr index e3f0df6fb5f1a..c3d5f21b0a51e 100644 --- a/src/test/ui/block-result/issue-3563.stderr +++ b/src/test/ui/block-result/issue-3563.stderr @@ -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 diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index b703632bf90c1..3cf0fd9a9eede 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -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 diff --git a/src/test/run-pass/issue-21410.rs b/src/test/ui/unboxed-closure-no-cyclic-sig.rs similarity index 83% rename from src/test/run-pass/issue-21410.rs rename to src/test/ui/unboxed-closure-no-cyclic-sig.rs index bc525ba54c354..78d119ef329d0 100644 --- a/src/test/run-pass/issue-21410.rs +++ b/src/test/ui/unboxed-closure-no-cyclic-sig.rs @@ -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) where F: FnOnce(Option) {} fn main() { diff --git a/src/test/ui/unboxed-closure-no-cyclic-sig.stderr b/src/test/ui/unboxed-closure-no-cyclic-sig.stderr new file mode 100644 index 0000000000000..a4279a2afac60 --- /dev/null +++ b/src/test/ui/unboxed-closure-no-cyclic-sig.stderr @@ -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 +