From 4a6cdd776d403bacce0a5471d77e8c76695c5bc5 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 16:59:23 +0200 Subject: Record method call substs and use them in call info --- crates/hir/src/semantics.rs | 10 ++++------ crates/hir/src/source_analyzer.rs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'crates/hir/src') 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::{ AsMacroCall, FunctionId, TraitId, VariantId, }; use hir_expand::{name::AsName, ExpansionInfo}; -use hir_ty::associated_type_shorthand_candidates; +use hir_ty::{associated_type_shorthand_candidates, Interner}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ @@ -501,14 +501,12 @@ impl<'db> SemanticsImpl<'db> { } fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { - self.analyze(call.syntax()).resolve_method_call(self.db, call) + self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id) } fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { - // FIXME: this erases Substs, we should instead record the correct - // substitution during inference and use that - let func = self.resolve_method_call(call)?; - let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build(); + let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?; + let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst); let resolver = self.analyze(call.syntax()).resolver; let ty = Type::new_with_resolver(self.db, &resolver, ty)?; 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 { &self, db: &dyn HirDatabase, call: &ast::MethodCallExpr, - ) -> Option { + ) -> Option<(FunctionId, Substitution)> { let expr_id = self.expr_id(db, &call.clone().into())?; self.infer.as_ref()?.method_resolution(expr_id) } -- cgit v1.2.3 From 7a0c93c58ac17b089edd8c9763fef303b7a81414 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 18:10:40 +0200 Subject: Infer correct expected type for generic struct fields --- crates/hir/src/lib.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'crates/hir/src') diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a7c42ca1e..edee99356 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -513,9 +513,9 @@ impl Field { } /// Returns the type as in the signature of the struct (i.e., with - /// placeholder types for type parameters). This is good for showing - /// signature help, but not so good to actually get the type of the field - /// when you actually have a variable of the struct. + /// placeholder types for type parameters). Only use this in the context of + /// the field *definition*; if you've already got a variable of the struct + /// type, use `Type::field_type` to get to the field type. pub fn ty(&self, db: &dyn HirDatabase) -> Type { let var_id = self.parent.into(); let generic_def_id: GenericDefId = match self.parent { @@ -1944,6 +1944,18 @@ impl Type { } } + pub fn field_type(&self, db: &dyn HirDatabase, field: Field) -> Option { + let (adt_id, substs) = self.ty.as_adt()?; + let variant_id: hir_def::VariantId = field.parent.into(); + if variant_id.adt_id() != adt_id { + return None; + } + + let ty = db.field_types(variant_id).get(field.id)?.clone(); + let ty = ty.substitute(&Interner, substs); + Some(self.derived(ty)) + } + pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { let (variant_id, substs) = match self.ty.kind(&Interner) { &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), -- cgit v1.2.3 From b8262099cc51065259daf10b4b23ff49ce74434f Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 23:54:35 +0200 Subject: Get rid of field_type again --- crates/hir/src/lib.rs | 15 +-------------- crates/hir/src/semantics.rs | 7 +++++-- crates/hir/src/source_analyzer.rs | 7 +++++-- 3 files changed, 11 insertions(+), 18 deletions(-) (limited to 'crates/hir/src') diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index edee99356..ca9a7f7fa 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -514,8 +514,7 @@ impl Field { /// Returns the type as in the signature of the struct (i.e., with /// placeholder types for type parameters). Only use this in the context of - /// the field *definition*; if you've already got a variable of the struct - /// type, use `Type::field_type` to get to the field type. + /// the field definition. pub fn ty(&self, db: &dyn HirDatabase) -> Type { let var_id = self.parent.into(); let generic_def_id: GenericDefId = match self.parent { @@ -1944,18 +1943,6 @@ impl Type { } } - pub fn field_type(&self, db: &dyn HirDatabase, field: Field) -> Option { - let (adt_id, substs) = self.ty.as_adt()?; - let variant_id: hir_def::VariantId = field.parent.into(); - if variant_id.adt_id() != adt_id { - return None; - } - - let ty = db.field_types(variant_id).get(field.id)?.clone(); - let ty = ty.substitute(&Interner, substs); - Some(self.derived(ty)) - } - pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { let (variant_id, substs) = match self.ty.kind(&Interner) { &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d65dd7df0..3aa467e3c 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -227,7 +227,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub fn resolve_record_field( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option)> { + ) -> Option<(Field, Option, Type)> { self.imp.resolve_record_field(field) } @@ -518,7 +518,10 @@ impl<'db> SemanticsImpl<'db> { self.analyze(field.syntax()).resolve_field(self.db, field) } - fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option)> { + fn resolve_record_field( + &self, + field: &ast::RecordExprField, + ) -> Option<(Field, Option, Type)> { self.analyze(field.syntax()).resolve_record_field(self.db, field) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index a1a9c727a..5a3d80e8e 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -161,7 +161,7 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, field: &ast::RecordExprField, - ) -> Option<(Field, Option)> { + ) -> Option<(Field, Option, Type)> { let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let expr = ast::Expr::from(record_expr); let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; @@ -178,10 +178,13 @@ impl SourceAnalyzer { _ => None, } }; + let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?; let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; let variant_data = variant.variant_data(db.upcast()); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; - Some((field.into(), local)) + let field_ty = + db.field_types(variant).get(field.local_id)?.clone().substitute(&Interner, subst); + Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)?)) } pub(crate) fn resolve_record_pat_field( -- cgit v1.2.3