Skip to content

Commit 4a6cdd7

Browse files
committed
Record method call substs and use them in call info
1 parent 96e5412 commit 4a6cdd7

File tree

9 files changed

+125
-45
lines changed

9 files changed

+125
-45
lines changed

crates/hir/src/semantics.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use hir_def::{
1111
AsMacroCall, FunctionId, TraitId, VariantId,
1212
};
1313
use hir_expand::{name::AsName, ExpansionInfo};
14-
use hir_ty::associated_type_shorthand_candidates;
14+
use hir_ty::{associated_type_shorthand_candidates, Interner};
1515
use itertools::Itertools;
1616
use rustc_hash::{FxHashMap, FxHashSet};
1717
use syntax::{
@@ -501,14 +501,12 @@ impl<'db> SemanticsImpl<'db> {
501501
}
502502

503503
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)
505505
}
506506

507507
fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
508-
// FIXME: this erases Substs, we should instead record the correct
509-
// substitution during inference and use that
510-
let func = self.resolve_method_call(call)?;
511-
let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
508+
let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
509+
let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst);
512510
let resolver = self.analyze(call.syntax()).resolver;
513511
let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
514512
let mut res = ty.as_callable(self.db)?;

crates/hir/src/source_analyzer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ impl SourceAnalyzer {
143143
&self,
144144
db: &dyn HirDatabase,
145145
call: &ast::MethodCallExpr,
146-
) -> Option<FunctionId> {
146+
) -> Option<(FunctionId, Substitution)> {
147147
let expr_id = self.expr_id(db, &call.clone().into())?;
148148
self.infer.as_ref()?.method_resolution(expr_id)
149149
}

crates/hir_ty/src/diagnostics/expr.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
181181
for (id, expr) in body.exprs.iter() {
182182
if let Expr::MethodCall { receiver, .. } = expr {
183183
let function_id = match self.infer.method_resolution(id) {
184-
Some(id) => id,
184+
Some((id, _)) => id,
185185
None => continue,
186186
};
187187

@@ -239,15 +239,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
239239
return;
240240
}
241241

242-
// FIXME: note that we erase information about substs here. This
243-
// is not right, but, luckily, doesn't matter as we care only
244-
// about the number of params
245-
let callee = match self.infer.method_resolution(call_id) {
246-
Some(callee) => callee,
242+
let (callee, subst) = match self.infer.method_resolution(call_id) {
243+
Some(it) => it,
247244
None => return,
248245
};
249-
let sig =
250-
db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0;
246+
let sig = db.callable_item_signature(callee.into()).substitute(&Interner, &subst);
251247

252248
(sig, args)
253249
}

crates/hir_ty/src/diagnostics/unsafe_check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ fn walk_unsafe(
105105
Expr::MethodCall { .. } => {
106106
if infer
107107
.method_resolution(current)
108-
.map(|func| db.function_data(func).is_unsafe())
108+
.map(|(func, _)| db.function_data(func).is_unsafe())
109109
.unwrap_or(false)
110110
{
111111
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });

crates/hir_ty/src/infer.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ use syntax::SmolStr;
3737
use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
3838
use crate::{
3939
db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
40-
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, TyBuilder,
41-
TyExt, TyKind,
40+
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution,
41+
TyBuilder, TyExt, TyKind,
4242
};
4343

4444
// This lint has a false positive here. See the link below for details.
@@ -132,7 +132,7 @@ impl Default for InternedStandardTypes {
132132
#[derive(Clone, PartialEq, Eq, Debug, Default)]
133133
pub struct InferenceResult {
134134
/// For each method call expr, records the function it resolves to.
135-
method_resolutions: FxHashMap<ExprId, FunctionId>,
135+
method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
136136
/// For each field access expr, records the field it resolves to.
137137
field_resolutions: FxHashMap<ExprId, FieldId>,
138138
/// For each struct literal or pattern, records the variant it resolves to.
@@ -152,8 +152,8 @@ pub struct InferenceResult {
152152
}
153153

154154
impl InferenceResult {
155-
pub fn method_resolution(&self, expr: ExprId) -> Option<FunctionId> {
156-
self.method_resolutions.get(&expr).copied()
155+
pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
156+
self.method_resolutions.get(&expr).cloned()
157157
}
158158
pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
159159
self.field_resolutions.get(&expr).copied()
@@ -284,14 +284,17 @@ impl<'a> InferenceContext<'a> {
284284
self.table.propagate_diverging_flag();
285285
let mut result = std::mem::take(&mut self.result);
286286
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());
288288
}
289289
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());
291291
}
292292
for mismatch in result.type_mismatches.values_mut() {
293-
mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone());
294-
mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone());
293+
mismatch.expected = self.table.resolve_completely(mismatch.expected.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());
295298
}
296299
result
297300
}
@@ -300,8 +303,8 @@ impl<'a> InferenceContext<'a> {
300303
self.result.type_of_expr.insert(expr, ty);
301304
}
302305

303-
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId) {
304-
self.result.method_resolutions.insert(expr, func);
306+
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
307+
self.result.method_resolutions.insert(expr, (func, subst));
305308
}
306309

