Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduce signature of generator on type mismatch #60592

Merged
merged 2 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.