Fix match ergonomics in closure parameters

Fixes #4476.
This commit is contained in:
Florian Diebold 2020-05-29 17:35:57 +02:00
parent 30658b25d2
commit 6f67a46a6a
2 changed files with 61 additions and 5 deletions

View file

@ -140,13 +140,13 @@ impl<'a> InferenceContext<'a> {
let mut sig_tys = Vec::new();
for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
let expected = if let Some(type_ref) = arg_type {
// collect explicitly written argument types
for arg_type in arg_types.iter() {
let arg_ty = if let Some(type_ref) = arg_type {
self.make_ty(type_ref)
} else {
Ty::Unknown
self.table.new_type_var()
};
let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
sig_tys.push(arg_ty);
}
@ -158,7 +158,7 @@ impl<'a> InferenceContext<'a> {
sig_tys.push(ret_ty.clone());
let sig_ty = Ty::apply(
TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
Substs(sig_tys.into()),
Substs(sig_tys.clone().into()),
);
let closure_ty =
Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty);
@ -168,6 +168,12 @@ impl<'a> InferenceContext<'a> {
// infer the body.
self.coerce(&closure_ty, &expected.ty);
// Now go through the argument patterns
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
let resolved = self.resolve_ty_as_possible(arg_ty);
self.infer_pat(*arg_pat, &resolved, BindingMode::default());
}
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());

View file

@ -520,3 +520,53 @@ fn main() {
105..107 '()': ()
")
}
#[test]
fn match_ergonomics_in_closure_params() {
assert_snapshot!(
infer(r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
fn test() {
foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
foo(&(1, "a"), |(x, y)| x);
}
"#),
@r###"
94..95 't': T
100..101 'f': F
111..122 '{ loop {} }': U
113..120 'loop {}': !
118..120 '{}': ()
134..233 '{ ... x); }': ()
140..143 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
140..167 'foo(&(...y)| x)': i32
144..153 '&(1, "a")': &(i32, &str)
145..153 '(1, "a")': (i32, &str)
146..147 '1': i32
149..152 '"a"': &str
155..166 '|&(x, y)| x': |&(i32, &str)| -> i32
156..163 '&(x, y)': &(i32, &str)
157..163 '(x, y)': (i32, &str)
158..159 'x': i32
161..162 'y': &str
165..166 'x': i32
204..207 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
204..230 'foo(&(...y)| x)': &i32
208..217 '&(1, "a")': &(i32, &str)
209..217 '(1, "a")': (i32, &str)
210..211 '1': i32
213..216 '"a"': &str
219..229 '|(x, y)| x': |&(i32, &str)| -> &i32
220..226 '(x, y)': (i32, &str)
221..222 'x': &i32
224..225 'y': &&str
228..229 'x': &i32
"###
);
}