307310
fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) {

crates/hir_ty/src/infer/expr.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -891,17 +891,21 @@ impl<'a> InferenceContext<'a> {
891891
method_name,
892892
)
893893
});
894-
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
894+
let (derefed_receiver_ty, method_ty, substs) = match resolved {
895895
Some((ty, func)) => {
896896
let ty = canonicalized_receiver.decanonicalize_ty(ty);
897-
self.write_method_resolution(tgt_expr, func);
898-
(ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into())))
897+
let generics = 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)
899901
}
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+
),
901907
};
902-
let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
903908
let method_ty = method_ty.substitute(&Interner, &substs);
904-
let method_ty = self.insert_type_vars(method_ty);
905909
self.register_obligations_for_call(&method_ty);
906910
let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
907911
Some(sig) => {
@@ -950,23 +954,21 @@ impl<'a> InferenceContext<'a> {
950954

951955
fn substs_for_method_call(
952956
&mut self,
953-
def_generics: Option<Generics>,
957+
def_generics: Generics,
954958
generic_args: Option<&GenericArgs>,
955959
receiver_ty: &Ty,
956960
) -> Substitution {
957961
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();
959963
assert_eq!(self_params, 0); // method shouldn't have another Self param
960964
let total_len = parent_params + type_params + impl_trait_params;
961965
let mut substs = Vec::with_capacity(total_len);
962966
// Parent arguments are unknown, except for the receiver type
963-
if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
964-
for (_id, param) in parent_generics {
965-
if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
966-
substs.push(receiver_ty.clone());
967-
} else {
968-
substs.push(self.err_ty());
969-
}
967+
for (_id, param) in def_generics.iter_parent() {
968+
if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
969+
substs.push(receiver_ty.clone());
970+
} else {
971+
substs.push(self.table.new_type_var());
970972
}
971973
}
972974
// handle provided type arguments
@@ -989,7 +991,7 @@ impl<'a> InferenceContext<'a> {
989991
};
990992
let supplied_params = substs.len();
991993
for _ in supplied_params..total_len {
992-
substs.push(self.err_ty());
994+
substs.push(self.table.new_type_var());
993995
}
994996
assert_eq!(substs.len(), total_len);
995997
Substitution::from_iter(&Interner, substs)

crates/hir_ty/src/infer/unify.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,11 @@ impl<'a> InferenceTable<'a> {
295295
.expect("fold failed unexpectedly")
296296
}
297297

298-
pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
299-
self.resolve_with_fallback(ty, |_, _, d, _| d)
298+
pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T::Result
299+
where
300+
T: HasInterner<Interner = Interner> + Fold<Interner>,
301+
{
302+
self.resolve_with_fallback(t, |_, _, d, _| d)
300303
}
301304

302305
/// Unify two types and register new trait goals that arise from that.

crates/ide_completion/src/context.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,19 @@ fn foo() {
784784
)
785785
}
786786

787+
#[test]
788+
fn expected_type_generic_struct_field() {
789+
check_expected_type_and_name(
790+
r#"
791+
struct Foo<T> { a: T }
792+
fn foo() -> Foo<u32> {
793+
Foo { a: $0 }
794+
}
795+
"#,
796+
expect![[r#"ty: u32, name: a"#]],
797+
)
798+
}
799+
787800
#[test]
788801
fn expected_type_struct_field_with_leading_char() {
789802
cov_mark::check!(expected_type_struct_field_with_leading_char);
@@ -895,4 +908,51 @@ fn foo() -> u32 {
895908
expect![[r#"ty: u32, name: ?"#]],
896909
)
897910
}
911+
912+
#[test]
913+
fn expected_type_closure_param() {
914+
check_expected_type_and_name(
915+
r#"
916+
fn foo() {
917+
bar(|| $0);
918+
}
919+
920+
fn bar(f: impl FnOnce() -> u32) {}
921+
#[lang = "fn_once"]
922+
trait 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#"
932+
fn foo() {
933+
bar::<u32>($0);
934+
}
935+
936+
fn 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#"
946+
fn foo() {
947+
S(1u32).bar($0);
948+
}
949+
950+
struct S<T>(T);
951+
impl<T> S<T> {
952+
fn bar(self, t: T) {}
953+
}
954+
"#,
955+
expect![[r#"ty: u32, name: t"#]],
956+
);
957+
}
898958
}

crates/ide_db/src/call_info/tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,24 @@ fn main() { S.foo($0); }
188188
);
189189
}
190190

191+
#[test]
192+
fn test_fn_signature_for_generic_method() {
193+
check(
194+
r#"
195+
struct S<T>(T);
196+
impl<T> S<T> {
197+
fn foo(&self, x: T) {}
198+
}
199+
200+
fn main() { S(1u32).foo($0); }
201+
"#,
202+
expect![[r#"
203+
fn foo(&self, x: u32)
204+
(<x: u32>)
205+
"#]],
206+
);
207+
}
208+
191209
#[test]
192210
fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
193211
check(

0 commit comments

Comments
 (0)