Skip to content

Commit

Permalink
Auto merge of #60592 - davidtwco:generator-signature-deduction, r=eddyb
Browse files Browse the repository at this point in the history
Deduce signature of generator on type mismatch

Contributes towards #54326.

r? @eddyb
  • Loading branch information
bors committed May 7, 2019
2 parents c6ac575 + f2919a3 commit f5371a5
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 32 deletions.
49 changes: 31 additions & 18 deletions src/librustc_typeck/check/closure.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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`.
17 changes: 17 additions & 0 deletions src/test/ui/generator/type-mismatch-signature-deduction.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 12 additions & 0 deletions src/test/ui/generator/type-mismatch-signature-deduction.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit f5371a5

Please sign in to comment.