diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-24 22:12:26 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-24 22:12:26 +0100 |
commit | c7420ddaaa76741d1eebe393406b38ba5596e54a (patch) | |
tree | ff9c2f3c665ef95ebf509dc69ff82d39ec42d176 /crates/ra_hir/src/ty/infer.rs | |
parent | 36fb3f53d712a11b7e3fc4bbd92094d1c8f19522 (diff) | |
parent | 6a8670665032f6103ca14e38ed9106126b20063d (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.rs | 63 |
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, ¶m_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, ¶m_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 | } |