aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs5
-rw-r--r--crates/hir/src/semantics.rs17
-rw-r--r--crates/hir/src/source_analyzer.rs9
-rw-r--r--crates/hir_def/src/item_tree.rs34
-rw-r--r--crates/hir_def/src/lib.rs8
-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_assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_getter.rs292
-rw-r--r--crates/ide_assists/src/handlers/generate_getter_mut.rs195
-rw-r--r--crates/ide_assists/src/lib.rs3
-rw-r--r--crates/ide_assists/src/tests.rs2
-rw-r--r--crates/ide_assists/src/tests/generated.rs6
-rw-r--r--crates/ide_completion/src/context.rs96
-rw-r--r--crates/ide_completion/src/render.rs7
-rw-r--r--crates/ide_db/src/call_info/tests.rs18
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/ty_filter.rs6
-rw-r--r--editors/code/src/config.ts2
-rw-r--r--editors/code/src/snippets.ts3
-rw-r--r--xtask/src/dist.rs8
24 files changed, 459 insertions, 336 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};
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::{
@@ -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/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 528270d49..4a5f44027 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -1,4 +1,34 @@
1//! A simplified AST that only contains items. 1//! A simplified AST that only contains items.
2//!
3//! This is the primary IR used throughout `hir_def`. It is the input to the name resolution
4//! algorithm, as well as to the queries defined in `adt.rs`, `data.rs`, and most things in
5//! `attr.rs`.
6//!
7//! `ItemTree`s are built per `HirFileId`, from the syntax tree of the parsed file. This means that
8//! they are crate-independent: they don't know which `#[cfg]`s are active or which module they
9//! belong to, since those concepts don't exist at this level (a single `ItemTree` might be part of
10//! multiple crates, or might be included into the same crate twice via `#[path]`).
11//!
12//! One important purpose of this layer is to provide an "invalidation barrier" for incremental
13//! computations: when typing inside an item body, the `ItemTree` of the modified file is typically
14//! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`).
15//!
16//! The `ItemTree` for the currently open file can be displayed by using the VS Code command
17//! "Rust Analyzer: Debug ItemTree".
18//!
19//! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many
20//! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name
21//! resolution has not yet been performed. `ItemTree`s are per-file, while rustc's AST and HIR are
22//! per-crate, because we are interested in incrementally computing it.
23//!
24//! The representation of items in the `ItemTree` should generally mirror the surface syntax: it is
25//! usually a bad idea to desugar a syntax-level construct to something that is structurally
26//! different here. Name resolution needs to be able to process attributes and expand macros
27//! (including attribute macros), and having a 1-to-1 mapping between syntax and the `ItemTree`
28//! avoids introducing subtle bugs.
29//!
30//! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
31//! surface syntax.
2 32
3mod lower; 33mod lower;
4mod pretty; 34mod pretty;
@@ -500,8 +530,8 @@ pub struct Import {
500 pub alias: Option<ImportAlias>, 530 pub alias: Option<ImportAlias>,
501 pub visibility: RawVisibilityId, 531 pub visibility: RawVisibilityId,
502 pub is_glob: bool, 532 pub is_glob: bool,
503 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many 533 /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to
504 /// `Import`s can map to the same `use` item. 534 /// the same `use` item.
505 pub ast_id: FileAstId<ast::Use>, 535 pub ast_id: FileAstId<ast::Use>,
506 /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. 536 /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`.
507 /// 537 ///
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
490trait Intern { 498trait 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;
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_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
86fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 86fn 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_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index df7d1bb95..09971226e 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -23,12 +23,46 @@ use crate::{
23// 23//
24// impl Person { 24// impl Person {
25// /// Get a reference to the person's name. 25// /// Get a reference to the person's name.
26// fn name(&self) -> &String { 26// fn $0name(&self) -> &str {
27// &self.name 27// self.name.as_str()
28// } 28// }
29// } 29// }
30// ``` 30// ```
31pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 generate_getter_impl(acc, ctx, false)
33}
34
35// Assist: generate_getter_mut
36//
37// Generate a mut getter method.
38//
39// ```
40// struct Person {
41// nam$0e: String,
42// }
43// ```
44// ->
45// ```
46// struct Person {
47// name: String,
48// }
49//
50// impl Person {
51// /// Get a mutable reference to the person's name.
52// fn $0name_mut(&mut self) -> &mut String {
53// &mut self.name
54// }
55// }
56// ```
57pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
58 generate_getter_impl(acc, ctx, true)
59}
60
61pub(crate) fn generate_getter_impl(
62 acc: &mut Assists,
63 ctx: &AssistContext,
64 mutable: bool,
65) -> Option<()> {
32 let strukt = ctx.find_node_at_offset::<ast::Struct>()?; 66 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
33 let field = ctx.find_node_at_offset::<ast::RecordField>()?; 67 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
34 68
@@ -37,39 +71,52 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
37 let field_ty = field.ty()?; 71 let field_ty = field.ty()?;
38 72
39 // Return early if we've found an existing fn 73 // Return early if we've found an existing fn
40 let fn_name = to_lower_snake_case(&field_name.to_string()); 74 let mut fn_name = to_lower_snake_case(&field_name.to_string());
75 if mutable {
76 format_to!(fn_name, "_mut");
77 }
41 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; 78 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?;
42 79
80 let (id, label) = if mutable {
81 ("generate_getter_mut", "Generate a mut getter method")
82 } else {
83 ("generate_getter", "Generate a getter method")
84 };
43 let target = field.syntax().text_range(); 85 let target = field.syntax().text_range();
44 acc.add_group( 86 acc.add_group(
45 &GroupLabel("Generate getter/setter".to_owned()), 87 &GroupLabel("Generate getter/setter".to_owned()),
46 AssistId("generate_getter", AssistKind::Generate), 88 AssistId(id, AssistKind::Generate),
47 "Generate a getter method", 89 label,
48 target, 90 target,
49 |builder| { 91 |builder| {
50 let mut buf = String::with_capacity(512); 92 let mut buf = String::with_capacity(512);
51 93
52 let fn_name_spaced = fn_name.replace('_', " ");
53 let strukt_name_spaced =
54 to_lower_snake_case(&strukt_name.to_string()).replace('_', " ");
55
56 if impl_def.is_some() { 94 if impl_def.is_some() {
57 buf.push('\n'); 95 buf.push('\n');
58 } 96 }
59 97
60 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); 98 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
99 let (ty, body) = if mutable {
100 (format!("&mut {}", field_ty), format!("&mut self.{}", field_name))
101 } else {
102 useless_type_special_case(&field_name.to_string(), &field_ty)
103 .unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name)))
104 };
105
61 format_to!( 106 format_to!(
62 buf, 107 buf,
63 " /// Get a reference to the {}'s {}. 108 " /// Get a {}reference to the {}'s {}.
64 {}fn {}(&self) -> &{} {{ 109 {}fn {}(&{}self) -> {} {{
65 &self.{} 110 {}
66 }}", 111 }}",
67 strukt_name_spaced, 112 mutable.then(|| "mutable ").unwrap_or_default(),
68 fn_name_spaced, 113 to_lower_snake_case(&strukt_name.to_string()).replace('_', " "),
114 fn_name.trim_end_matches("_mut").replace('_', " "),
69 vis, 115 vis,
70 fn_name, 116 fn_name,
71 field_ty, 117 mutable.then(|| "mut ").unwrap_or_default(),
72 fn_name, 118 ty,
119 body,
73 ); 120 );
74 121
75 let start_offset = impl_def 122 let start_offset = impl_def
@@ -79,56 +126,120 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
79 strukt.syntax().text_range().end() 126 strukt.syntax().text_range().end()
80 }); 127 });
81 128
82 builder.insert(start_offset, buf); 129 match ctx.config.snippet_cap {
130 Some(cap) => {
131 builder.insert_snippet(cap, start_offset, buf.replacen("fn ", "fn $0", 1))
132 }
133 None => builder.insert(start_offset, buf),
134 }
83 }, 135 },
84 ) 136 )
85} 137}
86 138
139fn useless_type_special_case(field_name: &str, field_ty: &ast::Type) -> Option<(String, String)> {
140 if field_ty.to_string() == "String" {
141 cov_mark::hit!(useless_type_special_case);
142 return Some(("&str".to_string(), format!("self.{}.as_str()", field_name)));
143 }
144 if let Some(arg) = ty_ctor(field_ty, "Vec") {
145 return Some((format!("&[{}]", arg), format!("self.{}.as_slice()", field_name)));
146 }
147 if let Some(arg) = ty_ctor(field_ty, "Box") {
148 return Some((format!("&{}", arg), format!("self.{}.as_ref()", field_name)));
149 }
150 if let Some(arg) = ty_ctor(field_ty, "Option") {
151 return Some((format!("Option<&{}>", arg), format!("self.{}.as_ref()", field_name)));
152 }
153 None
154}
155
156// FIXME: This should rely on semantic info.
157fn ty_ctor(ty: &ast::Type, ctor: &str) -> Option<String> {
158 let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string();
159 Some(res)
160}
161
87#[cfg(test)] 162#[cfg(test)]
88mod tests { 163mod tests {
89 use crate::tests::{check_assist, check_assist_not_applicable}; 164 use crate::tests::{check_assist, check_assist_not_applicable};
90 165
91 use super::*; 166 use super::*;
92 167
93 fn check_not_applicable(ra_fixture: &str) {
94 check_assist_not_applicable(generate_getter, ra_fixture)
95 }
96
97 #[test] 168 #[test]
98 fn test_generate_getter_from_field() { 169 fn test_generate_getter_from_field() {
99 check_assist( 170 check_assist(
100 generate_getter, 171 generate_getter,
101 r#" 172 r#"
102struct Context<T: Clone> { 173struct Context {
103 dat$0a: T, 174 dat$0a: Data,
104}"#, 175}
176"#,
105 r#" 177 r#"
106struct Context<T: Clone> { 178struct Context {
107 data: T, 179 data: Data,
108} 180}
109 181
110impl<T: Clone> Context<T> { 182impl Context {
111 /// Get a reference to the context's data. 183 /// Get a reference to the context's data.
112 fn data(&self) -> &T { 184 fn $0data(&self) -> &Data {
113 &self.data 185 &self.data
114 } 186 }
115}"#, 187}
188"#,
189 );
190
191 check_assist(
192 generate_getter_mut,
193 r#"
194struct Context {
195 dat$0a: Data,
196}
197"#,
198 r#"
199struct Context {
200 data: Data,
201}
202
203impl Context {
204 /// Get a mutable reference to the context's data.
205 fn $0data_mut(&mut self) -> &mut Data {
206 &mut self.data
207 }
208}
209"#,
116 ); 210 );
117 } 211 }
118 212
119 #[test] 213 #[test]
120 fn test_generate_getter_already_implemented() { 214 fn test_generate_getter_already_implemented() {
121 check_not_applicable( 215 check_assist_not_applicable(
216 generate_getter,
122 r#" 217 r#"
123struct Context<T: Clone> { 218struct Context {
124 dat$0a: T, 219 dat$0a: Data,
125} 220}
126 221
127impl<T: Clone> Context<T> { 222impl Context {
128 fn data(&self) -> &T { 223 fn data(&self) -> &Data {
129 &self.data 224 &self.data
130 } 225 }
131}"#, 226}
227"#,
228 );
229
230 check_assist_not_applicable(
231 generate_getter_mut,
232 r#"
233struct Context {
234 dat$0a: Data,
235}
236
237impl Context {
238 fn data_mut(&mut self) -> &mut Data {
239 &mut self.data
240 }
241}
242"#,
132 ); 243 );
133 } 244 }
134 245
@@ -137,20 +248,22 @@ impl<T: Clone> Context<T> {
137 check_assist( 248 check_assist(
138 generate_getter, 249 generate_getter,
139 r#" 250 r#"
140pub(crate) struct Context<T: Clone> { 251pub(crate) struct Context {
141 dat$0a: T, 252 dat$0a: Data,
142}"#, 253}
254"#,
143 r#" 255 r#"
144pub(crate) struct Context<T: Clone> { 256pub(crate) struct Context {
145 data: T, 257 data: Data,
146} 258}
147 259
148impl<T: Clone> Context<T> { 260impl Context {
149 /// Get a reference to the context's data. 261 /// Get a reference to the context's data.
150 pub(crate) fn data(&self) -> &T { 262 pub(crate) fn $0data(&self) -> &Data {
151 &self.data 263 &self.data
152 } 264 }
153}"#, 265}
266"#,
154 ); 267 );
155 } 268 }
156 269
@@ -159,34 +272,105 @@ impl<T: Clone> Context<T> {
159 check_assist( 272 check_assist(
160 generate_getter, 273 generate_getter,
161 r#" 274 r#"
162struct Context<T: Clone> { 275struct Context {
163 data: T, 276 data: Data,
164 cou$0nt: usize, 277 cou$0nt: usize,
165} 278}
166 279
167impl<T: Clone> Context<T> { 280impl Context {
168 /// Get a reference to the context's data. 281 /// Get a reference to the context's data.
169 fn data(&self) -> &T { 282 fn data(&self) -> &Data {
170 &self.data 283 &self.data
171 } 284 }
172}"#, 285}
286"#,
173 r#" 287 r#"
174struct Context<T: Clone> { 288struct Context {
175 data: T, 289 data: Data,
176 count: usize, 290 count: usize,
177} 291}
178 292
179impl<T: Clone> Context<T> { 293impl Context {
180 /// Get a reference to the context's data. 294 /// Get a reference to the context's data.
181 fn data(&self) -> &T { 295 fn data(&self) -> &Data {
182 &self.data 296 &self.data
183 } 297 }
184 298
185 /// Get a reference to the context's count. 299 /// Get a reference to the context's count.
186 fn count(&self) -> &usize { 300 fn $0count(&self) -> &usize {
187 &self.count 301 &self.count
188 } 302 }
189}"#, 303}
304"#,
305 );
306 }
307
308 #[test]
309 fn test_special_cases() {
310 cov_mark::check!(useless_type_special_case);
311 check_assist(
312 generate_getter,
313 r#"
314struct S { foo: $0String }
315"#,
316 r#"
317struct S { foo: String }
318
319impl S {
320 /// Get a reference to the s's foo.
321 fn $0foo(&self) -> &str {
322 self.foo.as_str()
323 }
324}
325"#,
326 );
327 check_assist(
328 generate_getter,
329 r#"
330struct S { foo: $0Box<Sweets> }
331"#,
332 r#"
333struct S { foo: Box<Sweets> }
334
335impl S {
336 /// Get a reference to the s's foo.
337 fn $0foo(&self) -> &Sweets {
338 self.foo.as_ref()
339 }
340}
341"#,
342 );
343 check_assist(
344 generate_getter,
345 r#"
346struct S { foo: $0Vec<()> }
347"#,
348 r#"
349struct S { foo: Vec<()> }
350
351impl S {
352 /// Get a reference to the s's foo.
353 fn $0foo(&self) -> &[()] {
354 self.foo.as_slice()
355 }
356}
357"#,
358 );
359 check_assist(
360 generate_getter,
361 r#"
362struct S { foo: $0Option<Failure> }
363"#,
364 r#"
365struct S { foo: Option<Failure> }
366
367impl S {
368 /// Get a reference to the s's foo.
369 fn $0foo(&self) -> Option<&Failure> {
370 self.foo.as_ref()
371 }
372}
373"#,
190 ); 374 );
191 } 375 }
192} 376}
diff --git a/crates/ide_assists/src/handlers/generate_getter_mut.rs b/crates/ide_assists/src/handlers/generate_getter_mut.rs
deleted file mode 100644
index 821c2eed5..000000000
--- a/crates/ide_assists/src/handlers/generate_getter_mut.rs
+++ /dev/null
@@ -1,195 +0,0 @@
1use stdx::{format_to, to_lower_snake_case};
2use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
3
4use crate::{
5 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
7};
8
9// Assist: generate_getter_mut
10//
11// Generate a mut getter method.
12//
13// ```
14// struct Person {
15// nam$0e: String,
16// }
17// ```
18// ->
19// ```
20// struct Person {
21// name: String,
22// }
23//
24// impl Person {
25// /// Get a mutable reference to the person's name.
26// fn name_mut(&mut self) -> &mut String {
27// &mut self.name
28// }
29// }
30// ```
31pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
33 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
34
35 let strukt_name = strukt.name()?;
36 let field_name = field.name()?;
37 let field_ty = field.ty()?;
38
39 // Return early if we've found an existing fn
40 let fn_name = to_lower_snake_case(&field_name.to_string());
41 let impl_def = find_struct_impl(
42 &ctx,
43 &ast::Adt::Struct(strukt.clone()),
44 format!("{}_mut", fn_name).as_str(),
45 )?;
46
47 let target = field.syntax().text_range();
48 acc.add_group(
49 &GroupLabel("Generate getter/setter".to_owned()),
50 AssistId("generate_getter_mut", AssistKind::Generate),
51 "Generate a mut getter method",
52 target,
53 |builder| {
54 let mut buf = String::with_capacity(512);
55 let fn_name_spaced = fn_name.replace('_', " ");
56 let strukt_name_spaced =
57 to_lower_snake_case(&strukt_name.to_string()).replace('_', " ");
58
59 if impl_def.is_some() {
60 buf.push('\n');
61 }
62
63 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
64 format_to!(
65 buf,
66 " /// Get a mutable reference to the {}'s {}.
67 {}fn {}_mut(&mut self) -> &mut {} {{
68 &mut self.{}
69 }}",
70 strukt_name_spaced,
71 fn_name_spaced,
72 vis,
73 fn_name,
74 field_ty,
75 fn_name,
76 );
77
78 let start_offset = impl_def
79 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
80 .unwrap_or_else(|| {
81 buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
82 strukt.syntax().text_range().end()
83 });
84
85 builder.insert(start_offset, buf);
86 },
87 )
88}
89
90#[cfg(test)]
91mod tests {
92 use crate::tests::{check_assist, check_assist_not_applicable};
93
94 use super::*;
95
96 fn check_not_applicable(ra_fixture: &str) {
97 check_assist_not_applicable(generate_getter_mut, ra_fixture)
98 }
99
100 #[test]
101 fn test_generate_getter_mut_from_field() {
102 check_assist(
103 generate_getter_mut,
104 r#"
105struct Context<T: Clone> {
106 dat$0a: T,
107}"#,
108 r#"
109struct Context<T: Clone> {
110 data: T,
111}
112
113impl<T: Clone> Context<T> {
114 /// Get a mutable reference to the context's data.
115 fn data_mut(&mut self) -> &mut T {
116 &mut self.data
117 }
118}"#,
119 );
120 }
121
122 #[test]
123 fn test_generate_getter_mut_already_implemented() {
124 check_not_applicable(
125 r#"
126struct Context<T: Clone> {
127 dat$0a: T,
128}
129
130impl<T: Clone> Context<T> {
131 fn data_mut(&mut self) -> &mut T {
132 &mut self.data
133 }
134}"#,
135 );
136 }
137
138 #[test]
139 fn test_generate_getter_mut_from_field_with_visibility_marker() {
140 check_assist(
141 generate_getter_mut,
142 r#"
143pub(crate) struct Context<T: Clone> {
144 dat$0a: T,
145}"#,
146 r#"
147pub(crate) struct Context<T: Clone> {
148 data: T,
149}
150
151impl<T: Clone> Context<T> {
152 /// Get a mutable reference to the context's data.
153 pub(crate) fn data_mut(&mut self) -> &mut T {
154 &mut self.data
155 }
156}"#,
157 );
158 }
159
160 #[test]
161 fn test_multiple_generate_getter_mut() {
162 check_assist(
163 generate_getter_mut,
164 r#"
165struct Context<T: Clone> {
166 data: T,
167 cou$0nt: usize,
168}
169
170impl<T: Clone> Context<T> {
171 /// Get a mutable reference to the context's data.
172 fn data_mut(&mut self) -> &mut T {
173 &mut self.data
174 }
175}"#,
176 r#"
177struct Context<T: Clone> {
178 data: T,
179 count: usize,
180}
181
182impl<T: Clone> Context<T> {
183 /// Get a mutable reference to the context's data.
184 fn data_mut(&mut self) -> &mut T {
185 &mut self.data
186 }
187
188 /// Get a mutable reference to the context's count.
189 fn count_mut(&mut self) -> &mut usize {
190 &mut self.count
191 }
192}"#,
193 );
194 }
195}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 4cd82f8c1..16af72927 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -206,7 +206,6 @@ mod handlers {
206 mod generate_enum_projection_method; 206 mod generate_enum_projection_method;
207 mod generate_from_impl_for_enum; 207 mod generate_from_impl_for_enum;
208 mod generate_function; 208 mod generate_function;
209 mod generate_getter_mut;
210 mod generate_getter; 209 mod generate_getter;
211 mod generate_impl; 210 mod generate_impl;
212 mod generate_new; 211 mod generate_new;
@@ -276,8 +275,8 @@ mod handlers {
276 generate_enum_projection_method::generate_enum_try_into_method, 275 generate_enum_projection_method::generate_enum_try_into_method,
277 generate_from_impl_for_enum::generate_from_impl_for_enum, 276 generate_from_impl_for_enum::generate_from_impl_for_enum,
278 generate_function::generate_function, 277 generate_function::generate_function,
279 generate_getter_mut::generate_getter_mut,
280 generate_getter::generate_getter, 278 generate_getter::generate_getter,
279 generate_getter::generate_getter_mut,
281 generate_impl::generate_impl, 280 generate_impl::generate_impl,
282 generate_new::generate_new, 281 generate_new::generate_new,
283 generate_setter::generate_setter, 282 generate_setter::generate_setter,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 6a9231e07..2b7c2d581 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -215,8 +215,8 @@ fn assist_order_field_struct() {
215 215
216 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); 216 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
217 assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`"); 217 assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`");
218 assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
219 assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method"); 218 assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
219 assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
220 assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method"); 220 assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
221 assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`"); 221 assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
222} 222}
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 4406406a2..8a9b0777c 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -786,8 +786,8 @@ struct Person {
786 786
787impl Person { 787impl Person {
788 /// Get a reference to the person's name. 788 /// Get a reference to the person's name.
789 fn name(&self) -> &String { 789 fn $0name(&self) -> &str {
790 &self.name 790 self.name.as_str()
791 } 791 }
792} 792}
793"#####, 793"#####,
@@ -810,7 +810,7 @@ struct Person {
810 810
811impl Person { 811impl Person {
812 /// Get a mutable reference to the person's name. 812 /// Get a mutable reference to the person's name.
813 fn name_mut(&mut self) -> &mut String { 813 fn $0name_mut(&mut self) -> &mut String {
814 &mut self.name 814 &mut self.name
815 } 815 }
816} 816}
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#"
796struct Foo<T> { a: T }
797fn 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#"
922fn foo() {
923 bar(|| a$0);
924}
925
926fn bar(f: impl FnOnce() -> u32) {}
927#[lang = "fn_once"]
928trait 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#"
938fn foo() {
939 bar::<u32>($0);
940}
941
942fn 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#"
952fn foo() {
953 S(1u32).bar($0);
954}
955
956struct S<T>(T);
957impl<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]
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#"
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),
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs
index 00678bf3e..766d8c628 100644
--- a/crates/ide_db/src/ty_filter.rs
+++ b/crates/ide_db/src/ty_filter.rs
@@ -4,7 +4,7 @@
4 4
5use std::iter; 5use std::iter;
6 6
7use hir::{Adt, Semantics, Type}; 7use hir::Semantics;
8use syntax::ast::{self, make}; 8use syntax::ast::{self, make};
9 9
10use crate::RootDatabase; 10use crate::RootDatabase;
@@ -20,9 +20,9 @@ impl TryEnum {
20 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; 20 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
21 21
22 /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`. 22 /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
23 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { 23 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &hir::Type) -> Option<TryEnum> {
24 let enum_ = match ty.as_adt() { 24 let enum_ = match ty.as_adt() {
25 Some(Adt::Enum(it)) => it, 25 Some(hir::Adt::Enum(it)) => it,
26 _ => return None, 26 _ => return None,
27 }; 27 };
28 TryEnum::ALL.iter().find_map(|&var| { 28 TryEnum::ALL.iter().find_map(|&var| {
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index fbb7a556a..d3d6e631a 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -34,7 +34,7 @@ export class Config {
34 readonly globalStoragePath: string; 34 readonly globalStoragePath: string;
35 35
36 constructor(ctx: vscode.ExtensionContext) { 36 constructor(ctx: vscode.ExtensionContext) {
37 this.globalStoragePath = ctx.globalStorageUri.path; 37 this.globalStoragePath = ctx.globalStorageUri.fsPath;
38 vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); 38 vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions);
39 this.refreshLogging(); 39 this.refreshLogging();
40 } 40 }
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts
index 9561aa345..58f7aa128 100644
--- a/editors/code/src/snippets.ts
+++ b/editors/code/src/snippets.ts
@@ -56,6 +56,9 @@ export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vs
56 } 56 }
57 }); 57 });
58 if (selections.length > 0) editor.selections = selections; 58 if (selections.length > 0) editor.selections = selections;
59 if (selections.length === 1) {
60 editor.revealRange(selections[0], vscode.TextEditorRevealType.InCenterIfOutsideViewport);
61 }
59} 62}
60 63
61function parseSnippet(snip: string): [string, [number, number]] | undefined { 64function parseSnippet(snip: string): [string, [number, number]] | undefined {
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 270719de7..7ac9ae5b8 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -66,12 +66,8 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
66 66
67fn dist_server(release_channel: &str) -> Result<()> { 67fn dist_server(release_channel: &str) -> Result<()> {
68 let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel); 68 let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
69 let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "true"); 69 let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin");
70 70 let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
71 // We want do enable debug symbols, but this causes our windows CI to fail:
72 // https://github.com/rust-lang/rust/issues/85598
73 //
74 // let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
75 71
76 let target = get_target(); 72 let target = get_target();
77 if target.contains("-linux-gnu") || target.contains("-linux-musl") { 73 if target.contains("-linux-gnu") || target.contains("-linux-musl") {