From 619a8185a607b216c64b58d230c3949ccef98a37 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 21:03:03 +0200 Subject: Give closures types --- crates/ra_hir/src/ty/infer.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir/src/ty/infer.rs') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 81a8623bf..c04f2a0c4 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -885,18 +885,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::Lambda { body, args, arg_types } => { assert_eq!(args.len(), arg_types.len()); + 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 { self.make_ty(type_ref) } else { Ty::Unknown }; - self.infer_pat(*arg_pat, &expected, BindingMode::default()); + let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default()); + sig_tys.push(arg_ty); } - // FIXME: infer lambda type etc. - let _body_ty = self.infer_expr(*body, &Expectation::none()); - Ty::Unknown + // add return type + let ret_ty = self.new_type_var(); + sig_tys.push(ret_ty.clone()); + let sig_ty = Ty::apply( + TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, + sig_tys.into(), + ); + let closure_ty = Ty::apply_one( + TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr }, + sig_ty, + ); + + self.infer_expr(*body, &Expectation::has_type(ret_ty)); + closure_ty } Expr::Call { callee, args } => { let callee_ty = self.infer_expr(*callee, &Expectation::none()); -- cgit v1.2.3 From a0aeb6e7ad7385811a4bb75577513339c9a9ed91 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 24 Sep 2019 19:04:53 +0200 Subject: Make the closure_1 test work --- crates/ra_hir/src/ty/infer.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'crates/ra_hir/src/ty/infer.rs') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index c04f2a0c4..4784fad85 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -909,6 +909,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { sig_ty, ); + // Eagerly try to relate the closure type with the expected + // type, otherwise we often won't have enough information to + // infer the body. + self.coerce(&closure_ty, &expected.ty); + self.infer_expr(*body, &Expectation::has_type(ret_ty)); closure_ty } -- cgit v1.2.3 From 6a8670665032f6103ca14e38ed9106126b20063d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 24 Sep 2019 23:04:33 +0200 Subject: Implement the call argument checking order hack for closures --- crates/ra_hir/src/ty/infer.rs | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'crates/ra_hir/src/ty/infer.rs') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 4784fad85..378d2f829 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -790,11 +790,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; self.unify(&expected_receiver_ty, &actual_receiver_ty); - let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); - for (arg, param_ty) in args.iter().zip(param_iter) { - let param_ty = self.normalize_associated_types_in(param_ty); - self.infer_expr(*arg, &Expectation::has_type(param_ty)); - } + self.check_call_arguments(args, ¶m_tys); let ret_ty = self.normalize_associated_types_in(ret_ty); ret_ty } @@ -928,11 +924,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } }; self.register_obligations_for_call(&callee_ty); - let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); - for (arg, param_ty) in args.iter().zip(param_iter) { - let param_ty = self.normalize_associated_types_in(param_ty); - self.infer_expr(*arg, &Expectation::has_type(param_ty)); - } + self.check_call_arguments(args, ¶m_tys); let ret_ty = self.normalize_associated_types_in(ret_ty); ret_ty } @@ -1274,6 +1266,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } + fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) { + // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 -- + // We do this in a pretty awful way: first we type-check any arguments + // that are not closures, then we type-check the closures. This is so + // that we have more information about the types of arguments when we + // type-check the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); + for (&arg, param_ty) in args.iter().zip(param_iter) { + let is_closure = match &self.body[arg] { + Expr::Lambda { .. } => true, + _ => false, + }; + + if is_closure != check_closures { + continue; + } + + let param_ty = self.normalize_associated_types_in(param_ty); + self.infer_expr(arg, &Expectation::has_type(param_ty)); + } + } + } + fn collect_const(&mut self, data: &ConstData) { self.return_ty = self.make_ty(data.type_ref()); } -- cgit v1.2.3