aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-24 22:04:33 +0100
committerFlorian Diebold <[email protected]>2019-09-24 22:05:12 +0100
commit6a8670665032f6103ca14e38ed9106126b20063d (patch)
treeff9c2f3c665ef95ebf509dc69ff82d39ec42d176 /crates/ra_hir/src
parenta0aeb6e7ad7385811a4bb75577513339c9a9ed91 (diff)
Implement the call argument checking order hack for closures
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/ty/infer.rs36
-rw-r--r--crates/ra_hir/src/ty/tests.rs80
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs4
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, &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 }
@@ -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, &param_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]
4082fn closure_as_argument_inference_order() {
4083 assert_snapshot!(
4084 infer(r#"
4085#[lang = "fn_once"]
4086trait FnOnce<Args> {
4087 type Output;
4088}
4089
4090fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
4091fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
4092
4093struct S;
4094impl 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
4101fn 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]
4082fn unselected_projection_in_trait_env_1() { 4162fn 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 {