diff options
author | Florian Diebold <[email protected]> | 2019-09-24 22:04:33 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-24 22:05:12 +0100 |
commit | 6a8670665032f6103ca14e38ed9106126b20063d (patch) | |
tree | ff9c2f3c665ef95ebf509dc69ff82d39ec42d176 /crates/ra_hir | |
parent | a0aeb6e7ad7385811a4bb75577513339c9a9ed91 (diff) |
Implement the call argument checking order hack for closures
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 80 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 4 |
3 files changed, 108 insertions, 12 deletions
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> { | |||
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 | } |
@@ -928,11 +924,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
928 | } | 924 | } |
929 | }; | 925 | }; |
930 | self.register_obligations_for_call(&callee_ty); | 926 | self.register_obligations_for_call(&callee_ty); |
931 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 927 | self.check_call_arguments(args, ¶m_tys); |
932 | for (arg, param_ty) in args.iter().zip(param_iter) { | ||
933 | let param_ty = self.normalize_associated_types_in(param_ty); | ||
934 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
935 | } | ||
936 | let ret_ty = self.normalize_associated_types_in(ret_ty); | 928 | let ret_ty = self.normalize_associated_types_in(ret_ty); |
937 | ret_ty | 929 | ret_ty |
938 | } | 930 | } |
@@ -1274,6 +1266,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1274 | ty | 1266 | ty |
1275 | } | 1267 | } |
1276 | 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 | |||
1277 | fn collect_const(&mut self, data: &ConstData) { | 1293 | fn collect_const(&mut self, data: &ConstData) { |
1278 | self.return_ty = self.make_ty(data.type_ref()); | 1294 | self.return_ty = self.make_ty(data.type_ref()); |
1279 | } | 1295 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 112b3d73f..2872cd27b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -4079,6 +4079,86 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
4079 | } | 4079 | } |
4080 | 4080 | ||
4081 | #[test] | 4081 | #[test] |
4082 | fn closure_as_argument_inference_order() { | ||
4083 | assert_snapshot!( | ||
4084 | infer(r#" | ||
4085 | #[lang = "fn_once"] | ||
4086 | trait FnOnce<Args> { | ||
4087 | type Output; | ||
4088 | } | ||
4089 | |||
4090 | fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {} | ||
4091 | fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {} | ||
4092 | |||
4093 | struct S; | ||
4094 | impl S { | ||
4095 | fn method(self) -> u64; | ||
4096 | |||
4097 | fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {} | ||
4098 | fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {} | ||
4099 | } | ||
4100 | |||
4101 | fn test() { | ||
4102 | let x1 = foo1(S, |s| s.method()); | ||
4103 | let x2 = foo2(|s| s.method(), S); | ||
4104 | let x3 = S.foo1(S, |s| s.method()); | ||
4105 | let x4 = S.foo2(|s| s.method(), S); | ||
4106 | } | ||
4107 | "#), | ||
4108 | @r###" | ||
4109 | [95; 96) 'x': T | ||
4110 | [101; 102) 'f': F | ||
4111 | [112; 114) '{}': () | ||
4112 | [148; 149) 'f': F | ||
4113 | [154; 155) 'x': T | ||
4114 | [165; 167) '{}': () | ||
4115 | [202; 206) 'self': S | ||
4116 | [254; 258) 'self': S | ||
4117 | [260; 261) 'x': T | ||
4118 | [266; 267) 'f': F | ||
4119 | [277; 279) '{}': () | ||
4120 | [317; 321) 'self': S | ||
4121 | [323; 324) 'f': F | ||
4122 | [329; 330) 'x': T | ||
4123 | [340; 342) '{}': () | ||
4124 | [356; 515) '{ ... S); }': () | ||
4125 | [366; 368) 'x1': u64 | ||
4126 | [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U | ||
4127 | [371; 394) 'foo1(S...hod())': u64 | ||
4128 | [376; 377) 'S': S | ||
4129 | [379; 393) '|s| s.method()': |S| -> u64 | ||
4130 | [380; 381) 's': S | ||
4131 | [383; 384) 's': S | ||
4132 | [383; 393) 's.method()': u64 | ||
4133 | [404; 406) 'x2': u64 | ||
4134 | [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U | ||
4135 | [409; 432) 'foo2(|...(), S)': u64 | ||
4136 | [414; 428) '|s| s.method()': |S| -> u64 | ||
4137 | [415; 416) 's': S | ||
4138 | [418; 419) 's': S | ||
4139 | [418; 428) 's.method()': u64 | ||
4140 | [430; 431) 'S': S | ||
4141 | [442; 444) 'x3': u64 | ||
4142 | [447; 448) 'S': S | ||
4143 | [447; 472) 'S.foo1...hod())': u64 | ||
4144 | [454; 455) 'S': S | ||
4145 | [457; 471) '|s| s.method()': |S| -> u64 | ||
4146 | [458; 459) 's': S | ||
4147 | [461; 462) 's': S | ||
4148 | [461; 471) 's.method()': u64 | ||
4149 | [482; 484) 'x4': u64 | ||
4150 | [487; 488) 'S': S | ||
4151 | [487; 512) 'S.foo2...(), S)': u64 | ||
4152 | [494; 508) '|s| s.method()': |S| -> u64 | ||
4153 | [495; 496) 's': S | ||
4154 | [498; 499) 's': S | ||
4155 | [498; 508) 's.method()': u64 | ||
4156 | [510; 511) 'S': S | ||
4157 | "### | ||
4158 | ); | ||
4159 | } | ||
4160 | |||
4161 | #[test] | ||
4082 | fn unselected_projection_in_trait_env_1() { | 4162 | fn unselected_projection_in_trait_env_1() { |
4083 | let t = type_at( | 4163 | let t = type_at( |
4084 | r#" | 4164 | r#" |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index f229b1aef..d83706f86 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -406,8 +406,8 @@ where | |||
406 | 406 | ||
407 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); | 407 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); |
408 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { | 408 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { |
409 | for fn_trait in | 409 | for &fn_trait in |
410 | [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter().copied() | 410 | [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() |
411 | { | 411 | { |
412 | if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { | 412 | if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { |
413 | if trait_ == actual_trait { | 413 | if trait_ == actual_trait { |