diff options
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 67 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 165 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 44 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 143 |
5 files changed, 353 insertions, 75 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 81a8623bf..76b4b6faa 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -436,7 +436,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
436 | 436 | ||
437 | fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { | 437 | fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { |
438 | let var = self.new_type_var(); | 438 | let var = self.new_type_var(); |
439 | let predicate = ProjectionPredicate { projection_ty: proj_ty.clone(), ty: var.clone() }; | 439 | let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; |
440 | let obligation = Obligation::Projection(predicate); | 440 | let obligation = Obligation::Projection(predicate); |
441 | self.obligations.push(obligation); | 441 | self.obligations.push(obligation); |
442 | var | 442 | var |
@@ -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 | } |
@@ -942,7 +953,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
942 | arm_tys.push(self.infer_expr_inner(arm.expr, &expected)); | 953 | arm_tys.push(self.infer_expr_inner(arm.expr, &expected)); |
943 | } | 954 | } |
944 | 955 | ||
945 | let lub_ty = calculate_least_upper_bound(expected.ty.clone(), &arm_tys); | 956 | let lub_ty = calculate_least_upper_bound(expected.ty, &arm_tys); |
946 | 957 | ||
947 | for arm_ty in &arm_tys { | 958 | for arm_ty in &arm_tys { |
948 | self.coerce(arm_ty, &lub_ty); | 959 | self.coerce(arm_ty, &lub_ty); |
@@ -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 | } |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 8b46b11a9..4b71b376f 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -16,6 +16,7 @@ use crate::{ | |||
16 | resolve::Resolver, | 16 | resolve::Resolver, |
17 | ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, | 17 | ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, |
18 | ty::{Ty, TypeCtor}, | 18 | ty::{Ty, TypeCtor}, |
19 | type_ref::Mutability, | ||
19 | AssocItem, Crate, Function, Module, Name, Trait, | 20 | AssocItem, Crate, Function, Module, Name, Trait, |
20 | }; | 21 | }; |
21 | 22 | ||
@@ -130,7 +131,7 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV | |||
130 | ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{ | 131 | ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{ |
131 | let mut v = ArrayVec::<[Crate; 2]>::new(); | 132 | let mut v = ArrayVec::<[Crate; 2]>::new(); |
132 | $( | 133 | $( |
133 | v.push($db.lang_item($cur_crate, $name.into())?.krate($db)?); | 134 | v.extend($db.lang_item($cur_crate, $name.into()).and_then(|item| item.krate($db))); |
134 | )+ | 135 | )+ |
135 | Some(v) | 136 | Some(v) |
136 | }}; | 137 | }}; |
@@ -149,8 +150,10 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV | |||
149 | TypeCtor::Int(UncertainIntTy::Known(i)) => { | 150 | TypeCtor::Int(UncertainIntTy::Known(i)) => { |
150 | lang_item_crate!(db, cur_crate, i.ty_to_string()) | 151 | lang_item_crate!(db, cur_crate, i.ty_to_string()) |
151 | } | 152 | } |
152 | TypeCtor::Str => lang_item_crate!(db, cur_crate, "str"), | 153 | TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), |
153 | TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), | 154 | TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), |
155 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), | ||
156 | TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!(db, cur_crate, "mut_ptr"), | ||
154 | _ => None, | 157 | _ => None, |
155 | }, | 158 | }, |
156 | _ => None, | 159 | _ => None, |
@@ -290,7 +293,7 @@ pub(crate) fn implements_trait( | |||
290 | return true; | 293 | return true; |
291 | } | 294 | } |
292 | let env = lower::trait_env(db, resolver); | 295 | let env = lower::trait_env(db, resolver); |
293 | let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); | 296 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); |
294 | let solution = db.trait_solve(krate, goal); | 297 | let solution = db.trait_solve(krate, goal); |
295 | 298 | ||
296 | solution.is_some() | 299 | solution.is_some() |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3ac1fbdd5..2872cd27b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1077,7 +1077,6 @@ fn test(x: &i32) { | |||
1077 | } | 1077 | } |
1078 | "#), | 1078 | "#), |
1079 | @r###" | 1079 | @r###" |
1080 | |||
1081 | [9; 10) 'x': &i32 | 1080 | [9; 10) 'x': &i32 |
1082 | [18; 369) '{ ...o_x; }': () | 1081 | [18; 369) '{ ...o_x; }': () |
1083 | [28; 29) 'y': &i32 | 1082 | [28; 29) 'y': &i32 |
@@ -1107,8 +1106,8 @@ fn test(x: &i32) { | |||
1107 | [177; 205) '{ ... }': () | 1106 | [177; 205) '{ ... }': () |
1108 | [191; 192) 'h': {unknown} | 1107 | [191; 192) 'h': {unknown} |
1109 | [195; 198) 'val': {unknown} | 1108 | [195; 198) 'val': {unknown} |
1110 | [215; 221) 'lambda': {unknown} | 1109 | [215; 221) 'lambda': |u64, u64, i32| -> i32 |
1111 | [224; 256) '|a: u6...b; c }': {unknown} | 1110 | [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32 |
1112 | [225; 226) 'a': u64 | 1111 | [225; 226) 'a': u64 |
1113 | [233; 234) 'b': u64 | 1112 | [233; 234) 'b': u64 |
1114 | [236; 237) 'c': i32 | 1113 | [236; 237) 'c': i32 |
@@ -2836,12 +2835,11 @@ fn test() -> u64 { | |||
2836 | } | 2835 | } |
2837 | "#), | 2836 | "#), |
2838 | @r###" | 2837 | @r###" |
2839 | |||
2840 | [44; 102) '{ ...0(2) }': u64 | 2838 | [44; 102) '{ ...0(2) }': u64 |
2841 | [54; 55) 'a': S | 2839 | [54; 55) 'a': S |
2842 | [58; 59) 'S': S(fn(u32) -> u64) -> S | 2840 | [58; 59) 'S': S(fn(u32) -> u64) -> S |
2843 | [58; 68) 'S(|i| 2*i)': S | 2841 | [58; 68) 'S(|i| 2*i)': S |
2844 | [60; 67) '|i| 2*i': fn(u32) -> u64 | 2842 | [60; 67) '|i| 2*i': |i32| -> i32 |
2845 | [61; 62) 'i': i32 | 2843 | [61; 62) 'i': i32 |
2846 | [64; 65) '2': i32 | 2844 | [64; 65) '2': i32 |
2847 | [64; 67) '2*i': i32 | 2845 | [64; 67) '2*i': i32 |
@@ -3802,13 +3800,13 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | |||
3802 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type | 3800 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type |
3803 | [296; 302) 'get(x)': {unknown} | 3801 | [296; 302) 'get(x)': {unknown} |
3804 | [300; 301) 'x': T | 3802 | [300; 301) 'x': T |
3805 | [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | 3803 | [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U |
3806 | [308; 315) 'get2(x)': {unknown} | 3804 | [308; 315) 'get2(x)': {unknown} |
3807 | [313; 314) 'x': T | 3805 | [313; 314) 'x': T |
3808 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type | 3806 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type |
3809 | [321; 327) 'get(y)': {unknown} | 3807 | [321; 327) 'get(y)': {unknown} |
3810 | [325; 326) 'y': impl Trait<Type = i64> | 3808 | [325; 326) 'y': impl Trait<Type = i64> |
3811 | [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | 3809 | [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U |
3812 | [333; 340) 'get2(y)': {unknown} | 3810 | [333; 340) 'get2(y)': {unknown} |
3813 | [338; 339) 'y': impl Trait<Type = i64> | 3811 | [338; 339) 'y': impl Trait<Type = i64> |
3814 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type | 3812 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type |
@@ -3992,49 +3990,50 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) { | |||
3992 | fn closure_1() { | 3990 | fn closure_1() { |
3993 | assert_snapshot!( | 3991 | assert_snapshot!( |
3994 | infer(r#" | 3992 | infer(r#" |
3993 | #[lang = "fn_once"] | ||
3995 | trait FnOnce<Args> { | 3994 | trait FnOnce<Args> { |
3996 | type Output; | 3995 | type Output; |
3997 | } | 3996 | } |
3998 | 3997 | ||
3999 | enum Option<T> { Some(T), None } | 3998 | enum Option<T> { Some(T), None } |
4000 | impl<T> Option<T> { | 3999 | impl<T> Option<T> { |
4001 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {} | 4000 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {} |
4002 | } | 4001 | } |
4003 | 4002 | ||
4004 | fn test() { | 4003 | fn test() { |
4005 | let x = Option::Some(1i32); | 4004 | let x = Option::Some(1u32); |
4006 | x.map(|v| v + 1); | 4005 | x.map(|v| v + 1); |
4007 | x.map(|_v| 1u64); | 4006 | x.map(|_v| 1u64); |
4008 | let y: Option<i64> = x.map(|_v| 1); | 4007 | let y: Option<i64> = x.map(|_v| 1); |
4009 | } | 4008 | } |
4010 | "#), | 4009 | "#), |
4011 | @r###" | 4010 | @r###" |
4012 | [128; 132) 'self': Option<T> | 4011 | [148; 152) 'self': Option<T> |
4013 | [134; 135) 'f': F | 4012 | [154; 155) 'f': F |
4014 | [145; 147) '{}': () | 4013 | [173; 175) '{}': () |
4015 | [161; 280) '{ ... 1); }': () | 4014 | [189; 308) '{ ... 1); }': () |
4016 | [171; 172) 'x': Option<i32> | 4015 | [199; 200) 'x': Option<u32> |
4017 | [175; 187) 'Option::Some': Some<i32>(T) -> Option<T> | 4016 | [203; 215) 'Option::Some': Some<u32>(T) -> Option<T> |
4018 | [175; 193) 'Option...(1i32)': Option<i32> | 4017 | [203; 221) 'Option...(1u32)': Option<u32> |
4019 | [188; 192) '1i32': i32 | 4018 | [216; 220) '1u32': u32 |
4020 | [199; 200) 'x': Option<i32> | 4019 | [227; 228) 'x': Option<u32> |
4021 | [199; 215) 'x.map(...v + 1)': {unknown} | 4020 | [227; 243) 'x.map(...v + 1)': Option<u32> |
4022 | [205; 214) '|v| v + 1': {unknown} | 4021 | [233; 242) '|v| v + 1': |u32| -> u32 |
4023 | [206; 207) 'v': {unknown} | 4022 | [234; 235) 'v': u32 |
4024 | [209; 210) 'v': {unknown} | 4023 | [237; 238) 'v': u32 |
4025 | [209; 214) 'v + 1': i32 | 4024 | [237; 242) 'v + 1': u32 |
4026 | [213; 214) '1': i32 | 4025 | [241; 242) '1': u32 |
4027 | [221; 222) 'x': Option<i32> | 4026 | [249; 250) 'x': Option<u32> |
4028 | [221; 237) 'x.map(... 1u64)': {unknown} | 4027 | [249; 265) 'x.map(... 1u64)': Option<u64> |
4029 | [227; 236) '|_v| 1u64': {unknown} | 4028 | [255; 264) '|_v| 1u64': |u32| -> u64 |
4030 | [228; 230) '_v': {unknown} | 4029 | [256; 258) '_v': u32 |
4031 | [232; 236) '1u64': u64 | 4030 | [260; 264) '1u64': u64 |
4032 | [247; 248) 'y': Option<i64> | 4031 | [275; 276) 'y': Option<i64> |
4033 | [264; 265) 'x': Option<i32> | 4032 | [292; 293) 'x': Option<u32> |
4034 | [264; 277) 'x.map(|_v| 1)': Option<i64> | 4033 | [292; 305) 'x.map(|_v| 1)': Option<i64> |
4035 | [270; 276) '|_v| 1': {unknown} | 4034 | [298; 304) '|_v| 1': |u32| -> i64 |
4036 | [271; 273) '_v': {unknown} | 4035 | [299; 301) '_v': u32 |
4037 | [275; 276) '1': i32 | 4036 | [303; 304) '1': i64 |
4038 | "### | 4037 | "### |
4039 | ); | 4038 | ); |
4040 | } | 4039 | } |
@@ -4060,17 +4059,17 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
4060 | [85; 86) 'f': F | 4059 | [85; 86) 'f': F |
4061 | [85; 89) 'f(1)': {unknown} | 4060 | [85; 89) 'f(1)': {unknown} |
4062 | [87; 88) '1': i32 | 4061 | [87; 88) '1': i32 |
4063 | [99; 100) 'g': {unknown} | 4062 | [99; 100) 'g': |u64| -> i32 |
4064 | [103; 112) '|v| v + 1': {unknown} | 4063 | [103; 112) '|v| v + 1': |u64| -> i32 |
4065 | [104; 105) 'v': {unknown} | 4064 | [104; 105) 'v': u64 |
4066 | [107; 108) 'v': {unknown} | 4065 | [107; 108) 'v': u64 |
4067 | [107; 112) 'v + 1': i32 | 4066 | [107; 112) 'v + 1': i32 |
4068 | [111; 112) '1': i32 | 4067 | [111; 112) '1': i32 |
4069 | [118; 119) 'g': {unknown} | 4068 | [118; 119) 'g': |u64| -> i32 |
4070 | [118; 125) 'g(1u64)': {unknown} | 4069 | [118; 125) 'g(1u64)': i32 |
4071 | [120; 124) '1u64': u64 | 4070 | [120; 124) '1u64': u64 |
4072 | [135; 136) 'h': {unknown} | 4071 | [135; 136) 'h': |u128| -> u128 |
4073 | [139; 152) '|v| 1u128 + v': {unknown} | 4072 | [139; 152) '|v| 1u128 + v': |u128| -> u128 |
4074 | [140; 141) 'v': u128 | 4073 | [140; 141) 'v': u128 |
4075 | [143; 148) '1u128': u128 | 4074 | [143; 148) '1u128': u128 |
4076 | [143; 152) '1u128 + v': u128 | 4075 | [143; 152) '1u128 + v': u128 |
@@ -4080,6 +4079,86 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
4080 | } | 4079 | } |
4081 | 4080 | ||
4082 | #[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] | ||
4083 | fn unselected_projection_in_trait_env_1() { | 4162 | fn unselected_projection_in_trait_env_1() { |
4084 | let t = type_at( | 4163 | let t = type_at( |
4085 | r#" | 4164 | r#" |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index c0c132809..d11dab294 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -9,7 +9,7 @@ use ra_prof::profile; | |||
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
10 | 10 | ||
11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 12 | use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait}; |
13 | 13 | ||
14 | use self::chalk::{from_chalk, ToChalk}; | 14 | use self::chalk::{from_chalk, ToChalk}; |
15 | 15 | ||
@@ -173,6 +173,14 @@ pub(crate) fn trait_solve_query( | |||
173 | ) -> Option<Solution> { | 173 | ) -> Option<Solution> { |
174 | let _p = profile("trait_solve_query"); | 174 | let _p = profile("trait_solve_query"); |
175 | debug!("trait_solve_query({})", goal.value.value.display(db)); | 175 | debug!("trait_solve_query({})", goal.value.value.display(db)); |
176 | |||
177 | if let Obligation::Projection(pred) = &goal.value.value { | ||
178 | if let Ty::Bound(_) = &pred.projection_ty.parameters[0] { | ||
179 | // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible | ||
180 | return Some(Solution::Ambig(Guidance::Unknown)); | ||
181 | } | ||
182 | } | ||
183 | |||
176 | let canonical = goal.to_chalk(db).cast(); | 184 | let canonical = goal.to_chalk(db).cast(); |
177 | // We currently don't deal with universes (I think / hope they're not yet | 185 | // We currently don't deal with universes (I think / hope they're not yet |
178 | // relevant for our use cases?) | 186 | // relevant for our use cases?) |
@@ -252,3 +260,37 @@ pub enum Guidance { | |||
252 | /// There's no useful information to feed back to type inference | 260 | /// There's no useful information to feed back to type inference |
253 | Unknown, | 261 | Unknown, |
254 | } | 262 | } |
263 | |||
264 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
265 | pub enum FnTrait { | ||
266 | FnOnce, | ||
267 | FnMut, | ||
268 | Fn, | ||
269 | } | ||
270 | |||
271 | impl FnTrait { | ||
272 | fn lang_item_name(self) -> &'static str { | ||
273 | match self { | ||
274 | FnTrait::FnOnce => "fn_once", | ||
275 | FnTrait::FnMut => "fn_mut", | ||
276 | FnTrait::Fn => "fn", | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
282 | pub struct ClosureFnTraitImplData { | ||
283 | def: DefWithBody, | ||
284 | expr: ExprId, | ||
285 | fn_trait: FnTrait, | ||
286 | } | ||
287 | |||
288 | /// An impl. Usually this comes from an impl block, but some built-in types get | ||
289 | /// synthetic impls. | ||
290 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
291 | pub enum Impl { | ||
292 | /// A normal impl from an impl block. | ||
293 | ImplBlock(ImplBlock), | ||
294 | /// Closure types implement the Fn traits synthetically. | ||
295 | ClosureFnTraitImpl(ClosureFnTraitImplData), | ||
296 | } | ||
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 2e17c00e4..d83706f86 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; | |||
12 | use ra_db::salsa::{InternId, InternKey}; | 12 | use ra_db::salsa::{InternId, InternKey}; |
13 | use test_utils::tested_by; | 13 | use test_utils::tested_by; |
14 | 14 | ||
15 | use super::{Canonical, ChalkContext, Obligation}; | 15 | use super::{Canonical, ChalkContext, Impl, Obligation}; |
16 | use crate::{ | 16 | use crate::{ |
17 | db::HirDatabase, | 17 | db::HirDatabase, |
18 | generics::GenericDef, | 18 | generics::GenericDef, |
@@ -111,7 +111,7 @@ impl ToChalk for Ty { | |||
111 | } | 111 | } |
112 | chalk_ir::Ty::ForAll(_) => unimplemented!(), | 112 | chalk_ir::Ty::ForAll(_) => unimplemented!(), |
113 | chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), | 113 | chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), |
114 | chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"), | 114 | chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, |
115 | } | 115 | } |
116 | } | 116 | } |
117 | } | 117 | } |
@@ -175,15 +175,15 @@ impl ToChalk for TypeCtor { | |||
175 | } | 175 | } |
176 | } | 176 | } |
177 | 177 | ||
178 | impl ToChalk for ImplBlock { | 178 | impl ToChalk for Impl { |
179 | type Chalk = chalk_ir::ImplId; | 179 | type Chalk = chalk_ir::ImplId; |
180 | 180 | ||
181 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { | 181 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { |
182 | db.intern_impl_block(self).into() | 182 | db.intern_impl(self).into() |
183 | } | 183 | } |
184 | 184 | ||
185 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock { | 185 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { |
186 | db.lookup_intern_impl_block(impl_id.into()) | 186 | db.lookup_intern_impl(impl_id.into()) |
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
@@ -385,18 +385,39 @@ where | |||
385 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { | 385 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { |
386 | self.db.impl_datum(self.krate, impl_id) | 386 | self.db.impl_datum(self.krate, impl_id) |
387 | } | 387 | } |
388 | fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { | 388 | fn impls_for_trait( |
389 | &self, | ||
390 | trait_id: chalk_ir::TraitId, | ||
391 | parameters: &[Parameter], | ||
392 | ) -> Vec<ImplId> { | ||
389 | debug!("impls_for_trait {:?}", trait_id); | 393 | debug!("impls_for_trait {:?}", trait_id); |
390 | if trait_id == UNKNOWN_TRAIT { | 394 | if trait_id == UNKNOWN_TRAIT { |
391 | return Vec::new(); | 395 | return Vec::new(); |
392 | } | 396 | } |
393 | let trait_: Trait = from_chalk(self.db, trait_id); | 397 | let trait_: Trait = from_chalk(self.db, trait_id); |
394 | let result: Vec<_> = self | 398 | let mut result: Vec<_> = self |
395 | .db | 399 | .db |
396 | .impls_for_trait(self.krate, trait_) | 400 | .impls_for_trait(self.krate, trait_) |
397 | .iter() | 401 | .iter() |
398 | .map(|impl_block| impl_block.to_chalk(self.db)) | 402 | .copied() |
403 | .map(Impl::ImplBlock) | ||
404 | .map(|impl_| impl_.to_chalk(self.db)) | ||
399 | .collect(); | 405 | .collect(); |
406 | |||
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 { | ||
409 | for &fn_trait in | ||
410 | [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() | ||
411 | { | ||
412 | if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { | ||
413 | if trait_ == actual_trait { | ||
414 | let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait }; | ||
415 | result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db)); | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
400 | debug!("impls_for_trait returned {} impls", result.len()); | 421 | debug!("impls_for_trait returned {} impls", result.len()); |
401 | result | 422 | result |
402 | } | 423 | } |
@@ -415,8 +436,7 @@ where | |||
415 | &self, | 436 | &self, |
416 | projection: &'p chalk_ir::ProjectionTy, | 437 | projection: &'p chalk_ir::ProjectionTy, |
417 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { | 438 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { |
418 | let proj_ty: ProjectionTy = from_chalk(self.db, projection.clone()); | 439 | debug!("split_projection {:?}", projection); |
419 | debug!("split_projection {:?} = {}", projection, proj_ty.display(self.db)); | ||
420 | // we don't support GATs, so I think this should always be correct currently | 440 | // we don't support GATs, so I think this should always be correct currently |
421 | (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) | 441 | (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) |
422 | } | 442 | } |
@@ -568,6 +588,10 @@ pub(crate) fn struct_datum_query( | |||
568 | type_alias.krate(db) != Some(krate), | 588 | type_alias.krate(db) != Some(krate), |
569 | ) | 589 | ) |
570 | } | 590 | } |
591 | TypeCtor::Closure { def, .. } => { | ||
592 | let upstream = def.krate(db) != Some(krate); | ||
593 | (1, vec![], upstream) | ||
594 | } | ||
571 | }; | 595 | }; |
572 | let flags = chalk_rust_ir::StructFlags { | 596 | let flags = chalk_rust_ir::StructFlags { |
573 | upstream, | 597 | upstream, |
@@ -595,7 +619,21 @@ pub(crate) fn impl_datum_query( | |||
595 | ) -> Arc<ImplDatum> { | 619 | ) -> Arc<ImplDatum> { |
596 | let _p = ra_prof::profile("impl_datum"); | 620 | let _p = ra_prof::profile("impl_datum"); |
597 | debug!("impl_datum {:?}", impl_id); | 621 | debug!("impl_datum {:?}", impl_id); |
598 | let impl_block: ImplBlock = from_chalk(db, impl_id); | 622 | let impl_: Impl = from_chalk(db, impl_id); |
623 | match impl_ { | ||
624 | Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), | ||
625 | Impl::ClosureFnTraitImpl(data) => { | ||
626 | closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum) | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
631 | fn impl_block_datum( | ||
632 | db: &impl HirDatabase, | ||
633 | krate: Crate, | ||
634 | impl_id: ImplId, | ||
635 | impl_block: ImplBlock, | ||
636 | ) -> Arc<ImplDatum> { | ||
599 | let generic_params = impl_block.generic_params(db); | 637 | let generic_params = impl_block.generic_params(db); |
600 | let bound_vars = Substs::bound_vars(&generic_params); | 638 | let bound_vars = Substs::bound_vars(&generic_params); |
601 | let trait_ref = impl_block | 639 | let trait_ref = impl_block |
@@ -654,6 +692,87 @@ pub(crate) fn impl_datum_query( | |||
654 | Arc::new(impl_datum) | 692 | Arc::new(impl_datum) |
655 | } | 693 | } |
656 | 694 | ||
695 | fn invalid_impl_datum() -> Arc<ImplDatum> { | ||
696 | let trait_ref = chalk_ir::TraitRef { | ||
697 | trait_id: UNKNOWN_TRAIT, | ||
698 | parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], | ||
699 | }; | ||
700 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | ||
701 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref), | ||
702 | where_clauses: Vec::new(), | ||
703 | associated_ty_values: Vec::new(), | ||
704 | impl_type: chalk_rust_ir::ImplType::External, | ||
705 | }; | ||
706 | let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, 1) }; | ||
707 | Arc::new(impl_datum) | ||
708 | } | ||
709 | |||
710 | fn closure_fn_trait_impl_datum( | ||
711 | db: &impl HirDatabase, | ||
712 | krate: Crate, | ||
713 | impl_id: ImplId, | ||
714 | data: super::ClosureFnTraitImplData, | ||
715 | ) -> Option<Arc<ImplDatum>> { | ||
716 | // for some closure |X, Y| -> Z: | ||
717 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } | ||
718 | |||
719 | let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; | ||
720 | let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait | ||
721 | |||
722 | let num_args: u16 = match &db.body_hir(data.def)[data.expr] { | ||
723 | crate::expr::Expr::Lambda { args, .. } => args.len() as u16, | ||
724 | _ => { | ||
725 | log::warn!("closure for closure type {:?} not found", data); | ||
726 | 0 | ||
727 | } | ||
728 | }; | ||
729 | |||
730 | let arg_ty = Ty::apply( | ||
731 | TypeCtor::Tuple { cardinality: num_args }, | ||
732 | (0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), | ||
733 | ); | ||
734 | let output_ty = Ty::Bound(num_args.into()); | ||
735 | let sig_ty = Ty::apply( | ||
736 | TypeCtor::FnPtr { num_args }, | ||
737 | (0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), | ||
738 | ); | ||
739 | |||
740 | let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); | ||
741 | |||
742 | let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() }; | ||
743 | |||
744 | let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?; | ||
745 | |||
746 | let output_ty_value = chalk_rust_ir::AssociatedTyValue { | ||
747 | associated_ty_id: output_ty_id.to_chalk(db), | ||
748 | impl_id, | ||
749 | value: make_binders( | ||
750 | chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) }, | ||
751 | 0, | ||
752 | ), | ||
753 | }; | ||
754 | |||
755 | let impl_type = chalk_rust_ir::ImplType::External; | ||
756 | |||
757 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | ||
758 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(db)), | ||
759 | where_clauses: Vec::new(), | ||
760 | associated_ty_values: vec![output_ty_value], | ||
761 | impl_type, | ||
762 | }; | ||
763 | let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, num_args as usize + 1) }; | ||
764 | Some(Arc::new(impl_datum)) | ||
765 | } | ||
766 | |||
767 | fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { | ||
768 | let lang_items = db.lang_items(krate); | ||
769 | let target = lang_items.target(fn_trait.lang_item_name())?; | ||
770 | match target { | ||
771 | crate::lang_item::LangItemTarget::Trait(t) => Some(*t), | ||
772 | _ => None, | ||
773 | } | ||
774 | } | ||
775 | |||
657 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { | 776 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { |
658 | T::from_intern_id(InternId::from(chalk_id.index)) | 777 | T::from_intern_id(InternId::from(chalk_id.index)) |
659 | } | 778 | } |