aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PRIVACY.md2
-rw-r--r--README.md4
-rw-r--r--crates/base_db/src/fixture.rs60
-rw-r--r--crates/hir/src/lib.rs8
-rw-r--r--crates/hir/src/source_analyzer.rs12
-rw-r--r--crates/hir_def/src/attr.rs66
-rw-r--r--crates/hir_def/src/db.rs15
-rw-r--r--crates/hir_def/src/item_scope.rs13
-rw-r--r--crates/hir_def/src/lib.rs8
-rw-r--r--crates/hir_def/src/nameres/collector.rs34
-rw-r--r--crates/hir_ty/src/autoderef.rs10
-rw-r--r--crates/hir_ty/src/infer.rs40
-rw-r--r--crates/hir_ty/src/infer/coerce.rs11
-rw-r--r--crates/hir_ty/src/infer/pat.rs6
-rw-r--r--crates/hir_ty/src/infer/unify.rs36
-rw-r--r--crates/hir_ty/src/lib.rs2
-rw-r--r--crates/hir_ty/src/method_resolution.rs54
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs22
-rw-r--r--crates/hir_ty/src/traits.rs16
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs118
-rw-r--r--crates/hir_ty/src/types.rs35
-rw-r--r--crates/ide/src/expand_macro.rs3
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs43
-rw-r--r--crates/ide_db/src/apply_change.rs4
-rw-r--r--crates/test_utils/src/fixture.rs62
-rw-r--r--docs/dev/README.md4
-rw-r--r--docs/dev/architecture.md13
-rw-r--r--docs/dev/lsp-extensions.md14
-rw-r--r--docs/dev/style.md10
-rw-r--r--docs/dev/syntax.md8
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
17If `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). 17If `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).
diff --git a/README.md b/README.md
index 085c8c0f6..5fbc03964 100644
--- a/README.md
+++ b/README.md
@@ -33,9 +33,9 @@ For usage and troubleshooting requests, please use "IDEs and Editors" category o
33 33
34https://users.rust-lang.org/c/ide/14 34https://users.rust-lang.org/c/ide/14
35 35
36For questions about development and implementation, join rls-2.0 working group on Zulip: 36For questions about development and implementation, join rust-analyzer working group on Zulip:
37 37
38https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0 38https://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//! ```
60use std::{mem, str::FromStr, sync::Arc}; 2use std::{mem, str::FromStr, sync::Arc};
61 3
62use cfg::CfgOptions; 4use 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};
65use itertools::Itertools; 64use itertools::Itertools;
66use rustc_hash::FxHashSet; 65use 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;
16use smallvec::{smallvec, SmallVec}; 16use smallvec::{smallvec, SmallVec};
17use syntax::{ 17use 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};
21use tt::Subtree; 21use 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
756pub(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
770pub(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 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use either::Either;
5use hir_expand::{db::AstDatabase, HirFileId}; 6use hir_expand::{db::AstDatabase, HirFileId};
6use la_arena::ArenaMap; 7use la_arena::ArenaMap;
7use syntax::SmolStr; 8use syntax::{ast, AstPtr, SmolStr};
8 9
9use crate::{ 10use 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};
11use stdx::format_to; 11use stdx::format_to;
12 12
13use crate::{ 13use 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
458trait Intern { 466trait 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};
43use crate::{ 43use 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)]
699pub struct InferenceVar {
700 index: u32,
701}
702
703impl 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 @@
7use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 7use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9 9
10use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; 10use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
11 11
12use super::{InEnvironment, InferenceContext}; 12use 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;
7use hir_def::{ 7use 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};
12use hir_expand::name::Name; 11use 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
562fn from_inference_var(var: InferenceVar) -> TypeVarId {
563 TypeVarId(var.index())
564}
565
566fn 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};
42pub use autoderef::autoderef; 42pub use autoderef::autoderef;
43pub use builder::TyBuilder; 43pub use builder::TyBuilder;
44pub use chalk_ext::{ProjectionTyExt, TyExt}; 44pub use chalk_ext::{ProjectionTyExt, TyExt};
45pub use infer::{could_unify, InferenceResult, InferenceVar}; 45pub use infer::{could_unify, InferenceResult};
46pub use lower::{ 46pub 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;
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use 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};
14use hir_expand::name::Name; 14use hir_expand::name::Name;
15use rustc_hash::{FxHashMap, FxHashSet}; 15use 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]
1297fn impl_in_unnamed_const() {
1298 check_types(
1299 r#"
1300struct S;
1301
1302trait Tr {
1303 fn method(&self) -> u16;
1304}
1305
1306const _: () = {
1307 impl Tr for S {}
1308};
1309
1310fn 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
10use crate::{ 10use 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
15use self::chalk::{from_chalk, Interner, ToChalk}; 15use 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;
10use hir_def::{GenericDefId, TypeAliasId}; 10use hir_def::{GenericDefId, TypeAliasId};
11 11
12use crate::{ 12use 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
19use super::interner::*; 18use 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.
194fn 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.
207fn 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
212impl ToChalk for GenericArg { 180impl 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
462impl 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
494pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> 474pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
495where 475where
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
12use crate::{ 12use 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)]
494pub struct SolutionVariables(pub Canonical<Substitution>); 493pub 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.
498pub enum Solution { 499pub 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)]
534pub struct InferenceVar {
535 index: u32,
536}
537
538impl From<u32> for InferenceVar {
539 fn from(index: u32) -> InferenceVar {
540 InferenceVar { index }
541 }
542}
543
544impl 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#"
1043mod m {
1044 pub fn some_fn() -> i32 {
1045 42
1046 }
1047}
1048struct Foo {
1049 some_field: i32,
1050}
1051fn 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#"
1063mod m {
1064 pub fn some_fn() -> i32 {
1065 42
1066 }
1067}
1068struct Foo {
1069 some_field: i32,
1070}
1071fn 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
4use rustc_hash::FxHashMap; 64use rustc_hash::FxHashMap;
5use stdx::{lines_with_ends, split_once, trim_indent}; 65use 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
24group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0). 24group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0).
25Discussion happens in this Zulip stream: 25Discussion happens in this Zulip stream:
26 26
27https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 27https://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.
45This is *the* entry point, but it front-loads a lot of complexity, so its fine to just skim through it. 45This 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
68VS Code plugin. 68VS Code plugin.
69 69
70### `libs/` 70### `lib/`
71 71
72rust-analyzer independent libraries which we publish to crates.io. 72rust-analyzer independent libraries which we publish to crates.io.
73It's not heavily utilized at the moment. 73It'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
141We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. 141We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation.
142Roughly, 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. 142Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions.
143The `base_db` crate provides basic infrastructure for interacting with salsa.
143Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. 144Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer.
144Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. 145Reading 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
221The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. 222The `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.
224Although at the moment it has only one consumer, the LSP server, LSP *does not* influence it's API design. 225Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design.
225Instead, 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. 226Instead, 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
310Some of the components of this repository are generated through automatic processes. 311Some ]components in this repository are generated through automatic processes.
311Generated code is updated automatically on `cargo test`. 312Generated code is updated automatically on `cargo test`.
312Generated code is generally committed to the git repository. 313Generated code is generally committed to the git repository.
313 314
@@ -389,7 +390,7 @@ fn spam() {
389``` 390```
390 391
391To specify input data, we use a single string literal in a special format, which can describe a set of rust files. 392To specify input data, we use a single string literal in a special format, which can describe a set of rust files.
392See the `Fixture` type. 393See 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.
395There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. 396There'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
53export interface TextDocumentEdit { 53export 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.
511This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. 511This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types.
512Generally, the client should re-query inlay hints after every modification. 512Generally, the client should re-query inlay hints after every modification.
513Note 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. 513Note 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.
514Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956 514Upstream 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
55We try to be very conservative with usage of crates.io dependencies. 55We try to be very conservative with usage of crates.io dependencies.
56Don't use small "helper" crates (exception: `itertools` is allowed). 56Don't use small "helper" crates (exception: `itertools` and `either` are allowed).
57If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. 57If there's some general reusable bit of code you need, consider adding it to the `stdx` crate.
58A useful exercise is to read Cargo.lock and see if some of the *transitive* dependencies do not make sense for rust-analyzer. 58A 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
332pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { 332pub 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.
588Reading order is important for new contributors. 588Reading order is important for new contributors.
589Grouping by crate allows to spot unwanted dependencies easier. 589Grouping by crate allows spotting unwanted dependencies easier.
590 590
591## Import Style 591## Import Style
592 592
@@ -779,7 +779,7 @@ assert!(x < y);
779assert!(x > 0); 779assert!(x > 0);
780 780
781// BAD 781// BAD
782assert!(x >= lo && x <= hi>); 782assert!(x >= lo && x <= hi);
783assert!(r1 < l2 || l1 > r2); 783assert!(r1 < l2 || l1 > r2);
784assert!(y > x); 784assert!(y > x);
785assert!(0 > x); 785assert!(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
147struct Token { 147struct 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
251impl PartialEq for SyntaxNode { 251impl 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
273The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. 273The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range.
274You can also use the similar trick to store a `SyntaxNode`. 274You can also use the similar trick to store a `SyntaxNode`.
275That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. 275That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`.
276However rust-analyzer goes even further. 276However, rust-analyzer goes even further.
277It 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>)`. 277It 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>)`.
278The `SyntaxNode` is the restored by reparsing the file and traversing it from root. 278The `SyntaxNode` is the restored by reparsing the file and traversing it from root.
279With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. 279With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage.