From eab5b263e8a6189868caf7bd135e3ce127b57424 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 05:15:04 -0500 Subject: [PATCH 01/26] flatten the arguments to `analyze_closure` They were oddly tupled. --- src/librustc_typeck/check/upvar.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 9a70a8699aa5c..2835c6c4916eb 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -79,7 +79,8 @@ 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), + self.fcx.analyze_closure(expr.id, + expr.hir_id, expr.span, body, cc, @@ -95,7 +96,8 @@ 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), + closure_node_id: ast::NodeId, + closure_hir_id: hir::HirId, span: Span, body: &hir::Body, capture_clause: hir::CaptureClause, From 1d96819dc0c300a22c08e57051a93652d728931a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 05:16:40 -0500 Subject: [PATCH 02/26] upvar.rs: rustfmt --- src/librustc_typeck/check/upvar.rs | 424 ++++++++++++++++------------- 1 file changed, 236 insertions(+), 188 deletions(-) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 2835c6c4916eb..63cdac10321d4 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -51,7 +51,7 @@ 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::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::util::nodemap::FxHashMap; use std::collections::hash_map::Entry; @@ -65,7 +65,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,15 +79,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); @@ -95,26 +91,33 @@ 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: ast::NodeId, - closure_hir_id: 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, + gen: 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) { + .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); @@ -135,19 +138,22 @@ 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); } }); @@ -159,25 +165,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + 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()) { + 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); } } - 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 @@ -194,22 +205,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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), + 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); + closure_node_id, + t + ); } }; // Equate the type variables 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(def_id, self.tcx) + .zip(final_upvar_tys) { self.demand_eqtype(span, final_upvar_ty, upvar_ty); } @@ -217,8 +234,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); + 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); } @@ -236,51 +252,61 @@ 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)>, 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; @@ -289,28 +315,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 @@ -319,16 +356,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 => {} } } - _ => { } + _ => {} } } @@ -336,8 +374,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) | @@ -370,8 +407,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) | @@ -395,16 +431,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, @@ -424,10 +455,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 } @@ -435,16 +468,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, } } @@ -453,13 +486,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 => { @@ -472,37 +509,54 @@ 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() + 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() + 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); + 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) | @@ -516,10 +570,8 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { (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))) - ); + self.adjust_closure_kinds + .insert(closure_id, (new_kind, Some((upvar_span, var_name)))); } } } @@ -527,44 +579,43 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } 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); } @@ -574,19 +625,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); } From 3349e7bb45c18485f1ba090f0f80bda67abd214e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 05:45:20 -0500 Subject: [PATCH 03/26] thread the closure-kind through in the closure substs Similar to how freshen handled things, but "always happening"; we can thus remove the corresponding code from `freshen`. --- src/librustc/infer/freshen.rs | 16 +---- src/librustc/infer/type_variable.rs | 5 +- src/librustc/ty/mod.rs | 10 +++ src/librustc/ty/sty.rs | 95 +++++++++++++++++++++++++--- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/upvar.rs | 8 +++ src/librustc_typeck/collect.rs | 13 +++- 7 files changed, 121 insertions(+), 28 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 41e7dffe54dc1..6d1ede8f1a5de 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -253,22 +253,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { 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) + (tcx.mk_fn_ptr(closure_sig.fold_with(this)), tcx.types.char) }, |substs| tcx.mk_closure(def_id, substs) ) 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/ty/mod.rs b/src/librustc/ty/mod.rs index a584f2ce1919a..93cb4344cb3b0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1962,6 +1962,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/sty.rs b/src/librustc/ty/sty.rs index 65406c3d16cc5..bc55ffdc31fd8 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -174,16 +174,22 @@ 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, 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. +/// - 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: /// @@ -256,14 +262,54 @@ 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>, + 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("closure-kind should be type"), + upvar_kinds: &self.substs[parent_len + 1..], + } + } + #[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 `None` + /// if inference has not yet completed. + pub fn opt_closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) + -> Option { + let closure_kind_ty = self.closure_kind_ty(def_id, tcx); + closure_kind_ty.to_opt_closure_kind() + } + + /// Returns the closure kind for this closure; may return `None` + /// if inference has not yet completed. + pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { + self.split(def_id, tcx).closure_kind_ty + } +} + +impl<'tcx> ClosureSubsts<'tcx> { + /// Returns the closure kind for this closure; only usable outside + /// of an inference context. + pub fn closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::ClosureKind { + self.opt_closure_kind(def_id, tcx).unwrap() } } @@ -1442,6 +1488,35 @@ 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, + + _ => bug!("cannot convert type `{:?}` to a closure kind", self), + } + } } /// Typed constant value. diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d475fb0cf1a14..90c4654dac9b2 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -100,7 +100,7 @@ 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 closure_type = self.tcx.mk_closure(expr_def_id, substs); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 63cdac10321d4..c4cdd958680d9 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -46,6 +46,7 @@ use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::TypeFoldable; use rustc::infer::UpvarRegion; use syntax::ast; use syntax_pos::Span; @@ -216,6 +217,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; + // Equate the type variable representing the closure kind. + let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); + if closure_kind_ty.needs_infer() { + let final_closure_kind = self.tables.borrow().closure_kinds()[closure_hir_id].0; + self.demand_eqtype(span, final_closure_kind.to_ty(self.tcx), closure_kind_ty); + } + // Equate the type variables with the actual types. let final_upvar_tys = self.final_upvar_tys(closure_node_id); debug!( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b5fbbeb1692e6..9ee3300e75375 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1015,8 +1015,19 @@ 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 as u32, + 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 { + types.extend(fv.iter().zip(1..).map(|(_, i)| ty::TypeParameterDef { index: type_start + i as u32, name: Symbol::intern(""), def_id, From 0ac8542abc0a2497cda02dcc0544c0da6f46644f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 08:50:44 -0500 Subject: [PATCH 04/26] make `mk_closure` take a `ClosureSubsts` --- src/librustc/infer/freshen.rs | 2 +- src/librustc/ty/context.rs | 8 +++----- src/librustc_typeck/check/closure.rs | 4 ++-- src/librustc_typeck/collect.rs | 21 +++++++++++++-------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 6d1ede8f1a5de..c4727c820b11b 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -256,7 +256,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { let closure_sig = this.infcx.fn_sig(def_id); (tcx.mk_fn_ptr(closure_sig.fold_with(this)), tcx.types.char) }, - |substs| tcx.mk_closure(def_id, substs) + |substs| tcx.mk_closure(def_id, ty::ClosureSubsts { substs }) ) } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 22a3edd200c4f..a3fe8398de211 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1981,11 +1981,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_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 90c4654dac9b2..1f96afe3ac882 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -103,11 +103,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .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); + return self.tcx.mk_generator(expr_def_id, substs, interior); } debug!( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 9ee3300e75375..8365081f5a7b7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1163,14 +1163,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)) { From decf3d33d08ad6c89843421ffca543dceb00bb78 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 08:50:59 -0500 Subject: [PATCH 05/26] make `ty::Predicate` carry a `ClosureSubsts` --- src/librustc/ich/impls_ty.rs | 3 ++- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/select.rs | 4 ++-- src/librustc/traits/util.rs | 4 ++-- src/librustc/ty/mod.rs | 10 +++++----- src/librustc/ty/structural_impls.rs | 14 +++++++++----- src/librustc/util/ppaux.rs | 6 +++--- 8 files changed, 25 insertions(+), 20 deletions(-) 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/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7c38cf75b8d5a..caed3639b5636 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -643,7 +643,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { violations) } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => { let found_kind = self.closure_kind(closure_def_id).unwrap(); let 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(); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 297feead61760..0dbf7a6a1f0b1 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -438,7 +438,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => { match selcx.infcx().closure_kind(closure_def_id) { Some(closure_kind) => { if closure_kind.extends(kind) { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7716770d318ba..a0d51101d7894 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -718,7 +718,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => { match self.infcx.closure_kind(closure_def_id) { Some(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, 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/mod.rs b/src/librustc/ty/mod.rs index 93cb4344cb3b0..1ae49808d3f5e 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() diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e5c24b4fcf921..73d1b4c340038 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)) @@ -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), } 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) From 716f75b1b84e6f615b4ab80965dfa9a2fc566a31 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 08:52:24 -0500 Subject: [PATCH 06/26] traits: prefer `ClosureSubsts` to `InferCtxt::closure_kind` --- src/librustc/traits/fulfill.rs | 4 ++-- src/librustc/traits/select.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 0dbf7a6a1f0b1..1595679e9ebb9 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, _closure_substs, kind) => { - match selcx.infcx().closure_kind(closure_def_id) { + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + match closure_substs.opt_closure_kind(closure_def_id, selcx.tcx()) { Some(closure_kind) => { if closure_kind.extends(kind) { Ok(Some(vec![])) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index a0d51101d7894..2ab44b9c8bb58 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, _closure_substs, kind) => { - match self.infcx.closure_kind(closure_def_id) { + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + match closure_substs.opt_closure_kind(closure_def_id, self.tcx()) { Some(closure_kind) => { if closure_kind.extends(kind) { EvaluatedToOk From 2dff9a49e5be5857610336e585eb8e7267dd142e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 09:45:48 -0500 Subject: [PATCH 07/26] stop using the `closure_kinds` query / table for anything Closure Kind is now extracted from the closure substs exclusively. --- src/librustc/infer/mod.rs | 25 ++---- src/librustc/middle/mem_categorization.rs | 17 +++- src/librustc/traits/error_reporting.rs | 4 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/select.rs | 6 +- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/sty.rs | 19 ++-- src/librustc_mir/build/mod.rs | 8 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans_utils/monomorphize.rs | 2 +- src/librustc_typeck/check/callee.rs | 6 +- src/librustc_typeck/check/closure.rs | 18 ++-- src/librustc_typeck/check/upvar.rs | 103 +++++++++++----------- src/test/compile-fail/issue-22638.rs | 2 +- 14 files changed, 107 insertions(+), 109 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4f923f0b249d6..905e45bf9f03d 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. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2c6bcc654a532..a41a809307149 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 `Fn`. + Some(infcx) => + infcx.closure_kind(closure_def_id, closure_substs) + .unwrap_or(ty::ClosureKind::Fn), + + 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 caed3639b5636..ccea981b78e04 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, _closure_substs, 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!( diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 1595679e9ebb9..6b681322c9bf5 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -439,7 +439,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - match closure_substs.opt_closure_kind(closure_def_id, selcx.tcx()) { + 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/select.rs b/src/librustc/traits/select.rs index 2ab44b9c8bb58..fba894d528e81 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - match closure_substs.opt_closure_kind(closure_def_id, self.tcx()) { + 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) { 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/sty.rs b/src/librustc/ty/sty.rs index bc55ffdc31fd8..e20db5e38071d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -290,16 +290,8 @@ impl<'tcx> ClosureSubsts<'tcx> { upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type")) } - /// Returns the closure kind for this closure; may return `None` - /// if inference has not yet completed. - pub fn opt_closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) - -> Option { - let closure_kind_ty = self.closure_kind_ty(def_id, tcx); - closure_kind_ty.to_opt_closure_kind() - } - - /// Returns the closure kind for this closure; may return `None` - /// if inference has not yet completed. + /// Returns the closure kind for this closure; may return a type + /// variable during inference. pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { self.split(def_id, tcx).closure_kind_ty } @@ -307,9 +299,10 @@ impl<'tcx> ClosureSubsts<'tcx> { impl<'tcx> ClosureSubsts<'tcx> { /// Returns the closure kind for this closure; only usable outside - /// of an inference context. + /// 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.opt_closure_kind(def_id, tcx).unwrap() + self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap() } } @@ -1514,6 +1507,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyInfer(_) => None, + TyError => Some(ty::ClosureKind::Fn), + _ => bug!("cannot convert type `{:?}` to a closure kind", self), } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index e722a589b66bf..c4966c012c70c 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -248,14 +248,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_trans/common.rs b/src/librustc_trans/common.rs index e3856cabcf910..7309b05d5a05a 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, 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 1f96afe3ac882..5eda205c26d50 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -107,6 +107,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let closure_type = self.tcx.mk_closure(expr_def_id, substs); if let Some(interior) = interior { + self.demand_eqtype(expr.span, + ty::ClosureKind::FnOnce.to_ty(self.tcx), + substs.closure_kind_ty(expr_def_id, self.tcx)); return self.tcx.mk_generator(expr_def_id, substs, interior); } @@ -135,15 +138,12 @@ 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 => {} - } + self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig); + if let Some(kind) = opt_kind { + self.tables.borrow_mut().closure_kinds_mut().insert(expr.hir_id, (kind, None)); + 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/upvar.rs b/src/librustc_typeck/check/upvar.rs index c4cdd958680d9..048f53f298806 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -46,7 +46,6 @@ use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::TypeFoldable; use rustc::infer::UpvarRegion; use syntax::ast; use syntax_pos::Span; @@ -158,40 +157,58 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); - { - 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); - } + // Extract the type of the closure. + 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 + ); + } + }; + + 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 { + let opt_adjusted = delegate.adjust_closure_kinds.remove(&closure_def_id.to_local()); + let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); + if let Some((kind, origin)) = opt_adjusted { + self.tables + .borrow_mut() + .closure_kinds_mut() + .insert(closure_hir_id, (kind, origin)); + + self.demand_eqtype(span, kind.to_ty(self.tcx), closure_kind_ty); + } else { + // If there are only reads, or no upvars, then the + // default of `Fn` will never *have* to be adjusted, so there will be + // no entry in the map. + self.demand_eqtype(span, ty::ClosureKind::Fn.to_ty(self.tcx), closure_kind_ty); } - 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 @@ -204,27 +221,7 @@ 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 variable representing the closure kind. - let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); - if closure_kind_ty.needs_infer() { - let final_closure_kind = self.tables.borrow().closure_kinds()[closure_hir_id].0; - self.demand_eqtype(span, final_closure_kind.to_ty(self.tcx), closure_kind_ty); - } - - // 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={:?}", 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) } From eb26e30b915ada4debd0d10ad95a9f6348faf4d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 12:30:13 -0500 Subject: [PATCH 08/26] kill the `closure_kind` query --- src/librustc/dep_graph/dep_node.rs | 1 - src/librustc/ty/maps/mod.rs | 4 ---- src/librustc/ty/maps/plumbing.rs | 1 - src/librustc_metadata/cstore_impl.rs | 1 - src/librustc_metadata/decoder.rs | 7 ------- src/librustc_metadata/encoder.rs | 1 - src/librustc_metadata/schema.rs | 3 +-- src/librustc_mir/hair/cx/expr.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 9 --------- 9 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 523a244c8361b..b1a49b87acd25 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -498,7 +498,6 @@ define_dep_nodes!( <'tcx> [] IsAutoImpl(DefId), [] ImplTraitRef(DefId), [] ImplPolarity(DefId), - [] ClosureKind(DefId), [] FnSignature(DefId), [] GenSignature(DefId), [] CoerceUnsizedInfo(DefId), diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 320f651484987..c27bc63ff8e82 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -167,10 +167,6 @@ 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, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 1ca8fc6eb480f..617712b87cf3b 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -782,7 +782,6 @@ 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!()); } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index b26ebfd6121b4..d18816262c025 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -141,7 +141,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, (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..349b1cd882816 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>) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 23e86b2d35a51..6228eb0f3863a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1214,7 +1214,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { 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)) diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 3efe74bfecc92..0593c3d8c0d3c 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -512,10 +512,9 @@ 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> { 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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b3a07027fb032..ce8c285f0e243 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -722,7 +722,6 @@ pub fn provide(providers: &mut Providers) { typeck_item_bodies, typeck_tables_of, has_typeck_tables, - closure_kind, generator_sig, adt_destructor, used_trait_imports, @@ -738,14 +737,6 @@ fn generator_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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 { From 54f4f396d90e492fe9ede8608fe1a870e21fd10e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 12:36:28 -0500 Subject: [PATCH 09/26] convert the `closure_kinds` map to just store the origin information The closure kinds themselves are now completely found in the `ClosureSubsts`. --- src/librustc/lib.rs | 1 + src/librustc/middle/mem_categorization.rs | 6 +- src/librustc/traits/error_reporting.rs | 10 +- src/librustc/ty/context.rs | 22 ++- src/librustc/ty/mod.rs | 3 + src/librustc_borrowck/borrowck/mod.rs | 6 +- src/librustc_borrowck/lib.rs | 1 + src/librustc_typeck/check/closure.rs | 1 - src/librustc_typeck/check/upvar.rs | 169 +++++++++++----------- src/librustc_typeck/check/writeback.rs | 4 +- 10 files changed, 108 insertions(+), 115 deletions(-) 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 a41a809307149..1636ab40d39ea 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -753,16 +753,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty::TyClosure(closure_def_id, closure_substs) => { match self.infcx { // During upvar inference we may not know the - // closure kind, just use `Fn`. + // closure kind, just use the LATTICE_BOTTOM value. Some(infcx) => infcx.closure_kind(closure_def_id, closure_substs) - .unwrap_or(ty::ClosureKind::Fn), + .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()) + .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 ccea981b78e04..46ec2be4a1f9b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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/ty/context.rs b/src/librustc/ty/context.rs index a3fe8398de211..6bd1a3564b1c0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -359,9 +359,9 @@ pub struct TypeckTables<'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)>)>, + /// 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)>, generator_sigs: ItemLocalMap>>, @@ -414,7 +414,7 @@ impl<'tcx> TypeckTables<'tcx> { 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(), @@ -624,19 +624,17 @@ impl<'tcx> TypeckTables<'tcx> { } } - 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 } } @@ -733,7 +731,7 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { 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, @@ -776,7 +774,7 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { }); 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); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1ae49808d3f5e..450e48f5fdcc7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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), 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_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 5eda205c26d50..2052160ac4708 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -140,7 +140,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig); if let Some(kind) = opt_kind { - self.tables.borrow_mut().closure_kinds_mut().insert(expr.hir_id, (kind, None)); self.demand_eqtype(expr.span, kind.to_ty(self.tcx), substs.closure_kind_ty(expr_def_id, self.tcx)); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 048f53f298806..2e0d0ddfc3936 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -45,6 +45,7 @@ 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; @@ -52,9 +53,6 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::def_id::LocalDefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc::util::nodemap::FxHashMap; - -use std::collections::hash_map::Entry; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { @@ -98,7 +96,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, body: &hir::Body, capture_clause: hir::CaptureClause, - gen: bool, + is_generator: bool, ) { /*! * Analysis starting point. @@ -110,24 +108,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 { @@ -157,24 +155,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); - // Extract the type of the closure. - 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 - ); - } - }; - 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(), + 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( @@ -185,22 +172,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.tables.borrow(), ).consume_body(body); - // Write the adjusted values back into the main tables. if infer_kind { - let opt_adjusted = delegate.adjust_closure_kinds.remove(&closure_def_id.to_local()); - let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); - if let Some((kind, origin)) = opt_adjusted { + // 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_kinds_mut() - .insert(closure_hir_id, (kind, origin)); - - self.demand_eqtype(span, kind.to_ty(self.tcx), closure_kind_ty); - } else { - // If there are only reads, or no upvars, then the - // default of `Fn` will never *have* to be adjusted, so there will be - // no entry in the map. - self.demand_eqtype(span, ty::ClosureKind::Fn.to_ty(self.tcx), closure_kind_ty); + .closure_kind_origins_mut() + .insert(closure_hir_id, origin); } } @@ -230,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { final_upvar_tys ); for (upvar_ty, final_upvar_ty) in closure_substs - .upvar_tys(def_id, self.tcx) + .upvar_tys(closure_def_id, self.tcx) .zip(final_upvar_tys) { self.demand_eqtype(span, final_upvar_ty, upvar_ty); @@ -238,11 +222,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); } } @@ -294,7 +276,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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>, } @@ -542,42 +541,36 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 - } + // 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)); } } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ce2ac73a27e0c..48af2f0eff715 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -252,12 +252,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.tables.closure_tys_mut().insert(hir_id, closure_ty); } - for (&id, &closure_kind) in fcx_tables.closure_kinds().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, }; - self.tables.closure_kinds_mut().insert(hir_id, closure_kind); + self.tables.closure_kind_origins_mut().insert(hir_id, origin); } } From d0bda669ea8dc42fc14fb267b7368bb1e42fad9a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 16:31:47 -0500 Subject: [PATCH 10/26] move the signature into the closure type --- .../infer/error_reporting/need_type_info.rs | 4 +-- src/librustc/ty/sty.rs | 26 ++++++++++++++++--- src/librustc/ty/wf.rs | 17 +++++++++++- src/librustc_typeck/check/closure.rs | 8 ++++++ src/librustc_typeck/collect.rs | 17 +++++++++--- ...ure-bounds-static-cant-capture-borrowed.rs | 3 +-- .../{run-pass => compile-fail}/issue-21410.rs | 2 +- .../{run-pass => compile-fail}/issue-25439.rs | 2 +- src/test/ui/block-result/issue-3563.stderr | 13 +--------- 9 files changed, 66 insertions(+), 26 deletions(-) rename src/test/{run-pass => compile-fail}/issue-21410.rs (92%) rename src/test/{run-pass => compile-fail}/issue-25439.rs (92%) 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/ty/sty.rs b/src/librustc/ty/sty.rs index e20db5e38071d..77aa35539677b 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -174,7 +174,7 @@ pub enum TypeVariants<'tcx> { /// A closure can be modeled as a struct that looks like: /// -/// struct Closure<'l0...'li, T0...Tj, CK, U0...Uk> { +/// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> { /// upvar0: U0, /// ... /// upvark: Uk @@ -187,6 +187,10 @@ pub enum TypeVariants<'tcx> { /// - 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`). @@ -266,6 +270,7 @@ pub struct ClosureSubsts<'tcx> { /// 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>], } @@ -277,8 +282,9 @@ impl<'tcx> ClosureSubsts<'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("closure-kind should be type"), - upvar_kinds: &self.substs[parent_len + 1..], + 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..], } } @@ -295,6 +301,20 @@ impl<'tcx> ClosureSubsts<'tcx> { 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. + pub fn closure_sig_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { + self.split(def_id, tcx).closure_sig_ty + } + + /// Extracts the signature from the closure. + pub fn closure_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> ty::PolyFnSig<'tcx> { + match &self.split(def_id, tcx).closure_sig_ty.sty { + ty::TyFnPtr(sig) => *sig, + t => bug!("closure_sig_ty is not a fn-ptr: {:?}", t), + } + } } impl<'tcx> ClosureSubsts<'tcx> { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c631e2c4db51b..5f5a418092b73 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -336,7 +336,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - ty::TyGenerator(..) | ty::TyClosure(..) => { + ty::TyGenerator(..) => { // the types in a closure or generator are always the types of // local variables (or possibly references to local // variables), we'll walk those. @@ -346,6 +346,21 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // WFedness.) } + ty::TyClosure(def_id, substs) => { + // Just check the upvar types for WF. 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). + 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(_) => { // let the loop iterate into the argument/return // types appearing in the fn signature diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 2052160ac4708..6c20468c286fc 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -110,6 +110,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.demand_eqtype(expr.span, ty::ClosureKind::FnOnce.to_ty(self.tcx), substs.closure_kind_ty(expr_def_id, self.tcx)); + self.demand_eqtype(expr.span, + self.tcx.types.char, // for generator, use some bogus type + substs.closure_sig_ty(expr_def_id, self.tcx)); return self.tcx.mk_generator(expr_def_id, substs, interior); } @@ -138,6 +141,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_kind ); + 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)); + self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig); if let Some(kind) = opt_kind { self.demand_eqtype(expr.span, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8365081f5a7b7..7a03d97c18a68 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1017,7 +1017,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node { // add a dummy parameter for the closure kind types.push(ty::TypeParameterDef { - index: type_start as u32, + index: type_start, name: Symbol::intern(""), def_id, has_default: false, @@ -1026,9 +1026,20 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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().zip(1..).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, 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/run-pass/issue-21410.rs b/src/test/compile-fail/issue-21410.rs similarity index 92% rename from src/test/run-pass/issue-21410.rs rename to src/test/compile-fail/issue-21410.rs index bc525ba54c354..731cfa2b04d28 100644 --- a/src/test/run-pass/issue-21410.rs +++ b/src/test/compile-fail/issue-21410.rs @@ -11,5 +11,5 @@ fn g(_: F) where F: FnOnce(Option) {} fn main() { - g(|_| { }); + g(|_| { }); //~ ERROR mismatched types } diff --git a/src/test/run-pass/issue-25439.rs b/src/test/compile-fail/issue-25439.rs similarity index 92% rename from src/test/run-pass/issue-25439.rs rename to src/test/compile-fail/issue-25439.rs index 88c48f42c513c..fc65ead6e6394 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 mismatched types } 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 From e6fca1d5655350a93bda4a1532800adad3bb96b7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 17:15:24 -0500 Subject: [PATCH 11/26] remove the `closure_tys` map from `TypeckTables` The information we need is now part of the closure type. --- src/librustc/infer/mod.rs | 14 +++++++++++--- src/librustc/ty/context.rs | 21 --------------------- src/librustc/ty/sty.rs | 25 +++++++++++++++---------- src/librustc_typeck/check/closure.rs | 1 - src/librustc_typeck/check/writeback.rs | 9 --------- src/librustc_typeck/collect.rs | 9 ++++++++- 6 files changed, 34 insertions(+), 45 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 905e45bf9f03d..05f1184fad3d3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1484,9 +1484,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { let hir_id = self.tcx.hir.node_to_hir_id(id); - if let Some(&ty) = tables.borrow().closure_tys().get(hir_id) { - return ty; - } + 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); } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6bd1a3564b1c0..ccd851799fe35 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -356,9 +356,6 @@ pub struct TypeckTables<'tcx> { /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, - /// Records the type of each closure. - closure_tys: 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)>, @@ -413,7 +410,6 @@ impl<'tcx> TypeckTables<'tcx> { upvar_capture_map: FxHashMap(), generator_sigs: ItemLocalMap(), generator_interiors: ItemLocalMap(), - closure_tys: ItemLocalMap(), closure_kind_origins: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(), fru_field_types: ItemLocalMap(), @@ -609,21 +605,6 @@ 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_kind_origins(&self) -> LocalTableInContext<(Span, ast::Name)> { LocalTableInContext { local_id_root: self.local_id_root, @@ -730,7 +711,6 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { ref pat_binding_modes, ref pat_adjustments, ref upvar_capture_map, - ref closure_tys, ref closure_kind_origins, ref liberated_fn_sigs, ref fru_field_types, @@ -773,7 +753,6 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { hcx.def_path_hash(closure_def_id)) }); - closure_tys.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); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 77aa35539677b..e581eac9ccd6c 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -297,24 +297,19 @@ impl<'tcx> ClosureSubsts<'tcx> { } /// Returns the closure kind for this closure; may return a type - /// variable during inference. + /// 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. + /// 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 } - - /// Extracts the signature from the closure. - pub fn closure_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> ty::PolyFnSig<'tcx> { - match &self.split(def_id, tcx).closure_sig_ty.sty { - ty::TyFnPtr(sig) => *sig, - t => bug!("closure_sig_ty is not a fn-ptr: {:?}", t), - } - } } impl<'tcx> ClosureSubsts<'tcx> { @@ -324,6 +319,16 @@ impl<'tcx> ClosureSubsts<'tcx> { 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), + } + } } impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 6c20468c286fc..5fd1a0afb3ea0 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -146,7 +146,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sig_fn_ptr_ty, substs.closure_sig_ty(expr_def_id, self.tcx)); - self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig); if let Some(kind) = opt_kind { self.demand_eqtype(expr.span, kind.to_ty(self.tcx), diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 48af2f0eff715..cf5864e910d2c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -243,15 +243,6 @@ 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() { - 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, &origin) in fcx_tables.closure_kind_origins().iter() { let hir_id = hir::HirId { owner: common_local_id_root.index, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7a03d97c18a68..90a3ab75751b0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1265,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 => { From 7c609eb090b42d590507d87895af9fc1e28eae11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 17:33:29 -0500 Subject: [PATCH 12/26] `TyClosure` no longer needs to use `freshen_closure_like` All the data is now part of its type. --- src/librustc/infer/freshen.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index c4727c820b11b..b1ee6d7a29824 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { self.infcx.tcx.mk_infer(freshener(index)) } - fn freshen_closure_like(&mut self, + fn freshen_generator_like(&mut self, def_id: DefId, substs: ty::ClosureSubsts<'tcx>, t: Ty<'tcx>, @@ -249,19 +249,8 @@ 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| { - let closure_sig = this.infcx.fn_sig(def_id); - (tcx.mk_fn_ptr(closure_sig.fold_with(this)), tcx.types.char) - }, - |substs| tcx.mk_closure(def_id, ty::ClosureSubsts { substs }) - ) - } - ty::TyGenerator(def_id, substs, interior) => { - self.freshen_closure_like( + self.freshen_generator_like( def_id, substs, t, |this| { let gen_sig = this.infcx.generator_sig(def_id).unwrap(); @@ -300,6 +289,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) } From 7010d8cf51d846acada6229528c729748cceea85 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Nov 2017 15:07:39 -0500 Subject: [PATCH 13/26] add Yield and Return type into generator --- src/librustc/ty/sty.rs | 36 ++++++++++++++++++++++++++++ src/librustc_typeck/check/closure.rs | 14 +++++------ src/librustc_typeck/check/mod.rs | 15 ++++++++++-- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e581eac9ccd6c..436238b5e3744 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -256,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, @@ -310,6 +321,31 @@ impl<'tcx> ClosureSubsts<'tcx> { 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. We treat this as a `PolyGenSig`, but since it only + /// contains associated types of the generator, at present it + /// never binds any regions. + pub fn generator_poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> { + ty::Binder( + ty::GenSig { + yield_ty: self.generator_yield_ty(def_id, tcx), + return_ty: self.generator_return_ty(def_id, tcx), + } + ) + } } impl<'tcx> ClosureSubsts<'tcx> { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 5fd1a0afb3ea0..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, @@ -106,13 +106,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = ty::ClosureSubsts { substs }; let closure_type = self.tcx.mk_closure(expr_def_id, substs); - if let Some(interior) = interior { + if let Some(GeneratorTypes { yield_ty, interior }) = generator_types { self.demand_eqtype(expr.span, - ty::ClosureKind::FnOnce.to_ty(self.tcx), - substs.closure_kind_ty(expr_def_id, self.tcx)); + yield_ty, + substs.generator_yield_ty(expr_def_id, self.tcx)); self.demand_eqtype(expr.span, - self.tcx.types.char, // for generator, use some bogus type - substs.closure_sig_ty(expr_def_id, self.tcx)); + liberated_sig.output(), + substs.generator_return_ty(expr_def_id, self.tcx)); return self.tcx.mk_generator(expr_def_id, substs, interior); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ce8c285f0e243..91283ab7a2f5c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -972,6 +972,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. @@ -985,7 +996,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(); @@ -1047,7 +1058,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().generator_interiors_mut().insert(fn_hir_id, interior); - Some(interior) + Some(GeneratorTypes { yield_ty: gen_sig.yield_ty, interior: interior }) } else { inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, None); None From 5e04c66885729bb0c5d58e1e1624f89b129bf6dd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Nov 2017 15:44:29 -0500 Subject: [PATCH 14/26] remove the `generator_sigs` map, query, and plumbing --- src/librustc/dep_graph/dep_node.rs | 1 - src/librustc/infer/freshen.rs | 107 +-------------------------- src/librustc/infer/mod.rs | 13 ---- src/librustc/traits/project.rs | 3 +- src/librustc/traits/select.rs | 3 +- src/librustc/ty/maps/mod.rs | 4 - src/librustc/ty/maps/plumbing.rs | 1 - src/librustc_metadata/cstore_impl.rs | 1 - src/librustc_metadata/decoder.rs | 17 ----- src/librustc_metadata/encoder.rs | 31 +++++--- src/librustc_metadata/schema.rs | 3 +- src/librustc_trans/common.rs | 2 +- src/librustc_typeck/check/mod.rs | 9 --- 13 files changed, 24 insertions(+), 171 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index b1a49b87acd25..db3aa9a1efa4b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -499,7 +499,6 @@ define_dep_nodes!( <'tcx> [] ImplTraitRef(DefId), [] ImplPolarity(DefId), [] FnSignature(DefId), - [] GenSignature(DefId), [] CoerceUnsizedInfo(DefId), [] ItemVarianceConstraints(DefId), diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index b1ee6d7a29824..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_generator_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,26 +163,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } - ty::TyGenerator(def_id, substs, interior) => { - self.freshen_generator_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(..) | diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 05f1184fad3d3..ca95d4fd29193 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1501,19 +1501,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/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 fba894d528e81..4bc3e2dd4d8d4 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index c27bc63ff8e82..228503b1a3f31 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -173,10 +173,6 @@ define_maps! { <'tcx> /// 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 617712b87cf3b..739537c7c3a71 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -783,7 +783,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); } DepKind::ImplPolarity => { force!(impl_polarity, 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_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d18816262c025..1f671adf4f8a4 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -136,7 +136,6 @@ 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))) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 349b1cd882816..633806d5ef568 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1036,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 6228eb0f3863a..80b68022fe2ac 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1205,18 +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 { - 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 0593c3d8c0d3c..8ff327463917a 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -518,7 +518,6 @@ 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_trans/common.rs b/src/librustc_trans/common.rs index 7309b05d5a05a..07bbd9b8c3dc1 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 91283ab7a2f5c..fe1d81a1231a6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -722,21 +722,12 @@ pub fn provide(providers: &mut Providers) { typeck_item_bodies, typeck_tables_of, has_typeck_tables, - 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 adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option { From 1e9de11e62adcf06418e2080c31c05e1c0cc92bd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Nov 2017 17:00:36 -0500 Subject: [PATCH 15/26] add a compile-fail test for cyclic generators being forbidden --- .../generator-yielding-or-returning-itself.rs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/compile-fail/generator-yielding-or-returning-itself.rs 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() { } From 5e0e8ae2912e7f6ca5416d4166d42653d0eedf8b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Nov 2017 14:58:29 -0500 Subject: [PATCH 16/26] rename `issue-21410.rs` to `ui/unboxed-closure-no-cyclic-sig.rs` --- .../issue-21410.rs => ui/unboxed-closure-no-cyclic-sig.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/{compile-fail/issue-21410.rs => ui/unboxed-closure-no-cyclic-sig.rs} (100%) diff --git a/src/test/compile-fail/issue-21410.rs b/src/test/ui/unboxed-closure-no-cyclic-sig.rs similarity index 100% rename from src/test/compile-fail/issue-21410.rs rename to src/test/ui/unboxed-closure-no-cyclic-sig.rs From 27bedfa36bda9ec75751b0f0b5dee782108b56d3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Nov 2017 11:13:13 -0500 Subject: [PATCH 17/26] give better error messages when a cycle arises --- src/librustc/diagnostics.rs | 32 ++++++++++ src/librustc/infer/combine.rs | 18 +++++- src/librustc/infer/error_reporting/mod.rs | 63 +++++++++++++------ src/librustc/ty/error.rs | 16 ++++- src/librustc/ty/structural_impls.rs | 6 +- src/librustc/ty/sty.rs | 7 +++ src/test/ui/span/coerce-suggestions.stderr | 3 - src/test/ui/unboxed-closure-no-cyclic-sig.rs | 6 +- .../ui/unboxed-closure-no-cyclic-sig.stderr | 12 ++++ 9 files changed, 134 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/unboxed-closure-no-cyclic-sig.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index bab3bded77b09..9b0483d00a446 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1969,8 +1969,40 @@ 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: + +```rust +fn fix(f: &F) + where F: Fn(&F) +{ + f(&f); } +fn main() { + let x = |y| { + // Here, when `x` is called, the parameter `y` is equal to `x`. + }; + fix(&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/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/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/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 73d1b4c340038..83207fbe3c346 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -423,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), @@ -1173,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)), @@ -1200,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(_) | @@ -1209,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 436238b5e3744..d2b6d14e28477 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1368,6 +1368,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, 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/ui/unboxed-closure-no-cyclic-sig.rs b/src/test/ui/unboxed-closure-no-cyclic-sig.rs index 731cfa2b04d28..78d119ef329d0 100644 --- a/src/test/ui/unboxed-closure-no-cyclic-sig.rs +++ b/src/test/ui/unboxed-closure-no-cyclic-sig.rs @@ -8,8 +8,12 @@ // 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() { - g(|_| { }); //~ ERROR mismatched types + g(|_| { }); } 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 + From d8969815cf98b247b94fa832be038e4483fd293d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Nov 2017 11:13:49 -0500 Subject: [PATCH 18/26] comment wf more --- src/librustc/ty/wf.rs | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 5f5a418092b73..2dd694501ed61 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -337,24 +337,36 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } ty::TyGenerator(..) => { - // the types in a closure or generator are always the types of - // local variables (or possibly references to local - // variables), we'll walk those. - // - // (Though, local variables are probably not - // needed, as they are separately checked w/r/t - // WFedness.) + // 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) => { - // Just check the upvar types for WF. 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). + // 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. 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); From 413f07438eb18cbb8973d47a516a78d258876346 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Nov 2017 11:16:25 -0500 Subject: [PATCH 19/26] remove `generator_sigs` from `TypeckTables` --- src/librustc/ty/context.rs | 23 ----------------------- src/librustc/ty/sty.rs | 22 +++++++++++++--------- src/librustc_mir/build/mod.rs | 9 +++++++-- src/librustc_typeck/check/mod.rs | 9 +-------- src/librustc_typeck/check/writeback.rs | 16 ---------------- 5 files changed, 21 insertions(+), 58 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ccd851799fe35..862d3e9bb8aa7 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -360,8 +360,6 @@ pub struct TypeckTables<'tcx> { /// not all closures are present in the map. closure_kind_origins: ItemLocalMap<(Span, ast::Name)>, - generator_sigs: ItemLocalMap>>, - generator_interiors: ItemLocalMap>, /// For each fn, records the "liberated" types of its arguments @@ -408,7 +406,6 @@ impl<'tcx> TypeckTables<'tcx> { pat_binding_modes: ItemLocalMap(), pat_adjustments: ItemLocalMap(), upvar_capture_map: FxHashMap(), - generator_sigs: ItemLocalMap(), generator_interiors: ItemLocalMap(), closure_kind_origins: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(), @@ -661,24 +658,6 @@ impl<'tcx> TypeckTables<'tcx> { } } - 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> { @@ -720,7 +699,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; @@ -757,7 +735,6 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { 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); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d2b6d14e28477..7406fbf820893 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -335,16 +335,20 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Return the "generator signature", which consists of its yield /// and return types. /// - /// NB. We treat this as a `PolyGenSig`, but since it only - /// contains associated types of the generator, at present it - /// never binds any regions. + /// 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( - ty::GenSig { - yield_ty: self.generator_yield_ty(def_id, tcx), - return_ty: self.generator_return_ty(def_id, 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), + } } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index c4966c012c70c..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()) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fe1d81a1231a6..2a23a6f82af87 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1037,21 +1037,14 @@ 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(GeneratorTypes { yield_ty: gen_sig.yield_ty, interior: 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/writeback.rs b/src/librustc_typeck/check/writeback.rs index cf5864e910d2c..57cebc12a4458 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -46,7 +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, @@ -391,21 +390,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - 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); From 22c0cbfa8675bf81091bd4bcf50b824fbffba108 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Nov 2017 11:19:38 -0500 Subject: [PATCH 20/26] remove `generator_interiors` map --- src/librustc/ty/context.rs | 23 ----------------------- src/librustc_mir/transform/generator.rs | 6 +++++- src/librustc_typeck/check/mod.rs | 3 --- src/librustc_typeck/check/writeback.rs | 13 ------------- 4 files changed, 5 insertions(+), 40 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 862d3e9bb8aa7..dbcdd17480eac 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -360,8 +360,6 @@ pub struct TypeckTables<'tcx> { /// not all closures are present in the map. closure_kind_origins: ItemLocalMap<(Span, ast::Name)>, - generator_interiors: ItemLocalMap>, - /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions /// (including late-bound regions) are replaced with free @@ -406,7 +404,6 @@ impl<'tcx> TypeckTables<'tcx> { pat_binding_modes: ItemLocalMap(), pat_adjustments: ItemLocalMap(), upvar_capture_map: FxHashMap(), - generator_interiors: ItemLocalMap(), closure_kind_origins: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(), fru_field_types: ItemLocalMap(), @@ -657,24 +654,6 @@ impl<'tcx> TypeckTables<'tcx> { data: &mut self.cast_kinds } } - - 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> { @@ -699,7 +678,6 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { ref used_trait_imports, tainted_by_errors, ref free_region_map, - ref generator_interiors, } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -735,7 +713,6 @@ impl<'gcx> HashStable> for TypeckTables<'gcx> { liberated_fn_sigs.hash_stable(hcx, hasher); fru_field_types.hash_stable(hcx, hasher); cast_kinds.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); 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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2a23a6f82af87..b70c62cd73339 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1040,9 +1040,6 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, 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(GeneratorTypes { yield_ty: fcx.yield_ty.unwrap(), interior: interior }) } else { None diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 57cebc12a4458..d399185012170 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -46,7 +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_interiors(); let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports, Rc::new(DefIdSet())); @@ -378,18 +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_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); From 83f5a9605f5fc566c9d6e1477d879382c0b1b8dc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Nov 2017 13:09:19 -0500 Subject: [PATCH 21/26] fix compile-fail tests --- src/test/compile-fail/issue-25439.rs | 2 +- src/test/compile-fail/occurs-check-2.rs | 2 -- src/test/compile-fail/occurs-check.rs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test/compile-fail/issue-25439.rs b/src/test/compile-fail/issue-25439.rs index fc65ead6e6394..6e33fd5ae71a6 100644 --- a/src/test/compile-fail/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); //~ ERROR mismatched types + 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 } From df6fdbc9ae333faf7963470d0a27cf3ed4f24f65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Nov 2017 18:02:41 -0500 Subject: [PATCH 22/26] fix closure inlining by spilling arguments to a temporary --- src/librustc_mir/transform/inline.rs | 47 ++++++++++++++--- .../mir-opt/inline-closure-borrows-arg.rs | 50 +++++++++++++++++++ src/test/mir-opt/inline-closure.rs | 6 ++- 3 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 src/test/mir-opt/inline-closure-borrows-arg.rs 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/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 From 2151e482acee9a8715a4bde3cfd477c4ecc20b0b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Nov 2017 13:34:24 -0500 Subject: [PATCH 23/26] fix example for E0644 --- src/librustc/diagnostics.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9b0483d00a446..fe3f1bbbe8c4c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1982,10 +1982,9 @@ fn fix(f: &F) } fn main() { - let x = |y| { + fix(&|y| { // Here, when `x` is called, the parameter `y` is equal to `x`. - }; - fix(&x); + }); } ``` From 9af5a068a5b7fc682c962b83a1783df6ae65f3e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Nov 2017 13:49:18 -0500 Subject: [PATCH 24/26] extend comment further to explain why we limit wf to `upvar_tys` --- src/librustc/ty/wf.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 2dd694501ed61..a851ccc34bfd6 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -367,6 +367,15 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // probably always be WF, because it should be // shorthand for something like `where(T: 'a) { // fn(&'a T) }`, as discussed in #25860. + // + // Note that we are also skipping the generic + // types. This is consistent with the `outlives` + // code, but anyway doesn't matter: within the fn + // body where they are created, the generics will + // always be WF, and outside of that fn body we + // are not directly inspecting closure types + // anyway, except via auto trait matching (which + // only inspects the upvar types). subtys.skip_current_subtree(); // subtree handled by compute_projection for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { self.compute(upvar_ty); From b9c766ccc04676630e2ea70a7ac7a3ea4bc01057 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Nov 2017 16:53:48 -0500 Subject: [PATCH 25/26] fix example more --- src/librustc/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index fe3f1bbbe8c4c..130266e627363 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1974,7 +1974,7 @@ A closure or generator was constructed that references its own type. Erroneous example: -```rust +```compile-fail,E0644 fn fix(f: &F) where F: Fn(&F) { From 00732a31a0a9b00d4ffb333473ae95e66f8e1dfc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Nov 2017 04:45:47 -0500 Subject: [PATCH 26/26] check that def_id is a local closure in InferCtxt::fn_sig Before we were assuming that *every* `fn_sig` must pertain to a local closure. --- src/librustc/infer/mod.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index ca95d4fd29193..7302bad0ca166 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1481,20 +1481,29 @@ 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); - 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); + // 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); + } + } } }