Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
davidtwco committed May 7, 2019
1 parent a416a19 commit f2919a3
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 53 deletions.
49 changes: 31 additions & 18 deletions src/librustc_typeck/check/closure.rs
Expand Up @@ -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
Expand All @@ -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 })
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/generator-yielding-or-returning-itself.rs
Expand Up @@ -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()
})
Expand Down
24 changes: 11 additions & 13 deletions 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
Expand All @@ -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`.
6 changes: 3 additions & 3 deletions src/test/ui/generator/type-mismatch-signature-deduction.rs
Expand Up @@ -2,15 +2,15 @@

use std::ops::Generator;

fn foo() -> impl Generator<Return = i32> { //~ ERROR type mismatch
fn foo() -> impl Generator<Return = i32> {
|| {
if false {
return Ok(6);
return Ok(6); //~ ERROR mismatched types [E0308]
}

yield ();

5 //~ ERROR mismatched types [E0308]
5
}
}

Expand Down
25 changes: 7 additions & 18 deletions 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<Return = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.

0 comments on commit f2919a3

Please sign in to comment.