Skip to content

Commit f5371a5

Browse files
committed
Auto merge of #60592 - davidtwco:generator-signature-deduction, r=eddyb
Deduce signature of generator on type mismatch Contributes towards #54326. r? @eddyb
2 parents c6ac575 + f2919a3 commit f5371a5

5 files changed

+72
-32
lines changed

src/librustc_typeck/check/closure.rs

+31-18
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
246246
}
247247

248248
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
249-
/// everything we need to know about a closure.
249+
/// everything we need to know about a closure or generator.
250250
///
251251
/// The `cause_span` should be the span that caused us to
252252
/// have this expected signature, or `None` if we can't readily
@@ -262,37 +262,50 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
262262

263263
let trait_ref = projection.to_poly_trait_ref(tcx);
264264

265-
if tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_none() {
265+
let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some();
266+
let gen_trait = tcx.lang_items().gen_trait().unwrap();
267+
let is_gen = gen_trait == trait_ref.def_id();
268+
if !is_fn && !is_gen {
269+
debug!("deduce_sig_from_projection: not fn or generator");
266270
return None;
267271
}
268272

269-
let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
270-
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
271-
debug!(
272-
"deduce_sig_from_projection: arg_param_ty {:?}",
273-
arg_param_ty
274-
);
273+
if is_gen {
274+
// Check that we deduce the signature from the `<_ as std::ops::Generator>::Return`
275+
// associated item and not yield.
276+
let return_assoc_item = self.tcx.associated_items(gen_trait).nth(1).unwrap().def_id;
277+
if return_assoc_item != projection.projection_def_id() {
278+
debug!("deduce_sig_from_projection: not return assoc item of generator");
279+
return None;
280+
}
281+
}
282+
283+
let input_tys = if is_fn {
284+
let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
285+
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
286+
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
275287

276-
let input_tys = match arg_param_ty.sty {
277-
ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()),
278-
_ => return None,
288+
match arg_param_ty.sty {
289+
ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(),
290+
_ => return None,
291+
}
292+
} else {
293+
// Generators cannot have explicit arguments.
294+
vec![]
279295
};
280296

281297
let ret_param_ty = projection.skip_binder().ty;
282298
let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
283-
debug!(
284-
"deduce_sig_from_projection: ret_param_ty {:?}",
285-
ret_param_ty
286-
);
299+
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
287300

288301
let sig = self.tcx.mk_fn_sig(
289-
input_tys,
290-
ret_param_ty,
302+
input_tys.iter(),
303+
&ret_param_ty,
291304
false,
292305
hir::Unsafety::Normal,
293306
Abi::Rust,
294307
);
295-
debug!("deduce_sig_from_projection: sig {:?}", sig);
308+
debug!("deduce_sig_from_projection: sig={:?}", sig);
296309

297310
Some(ExpectedSig { cause_span, sig })
298311
}

src/test/ui/generator-yielding-or-returning-itself.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn want_cyclic_generator_return<T>(_: T)
1313

1414
fn supply_cyclic_generator_return() {
1515
want_cyclic_generator_return(|| {
16-
//~^ ERROR type mismatch
16+
//~^ ERROR closure/generator type that references itself
1717
if false { yield None.unwrap(); }
1818
None.unwrap()
1919
})

src/test/ui/generator-yielding-or-returning-itself.stderr

+11-13
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
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 _]`
2-
--> $DIR/generator-yielding-or-returning-itself.rs:15:5
1+
error[E0644]: closure/generator type that references itself
2+
--> $DIR/generator-yielding-or-returning-itself.rs:15:34
33
|
4-
LL | want_cyclic_generator_return(|| {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
4+
LL | want_cyclic_generator_return(|| {
5+
| __________________________________^
6+
LL | |
7+
LL | | if false { yield None.unwrap(); }
8+
LL | | None.unwrap()
9+
LL | | })
10+
| |_____^ cyclic type of infinite size
611
|
712
= note: closures cannot capture themselves or take themselves as argument;
813
this error may be the result of a recent compiler bug-fix,
914
see https://github.com/rust-lang/rust/issues/46062 for more details
10-
note: required by `want_cyclic_generator_return`
11-
--> $DIR/generator-yielding-or-returning-itself.rs:9:1
12-
|
13-
LL | / pub fn want_cyclic_generator_return<T>(_: T)
14-
LL | | where T: Generator<Yield = (), Return = T>
15-
LL | | {
16-
LL | | }
17-
| |_^
1815

1916
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 _]`
2017
--> $DIR/generator-yielding-or-returning-itself.rs:28:5
@@ -36,4 +33,5 @@ LL | | }
3633

3734
error: aborting due to 2 previous errors
3835

39-
For more information about this error, try `rustc --explain E0271`.
36+
Some errors have detailed explanations: E0271, E0644.
37+
For more information about an error, try `rustc --explain E0271`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(generators, generator_trait)]
2+
3+
use std::ops::Generator;
4+
5+
fn foo() -> impl Generator<Return = i32> {
6+
|| {
7+
if false {
8+
return Ok(6); //~ ERROR mismatched types [E0308]
9+
}
10+
11+
yield ();
12+
13+
5
14+
}
15+
}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/type-mismatch-signature-deduction.rs:8:20
3+
|
4+
LL | return Ok(6);
5+
| ^^^^^ expected i32, found enum `std::result::Result`
6+
|
7+
= note: expected type `i32`
8+
found type `std::result::Result<{integer}, _>`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)