diff options
30 files changed, 450 insertions, 283 deletions
diff --git a/PRIVACY.md b/PRIVACY.md index dd165c0e2..27e39ca60 100644 --- a/PRIVACY.md +++ b/PRIVACY.md | |||
@@ -14,4 +14,4 @@ Any other editor plugins that integrate with `rust-analyzer` are not under the c | |||
14 | 14 | ||
15 | ## Others | 15 | ## Others |
16 | 16 | ||
17 | If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (off by default). | 17 | If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (on by default). |
@@ -33,9 +33,9 @@ For usage and troubleshooting requests, please use "IDEs and Editors" category o | |||
33 | 33 | ||
34 | https://users.rust-lang.org/c/ide/14 | 34 | https://users.rust-lang.org/c/ide/14 |
35 | 35 | ||
36 | For questions about development and implementation, join rls-2.0 working group on Zulip: | 36 | For questions about development and implementation, join rust-analyzer working group on Zulip: |
37 | 37 | ||
38 | https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0 | 38 | https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer |
39 | 39 | ||
40 | ## Quick Links | 40 | ## Quick Links |
41 | 41 | ||
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 8d4641355..04e2be390 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -1,62 +1,4 @@ | |||
1 | //! Fixtures are strings containing rust source code with optional metadata. | 1 | //! A set of high-level utility fixture methods to use in tests. |
2 | //! A fixture without metadata is parsed into a single source file. | ||
3 | //! Use this to test functionality local to one file. | ||
4 | //! | ||
5 | //! Simple Example: | ||
6 | //! ``` | ||
7 | //! r#" | ||
8 | //! fn main() { | ||
9 | //! println!("Hello World") | ||
10 | //! } | ||
11 | //! "# | ||
12 | //! ``` | ||
13 | //! | ||
14 | //! Metadata can be added to a fixture after a `//-` comment. | ||
15 | //! The basic form is specifying filenames, | ||
16 | //! which is also how to define multiple files in a single test fixture | ||
17 | //! | ||
18 | //! Example using two files in the same crate: | ||
19 | //! ``` | ||
20 | //! " | ||
21 | //! //- /main.rs | ||
22 | //! mod foo; | ||
23 | //! fn main() { | ||
24 | //! foo::bar(); | ||
25 | //! } | ||
26 | //! | ||
27 | //! //- /foo.rs | ||
28 | //! pub fn bar() {} | ||
29 | //! " | ||
30 | //! ``` | ||
31 | //! | ||
32 | //! Example using two crates with one file each, with one crate depending on the other: | ||
33 | //! ``` | ||
34 | //! r#" | ||
35 | //! //- /main.rs crate:a deps:b | ||
36 | //! fn main() { | ||
37 | //! b::foo(); | ||
38 | //! } | ||
39 | //! //- /lib.rs crate:b | ||
40 | //! pub fn b() { | ||
41 | //! println!("Hello World") | ||
42 | //! } | ||
43 | //! "# | ||
44 | //! ``` | ||
45 | //! | ||
46 | //! Metadata allows specifying all settings and variables | ||
47 | //! that are available in a real rust project: | ||
48 | //! - crate names via `crate:cratename` | ||
49 | //! - dependencies via `deps:dep1,dep2` | ||
50 | //! - configuration settings via `cfg:dbg=false,opt_level=2` | ||
51 | //! - environment variables via `env:PATH=/bin,RUST_LOG=debug` | ||
52 | //! | ||
53 | //! Example using all available metadata: | ||
54 | //! ``` | ||
55 | //! " | ||
56 | //! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo | ||
57 | //! fn insert_source_code_here() {} | ||
58 | //! " | ||
59 | //! ``` | ||
60 | use std::{mem, str::FromStr, sync::Arc}; | 2 | use std::{mem, str::FromStr, sync::Arc}; |
61 | 3 | ||
62 | use cfg::CfgOptions; | 4 | use cfg::CfgOptions; |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8d00f7401..caa22dace 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -58,9 +58,8 @@ use hir_ty::{ | |||
58 | subst_prefix, | 58 | subst_prefix, |
59 | traits::FnTrait, | 59 | traits::FnTrait, |
60 | AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, | 60 | AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, |
61 | DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, | 61 | DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution, |
62 | SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, | 62 | TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause, |
63 | TyVariableKind, WhereClause, | ||
64 | }; | 63 | }; |
65 | use itertools::Itertools; | 64 | use itertools::Itertools; |
66 | use rustc_hash::FxHashSet; | 65 | use rustc_hash::FxHashSet; |
@@ -1822,8 +1821,9 @@ impl Type { | |||
1822 | ); | 1821 | ); |
1823 | 1822 | ||
1824 | match db.trait_solve(self.krate, goal)? { | 1823 | match db.trait_solve(self.krate, goal)? { |
1825 | Solution::Unique(SolutionVariables(subst)) => subst | 1824 | Solution::Unique(s) => s |
1826 | .value | 1825 | .value |
1826 | .subst | ||
1827 | .interned() | 1827 | .interned() |
1828 | .first() | 1828 | .first() |
1829 | .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())), | 1829 | .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())), |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index c013e78d9..ce6f3c008 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -185,12 +185,16 @@ impl SourceAnalyzer { | |||
185 | 185 | ||
186 | pub(crate) fn resolve_record_pat_field( | 186 | pub(crate) fn resolve_record_pat_field( |
187 | &self, | 187 | &self, |
188 | _db: &dyn HirDatabase, | 188 | db: &dyn HirDatabase, |
189 | field: &ast::RecordPatField, | 189 | field: &ast::RecordPatField, |
190 | ) -> Option<Field> { | 190 | ) -> Option<Field> { |
191 | let pat_id = self.pat_id(&field.pat()?)?; | 191 | let field_name = field.field_name()?.as_name(); |
192 | let struct_field = self.infer.as_ref()?.record_pat_field_resolution(pat_id)?; | 192 | let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; |
193 | Some(struct_field.into()) | 193 | let pat_id = self.pat_id(&record_pat.into())?; |
194 | let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?; | ||
195 | let variant_data = variant.variant_data(db.upcast()); | ||
196 | let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; | ||
197 | Some(field.into()) | ||
194 | } | 198 | } |
195 | 199 | ||
196 | pub(crate) fn resolve_macro_call( | 200 | pub(crate) fn resolve_macro_call( |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index ab77d924a..d9df7564d 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -16,7 +16,7 @@ use mbe::ast_to_token_tree; | |||
16 | use smallvec::{smallvec, SmallVec}; | 16 | use smallvec::{smallvec, SmallVec}; |
17 | use syntax::{ | 17 | use syntax::{ |
18 | ast::{self, AstNode, AttrsOwner}, | 18 | ast::{self, AstNode, AttrsOwner}, |
19 | match_ast, AstToken, SmolStr, SyntaxNode, TextRange, TextSize, | 19 | match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize, |
20 | }; | 20 | }; |
21 | use tt::Subtree; | 21 | use tt::Subtree; |
22 | 22 | ||
@@ -215,12 +215,11 @@ impl Attrs { | |||
215 | let mut res = ArenaMap::default(); | 215 | let mut res = ArenaMap::default(); |
216 | 216 | ||
217 | for (id, fld) in src.value.iter() { | 217 | for (id, fld) in src.value.iter() { |
218 | let attrs = match fld { | 218 | let owner: &dyn AttrsOwner = match fld { |
219 | Either::Left(_tuple) => Attrs::default(), | 219 | Either::Left(tuple) => tuple, |
220 | Either::Right(record) => { | 220 | Either::Right(record) => record, |
221 | RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate) | ||
222 | } | ||
223 | }; | 221 | }; |
222 | let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate); | ||
224 | 223 | ||
225 | res.insert(id, attrs); | 224 | res.insert(id, attrs); |
226 | } | 225 | } |
@@ -404,10 +403,14 @@ impl AttrsWithOwner { | |||
404 | return AttrSourceMap { attrs }; | 403 | return AttrSourceMap { attrs }; |
405 | } | 404 | } |
406 | AttrDefId::FieldId(id) => { | 405 | AttrDefId::FieldId(id) => { |
407 | id.parent.child_source(db).map(|source| match &source[id.local_id] { | 406 | let map = db.fields_attrs_source_map(id.parent); |
408 | Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()), | 407 | let file_id = id.parent.file_id(db); |
409 | Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()), | 408 | let root = db.parse_or_expand(file_id).unwrap(); |
410 | }) | 409 | let owner = match &map[id.local_id] { |
410 | Either::Left(it) => ast::AttrsOwnerNode::new(it.to_node(&root)), | ||
411 | Either::Right(it) => ast::AttrsOwnerNode::new(it.to_node(&root)), | ||
412 | }; | ||
413 | InFile::new(file_id, owner) | ||
411 | } | 414 | } |
412 | AttrDefId::AdtId(adt) => match adt { | 415 | AttrDefId::AdtId(adt) => match adt { |
413 | AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), | 416 | AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), |
@@ -415,10 +418,12 @@ impl AttrsWithOwner { | |||
415 | AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), | 418 | AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), |
416 | }, | 419 | }, |
417 | AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), | 420 | AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), |
418 | AttrDefId::EnumVariantId(id) => id | 421 | AttrDefId::EnumVariantId(id) => { |
419 | .parent | 422 | let map = db.variants_attrs_source_map(id.parent); |
420 | .child_source(db) | 423 | let file_id = id.parent.lookup(db).id.file_id(); |
421 | .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())), | 424 | let root = db.parse_or_expand(file_id).unwrap(); |
425 | InFile::new(file_id, ast::AttrsOwnerNode::new(map[id.local_id].to_node(&root))) | ||
426 | } | ||
422 | AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), | 427 | AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), |
423 | AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), | 428 | AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), |
424 | AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), | 429 | AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), |
@@ -747,3 +752,36 @@ fn collect_attrs( | |||
747 | 752 | ||
748 | attrs.into_iter().map(|(_, attr)| attr) | 753 | attrs.into_iter().map(|(_, attr)| attr) |
749 | } | 754 | } |
755 | |||
756 | pub(crate) fn variants_attrs_source_map( | ||
757 | db: &dyn DefDatabase, | ||
758 | def: EnumId, | ||
759 | ) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>> { | ||
760 | let mut res = ArenaMap::default(); | ||
761 | let child_source = def.child_source(db); | ||
762 | |||
763 | for (idx, variant) in child_source.value.iter() { | ||
764 | res.insert(idx, AstPtr::new(variant)); | ||
765 | } | ||
766 | |||
767 | Arc::new(res) | ||
768 | } | ||
769 | |||
770 | pub(crate) fn fields_attrs_source_map( | ||
771 | db: &dyn DefDatabase, | ||
772 | def: VariantId, | ||
773 | ) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>> { | ||
774 | let mut res = ArenaMap::default(); | ||
775 | let child_source = def.child_source(db); | ||
776 | |||
777 | for (idx, variant) in child_source.value.iter() { | ||
778 | res.insert( | ||
779 | idx, | ||
780 | variant | ||
781 | .as_ref() | ||
782 | .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))), | ||
783 | ); | ||
784 | } | ||
785 | |||
786 | Arc::new(res) | ||
787 | } | ||
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 9b7a213a1..7eadc8e0d 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -2,9 +2,10 @@ | |||
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use either::Either; | ||
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 6 | use hir_expand::{db::AstDatabase, HirFileId}; |
6 | use la_arena::ArenaMap; | 7 | use la_arena::ArenaMap; |
7 | use syntax::SmolStr; | 8 | use syntax::{ast, AstPtr, SmolStr}; |
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | adt::{EnumData, StructData}, | 11 | adt::{EnumData, StructData}, |
@@ -122,6 +123,18 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
122 | #[salsa::invoke(Attrs::fields_attrs_query)] | 123 | #[salsa::invoke(Attrs::fields_attrs_query)] |
123 | fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; | 124 | fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; |
124 | 125 | ||
126 | #[salsa::invoke(crate::attr::variants_attrs_source_map)] | ||
127 | fn variants_attrs_source_map( | ||
128 | &self, | ||
129 | def: EnumId, | ||
130 | ) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>>; | ||
131 | |||
132 | #[salsa::invoke(crate::attr::fields_attrs_source_map)] | ||
133 | fn fields_attrs_source_map( | ||
134 | &self, | ||
135 | def: VariantId, | ||
136 | ) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>>; | ||
137 | |||
125 | #[salsa::invoke(AttrsWithOwner::attrs_query)] | 138 | #[salsa::invoke(AttrsWithOwner::attrs_query)] |
126 | fn attrs(&self, def: AttrDefId) -> AttrsWithOwner; | 139 | fn attrs(&self, def: AttrDefId) -> AttrsWithOwner; |
127 | 140 | ||
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index a8ee5eeac..9014468ea 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
11 | use stdx::format_to; | 11 | use stdx::format_to; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, | 14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId, |
15 | LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId, | 15 | LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -37,6 +37,7 @@ pub struct ItemScope { | |||
37 | 37 | ||
38 | defs: Vec<ModuleDefId>, | 38 | defs: Vec<ModuleDefId>, |
39 | impls: Vec<ImplId>, | 39 | impls: Vec<ImplId>, |
40 | unnamed_consts: Vec<ConstId>, | ||
40 | /// Traits imported via `use Trait as _;`. | 41 | /// Traits imported via `use Trait as _;`. |
41 | unnamed_trait_imports: FxHashMap<TraitId, Visibility>, | 42 | unnamed_trait_imports: FxHashMap<TraitId, Visibility>, |
42 | /// Macros visible in current module in legacy textual scope | 43 | /// Macros visible in current module in legacy textual scope |
@@ -106,6 +107,10 @@ impl ItemScope { | |||
106 | .map(|(_, v)| v) | 107 | .map(|(_, v)| v) |
107 | } | 108 | } |
108 | 109 | ||
110 | pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ { | ||
111 | self.unnamed_consts.iter().copied() | ||
112 | } | ||
113 | |||
109 | /// Iterate over all module scoped macros | 114 | /// Iterate over all module scoped macros |
110 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | 115 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { |
111 | self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) | 116 | self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) |
@@ -156,6 +161,10 @@ impl ItemScope { | |||
156 | self.impls.push(imp) | 161 | self.impls.push(imp) |
157 | } | 162 | } |
158 | 163 | ||
164 | pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) { | ||
165 | self.unnamed_consts.push(konst); | ||
166 | } | ||
167 | |||
159 | pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) { | 168 | pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) { |
160 | self.legacy_macros.insert(name, mac); | 169 | self.legacy_macros.insert(name, mac); |
161 | } | 170 | } |
@@ -295,6 +304,7 @@ impl ItemScope { | |||
295 | unresolved, | 304 | unresolved, |
296 | defs, | 305 | defs, |
297 | impls, | 306 | impls, |
307 | unnamed_consts, | ||
298 | unnamed_trait_imports, | 308 | unnamed_trait_imports, |
299 | legacy_macros, | 309 | legacy_macros, |
300 | } = self; | 310 | } = self; |
@@ -304,6 +314,7 @@ impl ItemScope { | |||
304 | unresolved.shrink_to_fit(); | 314 | unresolved.shrink_to_fit(); |
305 | defs.shrink_to_fit(); | 315 | defs.shrink_to_fit(); |
306 | impls.shrink_to_fit(); | 316 | impls.shrink_to_fit(); |
317 | unnamed_consts.shrink_to_fit(); | ||
307 | unnamed_trait_imports.shrink_to_fit(); | 318 | unnamed_trait_imports.shrink_to_fit(); |
308 | legacy_macros.shrink_to_fit(); | 319 | legacy_macros.shrink_to_fit(); |
309 | } | 320 | } |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index abd6c553f..e2af0e514 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -453,6 +453,14 @@ impl VariantId { | |||
453 | } | 453 | } |
454 | } | 454 | } |
455 | } | 455 | } |
456 | |||
457 | pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId { | ||
458 | match self { | ||
459 | VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(), | ||
460 | VariantId::StructId(it) => it.lookup(db).id.file_id(), | ||
461 | VariantId::UnionId(it) => it.lookup(db).id.file_id(), | ||
462 | } | ||
463 | } | ||
456 | } | 464 | } |
457 | 465 | ||
458 | trait Intern { | 466 | trait Intern { |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index f42f92702..492d8c71f 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -1163,19 +1163,27 @@ impl ModCollector<'_, '_> { | |||
1163 | } | 1163 | } |
1164 | ModItem::Const(id) => { | 1164 | ModItem::Const(id) => { |
1165 | let it = &self.item_tree[id]; | 1165 | let it = &self.item_tree[id]; |
1166 | 1166 | let const_id = ConstLoc { | |
1167 | if let Some(name) = &it.name { | 1167 | container: module.into(), |
1168 | def = Some(DefData { | 1168 | id: ItemTreeId::new(self.file_id, id), |
1169 | id: ConstLoc { | 1169 | } |
1170 | container: module.into(), | 1170 | .intern(self.def_collector.db); |
1171 | id: ItemTreeId::new(self.file_id, id), | 1171 | |
1172 | } | 1172 | match &it.name { |
1173 | .intern(self.def_collector.db) | 1173 | Some(name) => { |
1174 | .into(), | 1174 | def = Some(DefData { |
1175 | name, | 1175 | id: const_id.into(), |
1176 | visibility: &self.item_tree[it.visibility], | 1176 | name, |
1177 | has_constructor: false, | 1177 | visibility: &self.item_tree[it.visibility], |
1178 | }); | 1178 | has_constructor: false, |
1179 | }); | ||
1180 | } | ||
1181 | None => { | ||
1182 | // const _: T = ...; | ||
1183 | self.def_collector.def_map.modules[self.module_id] | ||
1184 | .scope | ||
1185 | .define_unnamed_const(const_id); | ||
1186 | } | ||
1179 | } | 1187 | } |
1180 | } | 1188 | } |
1181 | ModItem::Static(id) => { | 1189 | ModItem::Static(id) => { |
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index c5890e24d..80e192a57 100644 --- a/crates/hir_ty/src/autoderef.rs +++ b/crates/hir_ty/src/autoderef.rs | |||
@@ -120,8 +120,8 @@ fn deref_by_trait( | |||
120 | // assumptions will be broken. We would need to properly introduce | 120 | // assumptions will be broken. We would need to properly introduce |
121 | // new variables in that case | 121 | // new variables in that case |
122 | 122 | ||
123 | for i in 1..vars.0.binders.len(&Interner) { | 123 | for i in 1..vars.binders.len(&Interner) { |
124 | if vars.0.value.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner) | 124 | if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner) |
125 | != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) | 125 | != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) |
126 | { | 126 | { |
127 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); | 127 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); |
@@ -130,12 +130,12 @@ fn deref_by_trait( | |||
130 | } | 130 | } |
131 | Some(Canonical { | 131 | Some(Canonical { |
132 | value: vars | 132 | value: vars |
133 | .0 | ||
134 | .value | 133 | .value |
135 | .at(&Interner, vars.0.value.len(&Interner) - 1) | 134 | .subst |
135 | .at(&Interner, vars.value.subst.len(&Interner) - 1) | ||
136 | .assert_ty_ref(&Interner) | 136 | .assert_ty_ref(&Interner) |
137 | .clone(), | 137 | .clone(), |
138 | binders: vars.0.binders.clone(), | 138 | binders: vars.binders.clone(), |
139 | }) | 139 | }) |
140 | } | 140 | } |
141 | Solution::Ambig(_) => { | 141 | Solution::Ambig(_) => { |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 796f77ab0..6af0c59b8 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -42,7 +42,7 @@ use super::{ | |||
42 | }; | 42 | }; |
43 | use crate::{ | 43 | use crate::{ |
44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, | 44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, |
45 | to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyExt, TyKind, | 45 | to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, TyBuilder, TyExt, TyKind, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | // This lint has a false positive here. See the link below for details. | 48 | // This lint has a false positive here. See the link below for details. |
@@ -131,8 +131,7 @@ pub struct InferenceResult { | |||
131 | method_resolutions: FxHashMap<ExprId, FunctionId>, | 131 | method_resolutions: FxHashMap<ExprId, FunctionId>, |
132 | /// For each field access expr, records the field it resolves to. | 132 | /// For each field access expr, records the field it resolves to. |
133 | field_resolutions: FxHashMap<ExprId, FieldId>, | 133 | field_resolutions: FxHashMap<ExprId, FieldId>, |
134 | record_pat_field_resolutions: FxHashMap<PatId, FieldId>, | 134 | /// For each struct literal or pattern, records the variant it resolves to. |
135 | /// For each struct literal, records the variant it resolves to. | ||
136 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, | 135 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, |
137 | /// For each associated item record what it resolves to | 136 | /// For each associated item record what it resolves to |
138 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, | 137 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, |
@@ -151,9 +150,6 @@ impl InferenceResult { | |||
151 | pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { | 150 | pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { |
152 | self.field_resolutions.get(&expr).copied() | 151 | self.field_resolutions.get(&expr).copied() |
153 | } | 152 | } |
154 | pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> { | ||
155 | self.record_pat_field_resolutions.get(&pat).copied() | ||
156 | } | ||
157 | pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { | 153 | pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { |
158 | self.variant_resolutions.get(&id.into()).copied() | 154 | self.variant_resolutions.get(&id.into()).copied() |
159 | } | 155 | } |
@@ -346,11 +342,18 @@ impl<'a> InferenceContext<'a> { | |||
346 | self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); | 342 | self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); |
347 | 343 | ||
348 | match solution { | 344 | match solution { |
349 | Some(Solution::Unique(substs)) => { | 345 | Some(Solution::Unique(canonical_subst)) => { |
350 | canonicalized.apply_solution(self, substs.0); | 346 | canonicalized.apply_solution( |
347 | self, | ||
348 | Canonical { | ||
349 | binders: canonical_subst.binders, | ||
350 | // FIXME: handle constraints | ||
351 | value: canonical_subst.value.subst, | ||
352 | }, | ||
353 | ); | ||
351 | } | 354 | } |
352 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | 355 | Some(Solution::Ambig(Guidance::Definite(substs))) => { |
353 | canonicalized.apply_solution(self, substs.0); | 356 | canonicalized.apply_solution(self, substs); |
354 | self.obligations.push(obligation); | 357 | self.obligations.push(obligation); |
355 | } | 358 | } |
356 | Some(_) => { | 359 | Some(_) => { |
@@ -691,25 +694,6 @@ impl<'a> InferenceContext<'a> { | |||
691 | } | 694 | } |
692 | } | 695 | } |
693 | 696 | ||
694 | /// The kinds of placeholders we need during type inference. There's separate | ||
695 | /// values for general types, and for integer and float variables. The latter | ||
696 | /// two are used for inference of literal values (e.g. `100` could be one of | ||
697 | /// several integer types). | ||
698 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
699 | pub struct InferenceVar { | ||
700 | index: u32, | ||
701 | } | ||
702 | |||
703 | impl InferenceVar { | ||
704 | fn to_inner(self) -> unify::TypeVarId { | ||
705 | unify::TypeVarId(self.index) | ||
706 | } | ||
707 | |||
708 | fn from_inner(unify::TypeVarId(index): unify::TypeVarId) -> Self { | ||
709 | InferenceVar { index } | ||
710 | } | ||
711 | } | ||
712 | |||
713 | /// When inferring an expression, we propagate downward whatever type hint we | 697 | /// When inferring an expression, we propagate downward whatever type hint we |
714 | /// are able in the form of an `Expectation`. | 698 | /// are able in the form of an `Expectation`. |
715 | #[derive(Clone, PartialEq, Eq, Debug)] | 699 | #[derive(Clone, PartialEq, Eq, Debug)] |
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 159a53a63..f1af2a0bd 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -7,7 +7,7 @@ | |||
7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; | 7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; |
8 | use hir_def::lang_item::LangItemTarget; | 8 | use hir_def::lang_item::LangItemTarget; |
9 | 9 | ||
10 | use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; | 10 | use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; |
11 | 11 | ||
12 | use super::{InEnvironment, InferenceContext}; | 12 | use super::{InEnvironment, InferenceContext}; |
13 | 13 | ||
@@ -148,7 +148,14 @@ impl<'a> InferenceContext<'a> { | |||
148 | 148 | ||
149 | match solution { | 149 | match solution { |
150 | Solution::Unique(v) => { | 150 | Solution::Unique(v) => { |
151 | canonicalized.apply_solution(self, v.0); | 151 | canonicalized.apply_solution( |
152 | self, | ||
153 | Canonical { | ||
154 | binders: v.binders, | ||
155 | // FIXME handle constraints | ||
156 | value: v.value.subst, | ||
157 | }, | ||
158 | ); | ||
152 | } | 159 | } |
153 | _ => return None, | 160 | _ => return None, |
154 | }; | 161 | }; |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 942f70edf..e4813c87c 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -7,7 +7,6 @@ use chalk_ir::Mutability; | |||
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, | 8 | expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, |
9 | path::Path, | 9 | path::Path, |
10 | FieldId, | ||
11 | }; | 10 | }; |
12 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
13 | 12 | ||
@@ -80,11 +79,6 @@ impl<'a> InferenceContext<'a> { | |||
80 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); | 79 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); |
81 | for subpat in subpats { | 80 | for subpat in subpats { |
82 | let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); | 81 | let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); |
83 | if let Some(local_id) = matching_field { | ||
84 | let field_def = FieldId { parent: def.unwrap(), local_id }; | ||
85 | self.result.record_pat_field_resolutions.insert(subpat.pat, field_def); | ||
86 | } | ||
87 | |||
88 | let expected_ty = matching_field.map_or(self.err_ty(), |field| { | 82 | let expected_ty = matching_field.map_or(self.err_ty(), |field| { |
89 | field_tys[field].clone().substitute(&Interner, &substs) | 83 | field_tys[field].clone().substitute(&Interner, &substs) |
90 | }); | 84 | }); |
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index 7d76cda68..d717e3375 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -51,7 +51,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> { | |||
51 | t.fold_binders( | 51 | t.fold_binders( |
52 | &mut |ty, binders| match ty.kind(&Interner) { | 52 | &mut |ty, binders| match ty.kind(&Interner) { |
53 | &TyKind::InferenceVar(var, kind) => { | 53 | &TyKind::InferenceVar(var, kind) => { |
54 | let inner = var.to_inner(); | 54 | let inner = from_inference_var(var); |
55 | if self.var_stack.contains(&inner) { | 55 | if self.var_stack.contains(&inner) { |
56 | // recursive type | 56 | // recursive type |
57 | return self.ctx.table.type_variable_table.fallback_value(var, kind); | 57 | return self.ctx.table.type_variable_table.fallback_value(var, kind); |
@@ -65,7 +65,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> { | |||
65 | result | 65 | result |
66 | } else { | 66 | } else { |
67 | let root = self.ctx.table.var_unification_table.find(inner); | 67 | let root = self.ctx.table.var_unification_table.find(inner); |
68 | let position = self.add(InferenceVar::from_inner(root), kind); | 68 | let position = self.add(to_inference_var(root), kind); |
69 | TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner) | 69 | TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner) |
70 | } | 70 | } |
71 | } | 71 | } |
@@ -207,16 +207,16 @@ impl TypeVariableTable { | |||
207 | } | 207 | } |
208 | 208 | ||
209 | pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { | 209 | pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { |
210 | self.inner[iv.to_inner().0 as usize].diverging = diverging; | 210 | self.inner[from_inference_var(iv).0 as usize].diverging = diverging; |
211 | } | 211 | } |
212 | 212 | ||
213 | fn is_diverging(&mut self, iv: InferenceVar) -> bool { | 213 | fn is_diverging(&mut self, iv: InferenceVar) -> bool { |
214 | self.inner[iv.to_inner().0 as usize].diverging | 214 | self.inner[from_inference_var(iv).0 as usize].diverging |
215 | } | 215 | } |
216 | 216 | ||
217 | fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { | 217 | fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { |
218 | match kind { | 218 | match kind { |
219 | _ if self.inner[iv.to_inner().0 as usize].diverging => TyKind::Never, | 219 | _ if self.inner[from_inference_var(iv).0 as usize].diverging => TyKind::Never, |
220 | TyVariableKind::General => TyKind::Error, | 220 | TyVariableKind::General => TyKind::Error, |
221 | TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), | 221 | TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), |
222 | TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), | 222 | TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), |
@@ -250,7 +250,7 @@ impl InferenceTable { | |||
250 | self.type_variable_table.push(TypeVariableData { diverging }); | 250 | self.type_variable_table.push(TypeVariableData { diverging }); |
251 | let key = self.var_unification_table.new_key(TypeVarValue::Unknown); | 251 | let key = self.var_unification_table.new_key(TypeVarValue::Unknown); |
252 | assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1); | 252 | assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1); |
253 | TyKind::InferenceVar(InferenceVar::from_inner(key), kind).intern(&Interner) | 253 | TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner) |
254 | } | 254 | } |
255 | 255 | ||
256 | pub(crate) fn new_type_var(&mut self) -> Ty { | 256 | pub(crate) fn new_type_var(&mut self) -> Ty { |
@@ -369,8 +369,12 @@ impl InferenceTable { | |||
369 | == self.type_variable_table.is_diverging(*tv2) => | 369 | == self.type_variable_table.is_diverging(*tv2) => |
370 | { | 370 | { |
371 | // both type vars are unknown since we tried to resolve them | 371 | // both type vars are unknown since we tried to resolve them |
372 | if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) { | 372 | if !self |
373 | self.var_unification_table.union(tv1.to_inner(), tv2.to_inner()); | 373 | .var_unification_table |
374 | .unioned(from_inference_var(*tv1), from_inference_var(*tv2)) | ||
375 | { | ||
376 | self.var_unification_table | ||
377 | .union(from_inference_var(*tv1), from_inference_var(*tv2)); | ||
374 | self.revision += 1; | 378 | self.revision += 1; |
375 | } | 379 | } |
376 | true | 380 | true |
@@ -407,7 +411,7 @@ impl InferenceTable { | |||
407 | ) => { | 411 | ) => { |
408 | // the type var is unknown since we tried to resolve it | 412 | // the type var is unknown since we tried to resolve it |
409 | self.var_unification_table.union_value( | 413 | self.var_unification_table.union_value( |
410 | tv.to_inner(), | 414 | from_inference_var(*tv), |
411 | TypeVarValue::Known(other.clone().intern(&Interner)), | 415 | TypeVarValue::Known(other.clone().intern(&Interner)), |
412 | ); | 416 | ); |
413 | self.revision += 1; | 417 | self.revision += 1; |
@@ -462,7 +466,7 @@ impl InferenceTable { | |||
462 | } | 466 | } |
463 | match ty.kind(&Interner) { | 467 | match ty.kind(&Interner) { |
464 | TyKind::InferenceVar(tv, _) => { | 468 | TyKind::InferenceVar(tv, _) => { |
465 | let inner = tv.to_inner(); | 469 | let inner = from_inference_var(*tv); |
466 | match self.var_unification_table.inlined_probe_value(inner).known() { | 470 | match self.var_unification_table.inlined_probe_value(inner).known() { |
467 | Some(known_ty) => { | 471 | Some(known_ty) => { |
468 | // The known_ty can't be a type var itself | 472 | // The known_ty can't be a type var itself |
@@ -485,7 +489,7 @@ impl InferenceTable { | |||
485 | fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | 489 | fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
486 | ty.fold(&mut |ty| match ty.kind(&Interner) { | 490 | ty.fold(&mut |ty| match ty.kind(&Interner) { |
487 | &TyKind::InferenceVar(tv, kind) => { | 491 | &TyKind::InferenceVar(tv, kind) => { |
488 | let inner = tv.to_inner(); | 492 | let inner = from_inference_var(tv); |
489 | if tv_stack.contains(&inner) { | 493 | if tv_stack.contains(&inner) { |
490 | cov_mark::hit!(type_var_cycles_resolve_as_possible); | 494 | cov_mark::hit!(type_var_cycles_resolve_as_possible); |
491 | // recursive type | 495 | // recursive type |
@@ -512,7 +516,7 @@ impl InferenceTable { | |||
512 | fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | 516 | fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
513 | ty.fold(&mut |ty| match ty.kind(&Interner) { | 517 | ty.fold(&mut |ty| match ty.kind(&Interner) { |
514 | &TyKind::InferenceVar(tv, kind) => { | 518 | &TyKind::InferenceVar(tv, kind) => { |
515 | let inner = tv.to_inner(); | 519 | let inner = from_inference_var(tv); |
516 | if tv_stack.contains(&inner) { | 520 | if tv_stack.contains(&inner) { |
517 | cov_mark::hit!(type_var_cycles_resolve_completely); | 521 | cov_mark::hit!(type_var_cycles_resolve_completely); |
518 | // recursive type | 522 | // recursive type |
@@ -555,6 +559,14 @@ impl UnifyKey for TypeVarId { | |||
555 | } | 559 | } |
556 | } | 560 | } |
557 | 561 | ||
562 | fn from_inference_var(var: InferenceVar) -> TypeVarId { | ||
563 | TypeVarId(var.index()) | ||
564 | } | ||
565 | |||
566 | fn to_inference_var(TypeVarId(index): TypeVarId) -> InferenceVar { | ||
567 | index.into() | ||
568 | } | ||
569 | |||
558 | /// The value of a type variable: either we already know the type, or we don't | 570 | /// The value of a type variable: either we already know the type, or we don't |
559 | /// know it yet. | 571 | /// know it yet. |
560 | #[derive(Clone, PartialEq, Eq, Debug)] | 572 | #[derive(Clone, PartialEq, Eq, Debug)] |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index f5b658cba..5c83a508d 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -42,7 +42,7 @@ use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; | |||
42 | pub use autoderef::autoderef; | 42 | pub use autoderef::autoderef; |
43 | pub use builder::TyBuilder; | 43 | pub use builder::TyBuilder; |
44 | pub use chalk_ext::{ProjectionTyExt, TyExt}; | 44 | pub use chalk_ext::{ProjectionTyExt, TyExt}; |
45 | pub use infer::{could_unify, InferenceResult, InferenceVar}; | 45 | pub use infer::{could_unify, InferenceResult}; |
46 | pub use lower::{ | 46 | pub use lower::{ |
47 | associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, | 47 | associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, |
48 | TyDefId, TyLoweringContext, ValueTyDefId, | 48 | TyDefId, TyLoweringContext, ValueTyDefId, |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index ee725fd46..f29319f20 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -8,8 +8,8 @@ use arrayvec::ArrayVec; | |||
8 | use base_db::CrateId; | 8 | use base_db::CrateId; |
9 | use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; | 9 | use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; |
10 | use hir_def::{ | 10 | use hir_def::{ |
11 | lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule, | 11 | lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId, |
12 | ImplId, Lookup, ModuleId, TraitId, | 12 | GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId, |
13 | }; | 13 | }; |
14 | use hir_expand::name::Name; | 14 | use hir_expand::name::Name; |
15 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -100,25 +100,38 @@ impl TraitImpls { | |||
100 | let mut impls = Self { map: FxHashMap::default() }; | 100 | let mut impls = Self { map: FxHashMap::default() }; |
101 | 101 | ||
102 | let crate_def_map = db.crate_def_map(krate); | 102 | let crate_def_map = db.crate_def_map(krate); |
103 | for (_module_id, module_data) in crate_def_map.modules() { | 103 | collect_def_map(db, &crate_def_map, &mut impls); |
104 | for impl_id in module_data.scope.impls() { | 104 | |
105 | let target_trait = match db.impl_trait(impl_id) { | 105 | return Arc::new(impls); |
106 | Some(tr) => tr.skip_binders().hir_trait_id(), | 106 | |
107 | None => continue, | 107 | fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) { |
108 | }; | 108 | for (_module_id, module_data) in def_map.modules() { |
109 | let self_ty = db.impl_self_ty(impl_id); | 109 | for impl_id in module_data.scope.impls() { |
110 | let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders()); | 110 | let target_trait = match db.impl_trait(impl_id) { |
111 | impls | 111 | Some(tr) => tr.skip_binders().hir_trait_id(), |
112 | .map | 112 | None => continue, |
113 | .entry(target_trait) | 113 | }; |
114 | .or_default() | 114 | let self_ty = db.impl_self_ty(impl_id); |
115 | .entry(self_ty_fp) | 115 | let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders()); |
116 | .or_default() | 116 | impls |
117 | .push(impl_id); | 117 | .map |
118 | .entry(target_trait) | ||
119 | .or_default() | ||
120 | .entry(self_ty_fp) | ||
121 | .or_default() | ||
122 | .push(impl_id); | ||
123 | } | ||
124 | |||
125 | // To better support custom derives, collect impls in all unnamed const items. | ||
126 | // const _: () = { ... }; | ||
127 | for konst in module_data.scope.unnamed_consts() { | ||
128 | let body = db.body(konst.into()); | ||
129 | for (_, block_def_map) in body.blocks(db.upcast()) { | ||
130 | collect_def_map(db, &block_def_map, impls); | ||
131 | } | ||
132 | } | ||
118 | } | 133 | } |
119 | } | 134 | } |
120 | |||
121 | Arc::new(impls) | ||
122 | } | 135 | } |
123 | 136 | ||
124 | pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | 137 | pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { |
@@ -208,6 +221,9 @@ impl InherentImpls { | |||
208 | } | 221 | } |
209 | } | 222 | } |
210 | 223 | ||
224 | // NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only | ||
225 | // support trait impls there. | ||
226 | |||
211 | Arc::new(Self { map }) | 227 | Arc::new(Self { map }) |
212 | } | 228 | } |
213 | 229 | ||
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index 61f18b0d2..4b2c82b41 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -1292,3 +1292,25 @@ mod b { | |||
1292 | "#]], | 1292 | "#]], |
1293 | ) | 1293 | ) |
1294 | } | 1294 | } |
1295 | |||
1296 | #[test] | ||
1297 | fn impl_in_unnamed_const() { | ||
1298 | check_types( | ||
1299 | r#" | ||
1300 | struct S; | ||
1301 | |||
1302 | trait Tr { | ||
1303 | fn method(&self) -> u16; | ||
1304 | } | ||
1305 | |||
1306 | const _: () = { | ||
1307 | impl Tr for S {} | ||
1308 | }; | ||
1309 | |||
1310 | fn f() { | ||
1311 | S.method(); | ||
1312 | //^^^^^^^^^^ u16 | ||
1313 | } | ||
1314 | "#, | ||
1315 | ); | ||
1316 | } | ||
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs index c8883485c..3374532c3 100644 --- a/crates/hir_ty/src/traits.rs +++ b/crates/hir_ty/src/traits.rs | |||
@@ -9,7 +9,7 @@ use stdx::panic_context; | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, | 11 | db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, |
12 | Solution, SolutionVariables, Ty, TyKind, WhereClause, | 12 | Solution, Ty, TyKind, WhereClause, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use self::chalk::{from_chalk, Interner, ToChalk}; | 15 | use self::chalk::{from_chalk, Interner, ToChalk}; |
@@ -173,23 +173,15 @@ fn solution_from_chalk( | |||
173 | db: &dyn HirDatabase, | 173 | db: &dyn HirDatabase, |
174 | solution: chalk_solve::Solution<Interner>, | 174 | solution: chalk_solve::Solution<Interner>, |
175 | ) -> Solution { | 175 | ) -> Solution { |
176 | let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { | ||
177 | let result = from_chalk(db, subst); | ||
178 | SolutionVariables(result) | ||
179 | }; | ||
180 | match solution { | 176 | match solution { |
181 | chalk_solve::Solution::Unique(constr_subst) => { | 177 | chalk_solve::Solution::Unique(constr_subst) => { |
182 | let subst = chalk_ir::Canonical { | 178 | Solution::Unique(from_chalk(db, constr_subst)) |
183 | value: constr_subst.value.subst, | ||
184 | binders: constr_subst.binders, | ||
185 | }; | ||
186 | Solution::Unique(convert_subst(subst)) | ||
187 | } | 179 | } |
188 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => { | 180 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => { |
189 | Solution::Ambig(Guidance::Definite(convert_subst(subst))) | 181 | Solution::Ambig(Guidance::Definite(from_chalk(db, subst))) |
190 | } | 182 | } |
191 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => { | 183 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => { |
192 | Solution::Ambig(Guidance::Suggested(convert_subst(subst))) | 184 | Solution::Ambig(Guidance::Suggested(from_chalk(db, subst))) |
193 | } | 185 | } |
194 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => { | 186 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => { |
195 | Solution::Ambig(Guidance::Unknown) | 187 | Solution::Ambig(Guidance::Unknown) |
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs index cf73cb078..84abd99b2 100644 --- a/crates/hir_ty/src/traits/chalk/mapping.rs +++ b/crates/hir_ty/src/traits/chalk/mapping.rs | |||
@@ -10,10 +10,9 @@ use base_db::salsa::InternKey; | |||
10 | use hir_def::{GenericDefId, TypeAliasId}; | 10 | use hir_def::{GenericDefId, TypeAliasId}; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | chalk_ext::ProjectionTyExt, db::HirDatabase, dummy_usize_const, static_lifetime, AliasTy, | 13 | chalk_ext::ProjectionTyExt, db::HirDatabase, static_lifetime, AliasTy, CallableDefId, |
14 | CallableDefId, Canonical, Const, DomainGoal, FnPointer, GenericArg, InEnvironment, Lifetime, | 14 | Canonical, ConstrainedSubst, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, |
15 | OpaqueTy, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, | 15 | ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause, |
16 | WhereClause, | ||
17 | }; | 16 | }; |
18 | 17 | ||
19 | use super::interner::*; | 18 | use super::interner::*; |
@@ -23,16 +22,16 @@ impl ToChalk for Ty { | |||
23 | type Chalk = chalk_ir::Ty<Interner>; | 22 | type Chalk = chalk_ir::Ty<Interner>; |
24 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | 23 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { |
25 | match self.into_inner() { | 24 | match self.into_inner() { |
26 | TyKind::Ref(m, lt, ty) => ref_to_chalk(db, m, lt, ty), | 25 | TyKind::Ref(m, lt, ty) => { |
27 | TyKind::Array(ty, size) => array_to_chalk(db, ty, size), | 26 | chalk_ir::TyKind::Ref(m, lt, ty.to_chalk(db)).intern(&Interner) |
28 | TyKind::Function(FnPointer { sig, substitution: substs, .. }) => { | 27 | } |
28 | TyKind::Array(ty, size) => { | ||
29 | chalk_ir::TyKind::Array(ty.to_chalk(db), size).intern(&Interner) | ||
30 | } | ||
31 | TyKind::Function(FnPointer { sig, substitution: substs, num_binders }) => { | ||
29 | let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db)); | 32 | let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db)); |
30 | chalk_ir::TyKind::Function(chalk_ir::FnPointer { | 33 | chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders, sig, substitution }) |
31 | num_binders: 0, | 34 | .intern(&Interner) |
32 | sig, | ||
33 | substitution, | ||
34 | }) | ||
35 | .intern(&Interner) | ||
36 | } | 35 | } |
37 | TyKind::AssociatedType(assoc_type_id, substs) => { | 36 | TyKind::AssociatedType(assoc_type_id, substs) => { |
38 | let substitution = substs.to_chalk(db); | 37 | let substitution = substs.to_chalk(db); |
@@ -74,22 +73,13 @@ impl ToChalk for Ty { | |||
74 | chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner) | 73 | chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner) |
75 | } | 74 | } |
76 | TyKind::Alias(AliasTy::Projection(proj_ty)) => { | 75 | TyKind::Alias(AliasTy::Projection(proj_ty)) => { |
77 | let associated_ty_id = proj_ty.associated_ty_id; | 76 | chalk_ir::AliasTy::Projection(proj_ty.to_chalk(db)) |
78 | let substitution = proj_ty.substitution.to_chalk(db); | ||
79 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
80 | associated_ty_id, | ||
81 | substitution, | ||
82 | }) | ||
83 | .cast(&Interner) | ||
84 | .intern(&Interner) | ||
85 | } | ||
86 | TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
87 | let opaque_ty_id = opaque_ty.opaque_ty_id; | ||
88 | let substitution = opaque_ty.substitution.to_chalk(db); | ||
89 | chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id, substitution }) | ||
90 | .cast(&Interner) | 77 | .cast(&Interner) |
91 | .intern(&Interner) | 78 | .intern(&Interner) |
92 | } | 79 | } |
80 | TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
81 | chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)).cast(&Interner).intern(&Interner) | ||
82 | } | ||
93 | TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner), | 83 | TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner), |
94 | TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner), | 84 | TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner), |
95 | TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"), | 85 | TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"), |
@@ -101,7 +91,7 @@ impl ToChalk for Ty { | |||
101 | ); | 91 | ); |
102 | let bounded_ty = chalk_ir::DynTy { | 92 | let bounded_ty = chalk_ir::DynTy { |
103 | bounds: chalk_ir::Binders::new(binders, where_clauses), | 93 | bounds: chalk_ir::Binders::new(binders, where_clauses), |
104 | lifetime: static_lifetime(), | 94 | lifetime: dyn_ty.lifetime, |
105 | }; | 95 | }; |
106 | chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner) | 96 | chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner) |
107 | } | 97 | } |
@@ -114,17 +104,10 @@ impl ToChalk for Ty { | |||
114 | chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size), | 104 | chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size), |
115 | chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx), | 105 | chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx), |
116 | chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => { | 106 | chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => { |
117 | let associated_ty = proj.associated_ty_id; | 107 | TyKind::Alias(AliasTy::Projection(from_chalk(db, proj))) |
118 | let parameters = from_chalk(db, proj.substitution); | ||
119 | TyKind::Alias(AliasTy::Projection(ProjectionTy { | ||
120 | associated_ty_id: associated_ty, | ||
121 | substitution: parameters, | ||
122 | })) | ||
123 | } | 108 | } |
124 | chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { | 109 | chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { |
125 | let opaque_ty_id = opaque_ty.opaque_ty_id; | 110 | TyKind::Alias(AliasTy::Opaque(from_chalk(db, opaque_ty))) |
126 | let parameters = from_chalk(db, opaque_ty.substitution); | ||
127 | TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, substitution: parameters })) | ||
128 | } | 111 | } |
129 | chalk_ir::TyKind::Function(chalk_ir::FnPointer { | 112 | chalk_ir::TyKind::Function(chalk_ir::FnPointer { |
130 | num_binders, | 113 | num_binders, |
@@ -138,18 +121,19 @@ impl ToChalk for Ty { | |||
138 | } | 121 | } |
139 | chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx), | 122 | chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx), |
140 | chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error, | 123 | chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error, |
141 | chalk_ir::TyKind::Dyn(where_clauses) => { | 124 | chalk_ir::TyKind::Dyn(dyn_ty) => { |
142 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | 125 | assert_eq!(dyn_ty.bounds.binders.len(&Interner), 1); |
143 | let bounds = where_clauses | 126 | let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders(); |
144 | .bounds | 127 | let where_clauses = crate::QuantifiedWhereClauses::from_iter( |
145 | .skip_binders() | 128 | &Interner, |
146 | .iter(&Interner) | 129 | bounds.interned().iter().cloned().map(|p| from_chalk(db, p)), |
147 | .map(|c| from_chalk(db, c.clone())); | 130 | ); |
148 | TyKind::Dyn(crate::DynTy { | 131 | TyKind::Dyn(crate::DynTy { |
149 | bounds: crate::Binders::new( | 132 | bounds: crate::Binders::new(binders, where_clauses), |
150 | where_clauses.bounds.binders.clone(), | 133 | // HACK: we sometimes get lifetime variables back in solutions |
151 | crate::QuantifiedWhereClauses::from_iter(&Interner, bounds), | 134 | // from Chalk, and don't have the infrastructure to substitute |
152 | ), | 135 | // them yet. So for now we just turn them into 'static right |
136 | // when we get them | ||
153 | lifetime: static_lifetime(), | 137 | lifetime: static_lifetime(), |
154 | }) | 138 | }) |
155 | } | 139 | } |
@@ -169,8 +153,12 @@ impl ToChalk for Ty { | |||
169 | } | 153 | } |
170 | chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)), | 154 | chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)), |
171 | chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)), | 155 | chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)), |
172 | chalk_ir::TyKind::Ref(mutability, lifetime, ty) => { | 156 | chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => { |
173 | TyKind::Ref(mutability, lifetime, from_chalk(db, ty)) | 157 | // HACK: we sometimes get lifetime variables back in solutions |
158 | // from Chalk, and don't have the infrastructure to substitute | ||
159 | // them yet. So for now we just turn them into 'static right | ||
160 | // when we get them | ||
161 | TyKind::Ref(mutability, static_lifetime(), from_chalk(db, ty)) | ||
174 | } | 162 | } |
175 | chalk_ir::TyKind::Str => TyKind::Str, | 163 | chalk_ir::TyKind::Str => TyKind::Str, |
176 | chalk_ir::TyKind::Never => TyKind::Never, | 164 | chalk_ir::TyKind::Never => TyKind::Never, |
@@ -189,26 +177,6 @@ impl ToChalk for Ty { | |||
189 | } | 177 | } |
190 | } | 178 | } |
191 | 179 | ||
192 | /// We currently don't model lifetimes, but Chalk does. So, we have to insert a | ||
193 | /// fake lifetime here, because Chalks built-in logic may expect it to be there. | ||
194 | fn ref_to_chalk( | ||
195 | db: &dyn HirDatabase, | ||
196 | mutability: chalk_ir::Mutability, | ||
197 | _lifetime: Lifetime, | ||
198 | ty: Ty, | ||
199 | ) -> chalk_ir::Ty<Interner> { | ||
200 | let arg = ty.to_chalk(db); | ||
201 | let lifetime = static_lifetime(); | ||
202 | chalk_ir::TyKind::Ref(mutability, lifetime, arg).intern(&Interner) | ||
203 | } | ||
204 | |||
205 | /// We currently don't model constants, but Chalk does. So, we have to insert a | ||
206 | /// fake constant here, because Chalks built-in logic may expect it to be there. | ||
207 | fn array_to_chalk(db: &dyn HirDatabase, ty: Ty, _: Const) -> chalk_ir::Ty<Interner> { | ||
208 | let arg = ty.to_chalk(db); | ||
209 | chalk_ir::TyKind::Array(arg, dummy_usize_const()).intern(&Interner) | ||
210 | } | ||
211 | |||
212 | impl ToChalk for GenericArg { | 180 | impl ToChalk for GenericArg { |
213 | type Chalk = chalk_ir::GenericArg<Interner>; | 181 | type Chalk = chalk_ir::GenericArg<Interner>; |
214 | 182 | ||
@@ -491,6 +459,18 @@ where | |||
491 | } | 459 | } |
492 | } | 460 | } |
493 | 461 | ||
462 | impl ToChalk for crate::ConstrainedSubst { | ||
463 | type Chalk = chalk_ir::ConstrainedSubst<Interner>; | ||
464 | |||
465 | fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk { | ||
466 | unimplemented!() | ||
467 | } | ||
468 | |||
469 | fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self { | ||
470 | ConstrainedSubst { subst: from_chalk(db, chalk.subst) } | ||
471 | } | ||
472 | } | ||
473 | |||
494 | pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | 474 | pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> |
495 | where | 475 | where |
496 | T: HasInterner<Interner = Interner>, | 476 | T: HasInterner<Interner = Interner>, |
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs index 89c0ddd1a..c25bc2d6a 100644 --- a/crates/hir_ty/src/types.rs +++ b/crates/hir_ty/src/types.rs | |||
@@ -11,8 +11,7 @@ use smallvec::SmallVec; | |||
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId, | 13 | AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId, |
14 | InferenceVar, Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, | 14 | Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds, |
15 | VariableKinds, | ||
16 | }; | 15 | }; |
17 | 16 | ||
18 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 17 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
@@ -491,14 +490,16 @@ pub struct AliasEq { | |||
491 | } | 490 | } |
492 | 491 | ||
493 | #[derive(Clone, Debug, PartialEq, Eq)] | 492 | #[derive(Clone, Debug, PartialEq, Eq)] |
494 | pub struct SolutionVariables(pub Canonical<Substitution>); | 493 | pub struct ConstrainedSubst { |
494 | pub subst: Substitution, | ||
495 | } | ||
495 | 496 | ||
496 | #[derive(Clone, Debug, PartialEq, Eq)] | 497 | #[derive(Clone, Debug, PartialEq, Eq)] |
497 | /// A (possible) solution for a proposed goal. | 498 | /// A (possible) solution for a proposed goal. |
498 | pub enum Solution { | 499 | pub enum Solution { |
499 | /// The goal indeed holds, and there is a unique value for all existential | 500 | /// The goal indeed holds, and there is a unique value for all existential |
500 | /// variables. | 501 | /// variables. |
501 | Unique(SolutionVariables), | 502 | Unique(Canonical<ConstrainedSubst>), |
502 | 503 | ||
503 | /// The goal may be provable in multiple ways, but regardless we may have some guidance | 504 | /// The goal may be provable in multiple ways, but regardless we may have some guidance |
504 | /// for type inference. In this case, we don't return any lifetime | 505 | /// for type inference. In this case, we don't return any lifetime |
@@ -514,13 +515,35 @@ pub enum Guidance { | |||
514 | /// The existential variables *must* have the given values if the goal is | 515 | /// The existential variables *must* have the given values if the goal is |
515 | /// ever to hold, but that alone isn't enough to guarantee the goal will | 516 | /// ever to hold, but that alone isn't enough to guarantee the goal will |
516 | /// actually hold. | 517 | /// actually hold. |
517 | Definite(SolutionVariables), | 518 | Definite(Canonical<Substitution>), |
518 | 519 | ||
519 | /// There are multiple plausible values for the existentials, but the ones | 520 | /// There are multiple plausible values for the existentials, but the ones |
520 | /// here are suggested as the preferred choice heuristically. These should | 521 | /// here are suggested as the preferred choice heuristically. These should |
521 | /// be used for inference fallback only. | 522 | /// be used for inference fallback only. |
522 | Suggested(SolutionVariables), | 523 | Suggested(Canonical<Substitution>), |
523 | 524 | ||
524 | /// There's no useful information to feed back to type inference | 525 | /// There's no useful information to feed back to type inference |
525 | Unknown, | 526 | Unknown, |
526 | } | 527 | } |
528 | |||
529 | /// The kinds of placeholders we need during type inference. There's separate | ||
530 | /// values for general types, and for integer and float variables. The latter | ||
531 | /// two are used for inference of literal values (e.g. `100` could be one of | ||
532 | /// several integer types). | ||
533 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
534 | pub struct InferenceVar { | ||
535 | index: u32, | ||
536 | } | ||
537 | |||
538 | impl From<u32> for InferenceVar { | ||
539 | fn from(index: u32) -> InferenceVar { | ||
540 | InferenceVar { index } | ||
541 | } | ||
542 | } | ||
543 | |||
544 | impl InferenceVar { | ||
545 | /// Gets the underlying index value. | ||
546 | pub fn index(self) -> u32 { | ||
547 | self.index | ||
548 | } | ||
549 | } | ||
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 9eeabbeda..d5628e3df 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs | |||
@@ -103,6 +103,9 @@ fn insert_whitespaces(syn: SyntaxNode) -> String { | |||
103 | format!("\n{}}}", " ".repeat(indent)) | 103 | format!("\n{}}}", " ".repeat(indent)) |
104 | } | 104 | } |
105 | R_CURLY => format!("}}\n{}", " ".repeat(indent)), | 105 | R_CURLY => format!("}}\n{}", " ".repeat(indent)), |
106 | LIFETIME_IDENT if is_next(|it| it == IDENT, true) => { | ||
107 | format!("{} ", token.text().to_string()) | ||
108 | } | ||
106 | T![;] => format!(";\n{}", " ".repeat(indent)), | 109 | T![;] => format!(";\n{}", " ".repeat(indent)), |
107 | T![->] => " -> ".to_string(), | 110 | T![->] => " -> ".to_string(), |
108 | T![=] => " = ".to_string(), | 111 | T![=] => " = ".to_string(), |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 1ad017198..9ace13e41 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -113,6 +113,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
113 | if ctx.use_item_syntax.is_some() | 113 | if ctx.use_item_syntax.is_some() |
114 | || ctx.attribute_under_caret.is_some() | 114 | || ctx.attribute_under_caret.is_some() |
115 | || ctx.mod_declaration_under_caret.is_some() | 115 | || ctx.mod_declaration_under_caret.is_some() |
116 | || ctx.record_lit_syntax.is_some() | ||
116 | { | 117 | { |
117 | return None; | 118 | return None; |
118 | } | 119 | } |
@@ -1034,4 +1035,46 @@ fn main() { | |||
1034 | expect![[]], | 1035 | expect![[]], |
1035 | ); | 1036 | ); |
1036 | } | 1037 | } |
1038 | |||
1039 | #[test] | ||
1040 | fn no_fuzzy_during_fields_of_record_lit_syntax() { | ||
1041 | check( | ||
1042 | r#" | ||
1043 | mod m { | ||
1044 | pub fn some_fn() -> i32 { | ||
1045 | 42 | ||
1046 | } | ||
1047 | } | ||
1048 | struct Foo { | ||
1049 | some_field: i32, | ||
1050 | } | ||
1051 | fn main() { | ||
1052 | let _ = Foo { so$0 }; | ||
1053 | } | ||
1054 | "#, | ||
1055 | expect![[]], | ||
1056 | ); | ||
1057 | } | ||
1058 | |||
1059 | #[test] | ||
1060 | fn fuzzy_after_fields_of_record_lit_syntax() { | ||
1061 | check( | ||
1062 | r#" | ||
1063 | mod m { | ||
1064 | pub fn some_fn() -> i32 { | ||
1065 | 42 | ||
1066 | } | ||
1067 | } | ||
1068 | struct Foo { | ||
1069 | some_field: i32, | ||
1070 | } | ||
1071 | fn main() { | ||
1072 | let _ = Foo { some_field: so$0 }; | ||
1073 | } | ||
1074 | "#, | ||
1075 | expect![[r#" | ||
1076 | fn some_fn() (m::some_fn) fn() -> i32 | ||
1077 | "#]], | ||
1078 | ); | ||
1079 | } | ||
1037 | } | 1080 | } |
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs index 111e9325a..6c67425d7 100644 --- a/crates/ide_db/src/apply_change.rs +++ b/crates/ide_db/src/apply_change.rs | |||
@@ -152,6 +152,10 @@ impl RootDatabase { | |||
152 | hir::db::FileItemTreeQuery | 152 | hir::db::FileItemTreeQuery |
153 | hir::db::BlockDefMapQuery | 153 | hir::db::BlockDefMapQuery |
154 | hir::db::CrateDefMapQueryQuery | 154 | hir::db::CrateDefMapQueryQuery |
155 | hir::db::FieldsAttrsQuery | ||
156 | hir::db::VariantsAttrsQuery | ||
157 | hir::db::FieldsAttrsSourceMapQuery | ||
158 | hir::db::VariantsAttrsSourceMapQuery | ||
155 | hir::db::StructDataQuery | 159 | hir::db::StructDataQuery |
156 | hir::db::UnionDataQuery | 160 | hir::db::UnionDataQuery |
157 | hir::db::EnumDataQuery | 161 | hir::db::EnumDataQuery |
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index 6bc824e94..099baeca2 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs | |||
@@ -1,5 +1,65 @@ | |||
1 | //! Defines `Fixture` -- a convenient way to describe the initial state of | 1 | //! Defines `Fixture` -- a convenient way to describe the initial state of |
2 | //! rust-analyzer database from a single string. | 2 | //! rust-analyzer database from a single string. |
3 | //! | ||
4 | //! Fixtures are strings containing rust source code with optional metadata. | ||
5 | //! A fixture without metadata is parsed into a single source file. | ||
6 | //! Use this to test functionality local to one file. | ||
7 | //! | ||
8 | //! Simple Example: | ||
9 | //! ``` | ||
10 | //! r#" | ||
11 | //! fn main() { | ||
12 | //! println!("Hello World") | ||
13 | //! } | ||
14 | //! "# | ||
15 | //! ``` | ||
16 | //! | ||
17 | //! Metadata can be added to a fixture after a `//-` comment. | ||
18 | //! The basic form is specifying filenames, | ||
19 | //! which is also how to define multiple files in a single test fixture | ||
20 | //! | ||
21 | //! Example using two files in the same crate: | ||
22 | //! ``` | ||
23 | //! " | ||
24 | //! //- /main.rs | ||
25 | //! mod foo; | ||
26 | //! fn main() { | ||
27 | //! foo::bar(); | ||
28 | //! } | ||
29 | //! | ||
30 | //! //- /foo.rs | ||
31 | //! pub fn bar() {} | ||
32 | //! " | ||
33 | //! ``` | ||
34 | //! | ||
35 | //! Example using two crates with one file each, with one crate depending on the other: | ||
36 | //! ``` | ||
37 | //! r#" | ||
38 | //! //- /main.rs crate:a deps:b | ||
39 | //! fn main() { | ||
40 | //! b::foo(); | ||
41 | //! } | ||
42 | //! //- /lib.rs crate:b | ||
43 | //! pub fn b() { | ||
44 | //! println!("Hello World") | ||
45 | //! } | ||
46 | //! "# | ||
47 | //! ``` | ||
48 | //! | ||
49 | //! Metadata allows specifying all settings and variables | ||
50 | //! that are available in a real rust project: | ||
51 | //! - crate names via `crate:cratename` | ||
52 | //! - dependencies via `deps:dep1,dep2` | ||
53 | //! - configuration settings via `cfg:dbg=false,opt_level=2` | ||
54 | //! - environment variables via `env:PATH=/bin,RUST_LOG=debug` | ||
55 | //! | ||
56 | //! Example using all available metadata: | ||
57 | //! ``` | ||
58 | //! " | ||
59 | //! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo | ||
60 | //! fn insert_source_code_here() {} | ||
61 | //! " | ||
62 | //! ``` | ||
3 | 63 | ||
4 | use rustc_hash::FxHashMap; | 64 | use rustc_hash::FxHashMap; |
5 | use stdx::{lines_with_ends, split_once, trim_indent}; | 65 | use stdx::{lines_with_ends, split_once, trim_indent}; |
@@ -24,7 +84,7 @@ impl Fixture { | |||
24 | /// //- some meta | 84 | /// //- some meta |
25 | /// line 1 | 85 | /// line 1 |
26 | /// line 2 | 86 | /// line 2 |
27 | /// // - other meta | 87 | /// //- other meta |
28 | /// ``` | 88 | /// ``` |
29 | pub fn parse(ra_fixture: &str) -> Vec<Fixture> { | 89 | pub fn parse(ra_fixture: &str) -> Vec<Fixture> { |
30 | let fixture = trim_indent(ra_fixture); | 90 | let fixture = trim_indent(ra_fixture); |
diff --git a/docs/dev/README.md b/docs/dev/README.md index eab21a765..9c0eb1358 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -24,7 +24,7 @@ Rust Analyzer is a part of [RLS-2.0 working | |||
24 | group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0). | 24 | group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0). |
25 | Discussion happens in this Zulip stream: | 25 | Discussion happens in this Zulip stream: |
26 | 26 | ||
27 | https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | 27 | https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer |
28 | 28 | ||
29 | # Issue Labels | 29 | # Issue Labels |
30 | 30 | ||
@@ -32,6 +32,8 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | |||
32 | are good issues to get into the project. | 32 | are good issues to get into the project. |
33 | * [E-has-instructions](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) | 33 | * [E-has-instructions](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) |
34 | issues have links to the code in question and tests. | 34 | issues have links to the code in question and tests. |
35 | * [Broken Window](https://github.com/rust-analyzer/rust-analyzer/issues?q=is:issue+is:open+label:%22Broken+Window%22) | ||
36 | are issues which are not critical by themselves, but which should be fixed ASAP regardless, to avoid accumulation of technical debt. | ||
35 | * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), | 37 | * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), |
36 | [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), | 38 | [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), |
37 | [E-hard](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard), | 39 | [E-hard](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard), |
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index fb991133a..3ffd9e8cb 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c | |||
42 | ## Entry Points | 42 | ## Entry Points |
43 | 43 | ||
44 | `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. | 44 | `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. |
45 | This is *the* entry point, but it front-loads a lot of complexity, so its fine to just skim through it. | 45 | This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it. |
46 | 46 | ||
47 | `crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. | 47 | `crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. |
48 | 48 | ||
@@ -67,7 +67,7 @@ They are handled by Rust code in the xtask directory. | |||
67 | 67 | ||
68 | VS Code plugin. | 68 | VS Code plugin. |
69 | 69 | ||
70 | ### `libs/` | 70 | ### `lib/` |
71 | 71 | ||
72 | rust-analyzer independent libraries which we publish to crates.io. | 72 | rust-analyzer independent libraries which we publish to crates.io. |
73 | It's not heavily utilized at the moment. | 73 | It's not heavily utilized at the moment. |
@@ -139,7 +139,8 @@ If an AST method returns an `Option`, it *can* be `None` at runtime, even if thi | |||
139 | ### `crates/base_db` | 139 | ### `crates/base_db` |
140 | 140 | ||
141 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. | 141 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. |
142 | Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. The `base_db` crate provides basic infrastructure for interacting with salsa. | 142 | Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. |
143 | The `base_db` crate provides basic infrastructure for interacting with salsa. | ||
143 | Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. | 144 | Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. |
144 | Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. | 145 | Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. |
145 | 146 | ||
@@ -221,7 +222,7 @@ Internally, `ide` is split across several crates. `ide_assists`, `ide_completion | |||
221 | The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. | 222 | The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. |
222 | 223 | ||
223 | **Architecture Invariant:** `ide` crate strives to provide a _perfect_ API. | 224 | **Architecture Invariant:** `ide` crate strives to provide a _perfect_ API. |
224 | Although at the moment it has only one consumer, the LSP server, LSP *does not* influence it's API design. | 225 | Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design. |
225 | Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies. | 226 | Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies. |
226 | 227 | ||
227 | ### `crates/rust-analyzer` | 228 | ### `crates/rust-analyzer` |
@@ -307,7 +308,7 @@ This sections talks about the things which are everywhere and nowhere in particu | |||
307 | 308 | ||
308 | ### Code generation | 309 | ### Code generation |
309 | 310 | ||
310 | Some of the components of this repository are generated through automatic processes. | 311 | Some ]components in this repository are generated through automatic processes. |
311 | Generated code is updated automatically on `cargo test`. | 312 | Generated code is updated automatically on `cargo test`. |
312 | Generated code is generally committed to the git repository. | 313 | Generated code is generally committed to the git repository. |
313 | 314 | ||
@@ -389,7 +390,7 @@ fn spam() { | |||
389 | ``` | 390 | ``` |
390 | 391 | ||
391 | To specify input data, we use a single string literal in a special format, which can describe a set of rust files. | 392 | To specify input data, we use a single string literal in a special format, which can describe a set of rust files. |
392 | See the `Fixture` type. | 393 | See the `Fixture` its module for fixture examples and documentation. |
393 | 394 | ||
394 | **Architecture Invariant:** all code invariants are tested by `#[test]` tests. | 395 | **Architecture Invariant:** all code invariants are tested by `#[test]` tests. |
395 | There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. | 396 | There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 989771ac6..a46121bb2 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -51,8 +51,8 @@ interface SnippetTextEdit extends TextEdit { | |||
51 | 51 | ||
52 | ```typescript | 52 | ```typescript |
53 | export interface TextDocumentEdit { | 53 | export interface TextDocumentEdit { |
54 | textDocument: OptionalVersionedTextDocumentIdentifier; | 54 | textDocument: OptionalVersionedTextDocumentIdentifier; |
55 | edits: (TextEdit | SnippetTextEdit)[]; | 55 | edits: (TextEdit | SnippetTextEdit)[]; |
56 | } | 56 | } |
57 | ``` | 57 | ``` |
58 | 58 | ||
@@ -145,9 +145,9 @@ mod foo; | |||
145 | ### Unresolved Question | 145 | ### Unresolved Question |
146 | 146 | ||
147 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. | 147 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. |
148 | This is the approach IntelliJ Rust is takeing. | 148 | This is the approach IntelliJ Rust is taking. |
149 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. | 149 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. |
150 | If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising. | 150 | If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising. |
151 | 151 | ||
152 | ## Join Lines | 152 | ## Join Lines |
153 | 153 | ||
@@ -193,7 +193,7 @@ fn main() { | |||
193 | ### Unresolved Question | 193 | ### Unresolved Question |
194 | 194 | ||
195 | * What is the position of the cursor after `joinLines`? | 195 | * What is the position of the cursor after `joinLines`? |
196 | Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. | 196 | Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets. |
197 | However, it then becomes unclear how it works with multi cursor. | 197 | However, it then becomes unclear how it works with multi cursor. |
198 | 198 | ||
199 | ## On Enter | 199 | ## On Enter |
@@ -330,7 +330,7 @@ Moreover, it would be cool if editors didn't need to implement even basic langua | |||
330 | 330 | ||
331 | ### Unresolved Question | 331 | ### Unresolved Question |
332 | 332 | ||
333 | * Should we return a a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? | 333 | * Should we return a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? |
334 | This is how `SelectionRange` request works. | 334 | This is how `SelectionRange` request works. |
335 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? | 335 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? |
336 | 336 | ||
@@ -511,7 +511,7 @@ Expands macro call at a given position. | |||
511 | This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. | 511 | This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. |
512 | Generally, the client should re-query inlay hints after every modification. | 512 | Generally, the client should re-query inlay hints after every modification. |
513 | Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one. | 513 | Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one. |
514 | Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956 | 514 | Upstream issues: https://github.com/microsoft/language-server-protocol/issues/956 , https://github.com/rust-analyzer/rust-analyzer/issues/2797 |
515 | 515 | ||
516 | **Request:** | 516 | **Request:** |
517 | 517 | ||
diff --git a/docs/dev/style.md b/docs/dev/style.md index 48ce4b92a..468dedff2 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -53,9 +53,9 @@ https://www.tedinski.com/2018/02/06/system-boundaries.html | |||
53 | ## Crates.io Dependencies | 53 | ## Crates.io Dependencies |
54 | 54 | ||
55 | We try to be very conservative with usage of crates.io dependencies. | 55 | We try to be very conservative with usage of crates.io dependencies. |
56 | Don't use small "helper" crates (exception: `itertools` is allowed). | 56 | Don't use small "helper" crates (exception: `itertools` and `either` are allowed). |
57 | If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. | 57 | If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. |
58 | A useful exercise is to read Cargo.lock and see if some of the *transitive* dependencies do not make sense for rust-analyzer. | 58 | A useful exercise is to read Cargo.lock and see if some *transitive* dependencies do not make sense for rust-analyzer. |
59 | 59 | ||
60 | **Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break. | 60 | **Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break. |
61 | 61 | ||
@@ -330,7 +330,7 @@ When implementing `do_thing`, it might be very useful to create a context object | |||
330 | 330 | ||
331 | ```rust | 331 | ```rust |
332 | pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { | 332 | pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { |
333 | let mut ctx = Ctx { arg1, arg2 } | 333 | let mut ctx = Ctx { arg1, arg2 }; |
334 | ctx.run() | 334 | ctx.run() |
335 | } | 335 | } |
336 | 336 | ||
@@ -586,7 +586,7 @@ use super::{} | |||
586 | 586 | ||
587 | **Rationale:** consistency. | 587 | **Rationale:** consistency. |
588 | Reading order is important for new contributors. | 588 | Reading order is important for new contributors. |
589 | Grouping by crate allows to spot unwanted dependencies easier. | 589 | Grouping by crate allows spotting unwanted dependencies easier. |
590 | 590 | ||
591 | ## Import Style | 591 | ## Import Style |
592 | 592 | ||
@@ -779,7 +779,7 @@ assert!(x < y); | |||
779 | assert!(x > 0); | 779 | assert!(x > 0); |
780 | 780 | ||
781 | // BAD | 781 | // BAD |
782 | assert!(x >= lo && x <= hi>); | 782 | assert!(x >= lo && x <= hi); |
783 | assert!(r1 < l2 || l1 > r2); | 783 | assert!(r1 < l2 || l1 > r2); |
784 | assert!(y > x); | 784 | assert!(y > x); |
785 | assert!(0 > x); | 785 | assert!(0 > x); |
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index 737cc7a72..f7a0c09fc 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md | |||
@@ -145,7 +145,7 @@ Another alternative (used by swift and roslyn) is to explicitly divide the set o | |||
145 | 145 | ||
146 | ```rust | 146 | ```rust |
147 | struct Token { | 147 | struct Token { |
148 | kind: NonTriviaTokenKind | 148 | kind: NonTriviaTokenKind, |
149 | text: String, | 149 | text: String, |
150 | leading_trivia: Vec<TriviaToken>, | 150 | leading_trivia: Vec<TriviaToken>, |
151 | trailing_trivia: Vec<TriviaToken>, | 151 | trailing_trivia: Vec<TriviaToken>, |
@@ -240,7 +240,7 @@ impl SyntaxNode { | |||
240 | let child_offset = offset; | 240 | let child_offset = offset; |
241 | offset += green_child.text_len; | 241 | offset += green_child.text_len; |
242 | Arc::new(SyntaxData { | 242 | Arc::new(SyntaxData { |
243 | offset: child_offset; | 243 | offset: child_offset, |
244 | parent: Some(Arc::clone(self)), | 244 | parent: Some(Arc::clone(self)), |
245 | green: Arc::clone(green_child), | 245 | green: Arc::clone(green_child), |
246 | }) | 246 | }) |
@@ -249,7 +249,7 @@ impl SyntaxNode { | |||
249 | } | 249 | } |
250 | 250 | ||
251 | impl PartialEq for SyntaxNode { | 251 | impl PartialEq for SyntaxNode { |
252 | fn eq(&self, other: &SyntaxNode) { | 252 | fn eq(&self, other: &SyntaxNode) -> bool { |
253 | self.offset == other.offset | 253 | self.offset == other.offset |
254 | && Arc::ptr_eq(&self.green, &other.green) | 254 | && Arc::ptr_eq(&self.green, &other.green) |
255 | } | 255 | } |
@@ -273,7 +273,7 @@ This is OK because trees traversals mostly (always, in case of rust-analyzer) ru | |||
273 | The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. | 273 | The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. |
274 | You can also use the similar trick to store a `SyntaxNode`. | 274 | You can also use the similar trick to store a `SyntaxNode`. |
275 | That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. | 275 | That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. |
276 | However rust-analyzer goes even further. | 276 | However, rust-analyzer goes even further. |
277 | It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`. | 277 | It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`. |
278 | The `SyntaxNode` is the restored by reparsing the file and traversing it from root. | 278 | The `SyntaxNode` is the restored by reparsing the file and traversing it from root. |
279 | With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. | 279 | With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. |