Skip to content

Commit 6f67a46

Browse files
committed
Fix match ergonomics in closure parameters
Fixes #4476.
1 parent 30658b2 commit 6f67a46

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

crates/ra_hir_ty/src/infer/expr.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,13 @@ impl<'a> InferenceContext<'a> {
140140

141141
let mut sig_tys = Vec::new();
142142

143-
for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
144-
let expected = if let Some(type_ref) = arg_type {
143+
// collect explicitly written argument types
144+
for arg_type in arg_types.iter() {
145+
let arg_ty = if let Some(type_ref) = arg_type {
145146
self.make_ty(type_ref)
146147
} else {
147-
Ty::Unknown
148+
self.table.new_type_var()
148149
};
149-
let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
150150
sig_tys.push(arg_ty);
151151
}
152152

@@ -158,7 +158,7 @@ impl<'a> InferenceContext<'a> {
158158
sig_tys.push(ret_ty.clone());
159159
let sig_ty = Ty::apply(
160160
TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
161-
Substs(sig_tys.into()),
161+
Substs(sig_tys.clone().into()),
162162
);
163163
let closure_ty =
164164
Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty);
@@ -168,6 +168,12 @@ impl<'a> InferenceContext<'a> {
168168
// infer the body.
169169
self.coerce(&closure_ty, &expected.ty);
170170

171+
// Now go through the argument patterns
172+
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
173+
let resolved = self.resolve_ty_as_possible(arg_ty);
174+
self.infer_pat(*arg_pat, &resolved, BindingMode::default());
175+
}
176+
171177
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
172178
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
173179

crates/ra_hir_ty/src/tests/patterns.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,3 +520,53 @@ fn main() {
520520
105..107 '()': ()
521521
")
522522
}
523+
524+
#[test]
525+
fn match_ergonomics_in_closure_params() {
526+
assert_snapshot!(
527+
infer(r#"
528+
#[lang = "fn_once"]
529+
trait FnOnce<Args> {
530+
type Output;
531+
}
532+
533+
fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
534+
535+
fn test() {
536+
foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
537+
foo(&(1, "a"), |(x, y)| x);
538+
}
539+
"#),
540+
@r###"
541+
94..95 't': T
542+
100..101 'f': F
543+
111..122 '{ loop {} }': U
544+
113..120 'loop {}': !
545+
118..120 '{}': ()
546+
134..233 '{ ... x); }': ()
547+
140..143 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
548+
140..167 'foo(&(...y)| x)': i32
549+
144..153 '&(1, "a")': &(i32, &str)
550+
145..153 '(1, "a")': (i32, &str)
551+
146..147 '1': i32
552+
149..152 '"a"': &str
553+
155..166 '|&(x, y)| x': |&(i32, &str)| -> i32
554+
156..163 '&(x, y)': &(i32, &str)
555+
157..163 '(x, y)': (i32, &str)
556+
158..159 'x': i32
557+
161..162 'y': &str
558+
165..166 'x': i32
559+
204..207 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
560+
204..230 'foo(&(...y)| x)': &i32
561+
208..217 '&(1, "a")': &(i32, &str)
562+
209..217 '(1, "a")': (i32, &str)
563+
210..211 '1': i32
564+
213..216 '"a"': &str
565+
219..229 '|(x, y)| x': |&(i32, &str)| -> &i32
566+
220..226 '(x, y)': (i32, &str)
567+
221..222 'x': &i32
568+
224..225 'y': &&str
569+
228..229 'x': &i32
570+
"###
571+
);
572+
}

0 commit comments

Comments
 (0)