From a416a19153e799dae6679d8672703dbeb48730d5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 6 May 2019 20:45:47 +0100 Subject: [PATCH 1/2] Add test for current behaviour. This commit adds a test for the current behaviour of signature deduction of generators when there is a type mismatch between the return type of the function body and the signature. --- .../type-mismatch-signature-deduction.rs | 17 ++++++++++++++ .../type-mismatch-signature-deduction.stderr | 23 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/test/ui/generator/type-mismatch-signature-deduction.rs create mode 100644 src/test/ui/generator/type-mismatch-signature-deduction.stderr 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 0000000000000..7774ff48f56b7 --- /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 { //~ ERROR type mismatch + || { + if false { + return Ok(6); + } + + yield (); + + 5 //~ ERROR mismatched types [E0308] + } +} + +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 0000000000000..9ebf77a02f5ca --- /dev/null +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch-signature-deduction.rs:13:9 + | +LL | 5 + | ^ expected enum `std::result::Result`, found integer + | + = note: expected type `std::result::Result<{integer}, _>` + found type `{integer}` + +error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as std::ops::Generator>::Return == i32` + --> $DIR/type-mismatch-signature-deduction.rs:5:13 + | +LL | fn foo() -> impl Generator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found i32 + | + = note: expected type `std::result::Result<{integer}, _>` + found type `i32` + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0308. +For more information about an error, try `rustc --explain E0271`. From f2919a31c8101da2dd773ea5ffca4195e96d3d50 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 6 May 2019 22:56:47 +0100 Subject: [PATCH 2/2] Trust signature over return expr for generators. This commit extends the logic used to determine what the expected signature of a closure is so that it can also determine the expected signature of a generator. This improves a diagnostic where the fn signature was blamed instead of the generator body. It doesn't fix fix the diagnostic for `async fn`. --- src/librustc_typeck/check/closure.rs | 49 ++++++++++++------- .../generator-yielding-or-returning-itself.rs | 2 +- ...erator-yielding-or-returning-itself.stderr | 24 +++++---- .../type-mismatch-signature-deduction.rs | 6 +-- .../type-mismatch-signature-deduction.stderr | 25 +++------- 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 838874cc2bf07..3fa192f16f32e 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 "::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::>(), + _ => 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 30788e3c1864b..fd52667981873 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) 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 5834aed2450b1..42591683fe4e3 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) -LL | | where T: Generator -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 index 7774ff48f56b7..b9c6bc5d0796e 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.rs +++ b/src/test/ui/generator/type-mismatch-signature-deduction.rs @@ -2,15 +2,15 @@ use std::ops::Generator; -fn foo() -> impl Generator { //~ ERROR type mismatch +fn foo() -> impl Generator { || { if false { - return Ok(6); + return Ok(6); //~ ERROR mismatched types [E0308] } yield (); - 5 //~ ERROR mismatched types [E0308] + 5 } } diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 9ebf77a02f5ca..35d3f95c3e9e4 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -1,23 +1,12 @@ error[E0308]: mismatched types - --> $DIR/type-mismatch-signature-deduction.rs:13:9 + --> $DIR/type-mismatch-signature-deduction.rs:8:20 | -LL | 5 - | ^ expected enum `std::result::Result`, found integer +LL | return Ok(6); + | ^^^^^ expected i32, found enum `std::result::Result` | - = note: expected type `std::result::Result<{integer}, _>` - found type `{integer}` + = note: expected type `i32` + found type `std::result::Result<{integer}, _>` -error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as std::ops::Generator>::Return == i32` - --> $DIR/type-mismatch-signature-deduction.rs:5:13 - | -LL | fn foo() -> impl Generator { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found i32 - | - = note: expected type `std::result::Result<{integer}, _>` - found type `i32` - = note: the return type of a function must have a statically known size - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0308. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`.