From d0bda669ea8dc42fc14fb267b7368bb1e42fad9a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 16:31:47 -0500 Subject: [PATCH] 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 22d9a9e313b7..ea3c0a8ddb45 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 e20db5e38071..77aa35539677 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 c631e2c4db51..5f5a418092b7 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 2052160ac470..6c20468c286f 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 8365081f5a7b..7a03d97c18a6 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 16ed73e9095e..513a17e2ef2f 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 bc525ba54c35..731cfa2b04d2 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 88c48f42c513..fc65ead6e639 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 e3f0df6fb5f1..c3d5f21b0a51 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