about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-11-08 16:31:47 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-11-18 07:47:37 -0500
commitd0bda669ea8dc42fc14fb267b7368bb1e42fad9a (patch)
treefe8d80a0b1900a79a7131cd3cff8f8983f4cba9d
parent54f4f396d90e492fe9ede8608fe1a870e21fd10e (diff)
downloadrust-d0bda669ea8dc42fc14fb267b7368bb1e42fad9a.tar.gz
rust-d0bda669ea8dc42fc14fb267b7368bb1e42fad9a.zip
move the signature into the closure type
-rw-r--r--src/librustc/infer/error_reporting/need_type_info.rs4
-rw-r--r--src/librustc/ty/sty.rs26
-rw-r--r--src/librustc/ty/wf.rs17
-rw-r--r--src/librustc_typeck/check/closure.rs8
-rw-r--r--src/librustc_typeck/collect.rs17
-rw-r--r--src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs3
-rw-r--r--src/test/compile-fail/issue-21410.rs (renamed from src/test/run-pass/issue-21410.rs)2
-rw-r--r--src/test/compile-fail/issue-25439.rs (renamed from src/test/run-pass/issue-25439.rs)2
-rw-r--r--src/test/ui/block-result/issue-3563.stderr13
9 files changed, 66 insertions, 26 deletions
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 22d9a9e313b..ea3c0a8ddb4 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 e20db5e3807..77aa3553967 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 c631e2c4db5..5f5a418092b 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 2052160ac47..6c20468c286 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 8365081f5a7..7a03d97c18a 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("<closure_kind>"),
             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("<closure_signature>"),
+            def_id,
+            has_default: false,
+            object_lifetime_default: rl::Set1::Empty,
+            pure_wrt_drop: false,
+            synthetic: None,
+        });
+
         tcx.with_freevars(node_id, |fv| {
-            types.extend(fv.iter().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("<upvar>"),
                 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 16ed73e9095..513a17e2ef2 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<F>(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
index bc525ba54c3..731cfa2b04d 100644
--- a/src/test/run-pass/issue-21410.rs
+++ b/src/test/compile-fail/issue-21410.rs
@@ -11,5 +11,5 @@
 fn g<F>(_: F) where F: FnOnce(Option<F>) {}
 
 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
index 88c48f42c51..fc65ead6e63 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: F) -> i32 where F: Fn(Helper<F>, 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 e3f0df6fb5f..c3d5f21b0a5 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