8987: Fix lowering of FnOnce() without return type r=flodiebold a=flodiebold

This should result in an implicit `-> ()`, not leaving out the binding.

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2021-05-25 13:25:15 +00:00 committed by GitHub
commit 33fdd512e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 16 deletions

View file

@ -205,15 +205,14 @@ fn lower_generic_args_from_fn_path(
) -> Option<GenericArgs> { ) -> Option<GenericArgs> {
let mut args = Vec::new(); let mut args = Vec::new();
let mut bindings = Vec::new(); let mut bindings = Vec::new();
if let Some(params) = params { let params = params?;
let mut param_types = Vec::new(); let mut param_types = Vec::new();
for param in params.params() { for param in params.params() {
let type_ref = TypeRef::from_ast_opt(&ctx, param.ty()); let type_ref = TypeRef::from_ast_opt(&ctx, param.ty());
param_types.push(type_ref); param_types.push(type_ref);
}
let arg = GenericArg::Type(TypeRef::Tuple(param_types));
args.push(arg);
} }
let arg = GenericArg::Type(TypeRef::Tuple(param_types));
args.push(arg);
if let Some(ret_type) = ret_type { if let Some(ret_type) = ret_type {
let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty()); let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty());
bindings.push(AssociatedTypeBinding { bindings.push(AssociatedTypeBinding {
@ -221,10 +220,14 @@ fn lower_generic_args_from_fn_path(
type_ref: Some(type_ref), type_ref: Some(type_ref),
bounds: Vec::new(), bounds: Vec::new(),
}); });
}
if args.is_empty() && bindings.is_empty() {
None
} else { } else {
Some(GenericArgs { args, has_self_type: false, bindings }) // -> ()
let type_ref = TypeRef::Tuple(Vec::new());
bindings.push(AssociatedTypeBinding {
name: name![Output],
type_ref: Some(type_ref),
bounds: Vec::new(),
});
} }
Some(GenericArgs { args, has_self_type: false, bindings })
} }

View file

@ -778,8 +778,10 @@ fn write_bounds_like_dyn_trait(
} }
WhereClause::AliasEq(alias_eq) if is_fn_trait => { WhereClause::AliasEq(alias_eq) if is_fn_trait => {
is_fn_trait = false; is_fn_trait = false;
write!(f, " -> ")?; if !alias_eq.ty.is_unit() {
alias_eq.ty.hir_fmt(f)?; write!(f, " -> ")?;
alias_eq.ty.hir_fmt(f)?;
}
} }
WhereClause::AliasEq(AliasEq { ty, alias }) => { WhereClause::AliasEq(AliasEq { ty, alias }) => {
// in types in actual Rust, these will always come // in types in actual Rust, these will always come

View file

@ -3078,7 +3078,7 @@ fn infer_fn_trait_arg() {
#[test] #[test]
fn infer_box_fn_arg() { fn infer_box_fn_arg() {
// The type mismatch is a bug // The type mismatch is because we don't define Unsize and CoerceUnsized
check_infer_with_mismatches( check_infer_with_mismatches(
r#" r#"
//- /lib.rs deps:std //- /lib.rs deps:std
@ -3138,7 +3138,7 @@ fn foo() {
555..557 'ps': {unknown} 555..557 'ps': {unknown}
559..561 '{}': () 559..561 '{}': ()
568..569 'f': Box<dyn FnOnce(&Option<i32>)> 568..569 'f': Box<dyn FnOnce(&Option<i32>)>
568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> 568..573 'f(&s)': ()
570..572 '&s': &Option<i32> 570..572 '&s': &Option<i32>
571..572 's': Option<i32> 571..572 's': Option<i32>
549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()>
@ -3608,3 +3608,25 @@ fn main() {
"#]], "#]],
) )
} }
#[test]
fn fn_returning_unit() {
check_infer_with_mismatches(
r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
fn test<F: FnOnce()>(f: F) {
let _: () = f();
}"#,
expect![[r#"
82..83 'f': F
88..112 '{ ...f(); }': ()
98..99 '_': ()
106..107 'f': F
106..109 'f()': ()
"#]],
);
}