aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/infer.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-24 22:12:26 +0100
committerGitHub <[email protected]>2019-09-24 22:12:26 +0100
commitc7420ddaaa76741d1eebe393406b38ba5596e54a (patch)
treeff9c2f3c665ef95ebf509dc69ff82d39ec42d176 /crates/ra_hir/src/ty/infer.rs
parent36fb3f53d712a11b7e3fc4bbd92094d1c8f19522 (diff)
parent6a8670665032f6103ca14e38ed9106126b20063d (diff)
Merge #1845
1845: Closure types r=flodiebold a=flodiebold This adds types for closures and makes them implement the `Fn` traits (we don't currently care or try to infer `Fn` vs. `FnMut` vs. `FnOnce`; this would require move analysis, I think). This requires some changes in Chalk; one is that we need to know the self type when asked for impls, so we can synthesize `Fn` trait impls for closures; but also there's a problem that prevents us from normalizing the closure output type correctly that I _think_ will be fixed on the Chalk side (basically, we ask too early and try to solve `Normalize(<?1 as FnOnce<(u32,)>>::Output => ?0)` -- note the variable in the self type -- and instead of an ambiguous answer, we get back that it can't be solved, so we don't try again. Niko mentioned he's making all goals where the self type is unconstrained flounder, which I think would mean this would be ambiguous). Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r--crates/ra_hir/src/ty/infer.rs63
1 files changed, 49 insertions, 14 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 81a8623bf..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> {
790 }; 790 };
791 self.unify(&expected_receiver_ty, &actual_receiver_ty); 791 self.unify(&expected_receiver_ty, &actual_receiver_ty);
792 792
793 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 793 self.check_call_arguments(args, &param_tys);
794 for (arg, param_ty) in args.iter().zip(param_iter) {
795 let param_ty = self.normalize_associated_types_in(param_ty);
796 self.infer_expr(*arg, &Expectation::has_type(param_ty));
797 }
798 let ret_ty = self.normalize_associated_types_in(ret_ty); 794 let ret_ty = self.normalize_associated_types_in(ret_ty);
799 ret_ty 795 ret_ty
800 } 796 }
@@ -885,18 +881,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
885 Expr::Lambda { body, args, arg_types } => { 881 Expr::Lambda { body, args, arg_types } => {
886 assert_eq!(args.len(), arg_types.len()); 882 assert_eq!(args.len(), arg_types.len());
887 883
884 let mut sig_tys = Vec::new();
885
888 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { 886 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
889 let expected = if let Some(type_ref) = arg_type { 887 let expected = if let Some(type_ref) = arg_type {
890 self.make_ty(type_ref) 888 self.make_ty(type_ref)
891 } else { 889 } else {
892 Ty::Unknown 890 Ty::Unknown
893 }; 891 };
894 self.infer_pat(*arg_pat, &expected, BindingMode::default()); 892 let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
893 sig_tys.push(arg_ty);
895 } 894 }
896 895
897 // FIXME: infer lambda type etc. 896 // add return type
898 let _body_ty = self.infer_expr(*body, &Expectation::none()); 897 let ret_ty = self.new_type_var();
899 Ty::Unknown 898 sig_tys.push(ret_ty.clone());
899 let sig_ty = Ty::apply(
900 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
901 sig_tys.into(),
902 );
903 let closure_ty = Ty::apply_one(
904 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
905 sig_ty,
906 );
907
908 // Eagerly try to relate the closure type with the expected
909 // type, otherwise we often won't have enough information to
910 // infer the body.
911 self.coerce(&closure_ty, &expected.ty);
912
913 self.infer_expr(*body, &Expectation::has_type(ret_ty));
914 closure_ty
900 } 915 }
901 Expr::Call { callee, args } => { 916 Expr::Call { callee, args } => {
902 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 917 let callee_ty = self.infer_expr(*callee, &Expectation::none());
@@ -909,11 +924,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
909 } 924 }
910 }; 925 };
911 self.register_obligations_for_call(&callee_ty); 926 self.register_obligations_for_call(&callee_ty);
912 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 927 self.check_call_arguments(args, &param_tys);
913 for (arg, param_ty) in args.iter().zip(param_iter) {
914 let param_ty = self.normalize_associated_types_in(param_ty);
915 self.infer_expr(*arg, &Expectation::has_type(param_ty));
916 }
917 let ret_ty = self.normalize_associated_types_in(ret_ty); 928 let ret_ty = self.normalize_associated_types_in(ret_ty);
918 ret_ty 929 ret_ty
919 } 930 }
@@ -1255,6 +1266,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1255 ty 1266 ty
1256 } 1267 }
1257 1268
1269 fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) {
1270 // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
1271 // We do this in a pretty awful way: first we type-check any arguments
1272 // that are not closures, then we type-check the closures. This is so
1273 // that we have more information about the types of arguments when we
1274 // type-check the functions. This isn't really the right way to do this.
1275 for &check_closures in &[false, true] {
1276 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
1277 for (&arg, param_ty) in args.iter().zip(param_iter) {
1278 let is_closure = match &self.body[arg] {
1279 Expr::Lambda { .. } => true,
1280 _ => false,
1281 };
1282
1283 if is_closure != check_closures {
1284 continue;
1285 }
1286
1287 let param_ty = self.normalize_associated_types_in(param_ty);
1288 self.infer_expr(arg, &Expectation::has_type(param_ty));
1289 }
1290 }
1291 }
1292
1258 fn collect_const(&mut self, data: &ConstData) { 1293 fn collect_const(&mut self, data: &ConstData) {
1259 self.return_ty = self.make_ty(data.type_ref()); 1294 self.return_ty = self.make_ty(data.type_ref());
1260 } 1295 }