diff options
Diffstat (limited to 'crates')
82 files changed, 1255 insertions, 677 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 0ef77ef5d..64ccd11ee 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -53,11 +53,15 @@ impl SourceRoot { | |||
53 | } | 53 | } |
54 | 54 | ||
55 | /// `CrateGraph` is a bit of information which turns a set of text files into a | 55 | /// `CrateGraph` is a bit of information which turns a set of text files into a |
56 | /// number of Rust crates. Each crate is defined by the `FileId` of its root module, | 56 | /// number of Rust crates. |
57 | /// the set of cfg flags (not yet implemented) and the set of dependencies. Note | 57 | /// |
58 | /// that, due to cfg's, there might be several crates for a single `FileId`! As | 58 | /// Each crate is defined by the `FileId` of its root module, the set of enabled |
59 | /// in the rust-lang proper, a crate does not have a name. Instead, names are | 59 | /// `cfg` flags and the set of dependencies. |
60 | /// specified on dependency edges. That is, a crate might be known under | 60 | /// |
61 | /// Note that, due to cfg's, there might be several crates for a single `FileId`! | ||
62 | /// | ||
63 | /// For the purposes of analysis, a crate does not have a name. Instead, names | ||
64 | /// are specified on dependency edges. That is, a crate might be known under | ||
61 | /// different names in different dependent crates. | 65 | /// different names in different dependent crates. |
62 | /// | 66 | /// |
63 | /// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust | 67 | /// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust |
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 508ac37c2..c5cf803fd 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs | |||
@@ -92,7 +92,7 @@ impl HirDisplay for Function { | |||
92 | &data.ret_type | 92 | &data.ret_type |
93 | } else { | 93 | } else { |
94 | match &*data.ret_type { | 94 | match &*data.ret_type { |
95 | TypeRef::ImplTrait(bounds) => match &bounds[0] { | 95 | TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() { |
96 | TypeBound::Path(path) => { | 96 | TypeBound::Path(path) => { |
97 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings | 97 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings |
98 | [0] | 98 | [0] |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a7c42ca1e..cdf65a044 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 { |
@@ -552,10 +551,6 @@ impl Struct { | |||
552 | Module { id: self.id.lookup(db.upcast()).container } | 551 | Module { id: self.id.lookup(db.upcast()).container } |
553 | } | 552 | } |
554 | 553 | ||
555 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
556 | Some(self.module(db).krate()) | ||
557 | } | ||
558 | |||
559 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 554 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
560 | db.struct_data(self.id).name.clone() | 555 | db.struct_data(self.id).name.clone() |
561 | } | 556 | } |
@@ -640,10 +635,6 @@ impl Enum { | |||
640 | Module { id: self.id.lookup(db.upcast()).container } | 635 | Module { id: self.id.lookup(db.upcast()).container } |
641 | } | 636 | } |
642 | 637 | ||
643 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
644 | Some(self.module(db).krate()) | ||
645 | } | ||
646 | |||
647 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 638 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
648 | db.enum_data(self.id).name.clone() | 639 | db.enum_data(self.id).name.clone() |
649 | } | 640 | } |
@@ -673,6 +664,7 @@ impl Variant { | |||
673 | pub fn module(self, db: &dyn HirDatabase) -> Module { | 664 | pub fn module(self, db: &dyn HirDatabase) -> Module { |
674 | self.parent.module(db) | 665 | self.parent.module(db) |
675 | } | 666 | } |
667 | |||
676 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { | 668 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { |
677 | self.parent | 669 | self.parent |
678 | } | 670 | } |
@@ -729,10 +721,6 @@ impl Adt { | |||
729 | } | 721 | } |
730 | } | 722 | } |
731 | 723 | ||
732 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
733 | self.module(db).krate() | ||
734 | } | ||
735 | |||
736 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 724 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
737 | match self { | 725 | match self { |
738 | Adt::Struct(s) => s.name(db), | 726 | Adt::Struct(s) => s.name(db), |
@@ -821,10 +809,6 @@ impl Function { | |||
821 | self.id.lookup(db.upcast()).module(db.upcast()).into() | 809 | self.id.lookup(db.upcast()).module(db.upcast()).into() |
822 | } | 810 | } |
823 | 811 | ||
824 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
825 | Some(self.module(db).krate()) | ||
826 | } | ||
827 | |||
828 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 812 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
829 | db.function_data(self.id).name.clone() | 813 | db.function_data(self.id).name.clone() |
830 | } | 814 | } |
@@ -1014,10 +998,6 @@ impl Const { | |||
1014 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 998 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1015 | } | 999 | } |
1016 | 1000 | ||
1017 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
1018 | Some(self.module(db).krate()) | ||
1019 | } | ||
1020 | |||
1021 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 1001 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
1022 | db.const_data(self.id).name.clone() | 1002 | db.const_data(self.id).name.clone() |
1023 | } | 1003 | } |
@@ -1045,10 +1025,6 @@ impl Static { | |||
1045 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1025 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1046 | } | 1026 | } |
1047 | 1027 | ||
1048 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
1049 | Some(self.module(db).krate()) | ||
1050 | } | ||
1051 | |||
1052 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 1028 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
1053 | db.static_data(self.id).name.clone() | 1029 | db.static_data(self.id).name.clone() |
1054 | } | 1030 | } |
@@ -1112,10 +1088,6 @@ impl TypeAlias { | |||
1112 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1088 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1113 | } | 1089 | } |
1114 | 1090 | ||
1115 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1116 | self.module(db).krate() | ||
1117 | } | ||
1118 | |||
1119 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1091 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { |
1120 | db.type_alias_data(self.id).type_ref.as_deref().cloned() | 1092 | db.type_alias_data(self.id).type_ref.as_deref().cloned() |
1121 | } | 1093 | } |
@@ -1667,10 +1639,6 @@ impl Impl { | |||
1667 | self.id.lookup(db.upcast()).container.into() | 1639 | self.id.lookup(db.upcast()).container.into() |
1668 | } | 1640 | } |
1669 | 1641 | ||
1670 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1671 | Crate { id: self.module(db).id.krate() } | ||
1672 | } | ||
1673 | |||
1674 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | 1642 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { |
1675 | let src = self.source(db)?; | 1643 | let src = self.source(db)?; |
1676 | let item = src.file_id.is_builtin_derive(db.upcast())?; | 1644 | let item = src.file_id.is_builtin_derive(db.upcast())?; |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1b5064b5a..8d3c43d08 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::{ |
@@ -120,10 +120,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
120 | pub fn speculative_expand( | 120 | pub fn speculative_expand( |
121 | &self, | 121 | &self, |
122 | actual_macro_call: &ast::MacroCall, | 122 | actual_macro_call: &ast::MacroCall, |
123 | hypothetical_args: &ast::TokenTree, | 123 | speculative_args: &ast::TokenTree, |
124 | token_to_map: SyntaxToken, | 124 | token_to_map: SyntaxToken, |
125 | ) -> Option<(SyntaxNode, SyntaxToken)> { | 125 | ) -> Option<(SyntaxNode, SyntaxToken)> { |
126 | self.imp.speculative_expand(actual_macro_call, hypothetical_args, token_to_map) | 126 | self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map) |
127 | } | 127 | } |
128 | 128 | ||
129 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | 129 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { |
@@ -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 | ||
@@ -335,7 +335,7 @@ impl<'db> SemanticsImpl<'db> { | |||
335 | fn speculative_expand( | 335 | fn speculative_expand( |
336 | &self, | 336 | &self, |
337 | actual_macro_call: &ast::MacroCall, | 337 | actual_macro_call: &ast::MacroCall, |
338 | hypothetical_args: &ast::TokenTree, | 338 | speculative_args: &ast::TokenTree, |
339 | token_to_map: SyntaxToken, | 339 | token_to_map: SyntaxToken, |
340 | ) -> Option<(SyntaxNode, SyntaxToken)> { | 340 | ) -> Option<(SyntaxNode, SyntaxToken)> { |
341 | let sa = self.analyze(actual_macro_call.syntax()); | 341 | let sa = self.analyze(actual_macro_call.syntax()); |
@@ -344,10 +344,10 @@ impl<'db> SemanticsImpl<'db> { | |||
344 | let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { | 344 | let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { |
345 | sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) | 345 | sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) |
346 | })?; | 346 | })?; |
347 | hir_expand::db::expand_hypothetical( | 347 | hir_expand::db::expand_speculative( |
348 | self.db.upcast(), | 348 | self.db.upcast(), |
349 | macro_call_id, | 349 | macro_call_id, |
350 | hypothetical_args, | 350 | speculative_args, |
351 | token_to_map, | 351 | token_to_map, |
352 | ) | 352 | ) |
353 | } | 353 | } |
@@ -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/attr.rs b/crates/hir_def/src/attr.rs index 89a1ea770..385ba8c80 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -105,7 +105,7 @@ impl RawAttrs { | |||
105 | Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), | 105 | Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), |
106 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 106 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
107 | id, | 107 | id, |
108 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | 108 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), |
109 | path: Interned::new(ModPath::from(hir_expand::name!(doc))), | 109 | path: Interned::new(ModPath::from(hir_expand::name!(doc))), |
110 | }), | 110 | }), |
111 | }) | 111 | }) |
@@ -151,7 +151,7 @@ impl RawAttrs { | |||
151 | return smallvec![attr.clone()]; | 151 | return smallvec![attr.clone()]; |
152 | } | 152 | } |
153 | 153 | ||
154 | let subtree = match &attr.input { | 154 | let subtree = match attr.input.as_deref() { |
155 | Some(AttrInput::TokenTree(it)) => it, | 155 | Some(AttrInput::TokenTree(it)) => it, |
156 | _ => return smallvec![attr.clone()], | 156 | _ => return smallvec![attr.clone()], |
157 | }; | 157 | }; |
@@ -251,7 +251,7 @@ impl Attrs { | |||
251 | } | 251 | } |
252 | 252 | ||
253 | pub fn docs(&self) -> Option<Documentation> { | 253 | pub fn docs(&self) -> Option<Documentation> { |
254 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { | 254 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? { |
255 | AttrInput::Literal(s) => Some(s), | 255 | AttrInput::Literal(s) => Some(s), |
256 | AttrInput::TokenTree(_) => None, | 256 | AttrInput::TokenTree(_) => None, |
257 | }); | 257 | }); |
@@ -454,7 +454,7 @@ impl AttrsWithOwner { | |||
454 | db: &dyn DefDatabase, | 454 | db: &dyn DefDatabase, |
455 | ) -> Option<(Documentation, DocsRangeMap)> { | 455 | ) -> Option<(Documentation, DocsRangeMap)> { |
456 | // FIXME: code duplication in `docs` above | 456 | // FIXME: code duplication in `docs` above |
457 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { | 457 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? { |
458 | AttrInput::Literal(s) => Some((s, attr.id)), | 458 | AttrInput::Literal(s) => Some((s, attr.id)), |
459 | AttrInput::TokenTree(_) => None, | 459 | AttrInput::TokenTree(_) => None, |
460 | }); | 460 | }); |
@@ -637,10 +637,10 @@ pub(crate) struct AttrId { | |||
637 | pub struct Attr { | 637 | pub struct Attr { |
638 | pub(crate) id: AttrId, | 638 | pub(crate) id: AttrId, |
639 | pub(crate) path: Interned<ModPath>, | 639 | pub(crate) path: Interned<ModPath>, |
640 | pub(crate) input: Option<AttrInput>, | 640 | pub(crate) input: Option<Interned<AttrInput>>, |
641 | } | 641 | } |
642 | 642 | ||
643 | #[derive(Debug, Clone, PartialEq, Eq)] | 643 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
644 | pub enum AttrInput { | 644 | pub enum AttrInput { |
645 | /// `#[attr = "string"]` | 645 | /// `#[attr = "string"]` |
646 | Literal(SmolStr), | 646 | Literal(SmolStr), |
@@ -670,9 +670,9 @@ impl Attr { | |||
670 | ast::LiteralKind::String(string) => string.value()?.into(), | 670 | ast::LiteralKind::String(string) => string.value()?.into(), |
671 | _ => lit.syntax().first_token()?.text().trim_matches('"').into(), | 671 | _ => lit.syntax().first_token()?.text().trim_matches('"').into(), |
672 | }; | 672 | }; |
673 | Some(AttrInput::Literal(value)) | 673 | Some(Interned::new(AttrInput::Literal(value))) |
674 | } else if let Some(tt) = ast.token_tree() { | 674 | } else if let Some(tt) = ast.token_tree() { |
675 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0)) | 675 | Some(Interned::new(AttrInput::TokenTree(ast_to_token_tree(&tt).0))) |
676 | } else { | 676 | } else { |
677 | None | 677 | None |
678 | }; | 678 | }; |
@@ -688,7 +688,7 @@ impl Attr { | |||
688 | return None; | 688 | return None; |
689 | } | 689 | } |
690 | 690 | ||
691 | match &self.input { | 691 | match self.input.as_deref() { |
692 | Some(AttrInput::TokenTree(args)) => { | 692 | Some(AttrInput::TokenTree(args)) => { |
693 | let mut counter = 0; | 693 | let mut counter = 0; |
694 | let paths = args | 694 | let paths = args |
@@ -720,7 +720,7 @@ impl Attr { | |||
720 | } | 720 | } |
721 | 721 | ||
722 | pub fn string_value(&self) -> Option<&SmolStr> { | 722 | pub fn string_value(&self) -> Option<&SmolStr> { |
723 | match self.input.as_ref()? { | 723 | match self.input.as_deref()? { |
724 | AttrInput::Literal(it) => Some(it), | 724 | AttrInput::Literal(it) => Some(it), |
725 | _ => None, | 725 | _ => None, |
726 | } | 726 | } |
@@ -735,14 +735,14 @@ pub struct AttrQuery<'a> { | |||
735 | 735 | ||
736 | impl<'a> AttrQuery<'a> { | 736 | impl<'a> AttrQuery<'a> { |
737 | pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { | 737 | pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { |
738 | self.attrs().filter_map(|attr| match attr.input.as_ref()? { | 738 | self.attrs().filter_map(|attr| match attr.input.as_deref()? { |
739 | AttrInput::TokenTree(it) => Some(it), | 739 | AttrInput::TokenTree(it) => Some(it), |
740 | _ => None, | 740 | _ => None, |
741 | }) | 741 | }) |
742 | } | 742 | } |
743 | 743 | ||
744 | pub fn string_value(self) -> Option<&'a SmolStr> { | 744 | pub fn string_value(self) -> Option<&'a SmolStr> { |
745 | self.attrs().find_map(|attr| match attr.input.as_ref()? { | 745 | self.attrs().find_map(|attr| match attr.input.as_deref()? { |
746 | AttrInput::Literal(it) => Some(it), | 746 | AttrInput::Literal(it) => Some(it), |
747 | _ => None, | 747 | _ => None, |
748 | }) | 748 | }) |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 135a6698e..8bcac60ef 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -112,7 +112,7 @@ pub struct TypeAliasData { | |||
112 | pub visibility: RawVisibility, | 112 | pub visibility: RawVisibility, |
113 | pub is_extern: bool, | 113 | pub is_extern: bool, |
114 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | 114 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). |
115 | pub bounds: Vec<TypeBound>, | 115 | pub bounds: Vec<Interned<TypeBound>>, |
116 | } | 116 | } |
117 | 117 | ||
118 | impl TypeAliasData { | 118 | impl TypeAliasData { |
@@ -141,7 +141,7 @@ pub struct TraitData { | |||
141 | pub is_auto: bool, | 141 | pub is_auto: bool, |
142 | pub is_unsafe: bool, | 142 | pub is_unsafe: bool, |
143 | pub visibility: RawVisibility, | 143 | pub visibility: RawVisibility, |
144 | pub bounds: Box<[TypeBound]>, | 144 | pub bounds: Box<[Interned<TypeBound>]>, |
145 | } | 145 | } |
146 | 146 | ||
147 | impl TraitData { | 147 | impl TraitData { |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index de5acced8..44d22b918 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -68,9 +68,19 @@ pub struct GenericParams { | |||
68 | /// associated type bindings like `Iterator<Item = u32>`. | 68 | /// associated type bindings like `Iterator<Item = u32>`. |
69 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 69 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
70 | pub enum WherePredicate { | 70 | pub enum WherePredicate { |
71 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, | 71 | TypeBound { |
72 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, | 72 | target: WherePredicateTypeTarget, |
73 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, | 73 | bound: Interned<TypeBound>, |
74 | }, | ||
75 | Lifetime { | ||
76 | target: LifetimeRef, | ||
77 | bound: LifetimeRef, | ||
78 | }, | ||
79 | ForLifetime { | ||
80 | lifetimes: Box<[Name]>, | ||
81 | target: WherePredicateTypeTarget, | ||
82 | bound: Interned<TypeBound>, | ||
83 | }, | ||
74 | } | 84 | } |
75 | 85 | ||
76 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 86 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
@@ -339,11 +349,11 @@ impl GenericParams { | |||
339 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { | 349 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { |
340 | lifetimes: hrtb_lifetimes.clone(), | 350 | lifetimes: hrtb_lifetimes.clone(), |
341 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), | 351 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), |
342 | bound, | 352 | bound: Interned::new(bound), |
343 | }, | 353 | }, |
344 | None => WherePredicate::TypeBound { | 354 | None => WherePredicate::TypeBound { |
345 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), | 355 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), |
346 | bound, | 356 | bound: Interned::new(bound), |
347 | }, | 357 | }, |
348 | }, | 358 | }, |
349 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { | 359 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { |
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs index 5cc7f2df6..79ba970e7 100644 --- a/crates/hir_def/src/intern.rs +++ b/crates/hir_def/src/intern.rs | |||
@@ -216,7 +216,10 @@ pub use crate::_impl_internable as impl_internable; | |||
216 | impl_internable!( | 216 | impl_internable!( |
217 | crate::type_ref::TypeRef, | 217 | crate::type_ref::TypeRef, |
218 | crate::type_ref::TraitRef, | 218 | crate::type_ref::TraitRef, |
219 | crate::type_ref::TypeBound, | ||
219 | crate::path::ModPath, | 220 | crate::path::ModPath, |
221 | crate::path::GenericArgs, | ||
222 | crate::attr::AttrInput, | ||
220 | GenericParams, | 223 | GenericParams, |
221 | str, | 224 | str, |
222 | ); | 225 | ); |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 528270d49..11767d100 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 | ||
3 | mod lower; | 33 | mod lower; |
4 | mod pretty; | 34 | mod 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 | /// |
@@ -614,7 +644,7 @@ pub struct Trait { | |||
614 | pub generic_params: Interned<GenericParams>, | 644 | pub generic_params: Interned<GenericParams>, |
615 | pub is_auto: bool, | 645 | pub is_auto: bool, |
616 | pub is_unsafe: bool, | 646 | pub is_unsafe: bool, |
617 | pub bounds: Box<[TypeBound]>, | 647 | pub bounds: Box<[Interned<TypeBound>]>, |
618 | pub items: Box<[AssocItem]>, | 648 | pub items: Box<[AssocItem]>, |
619 | pub ast_id: FileAstId<ast::Trait>, | 649 | pub ast_id: FileAstId<ast::Trait>, |
620 | } | 650 | } |
@@ -634,7 +664,7 @@ pub struct TypeAlias { | |||
634 | pub name: Name, | 664 | pub name: Name, |
635 | pub visibility: RawVisibilityId, | 665 | pub visibility: RawVisibilityId, |
636 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | 666 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. |
637 | pub bounds: Box<[TypeBound]>, | 667 | pub bounds: Box<[Interned<TypeBound>]>, |
638 | pub generic_params: Interned<GenericParams>, | 668 | pub generic_params: Interned<GenericParams>, |
639 | pub type_ref: Option<Interned<TypeRef>>, | 669 | pub type_ref: Option<Interned<TypeRef>>, |
640 | pub is_extern: bool, | 670 | pub is_extern: bool, |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 91cf75371..b4389371f 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -384,7 +384,7 @@ impl<'a> Ctx<'a> { | |||
384 | 384 | ||
385 | let ret_type = if func.async_token().is_some() { | 385 | let ret_type = if func.async_token().is_some() { |
386 | let future_impl = desugar_future_path(ret_type); | 386 | let future_impl = desugar_future_path(ret_type); |
387 | let ty_bound = TypeBound::Path(future_impl); | 387 | let ty_bound = Interned::new(TypeBound::Path(future_impl)); |
388 | TypeRef::ImplTrait(vec![ty_bound]) | 388 | TypeRef::ImplTrait(vec![ty_bound]) |
389 | } else { | 389 | } else { |
390 | ret_type | 390 | ret_type |
@@ -738,11 +738,12 @@ impl<'a> Ctx<'a> { | |||
738 | Interned::new(generics) | 738 | Interned::new(generics) |
739 | } | 739 | } |
740 | 740 | ||
741 | fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { | 741 | fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<Interned<TypeBound>> { |
742 | match node.type_bound_list() { | 742 | match node.type_bound_list() { |
743 | Some(bound_list) => { | 743 | Some(bound_list) => bound_list |
744 | bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() | 744 | .bounds() |
745 | } | 745 | .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it))) |
746 | .collect(), | ||
746 | None => Vec::new(), | 747 | None => Vec::new(), |
747 | } | 748 | } |
748 | } | 749 | } |
@@ -810,7 +811,7 @@ fn desugar_future_path(orig: TypeRef) -> Path { | |||
810 | let binding = | 811 | let binding = |
811 | AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; | 812 | AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; |
812 | last.bindings.push(binding); | 813 | last.bindings.push(binding); |
813 | generic_args.push(Some(Arc::new(last))); | 814 | generic_args.push(Some(Interned::new(last))); |
814 | 815 | ||
815 | Path::from_known_path(path, generic_args) | 816 | Path::from_known_path(path, generic_args) |
816 | } | 817 | } |
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index 4bc87a0e2..9394a5de6 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs | |||
@@ -513,13 +513,13 @@ impl<'a> Printer<'a> { | |||
513 | } | 513 | } |
514 | } | 514 | } |
515 | 515 | ||
516 | fn print_type_bounds(&mut self, bounds: &[TypeBound]) { | 516 | fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) { |
517 | for (i, bound) in bounds.iter().enumerate() { | 517 | for (i, bound) in bounds.iter().enumerate() { |
518 | if i != 0 { | 518 | if i != 0 { |
519 | w!(self, " + "); | 519 | w!(self, " + "); |
520 | } | 520 | } |
521 | 521 | ||
522 | match bound { | 522 | match bound.as_ref() { |
523 | TypeBound::Path(path) => self.print_path(path), | 523 | TypeBound::Path(path) => self.print_path(path), |
524 | TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), | 524 | TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), |
525 | TypeBound::Error => w!(self, "{{unknown}}"), | 525 | TypeBound::Error => w!(self, "{{unknown}}"), |
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_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 014ea4de4..2ae740d0e 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -285,7 +285,7 @@ impl DefCollector<'_> { | |||
285 | let registered_name = if *attr_name == hir_expand::name![register_attr] | 285 | let registered_name = if *attr_name == hir_expand::name![register_attr] |
286 | || *attr_name == hir_expand::name![register_tool] | 286 | || *attr_name == hir_expand::name![register_tool] |
287 | { | 287 | { |
288 | match &attr.input { | 288 | match attr.input.as_deref() { |
289 | Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees { | 289 | Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees { |
290 | [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(), | 290 | [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(), |
291 | _ => continue, | 291 | _ => continue, |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 9b8873fd2..45ab9d0ff 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -4,7 +4,6 @@ mod lower; | |||
4 | use std::{ | 4 | use std::{ |
5 | fmt::{self, Display}, | 5 | fmt::{self, Display}, |
6 | iter, | 6 | iter, |
7 | sync::Arc, | ||
8 | }; | 7 | }; |
9 | 8 | ||
10 | use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; | 9 | use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; |
@@ -136,7 +135,7 @@ pub struct Path { | |||
136 | type_anchor: Option<Interned<TypeRef>>, | 135 | type_anchor: Option<Interned<TypeRef>>, |
137 | mod_path: Interned<ModPath>, | 136 | mod_path: Interned<ModPath>, |
138 | /// Invariant: the same len as `self.mod_path.segments` | 137 | /// Invariant: the same len as `self.mod_path.segments` |
139 | generic_args: Vec<Option<Arc<GenericArgs>>>, | 138 | generic_args: Vec<Option<Interned<GenericArgs>>>, |
140 | } | 139 | } |
141 | 140 | ||
142 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This | 141 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This |
@@ -165,7 +164,7 @@ pub struct AssociatedTypeBinding { | |||
165 | /// Bounds for the associated type, like in `Iterator<Item: | 164 | /// Bounds for the associated type, like in `Iterator<Item: |
166 | /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds` | 165 | /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds` |
167 | /// feature.) | 166 | /// feature.) |
168 | pub bounds: Vec<TypeBound>, | 167 | pub bounds: Vec<Interned<TypeBound>>, |
169 | } | 168 | } |
170 | 169 | ||
171 | /// A single generic argument. | 170 | /// A single generic argument. |
@@ -185,7 +184,7 @@ impl Path { | |||
185 | /// Converts a known mod path to `Path`. | 184 | /// Converts a known mod path to `Path`. |
186 | pub(crate) fn from_known_path( | 185 | pub(crate) fn from_known_path( |
187 | path: ModPath, | 186 | path: ModPath, |
188 | generic_args: Vec<Option<Arc<GenericArgs>>>, | 187 | generic_args: Vec<Option<Interned<GenericArgs>>>, |
189 | ) -> Path { | 188 | ) -> Path { |
190 | Path { type_anchor: None, mod_path: Interned::new(path), generic_args } | 189 | Path { type_anchor: None, mod_path: Interned::new(path), generic_args } |
191 | } | 190 | } |
@@ -239,7 +238,7 @@ pub struct PathSegment<'a> { | |||
239 | 238 | ||
240 | pub struct PathSegments<'a> { | 239 | pub struct PathSegments<'a> { |
241 | segments: &'a [Name], | 240 | segments: &'a [Name], |
242 | generic_args: &'a [Option<Arc<GenericArgs>>], | 241 | generic_args: &'a [Option<Interned<GenericArgs>>], |
243 | } | 242 | } |
244 | 243 | ||
245 | impl<'a> PathSegments<'a> { | 244 | impl<'a> PathSegments<'a> { |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index a873325b2..5d5dd9c8f 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | mod lower_use; | 3 | mod lower_use; |
4 | 4 | ||
5 | use crate::intern::Interned; | 5 | use crate::intern::Interned; |
6 | use std::sync::Arc; | ||
7 | 6 | ||
8 | use either::Either; | 7 | use either::Either; |
9 | use hir_expand::name::{name, AsName}; | 8 | use hir_expand::name::{name, AsName}; |
@@ -48,7 +47,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
48 | segment.ret_type(), | 47 | segment.ret_type(), |
49 | ) | 48 | ) |
50 | }) | 49 | }) |
51 | .map(Arc::new); | 50 | .map(Interned::new); |
52 | segments.push(name); | 51 | segments.push(name); |
53 | generic_args.push(args) | 52 | generic_args.push(args) |
54 | } | 53 | } |
@@ -87,13 +86,13 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
87 | // Insert the type reference (T in the above example) as Self parameter for the trait | 86 | // Insert the type reference (T in the above example) as Self parameter for the trait |
88 | let last_segment = | 87 | let last_segment = |
89 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; | 88 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; |
90 | if last_segment.is_none() { | 89 | let mut args_inner = match last_segment { |
91 | *last_segment = Some(Arc::new(GenericArgs::empty())); | 90 | Some(it) => it.as_ref().clone(), |
91 | None => GenericArgs::empty(), | ||
92 | }; | 92 | }; |
93 | let args = last_segment.as_mut().unwrap(); | ||
94 | let mut args_inner = Arc::make_mut(args); | ||
95 | args_inner.has_self_type = true; | 93 | args_inner.has_self_type = true; |
96 | args_inner.args.insert(0, GenericArg::Type(self_type)); | 94 | args_inner.args.insert(0, GenericArg::Type(self_type)); |
95 | *last_segment = Some(Interned::new(args_inner)); | ||
97 | } | 96 | } |
98 | } | 97 | } |
99 | } | 98 | } |
@@ -171,7 +170,9 @@ pub(super) fn lower_generic_args( | |||
171 | let name = name_ref.as_name(); | 170 | let name = name_ref.as_name(); |
172 | let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); | 171 | let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); |
173 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { | 172 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { |
174 | l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() | 173 | l.bounds() |
174 | .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))) | ||
175 | .collect() | ||
175 | } else { | 176 | } else { |
176 | Vec::new() | 177 | Vec::new() |
177 | }; | 178 | }; |
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index cdcab7110..cbde6b940 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -5,7 +5,7 @@ use hir_expand::{name::Name, AstId, InFile}; | |||
5 | use std::convert::TryInto; | 5 | use std::convert::TryInto; |
6 | use syntax::ast; | 6 | use syntax::ast; |
7 | 7 | ||
8 | use crate::{body::LowerCtx, path::Path}; | 8 | use crate::{body::LowerCtx, intern::Interned, path::Path}; |
9 | 9 | ||
10 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | 10 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
11 | pub enum Mutability { | 11 | pub enum Mutability { |
@@ -91,8 +91,8 @@ pub enum TypeRef { | |||
91 | /// A fn pointer. Last element of the vector is the return type. | 91 | /// A fn pointer. Last element of the vector is the return type. |
92 | Fn(Vec<TypeRef>, bool /*varargs*/), | 92 | Fn(Vec<TypeRef>, bool /*varargs*/), |
93 | // For | 93 | // For |
94 | ImplTrait(Vec<TypeBound>), | 94 | ImplTrait(Vec<Interned<TypeBound>>), |
95 | DynTrait(Vec<TypeBound>), | 95 | DynTrait(Vec<Interned<TypeBound>>), |
96 | Macro(AstId<ast::MacroCall>), | 96 | Macro(AstId<ast::MacroCall>), |
97 | Error, | 97 | Error, |
98 | } | 98 | } |
@@ -232,7 +232,7 @@ impl TypeRef { | |||
232 | | TypeRef::Slice(type_ref) => go(&type_ref, f), | 232 | | TypeRef::Slice(type_ref) => go(&type_ref, f), |
233 | TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { | 233 | TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { |
234 | for bound in bounds { | 234 | for bound in bounds { |
235 | match bound { | 235 | match bound.as_ref() { |
236 | TypeBound::Path(path) => go_path(path, f), | 236 | TypeBound::Path(path) => go_path(path, f), |
237 | TypeBound::Lifetime(_) | TypeBound::Error => (), | 237 | TypeBound::Lifetime(_) | TypeBound::Error => (), |
238 | } | 238 | } |
@@ -262,7 +262,7 @@ impl TypeRef { | |||
262 | go(type_ref, f); | 262 | go(type_ref, f); |
263 | } | 263 | } |
264 | for bound in &binding.bounds { | 264 | for bound in &binding.bounds { |
265 | match bound { | 265 | match bound.as_ref() { |
266 | TypeBound::Path(path) => go_path(path, f), | 266 | TypeBound::Path(path) => go_path(path, f), |
267 | TypeBound::Lifetime(_) | TypeBound::Error => (), | 267 | TypeBound::Lifetime(_) | TypeBound::Error => (), |
268 | } | 268 | } |
@@ -277,9 +277,9 @@ impl TypeRef { | |||
277 | pub(crate) fn type_bounds_from_ast( | 277 | pub(crate) fn type_bounds_from_ast( |
278 | lower_ctx: &LowerCtx, | 278 | lower_ctx: &LowerCtx, |
279 | type_bounds_opt: Option<ast::TypeBoundList>, | 279 | type_bounds_opt: Option<ast::TypeBoundList>, |
280 | ) -> Vec<TypeBound> { | 280 | ) -> Vec<Interned<TypeBound>> { |
281 | if let Some(type_bounds) = type_bounds_opt { | 281 | if let Some(type_bounds) = type_bounds_opt { |
282 | type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() | 282 | type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect() |
283 | } else { | 283 | } else { |
284 | vec![] | 284 | vec![] |
285 | } | 285 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 5c769c1bf..625c26f0a 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -131,15 +131,15 @@ pub trait AstDatabase: SourceDatabase { | |||
131 | /// used for completion, where we want to see what 'would happen' if we insert a | 131 | /// used for completion, where we want to see what 'would happen' if we insert a |
132 | /// token. The `token_to_map` mapped down into the expansion, with the mapped | 132 | /// token. The `token_to_map` mapped down into the expansion, with the mapped |
133 | /// token returned. | 133 | /// token returned. |
134 | pub fn expand_hypothetical( | 134 | pub fn expand_speculative( |
135 | db: &dyn AstDatabase, | 135 | db: &dyn AstDatabase, |
136 | actual_macro_call: MacroCallId, | 136 | actual_macro_call: MacroCallId, |
137 | hypothetical_args: &ast::TokenTree, | 137 | speculative_args: &ast::TokenTree, |
138 | token_to_map: SyntaxToken, | 138 | token_to_map: SyntaxToken, |
139 | ) -> Option<(SyntaxNode, SyntaxToken)> { | 139 | ) -> Option<(SyntaxNode, SyntaxToken)> { |
140 | let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax()); | 140 | let (tt, tmap_1) = mbe::syntax_node_to_token_tree(speculative_args.syntax()); |
141 | let range = | 141 | let range = |
142 | token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; | 142 | token_to_map.text_range().checked_sub(speculative_args.syntax().text_range().start())?; |
143 | let token_id = tmap_1.token_by_range(range)?; | 143 | let token_id = tmap_1.token_by_range(range)?; |
144 | 144 | ||
145 | let macro_def = { | 145 | let macro_def = { |
@@ -147,15 +147,15 @@ pub fn expand_hypothetical( | |||
147 | db.macro_def(loc.def)? | 147 | db.macro_def(loc.def)? |
148 | }; | 148 | }; |
149 | 149 | ||
150 | let hypothetical_expansion = macro_def.expand(db, actual_macro_call, &tt); | 150 | let speculative_expansion = macro_def.expand(db, actual_macro_call, &tt); |
151 | 151 | ||
152 | let fragment_kind = macro_fragment_kind(db, actual_macro_call); | 152 | let fragment_kind = macro_fragment_kind(db, actual_macro_call); |
153 | 153 | ||
154 | let (node, tmap_2) = | 154 | let (node, tmap_2) = |
155 | mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?; | 155 | mbe::token_tree_to_syntax_node(&speculative_expansion.value, fragment_kind).ok()?; |
156 | 156 | ||
157 | let token_id = macro_def.map_id_down(token_id); | 157 | let token_id = macro_def.map_id_down(token_id); |
158 | let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; | 158 | let range = tmap_2.range_by_token(token_id, token_to_map.kind())?; |
159 | let token = node.syntax_node().covering_element(range).into_token()?; | 159 | let token = node.syntax_node().covering_element(range).into_token()?; |
160 | Some((node.syntax_node(), token)) | 160 | Some((node.syntax_node(), token)) |
161 | } | 161 | } |
@@ -325,7 +325,7 @@ fn macro_expand_with_arg( | |||
325 | if let Some(eager) = &loc.eager { | 325 | if let Some(eager) = &loc.eager { |
326 | if arg.is_some() { | 326 | if arg.is_some() { |
327 | return ExpandResult::str_err( | 327 | return ExpandResult::str_err( |
328 | "hypothetical macro expansion not implemented for eager macro".to_owned(), | 328 | "speculative macro expansion not implemented for eager macro".to_owned(), |
329 | ); | 329 | ); |
330 | } else { | 330 | } else { |
331 | return ExpandResult { | 331 | return ExpandResult { |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 38e09fdd4..d98913907 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -154,7 +154,7 @@ impl HygieneInfo { | |||
154 | }, | 154 | }, |
155 | }; | 155 | }; |
156 | 156 | ||
157 | let range = token_map.range_by_token(token_id)?.by_kind(SyntaxKind::IDENT)?; | 157 | let range = token_map.range_by_token(token_id, SyntaxKind::IDENT)?; |
158 | Some((tt.with_value(range + tt.value), origin)) | 158 | Some((tt.with_value(range + tt.value), origin)) |
159 | } | 159 | } |
160 | } | 160 | } |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 92c679dd2..6be4516a3 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -329,7 +329,7 @@ impl ExpansionInfo { | |||
329 | let token_id = self.macro_arg.1.token_by_range(range)?; | 329 | let token_id = self.macro_arg.1.token_by_range(range)?; |
330 | let token_id = self.macro_def.map_id_down(token_id); | 330 | let token_id = self.macro_def.map_id_down(token_id); |
331 | 331 | ||
332 | let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?; | 332 | let range = self.exp_map.range_by_token(token_id, token.value.kind())?; |
333 | 333 | ||
334 | let token = self.expanded.value.covering_element(range).into_token()?; | 334 | let token = self.expanded.value.covering_element(range).into_token()?; |
335 | 335 | ||
@@ -354,7 +354,7 @@ impl ExpansionInfo { | |||
354 | }, | 354 | }, |
355 | }; | 355 | }; |
356 | 356 | ||
357 | let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; | 357 | let range = token_map.range_by_token(token_id, token.value.kind())?; |
358 | let token = | 358 | let token = |
359 | tt.value.covering_element(range + tt.value.text_range().start()).into_token()?; | 359 | tt.value.covering_element(range + tt.value.text_range().start()).into_token()?; |
360 | Some((tt.with_value(token), origin)) | 360 | Some((tt.with_value(token), origin)) |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 66b3418f2..a9994082a 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -18,9 +18,9 @@ ena = "0.14.0" | |||
18 | log = "0.4.8" | 18 | log = "0.4.8" |
19 | rustc-hash = "1.1.0" | 19 | rustc-hash = "1.1.0" |
20 | scoped-tls = "1" | 20 | scoped-tls = "1" |
21 | chalk-solve = { version = "0.64", default-features = false } | 21 | chalk-solve = { version = "0.67", default-features = false } |
22 | chalk-ir = "0.64" | 22 | chalk-ir = "0.67" |
23 | chalk-recursive = "0.64" | 23 | chalk-recursive = "0.67" |
24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
25 | 25 | ||
26 | stdx = { path = "../stdx", version = "0.0.0" } | 26 | stdx = { path = "../stdx", version = "0.0.0" } |
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/display.rs b/crates/hir_ty/src/display.rs index 7bbd1a1f7..637bbc634 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -13,6 +13,7 @@ use hir_def::{ | |||
13 | db::DefDatabase, | 13 | db::DefDatabase, |
14 | find_path, | 14 | find_path, |
15 | generics::TypeParamProvenance, | 15 | generics::TypeParamProvenance, |
16 | intern::{Internable, Interned}, | ||
16 | item_scope::ItemInNs, | 17 | item_scope::ItemInNs, |
17 | path::{Path, PathKind}, | 18 | path::{Path, PathKind}, |
18 | type_ref::{TypeBound, TypeRef}, | 19 | type_ref::{TypeBound, TypeRef}, |
@@ -256,6 +257,12 @@ impl<T: HirDisplay> HirDisplay for &'_ T { | |||
256 | } | 257 | } |
257 | } | 258 | } |
258 | 259 | ||
260 | impl<T: HirDisplay + Internable> HirDisplay for Interned<T> { | ||
261 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
262 | HirDisplay::hir_fmt(self.as_ref(), f) | ||
263 | } | ||
264 | } | ||
265 | |||
259 | impl HirDisplay for ProjectionTy { | 266 | impl HirDisplay for ProjectionTy { |
260 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | 267 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { |
261 | if f.should_truncate() { | 268 | if f.should_truncate() { |
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..79a732106 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -805,7 +805,7 @@ impl<'a> InferenceContext<'a> { | |||
805 | None => self.table.new_float_var(), | 805 | None => self.table.new_float_var(), |
806 | }, | 806 | }, |
807 | }, | 807 | }, |
808 | Expr::MacroStmts { tail } => self.infer_expr(*tail, expected), | 808 | Expr::MacroStmts { tail } => self.infer_expr_inner(*tail, expected), |
809 | }; | 809 | }; |
810 | // use a new type variable if we got unknown here | 810 | // use a new type variable if we got unknown here |
811 | let ty = self.insert_type_vars_shallow(ty); | 811 | let ty = self.insert_type_vars_shallow(ty); |
@@ -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/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8a375b973..c83933c73 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -10,6 +10,7 @@ use std::{iter, sync::Arc}; | |||
10 | 10 | ||
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; | 12 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; |
13 | use hir_def::intern::Interned; | ||
13 | use hir_def::{ | 14 | use hir_def::{ |
14 | adt::StructKind, | 15 | adt::StructKind, |
15 | body::{Expander, LowerCtx}, | 16 | body::{Expander, LowerCtx}, |
@@ -843,7 +844,7 @@ impl<'a> TyLoweringContext<'a> { | |||
843 | }) | 844 | }) |
844 | } | 845 | } |
845 | 846 | ||
846 | fn lower_impl_trait(&self, bounds: &[TypeBound]) -> ReturnTypeImplTrait { | 847 | fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait { |
847 | cov_mark::hit!(lower_rpit); | 848 | cov_mark::hit!(lower_rpit); |
848 | let self_ty = | 849 | let self_ty = |
849 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); | 850 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); |
@@ -1025,7 +1026,7 @@ pub(crate) fn trait_environment_query( | |||
1025 | }; | 1026 | }; |
1026 | if let Some(AssocContainerId::TraitId(trait_id)) = container { | 1027 | if let Some(AssocContainerId::TraitId(trait_id)) = container { |
1027 | // add `Self: Trait<T1, T2, ...>` to the environment in trait | 1028 | // add `Self: Trait<T1, T2, ...>` to the environment in trait |
1028 | // function default implementations (and hypothetical code | 1029 | // function default implementations (and speculative code |
1029 | // inside consts or type aliases) | 1030 | // inside consts or type aliases) |
1030 | cov_mark::hit!(trait_self_implements_self); | 1031 | cov_mark::hit!(trait_self_implements_self); |
1031 | let substs = TyBuilder::type_params_subst(db, trait_id); | 1032 | let substs = TyBuilder::type_params_subst(db, trait_id); |
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index bb568ea37..6dac7e103 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -832,11 +832,9 @@ fn coerce_unsize_super_trait_cycle() { | |||
832 | ); | 832 | ); |
833 | } | 833 | } |
834 | 834 | ||
835 | #[ignore] | ||
836 | #[test] | 835 | #[test] |
837 | fn coerce_unsize_generic() { | 836 | fn coerce_unsize_generic() { |
838 | // FIXME: Implement this | 837 | // FIXME: fix the type mismatches here |
839 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | ||
840 | check_infer_with_mismatches( | 838 | check_infer_with_mismatches( |
841 | r#" | 839 | r#" |
842 | #[lang = "unsize"] | 840 | #[lang = "unsize"] |
@@ -854,8 +852,58 @@ fn coerce_unsize_generic() { | |||
854 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | 852 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); |
855 | } | 853 | } |
856 | "#, | 854 | "#, |
857 | expect![[r" | 855 | expect![[r#" |
858 | "]], | 856 | 209..317 '{ ... }); }': () |
857 | 219..220 '_': &Foo<[usize]> | ||
858 | 238..259 '&Foo {..., 3] }': &Foo<[usize]> | ||
859 | 239..259 'Foo { ..., 3] }': Foo<[usize]> | ||
860 | 248..257 '[1, 2, 3]': [usize; 3] | ||
861 | 249..250 '1': usize | ||
862 | 252..253 '2': usize | ||
863 | 255..256 '3': usize | ||
864 | 269..270 '_': &Bar<[usize]> | ||
865 | 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]> | ||
866 | 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> | ||
867 | 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]> | ||
868 | 293..313 'Foo { ..., 3] }': Foo<[i32; 3]> | ||
869 | 302..311 '[1, 2, 3]': [i32; 3] | ||
870 | 303..304 '1': i32 | ||
871 | 306..307 '2': i32 | ||
872 | 309..310 '3': i32 | ||
873 | 248..257: expected [usize], got [usize; 3] | ||
874 | 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]> | ||
875 | "#]], | ||
876 | ); | ||
877 | } | ||
878 | |||
879 | #[test] | ||
880 | fn coerce_unsize_apit() { | ||
881 | // FIXME: #8984 | ||
882 | check_infer_with_mismatches( | ||
883 | r#" | ||
884 | #[lang = "sized"] | ||
885 | pub trait Sized {} | ||
886 | #[lang = "unsize"] | ||
887 | pub trait Unsize<T> {} | ||
888 | #[lang = "coerce_unsized"] | ||
889 | pub trait CoerceUnsized<T> {} | ||
890 | |||
891 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
892 | |||
893 | trait Foo {} | ||
894 | |||
895 | fn test(f: impl Foo) { | ||
896 | let _: &dyn Foo = &f; | ||
897 | } | ||
898 | "#, | ||
899 | expect![[r#" | ||
900 | 210..211 'f': impl Foo | ||
901 | 223..252 '{ ... &f; }': () | ||
902 | 233..234 '_': &dyn Foo | ||
903 | 247..249 '&f': &impl Foo | ||
904 | 248..249 'f': impl Foo | ||
905 | 247..249: expected &dyn Foo, got &impl Foo | ||
906 | "#]], | ||
859 | ); | 907 | ); |
860 | } | 908 | } |
861 | 909 | ||
@@ -912,3 +960,46 @@ fn test() -> i32 { | |||
912 | "#, | 960 | "#, |
913 | ) | 961 | ) |
914 | } | 962 | } |
963 | |||
964 | #[test] | ||
965 | fn panic_macro() { | ||
966 | check_infer_with_mismatches( | ||
967 | r#" | ||
968 | mod panic { | ||
969 | #[macro_export] | ||
970 | pub macro panic_2015 { | ||
971 | () => ( | ||
972 | $crate::panicking::panic() | ||
973 | ), | ||
974 | } | ||
975 | } | ||
976 | |||
977 | mod panicking { | ||
978 | pub fn panic() -> ! { loop {} } | ||
979 | } | ||
980 | |||
981 | #[rustc_builtin_macro = "core_panic"] | ||
982 | macro_rules! panic { | ||
983 | // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` | ||
984 | // depending on the edition of the caller. | ||
985 | ($($arg:tt)*) => { | ||
986 | /* compiler built-in */ | ||
987 | }; | ||
988 | } | ||
989 | |||
990 | fn main() { | ||
991 | panic!() | ||
992 | } | ||
993 | "#, | ||
994 | expect![[r#" | ||
995 | 174..185 '{ loop {} }': ! | ||
996 | 176..183 'loop {}': ! | ||
997 | 181..183 '{}': () | ||
998 | !0..24 '$crate...:panic': fn panic() -> ! | ||
999 | !0..26 '$crate...anic()': ! | ||
1000 | !0..26 '$crate...anic()': ! | ||
1001 | !0..28 '$crate...015!()': ! | ||
1002 | 454..470 '{ ...c!() }': () | ||
1003 | "#]], | ||
1004 | ); | ||
1005 | } | ||
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 320694a17..ec3828ab2 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -286,7 +286,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
286 | .and_then( | 286 | .and_then( |
287 | |url| if let Some(fragment) = fragment { url.join(&fragment).ok() } else { Some(url) }, | 287 | |url| if let Some(fragment) = fragment { url.join(&fragment).ok() } else { Some(url) }, |
288 | ) | 288 | ) |
289 | .map(|url| url.into_string()) | 289 | .map(|url| url.into()) |
290 | } | 290 | } |
291 | 291 | ||
292 | fn rewrite_intra_doc_link( | 292 | fn rewrite_intra_doc_link( |
@@ -325,7 +325,7 @@ fn rewrite_intra_doc_link( | |||
325 | }; | 325 | }; |
326 | } | 326 | } |
327 | 327 | ||
328 | Some((new_url.into_string(), strip_prefixes_suffixes(title).to_string())) | 328 | Some((new_url.into(), strip_prefixes_suffixes(title).to_string())) |
329 | } | 329 | } |
330 | 330 | ||
331 | /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). | 331 | /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). |
@@ -345,7 +345,7 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S | |||
345 | get_symbol_filename(db, &def).as_deref().map(|f| url.join(f).ok()).flatten() | 345 | get_symbol_filename(db, &def).as_deref().map(|f| url.join(f).ok()).flatten() |
346 | }) | 346 | }) |
347 | .and_then(|url| url.join(target).ok()) | 347 | .and_then(|url| url.join(target).ok()) |
348 | .map(|url| url.into_string()) | 348 | .map(|url| url.into()) |
349 | } | 349 | } |
350 | 350 | ||
351 | /// Rewrites a markdown document, applying 'callback' to each link. | 351 | /// Rewrites a markdown document, applying 'callback' to each link. |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index f3284bb96..004d9cb68 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use ide_db::base_db::Upcast; | ||
1 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 3 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 4 | ||
@@ -31,6 +32,7 @@ pub(crate) fn goto_type_definition( | |||
31 | ast::Pat(it) => sema.type_of_pat(&it)?, | 32 | ast::Pat(it) => sema.type_of_pat(&it)?, |
32 | ast::SelfParam(it) => sema.type_of_self(&it)?, | 33 | ast::SelfParam(it) => sema.type_of_self(&it)?, |
33 | ast::Type(it) => sema.resolve_type(&it)?, | 34 | ast::Type(it) => sema.resolve_type(&it)?, |
35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | ||
34 | _ => return None, | 36 | _ => return None, |
35 | } | 37 | } |
36 | }; | 38 | }; |
@@ -161,4 +163,34 @@ impl Foo$0 {} | |||
161 | "#, | 163 | "#, |
162 | ) | 164 | ) |
163 | } | 165 | } |
166 | |||
167 | #[test] | ||
168 | fn goto_def_for_struct_field() { | ||
169 | check( | ||
170 | r#" | ||
171 | struct Bar; | ||
172 | //^^^ | ||
173 | |||
174 | struct Foo { | ||
175 | bar$0: Bar, | ||
176 | } | ||
177 | "#, | ||
178 | ); | ||
179 | } | ||
180 | |||
181 | #[test] | ||
182 | fn goto_def_for_enum_struct_field() { | ||
183 | check( | ||
184 | r#" | ||
185 | struct Bar; | ||
186 | //^^^ | ||
187 | |||
188 | enum Foo { | ||
189 | Bar { | ||
190 | bar$0: Bar | ||
191 | }, | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
164 | } | 196 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 8f490e922..85f887737 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -219,7 +219,7 @@ fn hint_iterator( | |||
219 | ) -> Option<SmolStr> { | 219 | ) -> Option<SmolStr> { |
220 | let db = sema.db; | 220 | let db = sema.db; |
221 | let strukt = ty.strip_references().as_adt()?; | 221 | let strukt = ty.strip_references().as_adt()?; |
222 | let krate = strukt.krate(db); | 222 | let krate = strukt.module(db).krate(); |
223 | if krate != famous_defs.core()? { | 223 | if krate != famous_defs.core()? { |
224 | return None; | 224 | return None; |
225 | } | 225 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index f76715d84..ce1c76f37 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -227,7 +227,7 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> | |||
227 | let func = def.source(sema.db)?; | 227 | let func = def.source(sema.db)?; |
228 | let name_string = def.name(sema.db).to_string(); | 228 | let name_string = def.name(sema.db).to_string(); |
229 | 229 | ||
230 | let root = def.krate(sema.db)?.root_module(sema.db); | 230 | let root = def.module(sema.db).krate().root_module(sema.db); |
231 | 231 | ||
232 | let kind = if name_string == "main" && def.module(sema.db) == root { | 232 | let kind = if name_string == "main" && def.module(sema.db) == root { |
233 | RunnableKind::Bin | 233 | RunnableKind::Bin |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 9df8d21af..cf1a8bad7 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -80,6 +80,7 @@ pub(crate) fn highlight( | |||
80 | &mut hl, | 80 | &mut hl, |
81 | &sema, | 81 | &sema, |
82 | InFile::new(file_id.into(), &root), | 82 | InFile::new(file_id.into(), &root), |
83 | sema.scope(&root).krate(), | ||
83 | range_to_highlight, | 84 | range_to_highlight, |
84 | syntactic_name_ref_highlighting, | 85 | syntactic_name_ref_highlighting, |
85 | ); | 86 | ); |
@@ -90,6 +91,7 @@ fn traverse( | |||
90 | hl: &mut Highlights, | 91 | hl: &mut Highlights, |
91 | sema: &Semantics<RootDatabase>, | 92 | sema: &Semantics<RootDatabase>, |
92 | root: InFile<&SyntaxNode>, | 93 | root: InFile<&SyntaxNode>, |
94 | krate: Option<hir::Crate>, | ||
93 | range_to_highlight: TextRange, | 95 | range_to_highlight: TextRange, |
94 | syntactic_name_ref_highlighting: bool, | 96 | syntactic_name_ref_highlighting: bool, |
95 | ) { | 97 | ) { |
@@ -209,6 +211,7 @@ fn traverse( | |||
209 | 211 | ||
210 | if let Some((mut highlight, binding_hash)) = highlight::element( | 212 | if let Some((mut highlight, binding_hash)) = highlight::element( |
211 | &sema, | 213 | &sema, |
214 | krate, | ||
212 | &mut bindings_shadow_count, | 215 | &mut bindings_shadow_count, |
213 | syntactic_name_ref_highlighting, | 216 | syntactic_name_ref_highlighting, |
214 | element_to_highlight.clone(), | 217 | element_to_highlight.clone(), |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 058e37ff0..b4a3d39c9 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | 19 | ||
20 | pub(super) fn element( | 20 | pub(super) fn element( |
21 | sema: &Semantics<RootDatabase>, | 21 | sema: &Semantics<RootDatabase>, |
22 | krate: Option<hir::Crate>, | ||
22 | bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, | 23 | bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, |
23 | syntactic_name_ref_highlighting: bool, | 24 | syntactic_name_ref_highlighting: bool, |
24 | element: SyntaxElement, | 25 | element: SyntaxElement, |
@@ -46,8 +47,10 @@ pub(super) fn element( | |||
46 | 47 | ||
47 | match name_kind { | 48 | match name_kind { |
48 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), | 49 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), |
49 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | 50 | Some(NameClass::Definition(def)) => { |
50 | Some(NameClass::ConstReference(def)) => highlight_def(db, def), | 51 | highlight_def(db, krate, def) | HlMod::Definition |
52 | } | ||
53 | Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), | ||
51 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | 54 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { |
52 | let mut h = HlTag::Symbol(SymbolKind::Field).into(); | 55 | let mut h = HlTag::Symbol(SymbolKind::Field).into(); |
53 | if let Definition::Field(field) = field_ref { | 56 | if let Definition::Field(field) = field_ref { |
@@ -82,7 +85,7 @@ pub(super) fn element( | |||
82 | } | 85 | } |
83 | }; | 86 | }; |
84 | 87 | ||
85 | let mut h = highlight_def(db, def); | 88 | let mut h = highlight_def(db, krate, def); |
86 | 89 | ||
87 | if let Definition::Local(local) = &def { | 90 | if let Definition::Local(local) = &def { |
88 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | 91 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { |
@@ -136,9 +139,11 @@ pub(super) fn element( | |||
136 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | 139 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); |
137 | 140 | ||
138 | match NameClass::classify_lifetime(sema, &lifetime) { | 141 | match NameClass::classify_lifetime(sema, &lifetime) { |
139 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | 142 | Some(NameClass::Definition(def)) => { |
143 | highlight_def(db, krate, def) | HlMod::Definition | ||
144 | } | ||
140 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | 145 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { |
141 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | 146 | Some(NameRefClass::Definition(def)) => highlight_def(db, krate, def), |
142 | _ => SymbolKind::LifetimeParam.into(), | 147 | _ => SymbolKind::LifetimeParam.into(), |
143 | }, | 148 | }, |
144 | _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition, | 149 | _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition, |
@@ -277,12 +282,12 @@ pub(super) fn element( | |||
277 | hash((name, shadow_count)) | 282 | hash((name, shadow_count)) |
278 | } | 283 | } |
279 | } | 284 | } |
280 | fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | 285 | fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition) -> Highlight { |
281 | match def { | 286 | let mut h = match def { |
282 | Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro), | 287 | Definition::Macro(_) => Highlight::new(HlTag::Symbol(SymbolKind::Macro)), |
283 | Definition::Field(_) => HlTag::Symbol(SymbolKind::Field), | 288 | Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)), |
284 | Definition::ModuleDef(def) => match def { | 289 | Definition::ModuleDef(def) => match def { |
285 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), | 290 | hir::ModuleDef::Module(_) => Highlight::new(HlTag::Symbol(SymbolKind::Module)), |
286 | hir::ModuleDef::Function(func) => { | 291 | hir::ModuleDef::Function(func) => { |
287 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); | 292 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); |
288 | if let Some(item) = func.as_assoc_item(db) { | 293 | if let Some(item) = func.as_assoc_item(db) { |
@@ -314,14 +319,22 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
314 | if func.is_async(db) { | 319 | if func.is_async(db) { |
315 | h |= HlMod::Async; | 320 | h |= HlMod::Async; |
316 | } | 321 | } |
317 | return h; | 322 | |
323 | h | ||
318 | } | 324 | } |
319 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct), | 325 | hir::ModuleDef::Adt(adt) => { |
320 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum), | 326 | let h = match adt { |
321 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union), | 327 | hir::Adt::Struct(_) => HlTag::Symbol(SymbolKind::Struct), |
322 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), | 328 | hir::Adt::Enum(_) => HlTag::Symbol(SymbolKind::Enum), |
329 | hir::Adt::Union(_) => HlTag::Symbol(SymbolKind::Union), | ||
330 | }; | ||
331 | |||
332 | Highlight::new(h) | ||
333 | } | ||
334 | hir::ModuleDef::Variant(_) => Highlight::new(HlTag::Symbol(SymbolKind::Variant)), | ||
323 | hir::ModuleDef::Const(konst) => { | 335 | hir::ModuleDef::Const(konst) => { |
324 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); | 336 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); |
337 | |||
325 | if let Some(item) = konst.as_assoc_item(db) { | 338 | if let Some(item) = konst.as_assoc_item(db) { |
326 | h |= HlMod::Associated; | 339 | h |= HlMod::Associated; |
327 | match item.container(db) { | 340 | match item.container(db) { |
@@ -336,7 +349,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
336 | } | 349 | } |
337 | } | 350 | } |
338 | 351 | ||
339 | return h; | 352 | h |
340 | } | 353 | } |
341 | hir::ModuleDef::Trait(trait_) => { | 354 | hir::ModuleDef::Trait(trait_) => { |
342 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); | 355 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); |
@@ -344,10 +357,12 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
344 | if trait_.is_unsafe(db) { | 357 | if trait_.is_unsafe(db) { |
345 | h |= HlMod::Unsafe; | 358 | h |= HlMod::Unsafe; |
346 | } | 359 | } |
347 | return h; | 360 | |
361 | h | ||
348 | } | 362 | } |
349 | hir::ModuleDef::TypeAlias(type_) => { | 363 | hir::ModuleDef::TypeAlias(type_) => { |
350 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); | 364 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); |
365 | |||
351 | if let Some(item) = type_.as_assoc_item(db) { | 366 | if let Some(item) = type_.as_assoc_item(db) { |
352 | h |= HlMod::Associated; | 367 | h |= HlMod::Associated; |
353 | match item.container(db) { | 368 | match item.container(db) { |
@@ -361,23 +376,30 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
361 | } | 376 | } |
362 | } | 377 | } |
363 | } | 378 | } |
364 | return h; | 379 | |
380 | h | ||
365 | } | 381 | } |
366 | hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType, | 382 | hir::ModuleDef::BuiltinType(_) => Highlight::new(HlTag::BuiltinType), |
367 | hir::ModuleDef::Static(s) => { | 383 | hir::ModuleDef::Static(s) => { |
368 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); | 384 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); |
385 | |||
369 | if s.is_mut(db) { | 386 | if s.is_mut(db) { |
370 | h |= HlMod::Mutable; | 387 | h |= HlMod::Mutable; |
371 | h |= HlMod::Unsafe; | 388 | h |= HlMod::Unsafe; |
372 | } | 389 | } |
373 | return h; | 390 | |
391 | h | ||
374 | } | 392 | } |
375 | }, | 393 | }, |
376 | Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl), | 394 | Definition::SelfType(_) => Highlight::new(HlTag::Symbol(SymbolKind::Impl)), |
377 | Definition::GenericParam(it) => match it { | 395 | Definition::GenericParam(it) => match it { |
378 | hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam), | 396 | hir::GenericParam::TypeParam(_) => Highlight::new(HlTag::Symbol(SymbolKind::TypeParam)), |
379 | hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam), | 397 | hir::GenericParam::ConstParam(_) => { |
380 | hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam), | 398 | Highlight::new(HlTag::Symbol(SymbolKind::ConstParam)) |
399 | } | ||
400 | hir::GenericParam::LifetimeParam(_) => { | ||
401 | Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | ||
402 | } | ||
381 | }, | 403 | }, |
382 | Definition::Local(local) => { | 404 | Definition::Local(local) => { |
383 | let tag = if local.is_self(db) { | 405 | let tag = if local.is_self(db) { |
@@ -395,11 +417,19 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
395 | if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { | 417 | if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { |
396 | h |= HlMod::Callable; | 418 | h |= HlMod::Callable; |
397 | } | 419 | } |
398 | return h; | 420 | h |
399 | } | 421 | } |
400 | Definition::Label(_) => HlTag::Symbol(SymbolKind::Label), | 422 | Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)), |
423 | }; | ||
424 | |||
425 | let is_from_other_crate = def.module(db).map(hir::Module::krate) != krate; | ||
426 | let is_builtin_type = matches!(def, Definition::ModuleDef(hir::ModuleDef::BuiltinType(_))); | ||
427 | |||
428 | if is_from_other_crate && !is_builtin_type { | ||
429 | h |= HlMod::Library; | ||
401 | } | 430 | } |
402 | .into() | 431 | |
432 | h | ||
403 | } | 433 | } |
404 | 434 | ||
405 | fn highlight_func_by_name_ref( | 435 | fn highlight_func_by_name_ref( |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 27473a2f9..e94f17cd9 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -67,6 +67,8 @@ pub enum HlMod { | |||
67 | Trait, | 67 | Trait, |
68 | /// Used with keywords like `async` and `await`. | 68 | /// Used with keywords like `async` and `await`. |
69 | Async, | 69 | Async, |
70 | /// Used for items from other crates. | ||
71 | Library, | ||
70 | // Keep this last! | 72 | // Keep this last! |
71 | /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations. | 73 | /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations. |
72 | Unsafe, | 74 | Unsafe, |
@@ -189,6 +191,7 @@ impl HlMod { | |||
189 | HlMod::Static, | 191 | HlMod::Static, |
190 | HlMod::Trait, | 192 | HlMod::Trait, |
191 | HlMod::Async, | 193 | HlMod::Async, |
194 | HlMod::Library, | ||
192 | HlMod::Unsafe, | 195 | HlMod::Unsafe, |
193 | ]; | 196 | ]; |
194 | 197 | ||
@@ -207,6 +210,7 @@ impl HlMod { | |||
207 | HlMod::Static => "static", | 210 | HlMod::Static => "static", |
208 | HlMod::Trait => "trait", | 211 | HlMod::Trait => "trait", |
209 | HlMod::Async => "async", | 212 | HlMod::Async => "async", |
213 | HlMod::Library => "library", | ||
210 | HlMod::Unsafe => "unsafe", | 214 | HlMod::Unsafe => "unsafe", |
211 | } | 215 | } |
212 | } | 216 | } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 878431b56..055d21109 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -248,4 +248,20 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
248 | <span class="brace">}</span> | 248 | <span class="brace">}</span> |
249 | 249 | ||
250 | <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">Dangerous</span> <span class="brace">{</span><span class="brace">}</span> | 250 | <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">Dangerous</span> <span class="brace">{</span><span class="brace">}</span> |
251 | <span class="keyword">impl</span> <span class="trait unsafe">Dangerous</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file | 251 | <span class="keyword">impl</span> <span class="trait unsafe">Dangerous</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
252 | |||
253 | <span class="keyword">fn</span> <span class="function declaration">use_foo_items</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
254 | <span class="keyword">let</span> <span class="variable declaration">bob</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="struct library">Person</span> <span class="brace">{</span> | ||
255 | <span class="field library">name</span><span class="colon">:</span> <span class="string_literal">"Bob"</span><span class="comma">,</span> | ||
256 | <span class="field library">age</span><span class="colon">:</span> <span class="module library">foo</span><span class="operator">::</span><span class="module library">consts</span><span class="operator">::</span><span class="constant library">NUMBER</span><span class="comma">,</span> | ||
257 | <span class="brace">}</span><span class="semicolon">;</span> | ||
258 | |||
259 | <span class="keyword">let</span> <span class="variable declaration">control_flow</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="function library">identity</span><span class="parenthesis">(</span><span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Continue</span><span class="parenthesis">)</span><span class="semicolon">;</span> | ||
260 | |||
261 | <span class="keyword control">if</span> <span class="keyword">let</span> <span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Die</span> <span class="operator">=</span> <span class="variable">control_flow</span> <span class="brace">{</span> | ||
262 | foo::<span class="macro">die!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | ||
263 | <span class="brace">}</span> | ||
264 | <span class="brace">}</span> | ||
265 | |||
266 | |||
267 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 9ce26e930..be4447ebb 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -10,6 +10,7 @@ use crate::{fixture, FileRange, HlTag, TextRange}; | |||
10 | fn test_highlighting() { | 10 | fn test_highlighting() { |
11 | check_highlighting( | 11 | check_highlighting( |
12 | r#" | 12 | r#" |
13 | //- /main.rs crate:main deps:foo | ||
13 | use inner::{self as inner_mod}; | 14 | use inner::{self as inner_mod}; |
14 | mod inner {} | 15 | mod inner {} |
15 | 16 | ||
@@ -222,6 +223,43 @@ async fn async_main() { | |||
222 | 223 | ||
223 | unsafe trait Dangerous {} | 224 | unsafe trait Dangerous {} |
224 | impl Dangerous for () {} | 225 | impl Dangerous for () {} |
226 | |||
227 | fn use_foo_items() { | ||
228 | let bob = foo::Person { | ||
229 | name: "Bob", | ||
230 | age: foo::consts::NUMBER, | ||
231 | }; | ||
232 | |||
233 | let control_flow = foo::identity(foo::ControlFlow::Continue); | ||
234 | |||
235 | if let foo::ControlFlow::Die = control_flow { | ||
236 | foo::die!(); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | |||
241 | //- /foo.rs crate:foo | ||
242 | pub struct Person { | ||
243 | pub name: &'static str, | ||
244 | pub age: u8, | ||
245 | } | ||
246 | |||
247 | pub enum ControlFlow { | ||
248 | Continue, | ||
249 | Die, | ||
250 | } | ||
251 | |||
252 | pub fn identity<T>(x: T) -> T { x } | ||
253 | |||
254 | pub mod consts { | ||
255 | pub const NUMBER: i64 = 92; | ||
256 | } | ||
257 | |||
258 | macro_rules! die { | ||
259 | () => { | ||
260 | panic!(); | ||
261 | }; | ||
262 | } | ||
225 | "# | 263 | "# |
226 | .trim(), | 264 | .trim(), |
227 | expect_file!["./test_data/highlighting.html"], | 265 | expect_file!["./test_data/highlighting.html"], |
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 97435f021..3d2cd739a 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs | |||
@@ -31,8 +31,8 @@ use crate::{ | |||
31 | // | 31 | // |
32 | // fn handle(action: Action) { | 32 | // fn handle(action: Action) { |
33 | // match action { | 33 | // match action { |
34 | // $0Action::Move { distance } => {} | 34 | // $0Action::Move { distance } => todo!(), |
35 | // Action::Stop => {} | 35 | // Action::Stop => todo!(), |
36 | // } | 36 | // } |
37 | // } | 37 | // } |
38 | // ``` | 38 | // ``` |
@@ -129,7 +129,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
129 | |builder| { | 129 | |builder| { |
130 | let new_match_arm_list = match_arm_list.clone_for_update(); | 130 | let new_match_arm_list = match_arm_list.clone_for_update(); |
131 | let missing_arms = missing_pats | 131 | let missing_arms = missing_pats |
132 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) | 132 | .map(|pat| make::match_arm(iter::once(pat), make::ext::expr_todo())) |
133 | .map(|it| it.clone_for_update()); | 133 | .map(|it| it.clone_for_update()); |
134 | 134 | ||
135 | let catch_all_arm = new_match_arm_list | 135 | let catch_all_arm = new_match_arm_list |
@@ -350,8 +350,8 @@ fn foo(a: bool) { | |||
350 | r#" | 350 | r#" |
351 | fn foo(a: bool) { | 351 | fn foo(a: bool) { |
352 | match a { | 352 | match a { |
353 | $0true => {} | 353 | $0true => todo!(), |
354 | false => {} | 354 | false => todo!(), |
355 | } | 355 | } |
356 | } | 356 | } |
357 | "#, | 357 | "#, |
@@ -373,7 +373,7 @@ fn foo(a: bool) { | |||
373 | fn foo(a: bool) { | 373 | fn foo(a: bool) { |
374 | match a { | 374 | match a { |
375 | true => {} | 375 | true => {} |
376 | $0false => {} | 376 | $0false => todo!(), |
377 | } | 377 | } |
378 | } | 378 | } |
379 | "#, | 379 | "#, |
@@ -410,10 +410,10 @@ fn foo(a: bool) { | |||
410 | r#" | 410 | r#" |
411 | fn foo(a: bool) { | 411 | fn foo(a: bool) { |
412 | match (a, a) { | 412 | match (a, a) { |
413 | $0(true, true) => {} | 413 | $0(true, true) => todo!(), |
414 | (true, false) => {} | 414 | (true, false) => todo!(), |
415 | (false, true) => {} | 415 | (false, true) => todo!(), |
416 | (false, false) => {} | 416 | (false, false) => todo!(), |
417 | } | 417 | } |
418 | } | 418 | } |
419 | "#, | 419 | "#, |
@@ -435,9 +435,9 @@ fn foo(a: bool) { | |||
435 | fn foo(a: bool) { | 435 | fn foo(a: bool) { |
436 | match (a, a) { | 436 | match (a, a) { |
437 | (false, true) => {} | 437 | (false, true) => {} |
438 | $0(true, true) => {} | 438 | $0(true, true) => todo!(), |
439 | (true, false) => {} | 439 | (true, false) => todo!(), |
440 | (false, false) => {} | 440 | (false, false) => todo!(), |
441 | } | 441 | } |
442 | } | 442 | } |
443 | "#, | 443 | "#, |
@@ -471,7 +471,7 @@ fn main() { | |||
471 | match A::As { | 471 | match A::As { |
472 | A::Bs { x, y: Some(_) } => {} | 472 | A::Bs { x, y: Some(_) } => {} |
473 | A::Cs(_, Some(_)) => {} | 473 | A::Cs(_, Some(_)) => {} |
474 | $0A::As => {} | 474 | $0A::As => todo!(), |
475 | } | 475 | } |
476 | } | 476 | } |
477 | "#, | 477 | "#, |
@@ -499,7 +499,7 @@ use Option::*; | |||
499 | fn main() { | 499 | fn main() { |
500 | match None { | 500 | match None { |
501 | None => {} | 501 | None => {} |
502 | Some(${0:_}) => {} | 502 | Some(${0:_}) => todo!(), |
503 | } | 503 | } |
504 | } | 504 | } |
505 | "#, | 505 | "#, |
@@ -523,7 +523,7 @@ enum A { As, Bs, Cs(Option<i32>) } | |||
523 | fn main() { | 523 | fn main() { |
524 | match A::As { | 524 | match A::As { |
525 | A::Cs(_) | A::Bs => {} | 525 | A::Cs(_) | A::Bs => {} |
526 | $0A::As => {} | 526 | $0A::As => todo!(), |
527 | } | 527 | } |
528 | } | 528 | } |
529 | "#, | 529 | "#, |
@@ -553,8 +553,8 @@ fn main() { | |||
553 | A::Bs if 0 < 1 => {} | 553 | A::Bs if 0 < 1 => {} |
554 | A::Ds(_value) => { let x = 1; } | 554 | A::Ds(_value) => { let x = 1; } |
555 | A::Es(B::Xs) => (), | 555 | A::Es(B::Xs) => (), |
556 | $0A::As => {} | 556 | $0A::As => todo!(), |
557 | A::Cs => {} | 557 | A::Cs => todo!(), |
558 | } | 558 | } |
559 | } | 559 | } |
560 | "#, | 560 | "#, |
@@ -580,7 +580,7 @@ fn main() { | |||
580 | match A::As { | 580 | match A::As { |
581 | A::As(_) => {} | 581 | A::As(_) => {} |
582 | a @ A::Bs(_) => {} | 582 | a @ A::Bs(_) => {} |
583 | A::Cs(${0:_}) => {} | 583 | A::Cs(${0:_}) => todo!(), |
584 | } | 584 | } |
585 | } | 585 | } |
586 | "#, | 586 | "#, |
@@ -605,11 +605,11 @@ enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } } | |||
605 | fn main() { | 605 | fn main() { |
606 | let a = A::As; | 606 | let a = A::As; |
607 | match a { | 607 | match a { |
608 | $0A::As => {} | 608 | $0A::As => todo!(), |
609 | A::Bs => {} | 609 | A::Bs => todo!(), |
610 | A::Cs(_) => {} | 610 | A::Cs(_) => todo!(), |
611 | A::Ds(_, _) => {} | 611 | A::Ds(_, _) => todo!(), |
612 | A::Es { x, y } => {} | 612 | A::Es { x, y } => todo!(), |
613 | } | 613 | } |
614 | } | 614 | } |
615 | "#, | 615 | "#, |
@@ -638,10 +638,10 @@ fn main() { | |||
638 | let a = A::One; | 638 | let a = A::One; |
639 | let b = B::One; | 639 | let b = B::One; |
640 | match (a, b) { | 640 | match (a, b) { |
641 | $0(A::One, B::One) => {} | 641 | $0(A::One, B::One) => todo!(), |
642 | (A::One, B::Two) => {} | 642 | (A::One, B::Two) => todo!(), |
643 | (A::Two, B::One) => {} | 643 | (A::Two, B::One) => todo!(), |
644 | (A::Two, B::Two) => {} | 644 | (A::Two, B::Two) => todo!(), |
645 | } | 645 | } |
646 | } | 646 | } |
647 | "#, | 647 | "#, |
@@ -670,10 +670,10 @@ fn main() { | |||
670 | let a = A::One; | 670 | let a = A::One; |
671 | let b = B::One; | 671 | let b = B::One; |
672 | match (&a, &b) { | 672 | match (&a, &b) { |
673 | $0(A::One, B::One) => {} | 673 | $0(A::One, B::One) => todo!(), |
674 | (A::One, B::Two) => {} | 674 | (A::One, B::Two) => todo!(), |
675 | (A::Two, B::One) => {} | 675 | (A::Two, B::One) => todo!(), |
676 | (A::Two, B::Two) => {} | 676 | (A::Two, B::Two) => todo!(), |
677 | } | 677 | } |
678 | } | 678 | } |
679 | "#, | 679 | "#, |
@@ -705,9 +705,9 @@ fn main() { | |||
705 | let b = B::One; | 705 | let b = B::One; |
706 | match (a, b) { | 706 | match (a, b) { |
707 | (A::Two, B::One) => {} | 707 | (A::Two, B::One) => {} |
708 | $0(A::One, B::One) => {} | 708 | $0(A::One, B::One) => todo!(), |
709 | (A::One, B::Two) => {} | 709 | (A::One, B::Two) => todo!(), |
710 | (A::Two, B::Two) => {} | 710 | (A::Two, B::Two) => todo!(), |
711 | } | 711 | } |
712 | } | 712 | } |
713 | "#, | 713 | "#, |
@@ -736,7 +736,7 @@ fn main() { | |||
736 | match (a, b) { | 736 | match (a, b) { |
737 | (Some(_), _) => {} | 737 | (Some(_), _) => {} |
738 | (None, Some(_)) => {} | 738 | (None, Some(_)) => {} |
739 | $0(None, None) => {} | 739 | $0(None, None) => todo!(), |
740 | } | 740 | } |
741 | } | 741 | } |
742 | "#, | 742 | "#, |
@@ -801,8 +801,8 @@ enum A { One, Two } | |||
801 | fn main() { | 801 | fn main() { |
802 | let a = A::One; | 802 | let a = A::One; |
803 | match (a, ) { | 803 | match (a, ) { |
804 | $0(A::One,) => {} | 804 | $0(A::One,) => todo!(), |
805 | (A::Two,) => {} | 805 | (A::Two,) => todo!(), |
806 | } | 806 | } |
807 | } | 807 | } |
808 | "#, | 808 | "#, |
@@ -826,7 +826,7 @@ enum A { As } | |||
826 | 826 | ||
827 | fn foo(a: &A) { | 827 | fn foo(a: &A) { |
828 | match a { | 828 | match a { |
829 | $0A::As => {} | 829 | $0A::As => todo!(), |
830 | } | 830 | } |
831 | } | 831 | } |
832 | "#, | 832 | "#, |
@@ -851,7 +851,7 @@ enum A { | |||
851 | 851 | ||
852 | fn foo(a: &mut A) { | 852 | fn foo(a: &mut A) { |
853 | match a { | 853 | match a { |
854 | $0A::Es { x, y } => {} | 854 | $0A::Es { x, y } => todo!(), |
855 | } | 855 | } |
856 | } | 856 | } |
857 | "#, | 857 | "#, |
@@ -891,8 +891,8 @@ enum E { X, Y } | |||
891 | 891 | ||
892 | fn main() { | 892 | fn main() { |
893 | match E::X { | 893 | match E::X { |
894 | $0E::X => {} | 894 | $0E::X => todo!(), |
895 | E::Y => {} | 895 | E::Y => todo!(), |
896 | } | 896 | } |
897 | } | 897 | } |
898 | "#, | 898 | "#, |
@@ -919,8 +919,8 @@ use foo::E::X; | |||
919 | 919 | ||
920 | fn main() { | 920 | fn main() { |
921 | match X { | 921 | match X { |
922 | $0X => {} | 922 | $0X => todo!(), |
923 | foo::E::Y => {} | 923 | foo::E::Y => todo!(), |
924 | } | 924 | } |
925 | } | 925 | } |
926 | "#, | 926 | "#, |
@@ -947,7 +947,7 @@ fn foo(a: A) { | |||
947 | match a { | 947 | match a { |
948 | // foo bar baz | 948 | // foo bar baz |
949 | A::One => {} | 949 | A::One => {} |
950 | $0A::Two => {} | 950 | $0A::Two => todo!(), |
951 | // This is where the rest should be | 951 | // This is where the rest should be |
952 | } | 952 | } |
953 | } | 953 | } |
@@ -971,8 +971,8 @@ fn foo(a: A) { | |||
971 | enum A { One, Two } | 971 | enum A { One, Two } |
972 | fn foo(a: A) { | 972 | fn foo(a: A) { |
973 | match a { | 973 | match a { |
974 | $0A::One => {} | 974 | $0A::One => todo!(), |
975 | A::Two => {} | 975 | A::Two => todo!(), |
976 | // foo bar baz | 976 | // foo bar baz |
977 | } | 977 | } |
978 | } | 978 | } |
@@ -996,8 +996,8 @@ fn foo(a: A) { | |||
996 | enum A { One, Two, } | 996 | enum A { One, Two, } |
997 | fn foo(a: A) { | 997 | fn foo(a: A) { |
998 | match a { | 998 | match a { |
999 | $0A::One => {} | 999 | $0A::One => todo!(), |
1000 | A::Two => {} | 1000 | A::Two => todo!(), |
1001 | } | 1001 | } |
1002 | } | 1002 | } |
1003 | "#, | 1003 | "#, |
@@ -1021,8 +1021,8 @@ fn foo(opt: Option<i32>) { | |||
1021 | r#" | 1021 | r#" |
1022 | fn foo(opt: Option<i32>) { | 1022 | fn foo(opt: Option<i32>) { |
1023 | match opt { | 1023 | match opt { |
1024 | Some(${0:_}) => {} | 1024 | Some(${0:_}) => todo!(), |
1025 | None => {} | 1025 | None => todo!(), |
1026 | } | 1026 | } |
1027 | } | 1027 | } |
1028 | "#, | 1028 | "#, |
@@ -1054,9 +1054,9 @@ enum Test { | |||
1054 | 1054 | ||
1055 | fn foo(t: Test) { | 1055 | fn foo(t: Test) { |
1056 | m!(match t { | 1056 | m!(match t { |
1057 | $0Test::A => {} | 1057 | $0Test::A => todo!(), |
1058 | Test::B => {} | 1058 | Test::B => todo!(), |
1059 | Test::C => {} | 1059 | Test::C => todo!(), |
1060 | }); | 1060 | }); |
1061 | }"#, | 1061 | }"#, |
1062 | ); | 1062 | ); |
@@ -1076,4 +1076,44 @@ fn foo(tuple: (A, A)) { | |||
1076 | "#, | 1076 | "#, |
1077 | ); | 1077 | ); |
1078 | } | 1078 | } |
1079 | |||
1080 | #[test] | ||
1081 | fn adds_comma_before_new_arms() { | ||
1082 | check_assist( | ||
1083 | fill_match_arms, | ||
1084 | r#" | ||
1085 | fn foo(t: bool) { | ||
1086 | match $0t { | ||
1087 | true => 1 + 2 | ||
1088 | } | ||
1089 | }"#, | ||
1090 | r#" | ||
1091 | fn foo(t: bool) { | ||
1092 | match t { | ||
1093 | true => 1 + 2, | ||
1094 | $0false => todo!(), | ||
1095 | } | ||
1096 | }"#, | ||
1097 | ); | ||
1098 | } | ||
1099 | |||
1100 | #[test] | ||
1101 | fn does_not_add_extra_comma() { | ||
1102 | check_assist( | ||
1103 | fill_match_arms, | ||
1104 | r#" | ||
1105 | fn foo(t: bool) { | ||
1106 | match $0t { | ||
1107 | true => 1 + 2, | ||
1108 | } | ||
1109 | }"#, | ||
1110 | r#" | ||
1111 | fn foo(t: bool) { | ||
1112 | match t { | ||
1113 | true => 1 + 2, | ||
1114 | $0false => todo!(), | ||
1115 | } | ||
1116 | }"#, | ||
1117 | ); | ||
1118 | } | ||
1079 | } | 1119 | } |
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_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 | // ``` |
31 | pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(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 | // ``` | ||
57 | pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
58 | generate_getter_impl(acc, ctx, true) | ||
59 | } | ||
60 | |||
61 | pub(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 | ||
139 | fn 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. | ||
157 | fn 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)] |
88 | mod tests { | 163 | mod 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#" |
102 | struct Context<T: Clone> { | 173 | struct Context { |
103 | dat$0a: T, | 174 | dat$0a: Data, |
104 | }"#, | 175 | } |
176 | "#, | ||
105 | r#" | 177 | r#" |
106 | struct Context<T: Clone> { | 178 | struct Context { |
107 | data: T, | 179 | data: Data, |
108 | } | 180 | } |
109 | 181 | ||
110 | impl<T: Clone> Context<T> { | 182 | impl 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#" | ||
194 | struct Context { | ||
195 | dat$0a: Data, | ||
196 | } | ||
197 | "#, | ||
198 | r#" | ||
199 | struct Context { | ||
200 | data: Data, | ||
201 | } | ||
202 | |||
203 | impl 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#" |
123 | struct Context<T: Clone> { | 218 | struct Context { |
124 | dat$0a: T, | 219 | dat$0a: Data, |
125 | } | 220 | } |
126 | 221 | ||
127 | impl<T: Clone> Context<T> { | 222 | impl 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#" | ||
233 | struct Context { | ||
234 | dat$0a: Data, | ||
235 | } | ||
236 | |||
237 | impl 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#" |
140 | pub(crate) struct Context<T: Clone> { | 251 | pub(crate) struct Context { |
141 | dat$0a: T, | 252 | dat$0a: Data, |
142 | }"#, | 253 | } |
254 | "#, | ||
143 | r#" | 255 | r#" |
144 | pub(crate) struct Context<T: Clone> { | 256 | pub(crate) struct Context { |
145 | data: T, | 257 | data: Data, |
146 | } | 258 | } |
147 | 259 | ||
148 | impl<T: Clone> Context<T> { | 260 | impl 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#" |
162 | struct Context<T: Clone> { | 275 | struct Context { |
163 | data: T, | 276 | data: Data, |
164 | cou$0nt: usize, | 277 | cou$0nt: usize, |
165 | } | 278 | } |
166 | 279 | ||
167 | impl<T: Clone> Context<T> { | 280 | impl 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#" |
174 | struct Context<T: Clone> { | 288 | struct Context { |
175 | data: T, | 289 | data: Data, |
176 | count: usize, | 290 | count: usize, |
177 | } | 291 | } |
178 | 292 | ||
179 | impl<T: Clone> Context<T> { | 293 | impl 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#" | ||
314 | struct S { foo: $0String } | ||
315 | "#, | ||
316 | r#" | ||
317 | struct S { foo: String } | ||
318 | |||
319 | impl 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#" | ||
330 | struct S { foo: $0Box<Sweets> } | ||
331 | "#, | ||
332 | r#" | ||
333 | struct S { foo: Box<Sweets> } | ||
334 | |||
335 | impl 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#" | ||
346 | struct S { foo: $0Vec<()> } | ||
347 | "#, | ||
348 | r#" | ||
349 | struct S { foo: Vec<()> } | ||
350 | |||
351 | impl 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#" | ||
362 | struct S { foo: $0Option<Failure> } | ||
363 | "#, | ||
364 | r#" | ||
365 | struct S { foo: Option<Failure> } | ||
366 | |||
367 | impl 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 @@ | |||
1 | use stdx::{format_to, to_lower_snake_case}; | ||
2 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
3 | |||
4 | use 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 | // ``` | ||
31 | pub(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)] | ||
91 | mod 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#" | ||
105 | struct Context<T: Clone> { | ||
106 | dat$0a: T, | ||
107 | }"#, | ||
108 | r#" | ||
109 | struct Context<T: Clone> { | ||
110 | data: T, | ||
111 | } | ||
112 | |||
113 | impl<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#" | ||
126 | struct Context<T: Clone> { | ||
127 | dat$0a: T, | ||
128 | } | ||
129 | |||
130 | impl<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#" | ||
143 | pub(crate) struct Context<T: Clone> { | ||
144 | dat$0a: T, | ||
145 | }"#, | ||
146 | r#" | ||
147 | pub(crate) struct Context<T: Clone> { | ||
148 | data: T, | ||
149 | } | ||
150 | |||
151 | impl<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#" | ||
165 | struct Context<T: Clone> { | ||
166 | data: T, | ||
167 | cou$0nt: usize, | ||
168 | } | ||
169 | |||
170 | impl<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#" | ||
177 | struct Context<T: Clone> { | ||
178 | data: T, | ||
179 | count: usize, | ||
180 | } | ||
181 | |||
182 | impl<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..de5d9e55a 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -455,8 +455,8 @@ enum Action { Move { distance: u32 }, Stop } | |||
455 | 455 | ||
456 | fn handle(action: Action) { | 456 | fn handle(action: Action) { |
457 | match action { | 457 | match action { |
458 | $0Action::Move { distance } => {} | 458 | $0Action::Move { distance } => todo!(), |
459 | Action::Stop => {} | 459 | Action::Stop => todo!(), |
460 | } | 460 | } |
461 | } | 461 | } |
462 | "#####, | 462 | "#####, |
@@ -786,8 +786,8 @@ struct Person { | |||
786 | 786 | ||
787 | impl Person { | 787 | impl 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 | ||
811 | impl Person { | 811 | impl 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..2f3fb1710 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -196,46 +196,46 @@ impl<'a> CompletionContext<'a> { | |||
196 | }; | 196 | }; |
197 | 197 | ||
198 | let mut original_file = original_file.syntax().clone(); | 198 | let mut original_file = original_file.syntax().clone(); |
199 | let mut hypothetical_file = file_with_fake_ident.syntax().clone(); | 199 | let mut speculative_file = file_with_fake_ident.syntax().clone(); |
200 | let mut offset = position.offset; | 200 | let mut offset = position.offset; |
201 | let mut fake_ident_token = fake_ident_token; | 201 | let mut fake_ident_token = fake_ident_token; |
202 | 202 | ||
203 | // Are we inside a macro call? | 203 | // Are we inside a macro call? |
204 | while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = ( | 204 | while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = ( |
205 | find_node_at_offset::<ast::MacroCall>(&original_file, offset), | 205 | find_node_at_offset::<ast::MacroCall>(&original_file, offset), |
206 | find_node_at_offset::<ast::MacroCall>(&hypothetical_file, offset), | 206 | find_node_at_offset::<ast::MacroCall>(&speculative_file, offset), |
207 | ) { | 207 | ) { |
208 | if actual_macro_call.path().as_ref().map(|s| s.syntax().text()) | 208 | if actual_macro_call.path().as_ref().map(|s| s.syntax().text()) |
209 | != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text()) | 209 | != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text()) |
210 | { | 210 | { |
211 | break; | 211 | break; |
212 | } | 212 | } |
213 | let hypothetical_args = match macro_call_with_fake_ident.token_tree() { | 213 | let speculative_args = match macro_call_with_fake_ident.token_tree() { |
214 | Some(tt) => tt, | 214 | Some(tt) => tt, |
215 | None => break, | 215 | None => break, |
216 | }; | 216 | }; |
217 | if let (Some(actual_expansion), Some(hypothetical_expansion)) = ( | 217 | if let (Some(actual_expansion), Some(speculative_expansion)) = ( |
218 | ctx.sema.expand(&actual_macro_call), | 218 | ctx.sema.expand(&actual_macro_call), |
219 | ctx.sema.speculative_expand( | 219 | ctx.sema.speculative_expand( |
220 | &actual_macro_call, | 220 | &actual_macro_call, |
221 | &hypothetical_args, | 221 | &speculative_args, |
222 | fake_ident_token, | 222 | fake_ident_token, |
223 | ), | 223 | ), |
224 | ) { | 224 | ) { |
225 | let new_offset = hypothetical_expansion.1.text_range().start(); | 225 | let new_offset = speculative_expansion.1.text_range().start(); |
226 | if new_offset > actual_expansion.text_range().end() { | 226 | if new_offset > actual_expansion.text_range().end() { |
227 | break; | 227 | break; |
228 | } | 228 | } |
229 | original_file = actual_expansion; | 229 | original_file = actual_expansion; |
230 | hypothetical_file = hypothetical_expansion.0; | 230 | speculative_file = speculative_expansion.0; |
231 | fake_ident_token = hypothetical_expansion.1; | 231 | fake_ident_token = speculative_expansion.1; |
232 | offset = new_offset; | 232 | offset = new_offset; |
233 | } else { | 233 | } else { |
234 | break; | 234 | break; |
235 | } | 235 | } |
236 | } | 236 | } |
237 | ctx.fill_keyword_patterns(&hypothetical_file, offset); | 237 | ctx.fill_keyword_patterns(&speculative_file, offset); |
238 | ctx.fill(&original_file, hypothetical_file, offset); | 238 | ctx.fill(&original_file, speculative_file, offset); |
239 | Some(ctx) | 239 | Some(ctx) |
240 | } | 240 | } |
241 | 241 | ||
@@ -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/lib.rs b/crates/ide_completion/src/lib.rs index 645349215..1152a9850 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -107,7 +107,7 @@ pub use crate::{ | |||
107 | /// identifier prefix/fuzzy match should be done higher in the stack, together | 107 | /// identifier prefix/fuzzy match should be done higher in the stack, together |
108 | /// with ordering of completions (currently this is done by the client). | 108 | /// with ordering of completions (currently this is done by the client). |
109 | /// | 109 | /// |
110 | /// # Hypothetical Completion Problem | 110 | /// # Speculative Completion Problem |
111 | /// | 111 | /// |
112 | /// There's a curious unsolved problem in the current implementation. Often, you | 112 | /// There's a curious unsolved problem in the current implementation. Often, you |
113 | /// want to compute completions on a *slightly different* text document. | 113 | /// want to compute completions on a *slightly different* text document. |
@@ -121,7 +121,7 @@ pub use crate::{ | |||
121 | /// doesn't allow such "phantom" inputs. | 121 | /// doesn't allow such "phantom" inputs. |
122 | /// | 122 | /// |
123 | /// Another case where this would be instrumental is macro expansion. We want to | 123 | /// Another case where this would be instrumental is macro expansion. We want to |
124 | /// insert a fake ident and re-expand code. There's `expand_hypothetical` as a | 124 | /// insert a fake ident and re-expand code. There's `expand_speculative` as a |
125 | /// work-around for this. | 125 | /// work-around for this. |
126 | /// | 126 | /// |
127 | /// A different use-case is completion of injection (examples and links in doc | 127 | /// A different use-case is completion of injection (examples and links in doc |
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), |
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 | ||
5 | use std::iter; | 5 | use std::iter; |
6 | 6 | ||
7 | use hir::{Adt, Semantics, Type}; | 7 | use hir::Semantics; |
8 | use syntax::ast::{self, make}; | 8 | use syntax::ast::{self, make}; |
9 | 9 | ||
10 | use crate::RootDatabase; | 10 | use 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/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 3af5bc18b..b95374b76 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -14,6 +14,7 @@ mod tests; | |||
14 | 14 | ||
15 | #[cfg(test)] | 15 | #[cfg(test)] |
16 | mod benchmark; | 16 | mod benchmark; |
17 | mod token_map; | ||
17 | 18 | ||
18 | use std::fmt; | 19 | use std::fmt; |
19 | 20 | ||
@@ -63,9 +64,12 @@ impl fmt::Display for ExpandError { | |||
63 | } | 64 | } |
64 | } | 65 | } |
65 | 66 | ||
66 | pub use crate::syntax_bridge::{ | 67 | pub use crate::{ |
67 | ast_to_token_tree, parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree, | 68 | syntax_bridge::{ |
68 | token_tree_to_syntax_node, TokenMap, | 69 | ast_to_token_tree, parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree, |
70 | token_tree_to_syntax_node, | ||
71 | }, | ||
72 | token_map::TokenMap, | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | /// This struct contains AST for a single `macro_rules` definition. What might | 75 | /// This struct contains AST for a single `macro_rules` definition. What might |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index b13168bd3..b11172caf 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -10,36 +10,8 @@ use syntax::{ | |||
10 | }; | 10 | }; |
11 | use tt::buffer::{Cursor, TokenBuffer}; | 11 | use tt::buffer::{Cursor, TokenBuffer}; |
12 | 12 | ||
13 | use crate::ExpandError; | ||
14 | use crate::{subtree_source::SubtreeTokenSource, tt_iter::TtIter}; | 13 | use crate::{subtree_source::SubtreeTokenSource, tt_iter::TtIter}; |
15 | 14 | use crate::{ExpandError, TokenMap}; | |
16 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
17 | pub enum TokenTextRange { | ||
18 | Token(TextRange), | ||
19 | Delimiter(TextRange), | ||
20 | } | ||
21 | |||
22 | impl TokenTextRange { | ||
23 | pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> { | ||
24 | match self { | ||
25 | TokenTextRange::Token(it) => Some(it), | ||
26 | TokenTextRange::Delimiter(it) => match kind { | ||
27 | T!['{'] | T!['('] | T!['['] => Some(TextRange::at(it.start(), 1.into())), | ||
28 | T!['}'] | T![')'] | T![']'] => { | ||
29 | Some(TextRange::at(it.end() - TextSize::of('}'), 1.into())) | ||
30 | } | ||
31 | _ => None, | ||
32 | }, | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | |||
37 | /// Maps `tt::TokenId` to the relative range of the original token. | ||
38 | #[derive(Debug, PartialEq, Eq, Clone, Default)] | ||
39 | pub struct TokenMap { | ||
40 | /// Maps `tt::TokenId` to the *relative* source range. | ||
41 | entries: Vec<(tt::TokenId, TokenTextRange)>, | ||
42 | } | ||
43 | 15 | ||
44 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro | 16 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro |
45 | /// will consume). | 17 | /// will consume). |
@@ -53,7 +25,7 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) { | |||
53 | let global_offset = node.text_range().start(); | 25 | let global_offset = node.text_range().start(); |
54 | let mut c = Convertor::new(node, global_offset); | 26 | let mut c = Convertor::new(node, global_offset); |
55 | let subtree = c.go(); | 27 | let subtree = c.go(); |
56 | c.id_alloc.map.entries.shrink_to_fit(); | 28 | c.id_alloc.map.shrink_to_fit(); |
57 | (subtree, c.id_alloc.map) | 29 | (subtree, c.id_alloc.map) |
58 | } | 30 | } |
59 | 31 | ||
@@ -149,55 +121,6 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec<tt::Subtree> { | |||
149 | res | 121 | res |
150 | } | 122 | } |
151 | 123 | ||
152 | impl TokenMap { | ||
153 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { | ||
154 | let &(token_id, _) = self.entries.iter().find(|(_, range)| match range { | ||
155 | TokenTextRange::Token(it) => *it == relative_range, | ||
156 | TokenTextRange::Delimiter(it) => { | ||
157 | let open = TextRange::at(it.start(), 1.into()); | ||
158 | let close = TextRange::at(it.end() - TextSize::of('}'), 1.into()); | ||
159 | open == relative_range || close == relative_range | ||
160 | } | ||
161 | })?; | ||
162 | Some(token_id) | ||
163 | } | ||
164 | |||
165 | pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TokenTextRange> { | ||
166 | let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; | ||
167 | Some(range) | ||
168 | } | ||
169 | |||
170 | fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { | ||
171 | self.entries.push((token_id, TokenTextRange::Token(relative_range))); | ||
172 | } | ||
173 | |||
174 | fn insert_delim( | ||
175 | &mut self, | ||
176 | token_id: tt::TokenId, | ||
177 | open_relative_range: TextRange, | ||
178 | close_relative_range: TextRange, | ||
179 | ) -> usize { | ||
180 | let res = self.entries.len(); | ||
181 | let cover = open_relative_range.cover(close_relative_range); | ||
182 | |||
183 | self.entries.push((token_id, TokenTextRange::Delimiter(cover))); | ||
184 | res | ||
185 | } | ||
186 | |||
187 | fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) { | ||
188 | let (_, token_text_range) = &mut self.entries[idx]; | ||
189 | if let TokenTextRange::Delimiter(dim) = token_text_range { | ||
190 | let cover = dim.cover(close_relative_range); | ||
191 | *token_text_range = TokenTextRange::Delimiter(cover); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | fn remove_delim(&mut self, idx: usize) { | ||
196 | // FIXME: This could be accidentally quadratic | ||
197 | self.entries.remove(idx); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /// Returns the textual content of a doc comment block as a quoted string | 124 | /// Returns the textual content of a doc comment block as a quoted string |
202 | /// That is, strips leading `///` (or `/**`, etc) | 125 | /// That is, strips leading `///` (or `/**`, etc) |
203 | /// and strips the ending `*/` | 126 | /// and strips the ending `*/` |
@@ -634,7 +557,7 @@ impl<'a> TtTreeSink<'a> { | |||
634 | } | 557 | } |
635 | 558 | ||
636 | fn finish(mut self) -> (Parse<SyntaxNode>, TokenMap) { | 559 | fn finish(mut self) -> (Parse<SyntaxNode>, TokenMap) { |
637 | self.token_map.entries.shrink_to_fit(); | 560 | self.token_map.shrink_to_fit(); |
638 | (self.inner.finish(), self.token_map) | 561 | (self.inner.finish(), self.token_map) |
639 | } | 562 | } |
640 | } | 563 | } |
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs index 3a1d840ea..5f173f513 100644 --- a/crates/mbe/src/tests/expand.rs +++ b/crates/mbe/src/tests/expand.rs | |||
@@ -58,9 +58,8 @@ macro_rules! foobar { | |||
58 | let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap(); | 58 | let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap(); |
59 | let content = node.syntax_node().to_string(); | 59 | let content = node.syntax_node().to_string(); |
60 | 60 | ||
61 | let get_text = |id, kind| -> String { | 61 | let get_text = |
62 | content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string() | 62 | |id, kind| -> String { content[token_map.range_by_token(id, kind).unwrap()].to_string() }; |
63 | }; | ||
64 | 63 | ||
65 | assert_eq!(expanded.token_trees.len(), 4); | 64 | assert_eq!(expanded.token_trees.len(), 4); |
66 | // {($e:ident) => { fn $e() {} }} | 65 | // {($e:ident) => { fn $e() {} }} |
diff --git a/crates/mbe/src/token_map.rs b/crates/mbe/src/token_map.rs new file mode 100644 index 000000000..6df3de3b3 --- /dev/null +++ b/crates/mbe/src/token_map.rs | |||
@@ -0,0 +1,85 @@ | |||
1 | //! Mapping between `TokenId`s and the token's position in macro definitions or inputs. | ||
2 | |||
3 | use parser::{SyntaxKind, T}; | ||
4 | use syntax::{TextRange, TextSize}; | ||
5 | |||
6 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
7 | enum TokenTextRange { | ||
8 | Token(TextRange), | ||
9 | Delimiter(TextRange), | ||
10 | } | ||
11 | |||
12 | impl TokenTextRange { | ||
13 | fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> { | ||
14 | match self { | ||
15 | TokenTextRange::Token(it) => Some(it), | ||
16 | TokenTextRange::Delimiter(it) => match kind { | ||
17 | T!['{'] | T!['('] | T!['['] => Some(TextRange::at(it.start(), 1.into())), | ||
18 | T!['}'] | T![')'] | T![']'] => { | ||
19 | Some(TextRange::at(it.end() - TextSize::of('}'), 1.into())) | ||
20 | } | ||
21 | _ => None, | ||
22 | }, | ||
23 | } | ||
24 | } | ||
25 | } | ||
26 | |||
27 | /// Maps `tt::TokenId` to the relative range of the original token. | ||
28 | #[derive(Debug, PartialEq, Eq, Clone, Default)] | ||
29 | pub struct TokenMap { | ||
30 | /// Maps `tt::TokenId` to the *relative* source range. | ||
31 | entries: Vec<(tt::TokenId, TokenTextRange)>, | ||
32 | } | ||
33 | |||
34 | impl TokenMap { | ||
35 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { | ||
36 | let &(token_id, _) = self.entries.iter().find(|(_, range)| match range { | ||
37 | TokenTextRange::Token(it) => *it == relative_range, | ||
38 | TokenTextRange::Delimiter(it) => { | ||
39 | let open = TextRange::at(it.start(), 1.into()); | ||
40 | let close = TextRange::at(it.end() - TextSize::of('}'), 1.into()); | ||
41 | open == relative_range || close == relative_range | ||
42 | } | ||
43 | })?; | ||
44 | Some(token_id) | ||
45 | } | ||
46 | |||
47 | pub fn range_by_token(&self, token_id: tt::TokenId, kind: SyntaxKind) -> Option<TextRange> { | ||
48 | let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; | ||
49 | range.by_kind(kind) | ||
50 | } | ||
51 | |||
52 | pub(crate) fn shrink_to_fit(&mut self) { | ||
53 | self.entries.shrink_to_fit(); | ||
54 | } | ||
55 | |||
56 | pub(crate) fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { | ||
57 | self.entries.push((token_id, TokenTextRange::Token(relative_range))); | ||
58 | } | ||
59 | |||
60 | pub(crate) fn insert_delim( | ||
61 | &mut self, | ||
62 | token_id: tt::TokenId, | ||
63 | open_relative_range: TextRange, | ||
64 | close_relative_range: TextRange, | ||
65 | ) -> usize { | ||
66 | let res = self.entries.len(); | ||
67 | let cover = open_relative_range.cover(close_relative_range); | ||
68 | |||
69 | self.entries.push((token_id, TokenTextRange::Delimiter(cover))); | ||
70 | res | ||
71 | } | ||
72 | |||
73 | pub(crate) fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) { | ||
74 | let (_, token_text_range) = &mut self.entries[idx]; | ||
75 | if let TokenTextRange::Delimiter(dim) = token_text_range { | ||
76 | let cover = dim.cover(close_relative_range); | ||
77 | *token_text_range = TokenTextRange::Delimiter(cover); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | pub(crate) fn remove_delim(&mut self, idx: usize) { | ||
82 | // FIXME: This could be accidentally quadratic | ||
83 | self.entries.remove(idx); | ||
84 | } | ||
85 | } | ||
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml index 2ce5eeedd..2c4da394b 100644 --- a/crates/proc_macro_api/Cargo.toml +++ b/crates/proc_macro_api/Cargo.toml | |||
@@ -16,7 +16,7 @@ log = "0.4.8" | |||
16 | crossbeam-channel = "0.5.0" | 16 | crossbeam-channel = "0.5.0" |
17 | jod-thread = "0.1.1" | 17 | jod-thread = "0.1.1" |
18 | memmap2 = "0.2.0" | 18 | memmap2 = "0.2.0" |
19 | object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] } | 19 | object = { version = "0.24", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] } |
20 | snap = "1.0" | 20 | snap = "1.0" |
21 | 21 | ||
22 | tt = { path = "../tt", version = "0.0.0" } | 22 | tt = { path = "../tt", version = "0.0.0" } |
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml index 63b3f1532..4ea41175e 100644 --- a/crates/proc_macro_srv/Cargo.toml +++ b/crates/proc_macro_srv/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] } | 13 | object = { version = "0.24", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] } |
14 | libloading = "0.7.0" | 14 | libloading = "0.7.0" |
15 | memmap2 = "0.2.0" | 15 | memmap2 = "0.2.0" |
16 | 16 | ||
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs index baf10fea9..cccc53220 100644 --- a/crates/proc_macro_srv/src/dylib.rs +++ b/crates/proc_macro_srv/src/dylib.rs | |||
@@ -27,7 +27,7 @@ fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> { | |||
27 | let file = File::open(file)?; | 27 | let file = File::open(file)?; |
28 | let buffer = unsafe { Mmap::map(&file)? }; | 28 | let buffer = unsafe { Mmap::map(&file)? }; |
29 | 29 | ||
30 | Ok(object::File::parse(&buffer) | 30 | Ok(object::File::parse(&*buffer) |
31 | .map_err(invalid_data_err)? | 31 | .map_err(invalid_data_err)? |
32 | .exports() | 32 | .exports() |
33 | .map_err(invalid_data_err)? | 33 | .map_err(invalid_data_err)? |
diff --git a/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt b/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt index fa581f110..eb67c7134 100644 --- a/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt +++ b/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt | |||
@@ -23,7 +23,7 @@ SUBTREE $ | |||
23 | SUBTREE [] 4294967295 | 23 | SUBTREE [] 4294967295 |
24 | IDENT allow 4294967295 | 24 | IDENT allow 4294967295 |
25 | SUBTREE () 4294967295 | 25 | SUBTREE () 4294967295 |
26 | IDENT rust_2018_idioms 4294967295 | 26 | IDENT unused_extern_crates 4294967295 |
27 | PUNCH , [alone] 4294967295 | 27 | PUNCH , [alone] 4294967295 |
28 | IDENT clippy 4294967295 | 28 | IDENT clippy 4294967295 |
29 | PUNCH : [joint] 4294967295 | 29 | PUNCH : [joint] 4294967295 |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index ad705c752..a8fee4f08 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -121,7 +121,7 @@ pub struct PackageDependency { | |||
121 | pub kind: DepKind, | 121 | pub kind: DepKind, |
122 | } | 122 | } |
123 | 123 | ||
124 | #[derive(Debug, Clone, Eq, PartialEq)] | 124 | #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] |
125 | pub enum DepKind { | 125 | pub enum DepKind { |
126 | /// Available to the library, binary, and dev targets in the package (but not the build script). | 126 | /// Available to the library, binary, and dev targets in the package (but not the build script). |
127 | Normal, | 127 | Normal, |
@@ -132,17 +132,23 @@ pub enum DepKind { | |||
132 | } | 132 | } |
133 | 133 | ||
134 | impl DepKind { | 134 | impl DepKind { |
135 | fn new(list: &[cargo_metadata::DepKindInfo]) -> Self { | 135 | fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ { |
136 | let mut dep_kinds = Vec::new(); | ||
137 | if list.is_empty() { | ||
138 | dep_kinds.push(Self::Normal); | ||
139 | } | ||
136 | for info in list { | 140 | for info in list { |
137 | match info.kind { | 141 | let kind = match info.kind { |
138 | cargo_metadata::DependencyKind::Normal => return Self::Normal, | 142 | cargo_metadata::DependencyKind::Normal => Self::Normal, |
139 | cargo_metadata::DependencyKind::Development => return Self::Dev, | 143 | cargo_metadata::DependencyKind::Development => Self::Dev, |
140 | cargo_metadata::DependencyKind::Build => return Self::Build, | 144 | cargo_metadata::DependencyKind::Build => Self::Build, |
141 | cargo_metadata::DependencyKind::Unknown => continue, | 145 | cargo_metadata::DependencyKind::Unknown => continue, |
142 | } | 146 | }; |
147 | dep_kinds.push(kind); | ||
143 | } | 148 | } |
144 | 149 | dep_kinds.sort_unstable(); | |
145 | Self::Normal | 150 | dep_kinds.dedup(); |
151 | dep_kinds.into_iter() | ||
146 | } | 152 | } |
147 | } | 153 | } |
148 | 154 | ||
@@ -317,7 +323,11 @@ impl CargoWorkspace { | |||
317 | } | 323 | } |
318 | }; | 324 | }; |
319 | node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg)); | 325 | node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg)); |
320 | for dep_node in node.deps { | 326 | for (dep_node, kind) in node |
327 | .deps | ||
328 | .iter() | ||
329 | .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind))) | ||
330 | { | ||
321 | let pkg = match pkg_by_id.get(&dep_node.pkg) { | 331 | let pkg = match pkg_by_id.get(&dep_node.pkg) { |
322 | Some(&pkg) => pkg, | 332 | Some(&pkg) => pkg, |
323 | None => { | 333 | None => { |
@@ -328,11 +338,7 @@ impl CargoWorkspace { | |||
328 | continue; | 338 | continue; |
329 | } | 339 | } |
330 | }; | 340 | }; |
331 | let dep = PackageDependency { | 341 | let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind }; |
332 | name: dep_node.name, | ||
333 | pkg, | ||
334 | kind: DepKind::new(&dep_node.dep_kinds), | ||
335 | }; | ||
336 | packages[source].dependencies.push(dep); | 342 | packages[source].dependencies.push(dep); |
337 | } | 343 | } |
338 | packages[source].active_features.extend(node.features); | 344 | packages[source].active_features.extend(node.features); |
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index 3b0ff506d..4e39d6dd3 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -50,7 +50,9 @@ impl Sysroot { | |||
50 | 50 | ||
51 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { | 51 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { |
52 | log::debug!("Discovering sysroot for {}", cargo_toml.display()); | 52 | log::debug!("Discovering sysroot for {}", cargo_toml.display()); |
53 | let current_dir = cargo_toml.parent().unwrap(); | 53 | let current_dir = cargo_toml.parent().ok_or_else(|| { |
54 | format_err!("Failed to find the parent directory for {}", cargo_toml.display()) | ||
55 | })?; | ||
54 | let sysroot_dir = discover_sysroot_dir(current_dir)?; | 56 | let sysroot_dir = discover_sysroot_dir(current_dir)?; |
55 | let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, current_dir)?; | 57 | let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, current_dir)?; |
56 | let res = Sysroot::load(&sysroot_src_dir)?; | 58 | let res = Sysroot::load(&sysroot_src_dir)?; |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 607e62ea5..84990075f 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; | 5 | use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; |
6 | 6 | ||
7 | use anyhow::{Context, Result}; | 7 | use anyhow::{format_err, Context, Result}; |
8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; | 8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; |
9 | use cargo_workspace::DepKind; | 9 | use cargo_workspace::DepKind; |
10 | use cfg::CfgOptions; | 10 | use cfg::CfgOptions; |
@@ -49,6 +49,18 @@ pub enum ProjectWorkspace { | |||
49 | }, | 49 | }, |
50 | /// Project workspace was manually specified using a `rust-project.json` file. | 50 | /// Project workspace was manually specified using a `rust-project.json` file. |
51 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, | 51 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, |
52 | |||
53 | // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning. | ||
54 | // That's not the end user experience we should strive for. | ||
55 | // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working. | ||
56 | // That needs some changes on the salsa-level though. | ||
57 | // In particular, we should split the unified CrateGraph (which currently has maximal durability) into proper crate graph, and a set of ad hoc roots (with minimal durability). | ||
58 | // Then, we need to hide the graph behind the queries such that most queries look only at the proper crate graph, and fall back to ad hoc roots only if there's no results. | ||
59 | // After this, we should be able to tweak the logic in reload.rs to add newly opened files, which don't belong to any existing crates, to the set of the detached files. | ||
60 | // // | ||
61 | /// Project with a set of disjoint files, not belonging to any particular workspace. | ||
62 | /// Backed by basic sysroot crates for basic completion and highlighting. | ||
63 | DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Sysroot, rustc_cfg: Vec<CfgFlag> }, | ||
52 | } | 64 | } |
53 | 65 | ||
54 | impl fmt::Debug for ProjectWorkspace { | 66 | impl fmt::Debug for ProjectWorkspace { |
@@ -75,6 +87,12 @@ impl fmt::Debug for ProjectWorkspace { | |||
75 | debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); | 87 | debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); |
76 | debug_struct.finish() | 88 | debug_struct.finish() |
77 | } | 89 | } |
90 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f | ||
91 | .debug_struct("DetachedFiles") | ||
92 | .field("n_files", &files.len()) | ||
93 | .field("n_sysroot_crates", &sysroot.crates().len()) | ||
94 | .field("n_rustc_cfg", &rustc_cfg.len()) | ||
95 | .finish(), | ||
78 | } | 96 | } |
79 | } | 97 | } |
80 | } | 98 | } |
@@ -165,6 +183,14 @@ impl ProjectWorkspace { | |||
165 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) | 183 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) |
166 | } | 184 | } |
167 | 185 | ||
186 | pub fn load_detached_files(detached_files: Vec<AbsPathBuf>) -> Result<ProjectWorkspace> { | ||
187 | let sysroot = Sysroot::discover( | ||
188 | &detached_files.first().ok_or_else(|| format_err!("No detached files to load"))?, | ||
189 | )?; | ||
190 | let rustc_cfg = rustc_cfg::get(None, None); | ||
191 | Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg }) | ||
192 | } | ||
193 | |||
168 | /// Returns the roots for the current `ProjectWorkspace` | 194 | /// Returns the roots for the current `ProjectWorkspace` |
169 | /// The return type contains the path and whether or not | 195 | /// The return type contains the path and whether or not |
170 | /// the root is a member of the current workspace | 196 | /// the root is a member of the current workspace |
@@ -224,6 +250,19 @@ impl ProjectWorkspace { | |||
224 | }) | 250 | }) |
225 | })) | 251 | })) |
226 | .collect(), | 252 | .collect(), |
253 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files | ||
254 | .into_iter() | ||
255 | .map(|detached_file| PackageRoot { | ||
256 | is_member: true, | ||
257 | include: vec![detached_file.clone()], | ||
258 | exclude: Vec::new(), | ||
259 | }) | ||
260 | .chain(sysroot.crates().map(|krate| PackageRoot { | ||
261 | is_member: false, | ||
262 | include: vec![sysroot[krate].root_dir().to_path_buf()], | ||
263 | exclude: Vec::new(), | ||
264 | })) | ||
265 | .collect(), | ||
227 | } | 266 | } |
228 | } | 267 | } |
229 | 268 | ||
@@ -234,6 +273,9 @@ impl ProjectWorkspace { | |||
234 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); | 273 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); |
235 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len | 274 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len |
236 | } | 275 | } |
276 | ProjectWorkspace::DetachedFiles { sysroot, files, .. } => { | ||
277 | sysroot.crates().len() + files.len() | ||
278 | } | ||
237 | } | 279 | } |
238 | } | 280 | } |
239 | 281 | ||
@@ -267,6 +309,9 @@ impl ProjectWorkspace { | |||
267 | rustc, | 309 | rustc, |
268 | rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), | 310 | rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), |
269 | ), | 311 | ), |
312 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { | ||
313 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) | ||
314 | } | ||
270 | }; | 315 | }; |
271 | if crate_graph.patch_cfg_if() { | 316 | if crate_graph.patch_cfg_if() { |
272 | log::debug!("Patched std to depend on cfg-if") | 317 | log::debug!("Patched std to depend on cfg-if") |
@@ -474,6 +519,48 @@ fn cargo_to_crate_graph( | |||
474 | crate_graph | 519 | crate_graph |
475 | } | 520 | } |
476 | 521 | ||
522 | fn detached_files_to_crate_graph( | ||
523 | rustc_cfg: Vec<CfgFlag>, | ||
524 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | ||
525 | detached_files: &[AbsPathBuf], | ||
526 | sysroot: &Sysroot, | ||
527 | ) -> CrateGraph { | ||
528 | let _p = profile::span("detached_files_to_crate_graph"); | ||
529 | let mut crate_graph = CrateGraph::default(); | ||
530 | let (public_deps, _libproc_macro) = | ||
531 | sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); | ||
532 | |||
533 | let mut cfg_options = CfgOptions::default(); | ||
534 | cfg_options.extend(rustc_cfg); | ||
535 | |||
536 | for detached_file in detached_files { | ||
537 | let file_id = match load(&detached_file) { | ||
538 | Some(file_id) => file_id, | ||
539 | None => { | ||
540 | log::error!("Failed to load detached file {:?}", detached_file); | ||
541 | continue; | ||
542 | } | ||
543 | }; | ||
544 | let display_name = detached_file | ||
545 | .file_stem() | ||
546 | .and_then(|os_str| os_str.to_str()) | ||
547 | .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string())); | ||
548 | let detached_file_crate = crate_graph.add_crate_root( | ||
549 | file_id, | ||
550 | Edition::Edition2018, | ||
551 | display_name, | ||
552 | cfg_options.clone(), | ||
553 | Env::default(), | ||
554 | Vec::new(), | ||
555 | ); | ||
556 | |||
557 | for (name, krate) in public_deps.iter() { | ||
558 | add_dep(&mut crate_graph, detached_file_crate, name.clone(), *krate); | ||
559 | } | ||
560 | } | ||
561 | crate_graph | ||
562 | } | ||
563 | |||
477 | fn handle_rustc_crates( | 564 | fn handle_rustc_crates( |
478 | rustc_workspace: &CargoWorkspace, | 565 | rustc_workspace: &CargoWorkspace, |
479 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 566 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index f0abb5b15..6c883dd58 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -199,7 +199,7 @@ fn run_server() -> Result<()> { | |||
199 | config.update(json); | 199 | config.update(json); |
200 | } | 200 | } |
201 | 201 | ||
202 | if config.linked_projects().is_empty() { | 202 | if config.linked_projects().is_empty() && config.detached_files().is_empty() { |
203 | let workspace_roots = initialize_params | 203 | let workspace_roots = initialize_params |
204 | .workspace_folders | 204 | .workspace_folders |
205 | .map(|workspaces| { | 205 | .map(|workspaces| { |
@@ -217,7 +217,6 @@ fn run_server() -> Result<()> { | |||
217 | if discovered.is_empty() { | 217 | if discovered.is_empty() { |
218 | log::error!("failed to find any projects in {:?}", workspace_roots); | 218 | log::error!("failed to find any projects in {:?}", workspace_roots); |
219 | } | 219 | } |
220 | |||
221 | config.discovered_projects = Some(discovered); | 220 | config.discovered_projects = Some(discovered); |
222 | } | 221 | } |
223 | 222 | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 2e99db36c..7620a2fe1 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -240,6 +240,7 @@ impl Default for ConfigData { | |||
240 | pub struct Config { | 240 | pub struct Config { |
241 | caps: lsp_types::ClientCapabilities, | 241 | caps: lsp_types::ClientCapabilities, |
242 | data: ConfigData, | 242 | data: ConfigData, |
243 | detached_files: Vec<AbsPathBuf>, | ||
243 | pub discovered_projects: Option<Vec<ProjectManifest>>, | 244 | pub discovered_projects: Option<Vec<ProjectManifest>>, |
244 | pub root_path: AbsPathBuf, | 245 | pub root_path: AbsPathBuf, |
245 | } | 246 | } |
@@ -332,13 +333,23 @@ pub struct WorkspaceSymbolConfig { | |||
332 | 333 | ||
333 | impl Config { | 334 | impl Config { |
334 | pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { | 335 | pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { |
335 | Config { caps, data: ConfigData::default(), discovered_projects: None, root_path } | 336 | Config { |
337 | caps, | ||
338 | data: ConfigData::default(), | ||
339 | detached_files: Vec::new(), | ||
340 | discovered_projects: None, | ||
341 | root_path, | ||
342 | } | ||
336 | } | 343 | } |
337 | pub fn update(&mut self, json: serde_json::Value) { | 344 | pub fn update(&mut self, mut json: serde_json::Value) { |
338 | log::info!("updating config from JSON: {:#}", json); | 345 | log::info!("updating config from JSON: {:#}", json); |
339 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 346 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
340 | return; | 347 | return; |
341 | } | 348 | } |
349 | self.detached_files = get_field::<Vec<PathBuf>>(&mut json, "detachedFiles", None, "[]") | ||
350 | .into_iter() | ||
351 | .map(AbsPathBuf::assert) | ||
352 | .collect(); | ||
342 | self.data = ConfigData::from_json(json); | 353 | self.data = ConfigData::from_json(json); |
343 | } | 354 | } |
344 | 355 | ||
@@ -391,6 +402,10 @@ impl Config { | |||
391 | } | 402 | } |
392 | } | 403 | } |
393 | 404 | ||
405 | pub fn detached_files(&self) -> &[AbsPathBuf] { | ||
406 | &self.detached_files | ||
407 | } | ||
408 | |||
394 | pub fn did_save_text_document_dynamic_registration(&self) -> bool { | 409 | pub fn did_save_text_document_dynamic_registration(&self) -> bool { |
395 | let caps = | 410 | let caps = |
396 | try_or!(self.caps.text_document.as_ref()?.synchronization.clone()?, Default::default()); | 411 | try_or!(self.caps.text_document.as_ref()?.synchronization.clone()?, Default::default()); |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt index 227d96d51..bcc889681 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -33,6 +34,7 @@ | |||
33 | CodeDescription { | 34 | CodeDescription { |
34 | href: Url { | 35 | href: Url { |
35 | scheme: "https", | 36 | scheme: "https", |
37 | cannot_be_a_base: false, | ||
36 | username: "", | 38 | username: "", |
37 | password: None, | 39 | password: None, |
38 | host: Some( | 40 | host: Some( |
@@ -59,6 +61,7 @@ | |||
59 | location: Location { | 61 | location: Location { |
60 | uri: Url { | 62 | uri: Url { |
61 | scheme: "file", | 63 | scheme: "file", |
64 | cannot_be_a_base: false, | ||
62 | username: "", | 65 | username: "", |
63 | password: None, | 66 | password: None, |
64 | host: None, | 67 | host: None, |
@@ -84,6 +87,7 @@ | |||
84 | location: Location { | 87 | location: Location { |
85 | uri: Url { | 88 | uri: Url { |
86 | scheme: "file", | 89 | scheme: "file", |
90 | cannot_be_a_base: false, | ||
87 | username: "", | 91 | username: "", |
88 | password: None, | 92 | password: None, |
89 | host: None, | 93 | host: None, |
@@ -115,6 +119,7 @@ | |||
115 | MappedRustDiagnostic { | 119 | MappedRustDiagnostic { |
116 | url: Url { | 120 | url: Url { |
117 | scheme: "file", | 121 | scheme: "file", |
122 | cannot_be_a_base: false, | ||
118 | username: "", | 123 | username: "", |
119 | password: None, | 124 | password: None, |
120 | host: None, | 125 | host: None, |
@@ -146,6 +151,7 @@ | |||
146 | CodeDescription { | 151 | CodeDescription { |
147 | href: Url { | 152 | href: Url { |
148 | scheme: "https", | 153 | scheme: "https", |
154 | cannot_be_a_base: false, | ||
149 | username: "", | 155 | username: "", |
150 | password: None, | 156 | password: None, |
151 | host: Some( | 157 | host: Some( |
@@ -172,6 +178,7 @@ | |||
172 | location: Location { | 178 | location: Location { |
173 | uri: Url { | 179 | uri: Url { |
174 | scheme: "file", | 180 | scheme: "file", |
181 | cannot_be_a_base: false, | ||
175 | username: "", | 182 | username: "", |
176 | password: None, | 183 | password: None, |
177 | host: None, | 184 | host: None, |
@@ -203,6 +210,7 @@ | |||
203 | MappedRustDiagnostic { | 210 | MappedRustDiagnostic { |
204 | url: Url { | 211 | url: Url { |
205 | scheme: "file", | 212 | scheme: "file", |
213 | cannot_be_a_base: false, | ||
206 | username: "", | 214 | username: "", |
207 | password: None, | 215 | password: None, |
208 | host: None, | 216 | host: None, |
@@ -234,6 +242,7 @@ | |||
234 | CodeDescription { | 242 | CodeDescription { |
235 | href: Url { | 243 | href: Url { |
236 | scheme: "https", | 244 | scheme: "https", |
245 | cannot_be_a_base: false, | ||
237 | username: "", | 246 | username: "", |
238 | password: None, | 247 | password: None, |
239 | host: Some( | 248 | host: Some( |
@@ -260,6 +269,7 @@ | |||
260 | location: Location { | 269 | location: Location { |
261 | uri: Url { | 270 | uri: Url { |
262 | scheme: "file", | 271 | scheme: "file", |
272 | cannot_be_a_base: false, | ||
263 | username: "", | 273 | username: "", |
264 | password: None, | 274 | password: None, |
265 | host: None, | 275 | host: None, |
@@ -301,6 +311,7 @@ | |||
301 | { | 311 | { |
302 | Url { | 312 | Url { |
303 | scheme: "file", | 313 | scheme: "file", |
314 | cannot_be_a_base: false, | ||
304 | username: "", | 315 | username: "", |
305 | password: None, | 316 | password: None, |
306 | host: None, | 317 | host: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt index e5f01fb33..d5ab03576 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -33,6 +34,7 @@ | |||
33 | CodeDescription { | 34 | CodeDescription { |
34 | href: Url { | 35 | href: Url { |
35 | scheme: "https", | 36 | scheme: "https", |
37 | cannot_be_a_base: false, | ||
36 | username: "", | 38 | username: "", |
37 | password: None, | 39 | password: None, |
38 | host: Some( | 40 | host: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt index c847bbb35..8bee4cfe1 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -36,6 +37,7 @@ | |||
36 | location: Location { | 37 | location: Location { |
37 | uri: Url { | 38 | uri: Url { |
38 | scheme: "file", | 39 | scheme: "file", |
40 | cannot_be_a_base: false, | ||
39 | username: "", | 41 | username: "", |
40 | password: None, | 42 | password: None, |
41 | host: None, | 43 | host: None, |
@@ -67,6 +69,7 @@ | |||
67 | MappedRustDiagnostic { | 69 | MappedRustDiagnostic { |
68 | url: Url { | 70 | url: Url { |
69 | scheme: "file", | 71 | scheme: "file", |
72 | cannot_be_a_base: false, | ||
70 | username: "", | 73 | username: "", |
71 | password: None, | 74 | password: None, |
72 | host: None, | 75 | host: None, |
@@ -101,6 +104,7 @@ | |||
101 | location: Location { | 104 | location: Location { |
102 | uri: Url { | 105 | uri: Url { |
103 | scheme: "file", | 106 | scheme: "file", |
107 | cannot_be_a_base: false, | ||
104 | username: "", | 108 | username: "", |
105 | password: None, | 109 | password: None, |
106 | host: None, | 110 | host: None, |
@@ -132,6 +136,7 @@ | |||
132 | MappedRustDiagnostic { | 136 | MappedRustDiagnostic { |
133 | url: Url { | 137 | url: Url { |
134 | scheme: "file", | 138 | scheme: "file", |
139 | cannot_be_a_base: false, | ||
135 | username: "", | 140 | username: "", |
136 | password: None, | 141 | password: None, |
137 | host: None, | 142 | host: None, |
@@ -166,6 +171,7 @@ | |||
166 | location: Location { | 171 | location: Location { |
167 | uri: Url { | 172 | uri: Url { |
168 | scheme: "file", | 173 | scheme: "file", |
174 | cannot_be_a_base: false, | ||
169 | username: "", | 175 | username: "", |
170 | password: None, | 176 | password: None, |
171 | host: None, | 177 | host: None, |
@@ -191,6 +197,7 @@ | |||
191 | location: Location { | 197 | location: Location { |
192 | uri: Url { | 198 | uri: Url { |
193 | scheme: "file", | 199 | scheme: "file", |
200 | cannot_be_a_base: false, | ||
194 | username: "", | 201 | username: "", |
195 | password: None, | 202 | password: None, |
196 | host: None, | 203 | host: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt index 0d16af232..ada540ea6 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -33,6 +34,7 @@ | |||
33 | CodeDescription { | 34 | CodeDescription { |
34 | href: Url { | 35 | href: Url { |
35 | scheme: "https", | 36 | scheme: "https", |
37 | cannot_be_a_base: false, | ||
36 | username: "", | 38 | username: "", |
37 | password: None, | 39 | password: None, |
38 | host: Some( | 40 | host: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt index 31b6a12ce..05074a914 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -33,6 +34,7 @@ | |||
33 | CodeDescription { | 34 | CodeDescription { |
34 | href: Url { | 35 | href: Url { |
35 | scheme: "https", | 36 | scheme: "https", |
37 | cannot_be_a_base: false, | ||
36 | username: "", | 38 | username: "", |
37 | password: None, | 39 | password: None, |
38 | host: Some( | 40 | host: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index f8adfad3b..749f49438 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -40,6 +41,7 @@ | |||
40 | location: Location { | 41 | location: Location { |
41 | uri: Url { | 42 | uri: Url { |
42 | scheme: "file", | 43 | scheme: "file", |
44 | cannot_be_a_base: false, | ||
43 | username: "", | 45 | username: "", |
44 | password: None, | 46 | password: None, |
45 | host: None, | 47 | host: None, |
@@ -75,6 +77,7 @@ | |||
75 | MappedRustDiagnostic { | 77 | MappedRustDiagnostic { |
76 | url: Url { | 78 | url: Url { |
77 | scheme: "file", | 79 | scheme: "file", |
80 | cannot_be_a_base: false, | ||
78 | username: "", | 81 | username: "", |
79 | password: None, | 82 | password: None, |
80 | host: None, | 83 | host: None, |
@@ -113,6 +116,7 @@ | |||
113 | location: Location { | 116 | location: Location { |
114 | uri: Url { | 117 | uri: Url { |
115 | scheme: "file", | 118 | scheme: "file", |
119 | cannot_be_a_base: false, | ||
116 | username: "", | 120 | username: "", |
117 | password: None, | 121 | password: None, |
118 | host: None, | 122 | host: None, |
@@ -154,6 +158,7 @@ | |||
154 | { | 158 | { |
155 | Url { | 159 | Url { |
156 | scheme: "file", | 160 | scheme: "file", |
161 | cannot_be_a_base: false, | ||
157 | username: "", | 162 | username: "", |
158 | password: None, | 163 | password: None, |
159 | host: None, | 164 | host: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index 5a70d2ed7..d20a91b39 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -40,6 +41,7 @@ | |||
40 | location: Location { | 41 | location: Location { |
41 | uri: Url { | 42 | uri: Url { |
42 | scheme: "file", | 43 | scheme: "file", |
44 | cannot_be_a_base: false, | ||
43 | username: "", | 45 | username: "", |
44 | password: None, | 46 | password: None, |
45 | host: None, | 47 | host: None, |
@@ -75,6 +77,7 @@ | |||
75 | MappedRustDiagnostic { | 77 | MappedRustDiagnostic { |
76 | url: Url { | 78 | url: Url { |
77 | scheme: "file", | 79 | scheme: "file", |
80 | cannot_be_a_base: false, | ||
78 | username: "", | 81 | username: "", |
79 | password: None, | 82 | password: None, |
80 | host: None, | 83 | host: None, |
@@ -113,6 +116,7 @@ | |||
113 | location: Location { | 116 | location: Location { |
114 | uri: Url { | 117 | uri: Url { |
115 | scheme: "file", | 118 | scheme: "file", |
119 | cannot_be_a_base: false, | ||
116 | username: "", | 120 | username: "", |
117 | password: None, | 121 | password: None, |
118 | host: None, | 122 | host: None, |
@@ -154,6 +158,7 @@ | |||
154 | { | 158 | { |
155 | Url { | 159 | Url { |
156 | scheme: "file", | 160 | scheme: "file", |
161 | cannot_be_a_base: false, | ||
157 | username: "", | 162 | username: "", |
158 | password: None, | 163 | password: None, |
159 | host: None, | 164 | host: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index 04ca0c9c2..2a9c3a9af 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -40,6 +41,7 @@ | |||
40 | location: Location { | 41 | location: Location { |
41 | uri: Url { | 42 | uri: Url { |
42 | scheme: "file", | 43 | scheme: "file", |
44 | cannot_be_a_base: false, | ||
43 | username: "", | 45 | username: "", |
44 | password: None, | 46 | password: None, |
45 | host: None, | 47 | host: None, |
@@ -75,6 +77,7 @@ | |||
75 | MappedRustDiagnostic { | 77 | MappedRustDiagnostic { |
76 | url: Url { | 78 | url: Url { |
77 | scheme: "file", | 79 | scheme: "file", |
80 | cannot_be_a_base: false, | ||
78 | username: "", | 81 | username: "", |
79 | password: None, | 82 | password: None, |
80 | host: None, | 83 | host: None, |
@@ -113,6 +116,7 @@ | |||
113 | location: Location { | 116 | location: Location { |
114 | uri: Url { | 117 | uri: Url { |
115 | scheme: "file", | 118 | scheme: "file", |
119 | cannot_be_a_base: false, | ||
116 | username: "", | 120 | username: "", |
117 | password: None, | 121 | password: None, |
118 | host: None, | 122 | host: None, |
@@ -154,6 +158,7 @@ | |||
154 | { | 158 | { |
155 | Url { | 159 | Url { |
156 | scheme: "file", | 160 | scheme: "file", |
161 | cannot_be_a_base: false, | ||
157 | username: "", | 162 | username: "", |
158 | password: None, | 163 | password: None, |
159 | host: None, | 164 | host: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt index f7a313cf1..5ea27a152 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -33,6 +34,7 @@ | |||
33 | CodeDescription { | 34 | CodeDescription { |
34 | href: Url { | 35 | href: Url { |
35 | scheme: "https", | 36 | scheme: "https", |
37 | cannot_be_a_base: false, | ||
36 | username: "", | 38 | username: "", |
37 | password: None, | 39 | password: None, |
38 | host: Some( | 40 | host: Some( |
@@ -59,6 +61,7 @@ | |||
59 | location: Location { | 61 | location: Location { |
60 | uri: Url { | 62 | uri: Url { |
61 | scheme: "file", | 63 | scheme: "file", |
64 | cannot_be_a_base: false, | ||
62 | username: "", | 65 | username: "", |
63 | password: None, | 66 | password: None, |
64 | host: None, | 67 | host: None, |
@@ -90,6 +93,7 @@ | |||
90 | MappedRustDiagnostic { | 93 | MappedRustDiagnostic { |
91 | url: Url { | 94 | url: Url { |
92 | scheme: "file", | 95 | scheme: "file", |
96 | cannot_be_a_base: false, | ||
93 | username: "", | 97 | username: "", |
94 | password: None, | 98 | password: None, |
95 | host: None, | 99 | host: None, |
@@ -121,6 +125,7 @@ | |||
121 | CodeDescription { | 125 | CodeDescription { |
122 | href: Url { | 126 | href: Url { |
123 | scheme: "https", | 127 | scheme: "https", |
128 | cannot_be_a_base: false, | ||
124 | username: "", | 129 | username: "", |
125 | password: None, | 130 | password: None, |
126 | host: Some( | 131 | host: Some( |
@@ -147,6 +152,7 @@ | |||
147 | location: Location { | 152 | location: Location { |
148 | uri: Url { | 153 | uri: Url { |
149 | scheme: "file", | 154 | scheme: "file", |
155 | cannot_be_a_base: false, | ||
150 | username: "", | 156 | username: "", |
151 | password: None, | 157 | password: None, |
152 | host: None, | 158 | host: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index 57d2f1ae3..43b1ea765 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt | |||
@@ -2,6 +2,7 @@ | |||
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: Url { | 3 | url: Url { |
4 | scheme: "file", | 4 | scheme: "file", |
5 | cannot_be_a_base: false, | ||
5 | username: "", | 6 | username: "", |
6 | password: None, | 7 | password: None, |
7 | host: None, | 8 | host: None, |
@@ -33,6 +34,7 @@ | |||
33 | CodeDescription { | 34 | CodeDescription { |
34 | href: Url { | 35 | href: Url { |
35 | scheme: "https", | 36 | scheme: "https", |
37 | cannot_be_a_base: false, | ||
36 | username: "", | 38 | username: "", |
37 | password: None, | 39 | password: None, |
38 | host: Some( | 40 | host: Some( |
@@ -59,6 +61,7 @@ | |||
59 | location: Location { | 61 | location: Location { |
60 | uri: Url { | 62 | uri: Url { |
61 | scheme: "file", | 63 | scheme: "file", |
64 | cannot_be_a_base: false, | ||
62 | username: "", | 65 | username: "", |
63 | password: None, | 66 | password: None, |
64 | host: None, | 67 | host: None, |
@@ -84,6 +87,7 @@ | |||
84 | location: Location { | 87 | location: Location { |
85 | uri: Url { | 88 | uri: Url { |
86 | scheme: "file", | 89 | scheme: "file", |
90 | cannot_be_a_base: false, | ||
87 | username: "", | 91 | username: "", |
88 | password: None, | 92 | password: None, |
89 | host: None, | 93 | host: None, |
@@ -115,6 +119,7 @@ | |||
115 | MappedRustDiagnostic { | 119 | MappedRustDiagnostic { |
116 | url: Url { | 120 | url: Url { |
117 | scheme: "file", | 121 | scheme: "file", |
122 | cannot_be_a_base: false, | ||
118 | username: "", | 123 | username: "", |
119 | password: None, | 124 | password: None, |
120 | host: None, | 125 | host: None, |
@@ -146,6 +151,7 @@ | |||
146 | CodeDescription { | 151 | CodeDescription { |
147 | href: Url { | 152 | href: Url { |
148 | scheme: "https", | 153 | scheme: "https", |
154 | cannot_be_a_base: false, | ||
149 | username: "", | 155 | username: "", |
150 | password: None, | 156 | password: None, |
151 | host: Some( | 157 | host: Some( |
@@ -172,6 +178,7 @@ | |||
172 | location: Location { | 178 | location: Location { |
173 | uri: Url { | 179 | uri: Url { |
174 | scheme: "file", | 180 | scheme: "file", |
181 | cannot_be_a_base: false, | ||
175 | username: "", | 182 | username: "", |
176 | password: None, | 183 | password: None, |
177 | host: None, | 184 | host: None, |
@@ -203,6 +210,7 @@ | |||
203 | MappedRustDiagnostic { | 210 | MappedRustDiagnostic { |
204 | url: Url { | 211 | url: Url { |
205 | scheme: "file", | 212 | scheme: "file", |
213 | cannot_be_a_base: false, | ||
206 | username: "", | 214 | username: "", |
207 | password: None, | 215 | password: None, |
208 | host: None, | 216 | host: None, |
@@ -234,6 +242,7 @@ | |||
234 | CodeDescription { | 242 | CodeDescription { |
235 | href: Url { | 243 | href: Url { |
236 | scheme: "https", | 244 | scheme: "https", |
245 | cannot_be_a_base: false, | ||
237 | username: "", | 246 | username: "", |
238 | password: None, | 247 | password: None, |
239 | host: Some( | 248 | host: Some( |
@@ -260,6 +269,7 @@ | |||
260 | location: Location { | 269 | location: Location { |
261 | uri: Url { | 270 | uri: Url { |
262 | scheme: "file", | 271 | scheme: "file", |
272 | cannot_be_a_base: false, | ||
263 | username: "", | 273 | username: "", |
264 | password: None, | 274 | password: None, |
265 | host: None, | 275 | host: None, |
@@ -301,6 +311,7 @@ | |||
301 | { | 311 | { |
302 | Url { | 312 | Url { |
303 | scheme: "file", | 313 | scheme: "file", |
314 | cannot_be_a_base: false, | ||
304 | username: "", | 315 | username: "", |
305 | password: None, | 316 | password: None, |
306 | host: None, | 317 | host: None, |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 6f2f482c1..6a36d29d4 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -312,6 +312,7 @@ impl GlobalStateSnapshot { | |||
312 | cargo.target_by_root(&path).map(|it| (cargo, it)) | 312 | cargo.target_by_root(&path).map(|it| (cargo, it)) |
313 | } | 313 | } |
314 | ProjectWorkspace::Json { .. } => None, | 314 | ProjectWorkspace::Json { .. } => None, |
315 | ProjectWorkspace::DetachedFiles { .. } => None, | ||
315 | }) | 316 | }) |
316 | } | 317 | } |
317 | } | 318 | } |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 53161eb3e..456744603 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -661,19 +661,28 @@ pub(crate) fn handle_runnables( | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | None => { | 663 | None => { |
664 | res.push(lsp_ext::Runnable { | 664 | if !snap.config.linked_projects().is_empty() |
665 | label: "cargo check --workspace".to_string(), | 665 | || !snap |
666 | location: None, | 666 | .config |
667 | kind: lsp_ext::RunnableKind::Cargo, | 667 | .discovered_projects |
668 | args: lsp_ext::CargoRunnable { | 668 | .as_ref() |
669 | workspace_root: None, | 669 | .map(|projects| projects.is_empty()) |
670 | override_cargo: config.override_cargo, | 670 | .unwrap_or(true) |
671 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], | 671 | { |
672 | cargo_extra_args: config.cargo_extra_args, | 672 | res.push(lsp_ext::Runnable { |
673 | executable_args: Vec::new(), | 673 | label: "cargo check --workspace".to_string(), |
674 | expect_test: None, | 674 | location: None, |
675 | }, | 675 | kind: lsp_ext::RunnableKind::Cargo, |
676 | }); | 676 | args: lsp_ext::CargoRunnable { |
677 | workspace_root: None, | ||
678 | override_cargo: config.override_cargo, | ||
679 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], | ||
680 | cargo_extra_args: config.cargo_extra_args, | ||
681 | executable_args: Vec::new(), | ||
682 | expect_test: None, | ||
683 | }, | ||
684 | }); | ||
685 | } | ||
677 | } | 686 | } |
678 | } | 687 | } |
679 | Ok(res) | 688 | Ok(res) |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index e202da621..008758ea0 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -103,6 +103,7 @@ impl fmt::Debug for Event { | |||
103 | impl GlobalState { | 103 | impl GlobalState { |
104 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { | 104 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { |
105 | if self.config.linked_projects().is_empty() | 105 | if self.config.linked_projects().is_empty() |
106 | && self.config.detached_files().is_empty() | ||
106 | && self.config.notifications().cargo_toml_not_found | 107 | && self.config.notifications().cargo_toml_not_found |
107 | { | 108 | { |
108 | self.show_message( | 109 | self.show_message( |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 0ae2758cc..7a53e4a8b 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -147,6 +147,7 @@ impl GlobalState { | |||
147 | 147 | ||
148 | self.task_pool.handle.spawn_with_sender({ | 148 | self.task_pool.handle.spawn_with_sender({ |
149 | let linked_projects = self.config.linked_projects(); | 149 | let linked_projects = self.config.linked_projects(); |
150 | let detached_files = self.config.detached_files().to_vec(); | ||
150 | let cargo_config = self.config.cargo(); | 151 | let cargo_config = self.config.cargo(); |
151 | 152 | ||
152 | move |sender| { | 153 | move |sender| { |
@@ -161,7 +162,7 @@ impl GlobalState { | |||
161 | 162 | ||
162 | sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap(); | 163 | sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap(); |
163 | 164 | ||
164 | let workspaces = linked_projects | 165 | let mut workspaces = linked_projects |
165 | .iter() | 166 | .iter() |
166 | .map(|project| match project { | 167 | .map(|project| match project { |
167 | LinkedProject::ProjectManifest(manifest) => { | 168 | LinkedProject::ProjectManifest(manifest) => { |
@@ -180,6 +181,11 @@ impl GlobalState { | |||
180 | }) | 181 | }) |
181 | .collect::<Vec<_>>(); | 182 | .collect::<Vec<_>>(); |
182 | 183 | ||
184 | if !detached_files.is_empty() { | ||
185 | workspaces | ||
186 | .push(project_model::ProjectWorkspace::load_detached_files(detached_files)); | ||
187 | } | ||
188 | |||
183 | log::info!("did fetch workspaces {:?}", workspaces); | 189 | log::info!("did fetch workspaces {:?}", workspaces); |
184 | sender | 190 | sender |
185 | .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces))) | 191 | .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces))) |
@@ -407,6 +413,7 @@ impl GlobalState { | |||
407 | _ => None, | 413 | _ => None, |
408 | } | 414 | } |
409 | } | 415 | } |
416 | ProjectWorkspace::DetachedFiles { .. } => None, | ||
410 | }) | 417 | }) |
411 | .map(|(id, root)| { | 418 | .map(|(id, root)| { |
412 | let sender = sender.clone(); | 419 | let sender = sender.clone(); |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 4fd576adb..6129af95f 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -92,6 +92,7 @@ define_semantic_token_modifiers![ | |||
92 | (MUTABLE, "mutable"), | 92 | (MUTABLE, "mutable"), |
93 | (CONSUMING, "consuming"), | 93 | (CONSUMING, "consuming"), |
94 | (ASYNC, "async"), | 94 | (ASYNC, "async"), |
95 | (LIBRARY, "library"), | ||
95 | (UNSAFE, "unsafe"), | 96 | (UNSAFE, "unsafe"), |
96 | (ATTRIBUTE_MODIFIER, "attribute"), | 97 | (ATTRIBUTE_MODIFIER, "attribute"), |
97 | (TRAIT_MODIFIER, "trait"), | 98 | (TRAIT_MODIFIER, "trait"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 0a3a56773..ca9513928 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -504,6 +504,7 @@ fn semantic_token_type_and_modifiers( | |||
504 | HlMod::Mutable => semantic_tokens::MUTABLE, | 504 | HlMod::Mutable => semantic_tokens::MUTABLE, |
505 | HlMod::Consuming => semantic_tokens::CONSUMING, | 505 | HlMod::Consuming => semantic_tokens::CONSUMING, |
506 | HlMod::Async => semantic_tokens::ASYNC, | 506 | HlMod::Async => semantic_tokens::ASYNC, |
507 | HlMod::Library => semantic_tokens::LIBRARY, | ||
507 | HlMod::Unsafe => semantic_tokens::UNSAFE, | 508 | HlMod::Unsafe => semantic_tokens::UNSAFE, |
508 | HlMod::Callable => semantic_tokens::CALLABLE, | 509 | HlMod::Callable => semantic_tokens::CALLABLE, |
509 | HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, | 510 | HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, |
@@ -604,7 +605,7 @@ pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url { | |||
604 | // Note: lowercasing the `path` itself doesn't help, the `Url::parse` | 605 | // Note: lowercasing the `path` itself doesn't help, the `Url::parse` |
605 | // machinery *also* canonicalizes the drive letter. So, just massage the | 606 | // machinery *also* canonicalizes the drive letter. So, just massage the |
606 | // string in place. | 607 | // string in place. |
607 | let mut url = url.into_string(); | 608 | let mut url: String = url.into(); |
608 | url[driver_letter_range].make_ascii_lowercase(); | 609 | url[driver_letter_range].make_ascii_lowercase(); |
609 | lsp_types::Url::parse(&url).unwrap() | 610 | lsp_types::Url::parse(&url).unwrap() |
610 | } | 611 | } |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 747f0b9eb..a6c294245 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -14,7 +14,7 @@ doctest = false | |||
14 | cov-mark = { version = "1.1", features = ["thread-local"] } | 14 | cov-mark = { version = "1.1", features = ["thread-local"] } |
15 | itertools = "0.10.0" | 15 | itertools = "0.10.0" |
16 | rowan = "=0.13.0-pre.6" | 16 | rowan = "=0.13.0-pre.6" |
17 | rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" } | 17 | rustc_lexer = { version = "720.0.0", package = "rustc-ap-rustc_lexer" } |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | arrayvec = "0.7" | 19 | arrayvec = "0.7" |
20 | once_cell = "1.3.1" | 20 | once_cell = "1.3.1" |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index ca8103668..f7ee29d14 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -356,13 +356,17 @@ impl ast::MatchArm { | |||
356 | impl ast::MatchArmList { | 356 | impl ast::MatchArmList { |
357 | pub fn add_arm(&self, arm: ast::MatchArm) { | 357 | pub fn add_arm(&self, arm: ast::MatchArm) { |
358 | normalize_ws_between_braces(self.syntax()); | 358 | normalize_ws_between_braces(self.syntax()); |
359 | let mut elements = Vec::new(); | ||
359 | let position = match self.arms().last() { | 360 | let position = match self.arms().last() { |
360 | Some(last_arm) => { | 361 | Some(last_arm) => { |
361 | let curly = last_arm | 362 | let comma = last_arm |
362 | .syntax() | 363 | .syntax() |
363 | .siblings_with_tokens(Direction::Next) | 364 | .siblings_with_tokens(Direction::Next) |
364 | .find(|it| it.kind() == T![,]); | 365 | .find(|it| it.kind() == T![,]); |
365 | Position::after(curly.unwrap_or_else(|| last_arm.syntax().clone().into())) | 366 | if needs_comma(&last_arm) && comma.is_none() { |
367 | elements.push(make::token(SyntaxKind::COMMA).into()); | ||
368 | } | ||
369 | Position::after(comma.unwrap_or_else(|| last_arm.syntax().clone().into())) | ||
366 | } | 370 | } |
367 | None => match self.l_curly_token() { | 371 | None => match self.l_curly_token() { |
368 | Some(it) => Position::after(it), | 372 | Some(it) => Position::after(it), |
@@ -370,11 +374,16 @@ impl ast::MatchArmList { | |||
370 | }, | 374 | }, |
371 | }; | 375 | }; |
372 | let indent = IndentLevel::from_node(self.syntax()) + 1; | 376 | let indent = IndentLevel::from_node(self.syntax()) + 1; |
373 | let elements = vec![ | 377 | elements.push(make::tokens::whitespace(&format!("\n{}", indent)).into()); |
374 | make::tokens::whitespace(&format!("\n{}", indent)).into(), | 378 | elements.push(arm.syntax().clone().into()); |
375 | arm.syntax().clone().into(), | 379 | if needs_comma(&arm) { |
376 | ]; | 380 | elements.push(make::token(SyntaxKind::COMMA).into()); |
381 | } | ||
377 | ted::insert_all(position, elements); | 382 | ted::insert_all(position, elements); |
383 | |||
384 | fn needs_comma(arm: &ast::MatchArm) -> bool { | ||
385 | arm.expr().map_or(false, |e| !e.is_block_like()) | ||
386 | } | ||
378 | } | 387 | } |
379 | } | 388 | } |
380 | 389 | ||