aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2021-05-23 15:59:23 +0100
committerFlorian Diebold <[email protected]>2021-05-23 17:24:21 +0100
commit4a6cdd776d403bacce0a5471d77e8c76695c5bc5 (patch)
tree63f29d9de92697b522c6cc274324764c31ef904f /crates
parent96e5412f881608d703df129ed87f3488ad39a9e1 (diff)
Record method call substs and use them in call info
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/semantics.rs10
-rw-r--r--crates/hir/src/source_analyzer.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs12
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--crates/hir_ty/src/infer.rs25
-rw-r--r--crates/hir_ty/src/infer/expr.rs34
-rw-r--r--crates/hir_ty/src/infer/unify.rs7
-rw-r--r--crates/ide_completion/src/context.rs60
-rw-r--r--crates/ide_db/src/call_info/tests.rs18
9 files changed, 125 insertions, 45 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 1b5064b5a..d65dd7df0 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -11,7 +11,7 @@ use hir_def::{
11 AsMacroCall, FunctionId, TraitId, VariantId, 11 AsMacroCall, FunctionId, TraitId, VariantId,
12}; 12};
13use hir_expand::{name::AsName, ExpansionInfo}; 13use hir_expand::{name::AsName, ExpansionInfo};
14use hir_ty::associated_type_shorthand_candidates; 14use hir_ty::{associated_type_shorthand_candidates, Interner};
15use itertools::Itertools; 15use itertools::Itertools;
16use rustc_hash::{FxHashMap, FxHashSet}; 16use rustc_hash::{FxHashMap, FxHashSet};
17use syntax::{ 17use syntax::{
@@ -501,14 +501,12 @@ impl<'db> SemanticsImpl<'db> {
501 } 501 }
502 502
503 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { 503 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
504 self.analyze(call.syntax()).resolve_method_call(self.db, call) 504 self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id)
505 } 505 }
506 506
507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { 507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
508 // FIXME: this erases Substs, we should instead record the correct 508 let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
509 // substitution during inference and use that 509 let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst);
510 let func = self.resolve_method_call(call)?;
511 let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
512 let resolver = self.analyze(call.syntax()).resolver; 510 let resolver = self.analyze(call.syntax()).resolver;
513 let ty = Type::new_with_resolver(self.db, &resolver, ty)?; 511 let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
514 let mut res = ty.as_callable(self.db)?; 512 let mut res = ty.as_callable(self.db)?;
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index b5c65808e..a1a9c727a 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -143,7 +143,7 @@ impl SourceAnalyzer {
143 &self, 143 &self,
144 db: &dyn HirDatabase, 144 db: &dyn HirDatabase,
145 call: &ast::MethodCallExpr, 145 call: &ast::MethodCallExpr,
146 ) -> Option<FunctionId> { 146 ) -> Option<(FunctionId, Substitution)> {
147 let expr_id = self.expr_id(db, &call.clone().into())?; 147 let expr_id = self.expr_id(db, &call.clone().into())?;
148 self.infer.as_ref()?.method_resolution(expr_id) 148 self.infer.as_ref()?.method_resolution(expr_id)
149 } 149 }
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 53c4ee9da..d1f113e7f 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -181,7 +181,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
181 for (id, expr) in body.exprs.iter() { 181 for (id, expr) in body.exprs.iter() {
182 if let Expr::MethodCall { receiver, .. } = expr { 182 if let Expr::MethodCall { receiver, .. } = expr {
183 let function_id = match self.infer.method_resolution(id) { 183 let function_id = match self.infer.method_resolution(id) {
184 Some(id) => id, 184 Some((id, _)) => id,
185 None => continue, 185 None => continue,
186 }; 186 };
187 187
@@ -239,15 +239,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
239 return; 239 return;
240 } 240 }
241 241
242 // FIXME: note that we erase information about substs here. This 242 let (callee, subst) = match self.infer.method_resolution(call_id) {
243 // is not right, but, luckily, doesn't matter as we care only 243 Some(it) => it,
244 // about the number of params
245 let callee = match self.infer.method_resolution(call_id) {
246 Some(callee) => callee,
247 None => return, 244 None => return,
248 }; 245 };
249 let sig = 246 let sig = db.callable_item_signature(callee.into()).substitute(&Interner, &subst);
250 db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0;
251 247
252 (sig, args) 248 (sig, args)
253 } 249 }
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index ed97dc0e3..5d13bddea 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -105,7 +105,7 @@ fn walk_unsafe(
105 Expr::MethodCall { .. } => { 105 Expr::MethodCall { .. } => {
106 if infer 106 if infer
107 .method_resolution(current) 107 .method_resolution(current)
108 .map(|func| db.function_data(func).is_unsafe()) 108 .map(|(func, _)| db.function_data(func).is_unsafe())
109 .unwrap_or(false) 109 .unwrap_or(false)
110 { 110 {
111 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 111 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index f1cebbdb9..db3c937ff 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -37,8 +37,8 @@ use syntax::SmolStr;
37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; 37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
38use crate::{ 38use crate::{
39 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, 39 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
40 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, TyBuilder, 40 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution,
41 TyExt, TyKind, 41 TyBuilder, TyExt, TyKind,
42}; 42};
43 43
44// This lint has a false positive here. See the link below for details. 44// This lint has a false positive here. See the link below for details.
@@ -132,7 +132,7 @@ impl Default for InternedStandardTypes {
132#[derive(Clone, PartialEq, Eq, Debug, Default)] 132#[derive(Clone, PartialEq, Eq, Debug, Default)]
133pub struct InferenceResult { 133pub struct InferenceResult {
134 /// For each method call expr, records the function it resolves to. 134 /// For each method call expr, records the function it resolves to.
135 method_resolutions: FxHashMap<ExprId, FunctionId>, 135 method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
136 /// For each field access expr, records the field it resolves to. 136 /// For each field access expr, records the field it resolves to.
137 field_resolutions: FxHashMap<ExprId, FieldId>, 137 field_resolutions: FxHashMap<ExprId, FieldId>,
138 /// For each struct literal or pattern, records the variant it resolves to. 138 /// For each struct literal or pattern, records the variant it resolves to.
@@ -152,8 +152,8 @@ pub struct InferenceResult {
152} 152}
153 153
154impl InferenceResult { 154impl InferenceResult {
155 pub fn method_resolution(&self, expr: ExprId) -> Option<FunctionId> { 155 pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
156 self.method_resolutions.get(&expr).copied() 156 self.method_resolutions.get(&expr).cloned()
157 } 157 }
158 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { 158 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
159 self.field_resolutions.get(&expr).copied() 159 self.field_resolutions.get(&expr).copied()
@@ -284,14 +284,17 @@ impl<'a> InferenceContext<'a> {
284 self.table.propagate_diverging_flag(); 284 self.table.propagate_diverging_flag();
285 let mut result = std::mem::take(&mut self.result); 285 let mut result = std::mem::take(&mut self.result);
286 for ty in result.type_of_expr.values_mut() { 286 for ty in result.type_of_expr.values_mut() {
287 *ty = self.table.resolve_ty_completely(ty.clone()); 287 *ty = self.table.resolve_completely(ty.clone());
288 } 288 }
289 for ty in result.type_of_pat.values_mut() { 289 for ty in result.type_of_pat.values_mut() {
290 *ty = self.table.resolve_ty_completely(ty.clone()); 290 *ty = self.table.resolve_completely(ty.clone());
291 } 291 }
292 for mismatch in result.type_mismatches.values_mut() { 292 for mismatch in result.type_mismatches.values_mut() {
293 mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone()); 293 mismatch.expected = self.table.resolve_completely(mismatch.expected.clone());
294 mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone()); 294 mismatch.actual = self.table.resolve_completely(mismatch.actual.clone());
295 }
296 for (_, subst) in result.method_resolutions.values_mut() {
297 *subst = self.table.resolve_completely(subst.clone());
295 } 298 }
296 result 299 result
297 } 300 }
@@ -300,8 +303,8 @@ impl<'a> InferenceContext<'a> {
300 self.result.type_of_expr.insert(expr, ty); 303 self.result.type_of_expr.insert(expr, ty);
301 } 304 }
302 305
303 fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId) { 306 fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
304 self.result.method_resolutions.insert(expr, func); 307 self.result.method_resolutions.insert(expr, (func, subst));
305 } 308 }
306 309
307 fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) { 310 fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) {
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 08c05c67c..eab8fac91 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -891,17 +891,21 @@ impl<'a> InferenceContext<'a> {
891 method_name, 891 method_name,
892 ) 892 )
893 }); 893 });
894 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 894 let (derefed_receiver_ty, method_ty, substs) = match resolved {
895 Some((ty, func)) => { 895 Some((ty, func)) => {
896 let ty = canonicalized_receiver.decanonicalize_ty(ty); 896 let ty = canonicalized_receiver.decanonicalize_ty(ty);
897 self.write_method_resolution(tgt_expr, func); 897 let generics = generics(self.db.upcast(), func.into());
898 (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into()))) 898 let substs = self.substs_for_method_call(generics, generic_args, &ty);
899 self.write_method_resolution(tgt_expr, func, substs.clone());
900 (ty, self.db.value_ty(func.into()), substs)
899 } 901 }
900 None => (receiver_ty, Binders::empty(&Interner, self.err_ty()), None), 902 None => (
903 receiver_ty,
904 Binders::empty(&Interner, self.err_ty()),
905 Substitution::empty(&Interner),
906 ),
901 }; 907 };
902 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
903 let method_ty = method_ty.substitute(&Interner, &substs); 908 let method_ty = method_ty.substitute(&Interner, &substs);
904 let method_ty = self.insert_type_vars(method_ty);
905 self.register_obligations_for_call(&method_ty); 909 self.register_obligations_for_call(&method_ty);
906 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { 910 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
907 Some(sig) => { 911 Some(sig) => {
@@ -950,23 +954,21 @@ impl<'a> InferenceContext<'a> {
950 954
951 fn substs_for_method_call( 955 fn substs_for_method_call(
952 &mut self, 956 &mut self,
953 def_generics: Option<Generics>, 957 def_generics: Generics,
954 generic_args: Option<&GenericArgs>, 958 generic_args: Option<&GenericArgs>,
955 receiver_ty: &Ty, 959 receiver_ty: &Ty,
956 ) -> Substitution { 960 ) -> Substitution {
957 let (parent_params, self_params, type_params, impl_trait_params) = 961 let (parent_params, self_params, type_params, impl_trait_params) =
958 def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split()); 962 def_generics.provenance_split();
959 assert_eq!(self_params, 0); // method shouldn't have another Self param 963 assert_eq!(self_params, 0); // method shouldn't have another Self param
960 let total_len = parent_params + type_params + impl_trait_params; 964 let total_len = parent_params + type_params + impl_trait_params;
961 let mut substs = Vec::with_capacity(total_len); 965 let mut substs = Vec::with_capacity(total_len);
962 // Parent arguments are unknown, except for the receiver type 966 // Parent arguments are unknown, except for the receiver type
963 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 967 for (_id, param) in def_generics.iter_parent() {
964 for (_id, param) in parent_generics { 968 if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
965 if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf { 969 substs.push(receiver_ty.clone());
966 substs.push(receiver_ty.clone()); 970 } else {
967 } else { 971 substs.push(self.table.new_type_var());
968 substs.push(self.err_ty());
969 }
970 } 972 }
971 } 973 }
972 // handle provided type arguments 974 // handle provided type arguments
@@ -989,7 +991,7 @@ impl<'a> InferenceContext<'a> {
989 }; 991 };
990 let supplied_params = substs.len(); 992 let supplied_params = substs.len();
991 for _ in supplied_params..total_len { 993 for _ in supplied_params..total_len {
992 substs.push(self.err_ty()); 994 substs.push(self.table.new_type_var());
993 } 995 }
994 assert_eq!(substs.len(), total_len); 996 assert_eq!(substs.len(), total_len);
995 Substitution::from_iter(&Interner, substs) 997 Substitution::from_iter(&Interner, substs)
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index f8233cac3..ea5684229 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -295,8 +295,11 @@ impl<'a> InferenceTable<'a> {
295 .expect("fold failed unexpectedly") 295 .expect("fold failed unexpectedly")
296 } 296 }
297 297
298 pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 298 pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T::Result
299 self.resolve_with_fallback(ty, |_, _, d, _| d) 299 where
300 T: HasInterner<Interner = Interner> + Fold<Interner>,
301 {
302 self.resolve_with_fallback(t, |_, _, d, _| d)
300 } 303 }
301 304
302 /// Unify two types and register new trait goals that arise from that. 305 /// Unify two types and register new trait goals that arise from that.
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 787eb2fd3..c929d7394 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -785,6 +785,19 @@ fn foo() {
785 } 785 }
786 786
787 #[test] 787 #[test]
788 fn expected_type_generic_struct_field() {
789 check_expected_type_and_name(
790 r#"
791struct Foo<T> { a: T }
792fn foo() -> Foo<u32> {
793 Foo { a: $0 }
794}
795"#,
796 expect![[r#"ty: u32, name: a"#]],
797 )
798 }
799
800 #[test]
788 fn expected_type_struct_field_with_leading_char() { 801 fn expected_type_struct_field_with_leading_char() {
789 cov_mark::check!(expected_type_struct_field_with_leading_char); 802 cov_mark::check!(expected_type_struct_field_with_leading_char);
790 check_expected_type_and_name( 803 check_expected_type_and_name(
@@ -895,4 +908,51 @@ fn foo() -> u32 {
895 expect![[r#"ty: u32, name: ?"#]], 908 expect![[r#"ty: u32, name: ?"#]],
896 ) 909 )
897 } 910 }
911
912 #[test]
913 fn expected_type_closure_param() {
914 check_expected_type_and_name(
915 r#"
916fn foo() {
917 bar(|| $0);
918}
919
920fn bar(f: impl FnOnce() -> u32) {}
921#[lang = "fn_once"]
922trait FnOnce { type Output; }
923"#,
924 expect![[r#"ty: u32, name: ?"#]],
925 );
926 }
927
928 #[test]
929 fn expected_type_generic_function() {
930 check_expected_type_and_name(
931 r#"
932fn foo() {
933 bar::<u32>($0);
934}
935
936fn bar<T>(t: T) {}
937"#,
938 expect![[r#"ty: u32, name: t"#]],
939 );
940 }
941
942 #[test]
943 fn expected_type_generic_method() {
944 check_expected_type_and_name(
945 r#"
946fn foo() {
947 S(1u32).bar($0);
948}
949
950struct S<T>(T);
951impl<T> S<T> {
952 fn bar(self, t: T) {}
953}
954"#,
955 expect![[r#"ty: u32, name: t"#]],
956 );
957 }
898} 958}
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs
index be1cc12de..1aeda08e5 100644
--- a/crates/ide_db/src/call_info/tests.rs
+++ b/crates/ide_db/src/call_info/tests.rs
@@ -189,6 +189,24 @@ fn main() { S.foo($0); }
189} 189}
190 190
191#[test] 191#[test]
192fn test_fn_signature_for_generic_method() {
193 check(
194 r#"
195struct S<T>(T);
196impl<T> S<T> {
197 fn foo(&self, x: T) {}
198}
199
200fn main() { S(1u32).foo($0); }
201"#,
202 expect![[r#"
203 fn foo(&self, x: u32)
204 (<x: u32>)
205 "#]],
206 );
207}
208
209#[test]
192fn test_fn_signature_for_method_with_arg_as_assoc_fn() { 210fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
193 check( 211 check(
194 r#" 212 r#"