about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-05-07 13:49:36 +0000
committerbors <bors@rust-lang.org>2019-05-07 13:49:36 +0000
commitf5371a5ac7a9ef4446d46e7c8a2523e56f7a7900 (patch)
treeb888ba5ea5ad1f08e77e5439dc799a03e7b8d5e7
parentc6ac57564852cb6e2d0db60f7b46d9eb98d4b449 (diff)
parentf2919a31c8101da2dd773ea5ffca4195e96d3d50 (diff)
downloadrust-f5371a5ac7a9ef4446d46e7c8a2523e56f7a7900.tar.gz
rust-f5371a5ac7a9ef4446d46e7c8a2523e56f7a7900.zip
Auto merge of #60592 - davidtwco:generator-signature-deduction, r=eddyb
Deduce signature of generator on type mismatch

Contributes towards #54326.

r? @eddyb
-rw-r--r--src/librustc_typeck/check/closure.rs49
-rw-r--r--src/test/ui/generator-yielding-or-returning-itself.rs2
-rw-r--r--src/test/ui/generator-yielding-or-returning-itself.stderr24
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.rs17
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr12
5 files changed, 72 insertions, 32 deletions
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 838874cc2bf..3fa192f16f3 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
-    /// everything we need to know about a closure.
+    /// everything we need to know about a closure or generator.
     ///
     /// The `cause_span` should be the span that caused us to
     /// have this expected signature, or `None` if we can't readily
@@ -262,37 +262,50 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let trait_ref = projection.to_poly_trait_ref(tcx);
 
-        if tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_none() {
+        let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some();
+        let gen_trait = tcx.lang_items().gen_trait().unwrap();
+        let is_gen = gen_trait == trait_ref.def_id();
+        if !is_fn && !is_gen {
+            debug!("deduce_sig_from_projection: not fn or generator");
             return None;
         }
 
-        let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
-        let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
-        debug!(
-            "deduce_sig_from_projection: arg_param_ty {:?}",
-            arg_param_ty
-        );
+        if is_gen {
+            // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return`
+            // associated item and not yield.
+            let return_assoc_item = self.tcx.associated_items(gen_trait).nth(1).unwrap().def_id;
+            if return_assoc_item != projection.projection_def_id() {
+                debug!("deduce_sig_from_projection: not return assoc item of generator");
+                return None;
+            }
+        }
+
+        let input_tys = if is_fn {
+            let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+            let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
+            debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
-        let input_tys = match arg_param_ty.sty {
-            ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()),
-            _ => return None,
+            match arg_param_ty.sty {
+                ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(),
+                _ => return None,
+            }
+        } else {
+            // Generators cannot have explicit arguments.
+            vec![]
         };
 
         let ret_param_ty = projection.skip_binder().ty;
         let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
-        debug!(
-            "deduce_sig_from_projection: ret_param_ty {:?}",
-            ret_param_ty
-        );
+        debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
 
         let sig = self.tcx.mk_fn_sig(
-            input_tys,
-            ret_param_ty,
+            input_tys.iter(),
+            &ret_param_ty,
             false,
             hir::Unsafety::Normal,
             Abi::Rust,
         );
-        debug!("deduce_sig_from_projection: sig {:?}", sig);
+        debug!("deduce_sig_from_projection: sig={:?}", sig);
 
         Some(ExpectedSig { cause_span, sig })
     }
diff --git a/src/test/ui/generator-yielding-or-returning-itself.rs b/src/test/ui/generator-yielding-or-returning-itself.rs
index 30788e3c186..fd526679818 100644
--- a/src/test/ui/generator-yielding-or-returning-itself.rs
+++ b/src/test/ui/generator-yielding-or-returning-itself.rs
@@ -13,7 +13,7 @@ pub fn want_cyclic_generator_return<T>(_: T)
 
 fn supply_cyclic_generator_return() {
     want_cyclic_generator_return(|| {
-        //~^ ERROR type mismatch
+        //~^ ERROR closure/generator type that references itself
         if false { yield None.unwrap(); }
         None.unwrap()
     })
diff --git a/src/test/ui/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator-yielding-or-returning-itself.stderr
index 5834aed2450..42591683fe4 100644
--- a/src/test/ui/generator-yielding-or-returning-itself.stderr
+++ b/src/test/ui/generator-yielding-or-returning-itself.stderr
@@ -1,20 +1,17 @@
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as std::ops::Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]`
-  --> $DIR/generator-yielding-or-returning-itself.rs:15:5
+error[E0644]: closure/generator type that references itself
+  --> $DIR/generator-yielding-or-returning-itself.rs:15:34
    |
-LL |     want_cyclic_generator_return(|| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+LL |       want_cyclic_generator_return(|| {
+   |  __________________________________^
+LL | |
+LL | |         if false { yield None.unwrap(); }
+LL | |         None.unwrap()
+LL | |     })
+   | |_____^ 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
-note: required by `want_cyclic_generator_return`
-  --> $DIR/generator-yielding-or-returning-itself.rs:9:1
-   |
-LL | / pub fn want_cyclic_generator_return<T>(_: T)
-LL | |     where T: Generator<Yield = (), Return = T>
-LL | | {
-LL | | }
-   | |_^
 
 error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]`
   --> $DIR/generator-yielding-or-returning-itself.rs:28:5
@@ -36,4 +33,5 @@ LL | | }
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0644.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.rs b/src/test/ui/generator/type-mismatch-signature-deduction.rs
new file mode 100644
index 00000000000..b9c6bc5d079
--- /dev/null
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.rs
@@ -0,0 +1,17 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn foo() -> impl Generator<Return = i32> {
+    || {
+        if false {
+            return Ok(6); //~ ERROR mismatched types [E0308]
+        }
+
+        yield ();
+
+        5
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
new file mode 100644
index 00000000000..35d3f95c3e9
--- /dev/null
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-signature-deduction.rs:8:20
+   |
+LL |             return Ok(6);
+   |                    ^^^^^ expected i32, found enum `std::result::Result`
+   |
+   = note: expected type `i32`
+              found type `std::result::Result<{integer}, _>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.