diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-23 22:55:51 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-23 22:55:51 +0100 |
commit | 495c9586ec51e0cf9b06397d99ec4f65c55e7a28 (patch) | |
tree | c18eb1b1568ab0f0251339f7995b6ea177b3285f /crates | |
parent | a2ce091fd7e149f809bdf0ee0d960d9e185ee5fb (diff) | |
parent | b8262099cc51065259daf10b4b23ff49ce74434f (diff) |
Merge #8945
8945: fix: Make expected type work in more situations r=flodiebold a=flodiebold
Also makes call info show the correct types for generic methods.
![2021-05-23-182952_1134x616_scrot](https://user-images.githubusercontent.com/906069/119269023-dd5a5b00-bbf5-11eb-993a-b6e122c3b9a6.png)
![2021-05-23-183117_922x696_scrot](https://user-images.githubusercontent.com/906069/119269025-dfbcb500-bbf5-11eb-983c-fc415b8428e0.png)
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/hir/src/semantics.rs | 17 | ||||
-rw-r--r-- | crates/hir/src/source_analyzer.rs | 9 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 12 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/unsafe_check.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/infer.rs | 25 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 34 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/unify.rs | 7 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/fix_visibility.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 96 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 7 | ||||
-rw-r--r-- | crates/ide_db/src/call_info/tests.rs | 18 | ||||
-rw-r--r-- | crates/ide_db/src/defs.rs | 2 |
14 files changed, 175 insertions, 69 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a7c42ca1e..ca9a7f7fa 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -513,9 +513,8 @@ impl Field { | |||
513 | } | 513 | } |
514 | 514 | ||
515 | /// Returns the type as in the signature of the struct (i.e., with | 515 | /// Returns the type as in the signature of the struct (i.e., with |
516 | /// placeholder types for type parameters). This is good for showing | 516 | /// placeholder types for type parameters). Only use this in the context of |
517 | /// signature help, but not so good to actually get the type of the field | 517 | /// the field definition. |
518 | /// when you actually have a variable of the struct. | ||
519 | pub fn ty(&self, db: &dyn HirDatabase) -> Type { | 518 | pub fn ty(&self, db: &dyn HirDatabase) -> Type { |
520 | let var_id = self.parent.into(); | 519 | let var_id = self.parent.into(); |
521 | let generic_def_id: GenericDefId = match self.parent { | 520 | let generic_def_id: GenericDefId = match self.parent { |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1b5064b5a..3aa467e3c 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 | }; |
13 | use hir_expand::{name::AsName, ExpansionInfo}; | 13 | use hir_expand::{name::AsName, ExpansionInfo}; |
14 | use hir_ty::associated_type_shorthand_candidates; | 14 | use hir_ty::{associated_type_shorthand_candidates, Interner}; |
15 | use itertools::Itertools; | 15 | use itertools::Itertools; |
16 | use rustc_hash::{FxHashMap, FxHashSet}; | 16 | use rustc_hash::{FxHashMap, FxHashSet}; |
17 | use syntax::{ | 17 | use syntax::{ |
@@ -227,7 +227,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
227 | pub fn resolve_record_field( | 227 | pub fn resolve_record_field( |
228 | &self, | 228 | &self, |
229 | field: &ast::RecordExprField, | 229 | field: &ast::RecordExprField, |
230 | ) -> Option<(Field, Option<Local>)> { | 230 | ) -> Option<(Field, Option<Local>, Type)> { |
231 | self.imp.resolve_record_field(field) | 231 | self.imp.resolve_record_field(field) |
232 | } | 232 | } |
233 | 233 | ||
@@ -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)?; |
@@ -520,7 +518,10 @@ impl<'db> SemanticsImpl<'db> { | |||
520 | self.analyze(field.syntax()).resolve_field(self.db, field) | 518 | self.analyze(field.syntax()).resolve_field(self.db, field) |
521 | } | 519 | } |
522 | 520 | ||
523 | fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> { | 521 | fn resolve_record_field( |
522 | &self, | ||
523 | field: &ast::RecordExprField, | ||
524 | ) -> Option<(Field, Option<Local>, Type)> { | ||
524 | self.analyze(field.syntax()).resolve_record_field(self.db, field) | 525 | self.analyze(field.syntax()).resolve_record_field(self.db, field) |
525 | } | 526 | } |
526 | 527 | ||
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 20753314d..3f940124c 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 | } |
@@ -161,7 +161,7 @@ impl SourceAnalyzer { | |||
161 | &self, | 161 | &self, |
162 | db: &dyn HirDatabase, | 162 | db: &dyn HirDatabase, |
163 | field: &ast::RecordExprField, | 163 | field: &ast::RecordExprField, |
164 | ) -> Option<(Field, Option<Local>)> { | 164 | ) -> Option<(Field, Option<Local>, Type)> { |
165 | let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; | 165 | let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; |
166 | let expr = ast::Expr::from(record_expr); | 166 | let expr = ast::Expr::from(record_expr); |
167 | let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; | 167 | let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; |
@@ -178,10 +178,13 @@ impl SourceAnalyzer { | |||
178 | _ => None, | 178 | _ => None, |
179 | } | 179 | } |
180 | }; | 180 | }; |
181 | let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?; | ||
181 | let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; | 182 | let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; |
182 | let variant_data = variant.variant_data(db.upcast()); | 183 | let variant_data = variant.variant_data(db.upcast()); |
183 | let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; | 184 | let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; |
184 | Some((field.into(), local)) | 185 | let field_ty = |
186 | db.field_types(variant).get(field.local_id)?.clone().substitute(&Interner, subst); | ||
187 | Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)?)) | ||
185 | } | 188 | } |
186 | 189 | ||
187 | pub(crate) fn resolve_record_pat_field( | 190 | pub(crate) fn resolve_record_pat_field( |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index a82ea5957..70001cac8 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -485,6 +485,14 @@ impl VariantId { | |||
485 | VariantId::UnionId(it) => it.lookup(db).id.file_id(), | 485 | VariantId::UnionId(it) => it.lookup(db).id.file_id(), |
486 | } | 486 | } |
487 | } | 487 | } |
488 | |||
489 | pub fn adt_id(self) -> AdtId { | ||
490 | match self { | ||
491 | VariantId::EnumVariantId(it) => it.parent.into(), | ||
492 | VariantId::StructId(it) => it.into(), | ||
493 | VariantId::UnionId(it) => it.into(), | ||
494 | } | ||
495 | } | ||
488 | } | 496 | } |
489 | 497 | ||
490 | trait Intern { | 498 | trait Intern { |
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; | |||
37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; | 37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; |
38 | use crate::{ | 38 | use 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)] |
133 | pub struct InferenceResult { | 133 | pub 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 | ||
154 | impl InferenceResult { | 154 | impl 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_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs index 6c7824e55..89f7b2c2c 100644 --- a/crates/ide_assists/src/handlers/fix_visibility.rs +++ b/crates/ide_assists/src/handlers/fix_visibility.rs | |||
@@ -85,7 +85,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O | |||
85 | 85 | ||
86 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 86 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
87 | let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; | 87 | let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; |
88 | let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; | 88 | let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?; |
89 | 89 | ||
90 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; | 90 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; |
91 | let visibility = record_field_def.visibility(ctx.db()); | 91 | let visibility = record_field_def.visibility(ctx.db()); |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 787eb2fd3..1ec59ff80 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -337,25 +337,24 @@ impl<'a> CompletionContext<'a> { | |||
337 | }, | 337 | }, |
338 | ast::RecordExprFieldList(_it) => { | 338 | ast::RecordExprFieldList(_it) => { |
339 | cov_mark::hit!(expected_type_struct_field_without_leading_char); | 339 | cov_mark::hit!(expected_type_struct_field_without_leading_char); |
340 | self.token.prev_sibling_or_token() | 340 | // wouldn't try {} be nice... |
341 | .and_then(|se| se.into_node()) | 341 | (|| { |
342 | .and_then(|node| ast::RecordExprField::cast(node)) | 342 | let expr_field = self.token.prev_sibling_or_token()? |
343 | .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf))) | 343 | .into_node() |
344 | .map(|(f, rf)|( | 344 | .and_then(|node| ast::RecordExprField::cast(node))?; |
345 | Some(f.0.ty(self.db)), | 345 | let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?; |
346 | rf.field_name().map(NameOrNameRef::NameRef), | 346 | Some(( |
347 | Some(ty), | ||
348 | expr_field.field_name().map(NameOrNameRef::NameRef), | ||
347 | )) | 349 | )) |
348 | .unwrap_or((None, None)) | 350 | })().unwrap_or((None, None)) |
349 | }, | 351 | }, |
350 | ast::RecordExprField(it) => { | 352 | ast::RecordExprField(it) => { |
351 | cov_mark::hit!(expected_type_struct_field_with_leading_char); | 353 | cov_mark::hit!(expected_type_struct_field_with_leading_char); |
352 | self.sema | 354 | ( |
353 | .resolve_record_field(&it) | 355 | it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)), |
354 | .map(|f|( | 356 | it.field_name().map(NameOrNameRef::NameRef), |
355 | Some(f.0.ty(self.db)), | 357 | ) |
356 | it.field_name().map(NameOrNameRef::NameRef), | ||
357 | )) | ||
358 | .unwrap_or((None, None)) | ||
359 | }, | 358 | }, |
360 | ast::MatchExpr(it) => { | 359 | ast::MatchExpr(it) => { |
361 | cov_mark::hit!(expected_type_match_arm_without_leading_char); | 360 | cov_mark::hit!(expected_type_match_arm_without_leading_char); |
@@ -382,6 +381,12 @@ impl<'a> CompletionContext<'a> { | |||
382 | let def = self.sema.to_def(&it); | 381 | let def = self.sema.to_def(&it); |
383 | (def.map(|def| def.ret_type(self.db)), None) | 382 | (def.map(|def| def.ret_type(self.db)), None) |
384 | }, | 383 | }, |
384 | ast::ClosureExpr(it) => { | ||
385 | let ty = self.sema.type_of_expr(&it.into()); | ||
386 | ty.and_then(|ty| ty.as_callable(self.db)) | ||
387 | .map(|c| (Some(c.return_type()), None)) | ||
388 | .unwrap_or((None, None)) | ||
389 | }, | ||
385 | ast::Stmt(_it) => (None, None), | 390 | ast::Stmt(_it) => (None, None), |
386 | _ => { | 391 | _ => { |
387 | match node.parent() { | 392 | match node.parent() { |
@@ -785,6 +790,19 @@ fn foo() { | |||
785 | } | 790 | } |
786 | 791 | ||
787 | #[test] | 792 | #[test] |
793 | fn expected_type_generic_struct_field() { | ||
794 | check_expected_type_and_name( | ||
795 | r#" | ||
796 | struct Foo<T> { a: T } | ||
797 | fn foo() -> Foo<u32> { | ||
798 | Foo { a: $0 } | ||
799 | } | ||
800 | "#, | ||
801 | expect![[r#"ty: u32, name: a"#]], | ||
802 | ) | ||
803 | } | ||
804 | |||
805 | #[test] | ||
788 | fn expected_type_struct_field_with_leading_char() { | 806 | fn expected_type_struct_field_with_leading_char() { |
789 | cov_mark::check!(expected_type_struct_field_with_leading_char); | 807 | cov_mark::check!(expected_type_struct_field_with_leading_char); |
790 | check_expected_type_and_name( | 808 | check_expected_type_and_name( |
@@ -895,4 +913,52 @@ fn foo() -> u32 { | |||
895 | expect![[r#"ty: u32, name: ?"#]], | 913 | expect![[r#"ty: u32, name: ?"#]], |
896 | ) | 914 | ) |
897 | } | 915 | } |
916 | |||
917 | #[test] | ||
918 | fn expected_type_closure_param_return() { | ||
919 | // FIXME: make this work with `|| $0` | ||
920 | check_expected_type_and_name( | ||
921 | r#" | ||
922 | fn foo() { | ||
923 | bar(|| a$0); | ||
924 | } | ||
925 | |||
926 | fn bar(f: impl FnOnce() -> u32) {} | ||
927 | #[lang = "fn_once"] | ||
928 | trait FnOnce { type Output; } | ||
929 | "#, | ||
930 | expect![[r#"ty: u32, name: ?"#]], | ||
931 | ); | ||
932 | } | ||
933 | |||
934 | #[test] | ||
935 | fn expected_type_generic_function() { | ||
936 | check_expected_type_and_name( | ||
937 | r#" | ||
938 | fn foo() { | ||
939 | bar::<u32>($0); | ||
940 | } | ||
941 | |||
942 | fn bar<T>(t: T) {} | ||
943 | "#, | ||
944 | expect![[r#"ty: u32, name: t"#]], | ||
945 | ); | ||
946 | } | ||
947 | |||
948 | #[test] | ||
949 | fn expected_type_generic_method() { | ||
950 | check_expected_type_and_name( | ||
951 | r#" | ||
952 | fn foo() { | ||
953 | S(1u32).bar($0); | ||
954 | } | ||
955 | |||
956 | struct S<T>(T); | ||
957 | impl<T> S<T> { | ||
958 | fn bar(self, t: T) {} | ||
959 | } | ||
960 | "#, | ||
961 | expect![[r#"ty: u32, name: t"#]], | ||
962 | ); | ||
963 | } | ||
898 | } | 964 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 6b04ee164..d7f96b864 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -667,6 +667,13 @@ fn foo() { A { the$0 } } | |||
667 | ), | 667 | ), |
668 | detail: "u32", | 668 | detail: "u32", |
669 | deprecated: true, | 669 | deprecated: true, |
670 | relevance: CompletionRelevance { | ||
671 | exact_name_match: false, | ||
672 | type_match: Some( | ||
673 | CouldUnify, | ||
674 | ), | ||
675 | is_local: false, | ||
676 | }, | ||
670 | }, | 677 | }, |
671 | ] | 678 | ] |
672 | "#]], | 679 | "#]], |
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] |
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 | |||
209 | #[test] | ||
192 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { | 210 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { |
193 | check( | 211 | check( |
194 | r#" | 212 | r#" |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index de0dc2a40..1dcccbb8b 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -311,7 +311,7 @@ impl NameRefClass { | |||
311 | } | 311 | } |
312 | 312 | ||
313 | if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { | 313 | if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { |
314 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { | 314 | if let Some((field, local, _)) = sema.resolve_record_field(&record_field) { |
315 | let field = Definition::Field(field); | 315 | let field = Definition::Field(field); |
316 | let res = match local { | 316 | let res = match local { |
317 | None => NameRefClass::Definition(field), | 317 | None => NameRefClass::Definition(field), |