aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/has_source.rs15
-rw-r--r--crates/hir/src/lib.rs42
-rw-r--r--crates/hir/src/semantics/source_to_def.rs8
-rw-r--r--crates/hir_def/src/attr.rs66
-rw-r--r--crates/hir_def/src/import_map.rs18
-rw-r--r--crates/hir_def/src/item_scope.rs2
-rw-r--r--crates/hir_def/src/lib.rs8
-rw-r--r--crates/hir_def/src/nameres.rs12
-rw-r--r--crates/hir_def/src/nameres/collector.rs47
-rw-r--r--crates/hir_def/src/nameres/proc_macro.rs71
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs26
-rw-r--r--crates/hir_expand/src/builtin_derive.rs6
-rw-r--r--crates/hir_expand/src/builtin_macro.rs13
-rw-r--r--crates/hir_expand/src/db.rs14
-rw-r--r--crates/hir_expand/src/eager.rs12
-rw-r--r--crates/hir_expand/src/hygiene.rs12
-rw-r--r--crates/hir_expand/src/lib.rs26
-rw-r--r--crates/hir_ty/src/autoderef.rs20
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs15
-rw-r--r--crates/hir_ty/src/display.rs72
-rw-r--r--crates/hir_ty/src/infer.rs21
-rw-r--r--crates/hir_ty/src/infer/coerce.rs6
-rw-r--r--crates/hir_ty/src/infer/expr.rs13
-rw-r--r--crates/hir_ty/src/infer/path.rs12
-rw-r--r--crates/hir_ty/src/infer/unify.rs39
-rw-r--r--crates/hir_ty/src/lib.rs88
-rw-r--r--crates/hir_ty/src/lower.rs32
-rw-r--r--crates/hir_ty/src/method_resolution.rs5
-rw-r--r--crates/hir_ty/src/traits.rs39
-rw-r--r--crates/hir_ty/src/traits/chalk.rs26
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs107
-rw-r--r--crates/hir_ty/src/utils.rs10
-rw-r--r--crates/ide/src/display/navigation_target.rs8
-rw-r--r--crates/ide/src/goto_definition.rs17
-rw-r--r--crates/ide/src/hover.rs14
-rw-r--r--crates/ide/src/syntax_highlighting.rs16
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs66
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs14
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html2
-rw-r--r--crates/ide_assists/src/handlers/qualify_path.rs37
-rw-r--r--crates/ide_completion/src/render/macro_.rs2
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs6
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
-rw-r--r--docs/user/manual.adoc6
54 files changed, 746 insertions, 371 deletions
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 262002671..d57fad9ed 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -6,7 +6,7 @@ use hir_def::{
6 src::{HasChildSource, HasSource as _}, 6 src::{HasChildSource, HasSource as _},
7 Lookup, VariantId, 7 Lookup, VariantId,
8}; 8};
9use hir_expand::InFile; 9use hir_expand::{InFile, MacroDefKind};
10use syntax::ast; 10use syntax::ast;
11 11
12use crate::{ 12use crate::{
@@ -111,10 +111,17 @@ impl HasSource for TypeAlias {
111 } 111 }
112} 112}
113impl HasSource for MacroDef { 113impl HasSource for MacroDef {
114 type Ast = ast::Macro; 114 type Ast = Either<ast::Macro, ast::Fn>;
115 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { 115 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
116 let ast_id = self.id.ast_id?; 116 Some(match &self.id.kind {
117 Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) }) 117 MacroDefKind::Declarative(id)
118 | MacroDefKind::BuiltIn(_, id)
119 | MacroDefKind::BuiltInDerive(_, id)
120 | MacroDefKind::BuiltInEager(_, id) => {
121 id.with_value(Either::Left(id.to_node(db.upcast())))
122 }
123 MacroDefKind::ProcMacro(_, id) => id.map(|_| Either::Right(id.to_node(db.upcast()))),
124 })
118 } 125 }
119} 126}
120impl HasSource for Impl { 127impl HasSource for Impl {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b41a36a78..5ebd0a3b8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -56,9 +56,9 @@ use hir_ty::{
56 primitive::UintTy, 56 primitive::UintTy,
57 to_assoc_type_id, 57 to_assoc_type_id,
58 traits::{FnTrait, Solution, SolutionVariables}, 58 traits::{FnTrait, Solution, SolutionVariables},
59 AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, 59 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex,
60 InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substitution, 60 GenericPredicate, InEnvironment, Interner, Obligation, ProjectionTy, Scalar, Substitution, Ty,
61 Ty, TyDefId, TyKind, TyVariableKind, 61 TyDefId, TyKind, TyVariableKind,
62}; 62};
63use itertools::Itertools; 63use itertools::Itertools;
64use rustc_hash::FxHashSet; 64use rustc_hash::FxHashSet;
@@ -1144,17 +1144,21 @@ impl MacroDef {
1144 1144
1145 /// XXX: this parses the file 1145 /// XXX: this parses the file
1146 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 1146 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1147 self.source(db)?.value.name().map(|it| it.as_name()) 1147 match self.source(db)?.value {
1148 Either::Left(it) => it.name().map(|it| it.as_name()),
1149 Either::Right(it) => it.name().map(|it| it.as_name()),
1150 }
1148 } 1151 }
1149 1152
1150 /// Indicate it is a proc-macro 1153 /// Indicate it is a proc-macro
1151 pub fn is_proc_macro(&self) -> bool { 1154 pub fn is_proc_macro(&self) -> bool {
1152 matches!(self.id.kind, MacroDefKind::ProcMacro(_)) 1155 matches!(self.id.kind, MacroDefKind::ProcMacro(..))
1153 } 1156 }
1154 1157
1155 /// Indicate it is a derive macro 1158 /// Indicate it is a derive macro
1156 pub fn is_derive_macro(&self) -> bool { 1159 pub fn is_derive_macro(&self) -> bool {
1157 matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_)) 1160 // FIXME: wrong for `ProcMacro`
1161 matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..))
1158 } 1162 }
1159} 1163}
1160 1164
@@ -1458,7 +1462,7 @@ impl TypeParam {
1458 .into_iter() 1462 .into_iter()
1459 .filter_map(|pred| match &pred.value { 1463 .filter_map(|pred| match &pred.value {
1460 hir_ty::GenericPredicate::Implemented(trait_ref) => { 1464 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1461 Some(Trait::from(trait_ref.trait_)) 1465 Some(Trait::from(trait_ref.hir_trait_id()))
1462 } 1466 }
1463 _ => None, 1467 _ => None,
1464 }) 1468 })
@@ -1753,8 +1757,8 @@ impl Type {
1753 1757
1754 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { 1758 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1755 let trait_ref = hir_ty::TraitRef { 1759 let trait_ref = hir_ty::TraitRef {
1756 trait_: trait_.id, 1760 trait_id: hir_ty::to_chalk_trait_id(trait_.id),
1757 substs: Substitution::build_for_def(db, trait_.id) 1761 substitution: Substitution::build_for_def(db, trait_.id)
1758 .push(self.ty.value.clone()) 1762 .push(self.ty.value.clone())
1759 .fill(args.iter().map(|t| t.ty.value.clone())) 1763 .fill(args.iter().map(|t| t.ty.value.clone()))
1760 .build(), 1764 .build(),
@@ -1782,17 +1786,17 @@ impl Type {
1782 .push(self.ty.value.clone()) 1786 .push(self.ty.value.clone())
1783 .fill(args.iter().map(|t| t.ty.value.clone())) 1787 .fill(args.iter().map(|t| t.ty.value.clone()))
1784 .build(); 1788 .build();
1785 let predicate = ProjectionPredicate {
1786 projection_ty: ProjectionTy {
1787 associated_ty_id: to_assoc_type_id(alias.id),
1788 substitution: subst,
1789 },
1790 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner),
1791 };
1792 let goal = Canonical { 1789 let goal = Canonical {
1793 value: InEnvironment::new( 1790 value: InEnvironment::new(
1794 self.ty.environment.clone(), 1791 self.ty.environment.clone(),
1795 Obligation::Projection(predicate), 1792 Obligation::AliasEq(AliasEq {
1793 alias: AliasTy::Projection(ProjectionTy {
1794 associated_ty_id: to_assoc_type_id(alias.id),
1795 substitution: subst,
1796 }),
1797 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
1798 .intern(&Interner),
1799 }),
1796 ), 1800 ),
1797 kinds: Arc::new([TyVariableKind::General]), 1801 kinds: Arc::new([TyVariableKind::General]),
1798 }; 1802 };
@@ -2019,7 +2023,7 @@ impl Type {
2019 it.into_iter() 2023 it.into_iter()
2020 .filter_map(|pred| match pred { 2024 .filter_map(|pred| match pred {
2021 hir_ty::GenericPredicate::Implemented(trait_ref) => { 2025 hir_ty::GenericPredicate::Implemented(trait_ref) => {
2022 Some(Trait::from(trait_ref.trait_)) 2026 Some(Trait::from(trait_ref.hir_trait_id()))
2023 } 2027 }
2024 _ => None, 2028 _ => None,
2025 }) 2029 })
@@ -2063,7 +2067,7 @@ impl Type {
2063 match pred { 2067 match pred {
2064 GenericPredicate::Implemented(trait_ref) => { 2068 GenericPredicate::Implemented(trait_ref) => {
2065 cb(type_.clone()); 2069 cb(type_.clone());
2066 walk_substs(db, type_, &trait_ref.substs, cb); 2070 walk_substs(db, type_, &trait_ref.substitution, cb);
2067 } 2071 }
2068 _ => (), 2072 _ => (),
2069 } 2073 }
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index c6ad5ecb5..762809fcd 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -195,12 +195,12 @@ impl SourceToDefCtx<'_, '_> {
195 &mut self, 195 &mut self,
196 src: InFile<ast::MacroRules>, 196 src: InFile<ast::MacroRules>,
197 ) -> Option<MacroDefId> { 197 ) -> Option<MacroDefId> {
198 let kind = MacroDefKind::Declarative; 198 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
199 let ast_id = AstId::new(src.file_id, file_ast_id.upcast());
200 let kind = MacroDefKind::Declarative(ast_id);
199 let file_id = src.file_id.original_file(self.db.upcast()); 201 let file_id = src.file_id.original_file(self.db.upcast());
200 let krate = self.file_to_def(file_id).get(0).copied()?.krate(); 202 let krate = self.file_to_def(file_id).get(0).copied()?.krate();
201 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); 203 Some(MacroDefId { krate, kind, local_inner: false })
202 let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
203 Some(MacroDefId { krate, ast_id, kind, local_inner: false })
204 } 204 }
205 205
206 pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { 206 pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 85d01ac3e..0360fb627 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -209,7 +209,7 @@ impl Attrs {
209 }, 209 },
210 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), 210 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
211 AttrDefId::MacroDefId(it) => { 211 AttrDefId::MacroDefId(it) => {
212 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) 212 it.ast_id().map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
213 } 213 }
214 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), 214 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
215 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), 215 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
@@ -283,8 +283,51 @@ impl Attrs {
283 /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes. 283 /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
284 /// 284 ///
285 /// `owner` must be the original owner of the attributes. 285 /// `owner` must be the original owner of the attributes.
286 pub fn source_map(&self, owner: &dyn ast::AttrsOwner) -> AttrSourceMap { 286 // FIXME: figure out a better api that doesnt require the for_module hack
287 AttrSourceMap { attrs: collect_attrs(owner).collect() } 287 pub fn source_map(&self, owner: InFile<&dyn ast::AttrsOwner>) -> AttrSourceMap {
288 // FIXME: This doesn't work correctly for modules, as the attributes there can have up to
289 // two different owners
290 AttrSourceMap {
291 attrs: collect_attrs(owner.value)
292 .map(|attr| InFile::new(owner.file_id, attr))
293 .collect(),
294 }
295 }
296
297 pub fn source_map_for_module(
298 &self,
299 db: &dyn DefDatabase,
300 module: crate::ModuleId,
301 ) -> AttrSourceMap {
302 let def_map = module.def_map(db);
303 let mod_data = &def_map[module.local_id];
304 let attrs = match mod_data.declaration_source(db) {
305 Some(it) => {
306 let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner)
307 .map(|attr| InFile::new(it.file_id, attr))
308 .collect();
309 if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
310 mod_data.definition_source(db)
311 {
312 attrs.extend(
313 collect_attrs(&file as &dyn ast::AttrsOwner)
314 .map(|attr| InFile::new(file_id, attr)),
315 )
316 }
317 attrs
318 }
319 None => {
320 let InFile { file_id, value } = mod_data.definition_source(db);
321 match &value {
322 ModuleSource::SourceFile(file) => collect_attrs(file as &dyn ast::AttrsOwner),
323 ModuleSource::Module(module) => collect_attrs(module as &dyn ast::AttrsOwner),
324 ModuleSource::BlockExpr(block) => collect_attrs(block as &dyn ast::AttrsOwner),
325 }
326 .map(|attr| InFile::new(file_id, attr))
327 .collect()
328 }
329 };
330 AttrSourceMap { attrs }
288 } 331 }
289 332
290 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { 333 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
@@ -379,7 +422,7 @@ fn inner_attributes(
379} 422}
380 423
381pub struct AttrSourceMap { 424pub struct AttrSourceMap {
382 attrs: Vec<Either<ast::Attr, ast::Comment>>, 425 attrs: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
383} 426}
384 427
385impl AttrSourceMap { 428impl AttrSourceMap {
@@ -389,10 +432,11 @@ impl AttrSourceMap {
389 /// 432 ///
390 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of 433 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
391 /// the attribute represented by `Attr`. 434 /// the attribute represented by `Attr`.
392 pub fn source_of(&self, attr: &Attr) -> &Either<ast::Attr, ast::Comment> { 435 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
393 self.attrs 436 self.attrs
394 .get(attr.index as usize) 437 .get(attr.index as usize)
395 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index)) 438 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index))
439 .as_ref()
396 } 440 }
397} 441}
398 442
@@ -428,18 +472,6 @@ impl Attr {
428 Some(Attr { index, path, input }) 472 Some(Attr { index, path, input })
429 } 473 }
430 474
431 /// Maps this lowered `Attr` back to its original syntax node.
432 ///
433 /// `owner` must be the original owner of the attribute.
434 ///
435 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
436 /// the attribute represented by `Attr`.
437 pub fn to_src(&self, owner: &dyn ast::AttrsOwner) -> Either<ast::Attr, ast::Comment> {
438 collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| {
439 panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax())
440 })
441 }
442
443 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 475 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
444 /// to derive macros. 476 /// to derive macros.
445 /// 477 ///
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 369bc3350..960cabb5f 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -912,10 +912,10 @@ mod tests {
912 dep::fmt (t) 912 dep::fmt (t)
913 dep::format (f) 913 dep::format (f)
914 dep::Fmt (v) 914 dep::Fmt (v)
915 dep::fmt::Display (t) 915 dep::Fmt (m)
916 dep::Fmt (t) 916 dep::Fmt (t)
917 dep::fmt::Display::fmt (a) 917 dep::fmt::Display::fmt (a)
918 dep::Fmt (m) 918 dep::fmt::Display (t)
919 "#]], 919 "#]],
920 ); 920 );
921 921
@@ -926,9 +926,9 @@ mod tests {
926 expect![[r#" 926 expect![[r#"
927 dep::fmt (t) 927 dep::fmt (t)
928 dep::Fmt (v) 928 dep::Fmt (v)
929 dep::Fmt (m)
929 dep::Fmt (t) 930 dep::Fmt (t)
930 dep::fmt::Display::fmt (a) 931 dep::fmt::Display::fmt (a)
931 dep::Fmt (m)
932 "#]], 932 "#]],
933 ); 933 );
934 934
@@ -939,10 +939,10 @@ mod tests {
939 expect![[r#" 939 expect![[r#"
940 dep::fmt (t) 940 dep::fmt (t)
941 dep::Fmt (v) 941 dep::Fmt (v)
942 dep::fmt::Display (t) 942 dep::Fmt (m)
943 dep::Fmt (t) 943 dep::Fmt (t)
944 dep::fmt::Display::fmt (a) 944 dep::fmt::Display::fmt (a)
945 dep::Fmt (m) 945 dep::fmt::Display (t)
946 "#]], 946 "#]],
947 ); 947 );
948 } 948 }
@@ -980,10 +980,10 @@ mod tests {
980 expect![[r#" 980 expect![[r#"
981 dep::fmt (t) 981 dep::fmt (t)
982 dep::Fmt (v) 982 dep::Fmt (v)
983 dep::fmt::Display (t) 983 dep::Fmt (m)
984 dep::Fmt (t) 984 dep::Fmt (t)
985 dep::fmt::Display::fmt (a) 985 dep::fmt::Display::fmt (a)
986 dep::Fmt (m) 986 dep::fmt::Display (t)
987 "#]], 987 "#]],
988 ); 988 );
989 989
@@ -994,9 +994,9 @@ mod tests {
994 expect![[r#" 994 expect![[r#"
995 dep::fmt (t) 995 dep::fmt (t)
996 dep::Fmt (v) 996 dep::Fmt (v)
997 dep::Fmt (m)
997 dep::Fmt (t) 998 dep::Fmt (t)
998 dep::fmt::Display::fmt (a) 999 dep::fmt::Display::fmt (a)
999 dep::Fmt (m)
1000 "#]], 1000 "#]],
1001 ); 1001 );
1002 } 1002 }
@@ -1058,8 +1058,8 @@ mod tests {
1058 Query::new("".to_string()).limit(2), 1058 Query::new("".to_string()).limit(2),
1059 expect![[r#" 1059 expect![[r#"
1060 dep::fmt (t) 1060 dep::fmt (t)
1061 dep::Fmt (t)
1062 dep::Fmt (m) 1061 dep::Fmt (m)
1062 dep::Fmt (t)
1063 dep::Fmt (v) 1063 dep::Fmt (v)
1064 "#]], 1064 "#]],
1065 ); 1065 );
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index aafd73b60..f3ebe7c72 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -252,7 +252,7 @@ impl ItemScope {
252 .for_each(|vis| *vis = Visibility::Module(this_module)); 252 .for_each(|vis| *vis = Visibility::Module(this_module));
253 253
254 for (mac, vis) in self.macros.values_mut() { 254 for (mac, vis) in self.macros.values_mut() {
255 if let MacroDefKind::ProcMacro(_) = mac.kind { 255 if let MacroDefKind::ProcMacro(..) = mac.kind {
256 // FIXME: Technically this is insufficient since reexports of proc macros are also 256 // FIXME: Technically this is insufficient since reexports of proc macros are also
257 // forbidden. Practically nobody does that. 257 // forbidden. Practically nobody does that.
258 continue; 258 continue;
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 6758411a0..50e730444 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -76,7 +76,11 @@ use stdx::impl_from;
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77pub struct ModuleId { 77pub struct ModuleId {
78 krate: CrateId, 78 krate: CrateId,
79 /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
80 /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
81 /// `DefMap` of `krate`.
79 block: Option<BlockId>, 82 block: Option<BlockId>,
83 /// The module's ID in its originating `DefMap`.
80 pub local_id: LocalModuleId, 84 pub local_id: LocalModuleId,
81} 85}
82 86
@@ -87,7 +91,7 @@ impl ModuleId {
87 db.block_def_map(block).unwrap_or_else(|| { 91 db.block_def_map(block).unwrap_or_else(|| {
88 // NOTE: This should be unreachable - all `ModuleId`s come from their `DefMap`s, 92 // NOTE: This should be unreachable - all `ModuleId`s come from their `DefMap`s,
89 // so the `DefMap` here must exist. 93 // so the `DefMap` here must exist.
90 panic!("no `block_def_map` for `ModuleId` {:?}", self); 94 unreachable!("no `block_def_map` for `ModuleId` {:?}", self);
91 }) 95 })
92 } 96 }
93 None => db.crate_def_map(self.krate), 97 None => db.crate_def_map(self.krate),
@@ -650,7 +654,7 @@ fn macro_call_as_call_id(
650) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { 654) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
651 let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; 655 let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?;
652 656
653 let res = if let MacroDefKind::BuiltInEager(_) = def.kind { 657 let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
654 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); 658 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
655 let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id); 659 let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id);
656 660
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index c97be584e..1ac326f97 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -53,11 +53,12 @@ mod path_resolution;
53 53
54#[cfg(test)] 54#[cfg(test)]
55mod tests; 55mod tests;
56mod proc_macro;
56 57
57use std::sync::Arc; 58use std::sync::Arc;
58 59
59use base_db::{CrateId, Edition, FileId}; 60use base_db::{CrateId, Edition, FileId};
60use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; 61use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId};
61use la_arena::Arena; 62use la_arena::Arena;
62use profile::Count; 63use profile::Count;
63use rustc_hash::FxHashMap; 64use rustc_hash::FxHashMap;
@@ -73,6 +74,8 @@ use crate::{
73 AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId, 74 AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId,
74}; 75};
75 76
77use self::proc_macro::ProcMacroDef;
78
76/// Contains the results of (early) name resolution. 79/// Contains the results of (early) name resolution.
77/// 80///
78/// A `DefMap` stores the module tree and the definitions that are in scope in every module after 81/// A `DefMap` stores the module tree and the definitions that are in scope in every module after
@@ -95,6 +98,12 @@ pub struct DefMap {
95 prelude: Option<ModuleId>, 98 prelude: Option<ModuleId>,
96 extern_prelude: FxHashMap<Name, ModuleDefId>, 99 extern_prelude: FxHashMap<Name, ModuleDefId>,
97 100
101 /// Side table with additional proc. macro info, for use by name resolution in downstream
102 /// crates.
103 ///
104 /// (the primary purpose is to resolve derive helpers)
105 exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
106
98 edition: Edition, 107 edition: Edition,
99 diagnostics: Vec<DefDiagnostic>, 108 diagnostics: Vec<DefDiagnostic>,
100} 109}
@@ -237,6 +246,7 @@ impl DefMap {
237 krate, 246 krate,
238 edition, 247 edition,
239 extern_prelude: FxHashMap::default(), 248 extern_prelude: FxHashMap::default(),
249 exported_proc_macros: FxHashMap::default(),
240 prelude: None, 250 prelude: None,
241 root, 251 root,
242 modules, 252 modules,
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d0fefb5af..dcedf7766 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -18,7 +18,6 @@ use hir_expand::{
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
20use syntax::ast; 20use syntax::ast;
21use tt::{Leaf, TokenTree};
22 21
23use crate::{ 22use crate::{
24 attr::Attrs, 23 attr::Attrs,
@@ -42,6 +41,8 @@ use crate::{
42 UnresolvedMacro, 41 UnresolvedMacro,
43}; 42};
44 43
44use super::proc_macro::ProcMacroDef;
45
45const GLOB_RECURSION_LIMIT: usize = 100; 46const GLOB_RECURSION_LIMIT: usize = 100;
46const EXPANSION_DEPTH_LIMIT: usize = 128; 47const EXPANSION_DEPTH_LIMIT: usize = 128;
47const FIXED_POINT_LIMIT: usize = 8192; 48const FIXED_POINT_LIMIT: usize = 8192;
@@ -353,24 +354,23 @@ impl DefCollector<'_> {
353 /// use a dummy expander that always errors. This comes with the drawback of macros potentially 354 /// use a dummy expander that always errors. This comes with the drawback of macros potentially
354 /// going out of sync with what the build system sees (since we resolve using VFS state, but 355 /// going out of sync with what the build system sees (since we resolve using VFS state, but
355 /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. 356 /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
356 fn resolve_proc_macro(&mut self, name: &Name) { 357 fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) {
357 self.exports_proc_macros = true; 358 self.exports_proc_macros = true;
358 let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { 359 let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
359 Some((_, expander)) => MacroDefId { 360 Some((_, expander)) => MacroDefId {
360 ast_id: None,
361 krate: self.def_map.krate, 361 krate: self.def_map.krate,
362 kind: MacroDefKind::ProcMacro(*expander), 362 kind: MacroDefKind::ProcMacro(*expander, ast_id),
363 local_inner: false, 363 local_inner: false,
364 }, 364 },
365 None => MacroDefId { 365 None => MacroDefId {
366 ast_id: None,
367 krate: self.def_map.krate, 366 krate: self.def_map.krate,
368 kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)), 367 kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id),
369 local_inner: false, 368 local_inner: false,
370 }, 369 },
371 }; 370 };
372 371
373 self.define_proc_macro(name.clone(), macro_def); 372 self.define_proc_macro(def.name.clone(), macro_def);
373 self.def_map.exported_proc_macros.insert(macro_def, def);
374 } 374 }
375 375
376 /// Define a macro with `macro_rules`. 376 /// Define a macro with `macro_rules`.
@@ -1118,7 +1118,8 @@ impl ModCollector<'_, '_> {
1118 ModItem::Function(id) => { 1118 ModItem::Function(id) => {
1119 let func = &self.item_tree[id]; 1119 let func = &self.item_tree[id];
1120 1120
1121 self.collect_proc_macro_def(&func.name, &attrs); 1121 let ast_id = InFile::new(self.file_id, func.ast_id);
1122 self.collect_proc_macro_def(&func.name, ast_id, &attrs);
1122 1123
1123 def = Some(DefData { 1124 def = Some(DefData {
1124 id: FunctionLoc { 1125 id: FunctionLoc {
@@ -1385,28 +1386,11 @@ impl ModCollector<'_, '_> {
1385 } 1386 }
1386 1387
1387 /// If `attrs` registers a procedural macro, collects its definition. 1388 /// If `attrs` registers a procedural macro, collects its definition.
1388 fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) { 1389 fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) {
1389 // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere 1390 // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
1390 // FIXME: distinguish the type of macro 1391 if let Some(proc_macro) = attrs.parse_proc_macro_decl(func_name) {
1391 let macro_name = if attrs.by_key("proc_macro").exists() 1392 self.def_collector.export_proc_macro(proc_macro, ast_id);
1392 || attrs.by_key("proc_macro_attribute").exists() 1393 }
1393 {
1394 func_name.clone()
1395 } else {
1396 let derive = attrs.by_key("proc_macro_derive");
1397 if let Some(arg) = derive.tt_values().next() {
1398 if let [TokenTree::Leaf(Leaf::Ident(trait_name)), ..] = &*arg.token_trees {
1399 trait_name.as_name()
1400 } else {
1401 log::trace!("malformed `#[proc_macro_derive]`: {}", arg);
1402 return;
1403 }
1404 } else {
1405 return;
1406 }
1407 };
1408
1409 self.def_collector.resolve_proc_macro(&macro_name);
1410 } 1394 }
1411 1395
1412 fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { 1396 fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
@@ -1445,9 +1429,8 @@ impl ModCollector<'_, '_> {
1445 1429
1446 // Case 2: normal `macro_rules!` macro 1430 // Case 2: normal `macro_rules!` macro
1447 let macro_id = MacroDefId { 1431 let macro_id = MacroDefId {
1448 ast_id: Some(ast_id),
1449 krate: self.def_collector.def_map.krate, 1432 krate: self.def_collector.def_map.krate,
1450 kind: MacroDefKind::Declarative, 1433 kind: MacroDefKind::Declarative(ast_id),
1451 local_inner: is_local_inner, 1434 local_inner: is_local_inner,
1452 }; 1435 };
1453 self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); 1436 self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export);
diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs
new file mode 100644
index 000000000..156598f19
--- /dev/null
+++ b/crates/hir_def/src/nameres/proc_macro.rs
@@ -0,0 +1,71 @@
1//! Nameres-specific procedural macro data and helpers.
2
3use hir_expand::name::{AsName, Name};
4use tt::{Leaf, TokenTree};
5
6use crate::attr::Attrs;
7
8#[derive(Debug, PartialEq, Eq)]
9pub(super) struct ProcMacroDef {
10 pub(super) name: Name,
11 pub(super) kind: ProcMacroKind,
12}
13
14#[derive(Debug, PartialEq, Eq)]
15pub(super) enum ProcMacroKind {
16 CustomDerive { helpers: Box<[Name]> },
17 FnLike,
18 Attr,
19}
20
21impl Attrs {
22 #[rustfmt::skip]
23 pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
24 if self.by_key("proc_macro").exists() {
25 Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
26 } else if self.by_key("proc_macro_attribute").exists() {
27 Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
28 } else if self.by_key("proc_macro_derive").exists() {
29 let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap();
30
31 match &*derive.token_trees {
32 // `#[proc_macro_derive(Trait)]`
33 [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
34 name: trait_name.as_name(),
35 kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
36 }),
37
38 // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]`
39 [
40 TokenTree::Leaf(Leaf::Ident(trait_name)),
41 TokenTree::Leaf(Leaf::Punct(comma)),
42 TokenTree::Leaf(Leaf::Ident(attributes)),
43 TokenTree::Subtree(helpers)
44 ] if comma.char == ',' && attributes.text == "attributes" =>
45 {
46 let helpers = helpers.token_trees.iter()
47 .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
48 .map(|tt| {
49 match tt {
50 TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
51 _ => None
52 }
53 })
54 .collect::<Option<Box<[_]>>>()?;
55
56 Some(ProcMacroDef {
57 name: trait_name.as_name(),
58 kind: ProcMacroKind::CustomDerive { helpers },
59 })
60 }
61
62 _ => {
63 log::trace!("malformed `#[proc_macro_derive]`: {}", derive);
64 None
65 }
66 }
67 } else {
68 None
69 }
70 }
71}
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index f65a655bf..d59d3c0db 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -1,4 +1,5 @@
1use super::*; 1use super::*;
2use crate::nameres::proc_macro::{ProcMacroDef, ProcMacroKind};
2 3
3#[test] 4#[test]
4fn macro_rules_are_globally_visible() { 5fn macro_rules_are_globally_visible() {
@@ -790,3 +791,28 @@ fn proc_macro_censoring() {
790 "#]], 791 "#]],
791 ); 792 );
792} 793}
794
795#[test]
796fn collects_derive_helpers() {
797 let def_map = compute_crate_def_map(
798 r"
799 struct TokenStream;
800
801 #[proc_macro_derive(AnotherTrait, attributes(helper_attr))]
802 pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
803 TokenStream
804 }
805 ",
806 );
807
808 assert_eq!(def_map.exported_proc_macros.len(), 1);
809 match def_map.exported_proc_macros.values().next() {
810 Some(ProcMacroDef { kind: ProcMacroKind::CustomDerive { helpers }, .. }) => {
811 match &**helpers {
812 [attr] => assert_eq!(attr.to_string(), "helper_attr"),
813 _ => unreachable!(),
814 }
815 }
816 _ => unreachable!(),
817 }
818}
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index a8d267c30..60fd2ebdd 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -61,8 +61,7 @@ pub fn find_builtin_derive(
61 let expander = BuiltinDeriveExpander::find_by_name(ident)?; 61 let expander = BuiltinDeriveExpander::find_by_name(ident)?;
62 Some(MacroDefId { 62 Some(MacroDefId {
63 krate, 63 krate,
64 ast_id: Some(ast_id), 64 kind: MacroDefKind::BuiltInDerive(expander, ast_id),
65 kind: MacroDefKind::BuiltInDerive(expander),
66 local_inner: false, 65 local_inner: false,
67 }) 66 })
68} 67}
@@ -314,8 +313,7 @@ $0
314 let loc = MacroCallLoc { 313 let loc = MacroCallLoc {
315 def: MacroDefId { 314 def: MacroDefId {
316 krate: CrateId(0), 315 krate: CrateId(0),
317 ast_id: Some(macro_ast_id), 316 kind: MacroDefKind::BuiltInDerive(expander, macro_ast_id),
318 kind: MacroDefKind::BuiltInDerive(expander),
319 local_inner: false, 317 local_inner: false,
320 }, 318 },
321 krate: CrateId(0), 319 krate: CrateId(0),
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index fce09a9e7..8529b43b6 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -71,14 +71,12 @@ pub fn find_builtin_macro(
71 match kind { 71 match kind {
72 Either::Left(kind) => Some(MacroDefId { 72 Either::Left(kind) => Some(MacroDefId {
73 krate, 73 krate,
74 ast_id: Some(ast_id), 74 kind: MacroDefKind::BuiltIn(kind, ast_id),
75 kind: MacroDefKind::BuiltIn(kind),
76 local_inner: false, 75 local_inner: false,
77 }), 76 }),
78 Either::Right(kind) => Some(MacroDefId { 77 Either::Right(kind) => Some(MacroDefId {
79 krate, 78 krate,
80 ast_id: Some(ast_id), 79 kind: MacroDefKind::BuiltInEager(kind, ast_id),
81 kind: MacroDefKind::BuiltInEager(kind),
82 local_inner: false, 80 local_inner: false,
83 }), 81 }),
84 } 82 }
@@ -512,6 +510,7 @@ mod tests {
512 let macro_call = macro_calls.pop().unwrap(); 510 let macro_call = macro_calls.pop().unwrap();
513 511
514 let expander = find_by_name(&macro_rules.name().unwrap().as_name()).unwrap(); 512 let expander = find_by_name(&macro_rules.name().unwrap().as_name()).unwrap();
513 let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules));
515 514
516 let krate = CrateId(0); 515 let krate = CrateId(0);
517 let file_id = match expander { 516 let file_id = match expander {
@@ -519,8 +518,7 @@ mod tests {
519 // the first one should be a macro_rules 518 // the first one should be a macro_rules
520 let def = MacroDefId { 519 let def = MacroDefId {
521 krate: CrateId(0), 520 krate: CrateId(0),
522 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))), 521 kind: MacroDefKind::BuiltIn(expander, ast_id),
523 kind: MacroDefKind::BuiltIn(expander),
524 local_inner: false, 522 local_inner: false,
525 }; 523 };
526 524
@@ -540,8 +538,7 @@ mod tests {
540 // the first one should be a macro_rules 538 // the first one should be a macro_rules
541 let def = MacroDefId { 539 let def = MacroDefId {
542 krate, 540 krate,
543 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))), 541 kind: MacroDefKind::BuiltInEager(expander, ast_id),
544 kind: MacroDefKind::BuiltInEager(expander),
545 local_inner: false, 542 local_inner: false,
546 }; 543 };
547 544
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index a3070f1f9..2748e25cf 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -130,8 +130,8 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
130 130
131fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 131fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
132 match id.kind { 132 match id.kind {
133 MacroDefKind::Declarative => { 133 MacroDefKind::Declarative(ast_id) => {
134 let macro_rules = match id.ast_id?.to_node(db) { 134 let macro_rules = match ast_id.to_node(db) {
135 syntax::ast::Macro::MacroRules(mac) => mac, 135 syntax::ast::Macro::MacroRules(mac) => mac,
136 syntax::ast::Macro::MacroDef(_) => return None, 136 syntax::ast::Macro::MacroDef(_) => return None,
137 }; 137 };
@@ -150,14 +150,14 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
150 }; 150 };
151 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 151 Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
152 } 152 }
153 MacroDefKind::BuiltIn(expander) => { 153 MacroDefKind::BuiltIn(expander, _) => {
154 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) 154 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
155 } 155 }
156 MacroDefKind::BuiltInDerive(expander) => { 156 MacroDefKind::BuiltInDerive(expander, _) => {
157 Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) 157 Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
158 } 158 }
159 MacroDefKind::BuiltInEager(_) => None, 159 MacroDefKind::BuiltInEager(..) => None,
160 MacroDefKind::ProcMacro(expander) => { 160 MacroDefKind::ProcMacro(expander, ..) => {
161 Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default()))) 161 Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default())))
162 } 162 }
163 } 163 }
@@ -269,7 +269,7 @@ fn expand_proc_macro(
269 }; 269 };
270 270
271 let expander = match loc.def.kind { 271 let expander = match loc.def.kind {
272 MacroDefKind::ProcMacro(expander) => expander, 272 MacroDefKind::ProcMacro(expander, ..) => expander,
273 _ => unreachable!(), 273 _ => unreachable!(),
274 }; 274 };
275 275
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index dc618a9ee..04f374a29 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -140,7 +140,7 @@ pub fn expand_eager_macro(
140 let subtree = 140 let subtree =
141 diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?; 141 diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;
142 142
143 if let MacroDefKind::BuiltInEager(eager) = def.kind { 143 if let MacroDefKind::BuiltInEager(eager, _) = def.kind {
144 let res = eager.expand(db, arg_id, &subtree); 144 let res = eager.expand(db, arg_id, &subtree);
145 145
146 let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; 146 let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?;
@@ -193,7 +193,7 @@ fn eager_macro_recur(
193 let def = diagnostic_sink 193 let def = diagnostic_sink
194 .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?; 194 .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
195 let insert = match def.kind { 195 let insert = match def.kind {
196 MacroDefKind::BuiltInEager(_) => { 196 MacroDefKind::BuiltInEager(..) => {
197 let id: MacroCallId = expand_eager_macro( 197 let id: MacroCallId = expand_eager_macro(
198 db, 198 db,
199 krate, 199 krate,
@@ -206,10 +206,10 @@ fn eager_macro_recur(
206 db.parse_or_expand(id.as_file()) 206 db.parse_or_expand(id.as_file())
207 .expect("successful macro expansion should be parseable") 207 .expect("successful macro expansion should be parseable")
208 } 208 }
209 MacroDefKind::Declarative 209 MacroDefKind::Declarative(_)
210 | MacroDefKind::BuiltIn(_) 210 | MacroDefKind::BuiltIn(..)
211 | MacroDefKind::BuiltInDerive(_) 211 | MacroDefKind::BuiltInDerive(..)
212 | MacroDefKind::ProcMacro(_) => { 212 | MacroDefKind::ProcMacro(..) => {
213 let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); 213 let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
214 let val = diagnostic_sink.expand_result_option(res)?; 214 let val = diagnostic_sink.expand_result_option(res)?;
215 215
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 87cad326d..20cda1683 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -145,7 +145,7 @@ fn make_hygiene_info(
145) -> Option<HygieneInfo> { 145) -> Option<HygieneInfo> {
146 let arg_tt = loc.kind.arg(db)?; 146 let arg_tt = loc.kind.arg(db)?;
147 147
148 let def_offset = loc.def.ast_id.and_then(|id| { 148 let def_offset = loc.def.ast_id().and_then(|id| {
149 let def_tt = match id.to_node(db) { 149 let def_tt = match id.to_node(db) {
150 ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), 150 ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
151 ast::Macro::MacroDef(_) => return None, 151 ast::Macro::MacroDef(_) => return None,
@@ -176,13 +176,13 @@ impl HygieneFrame {
176 let loc = db.lookup_intern_macro(id); 176 let loc = db.lookup_intern_macro(id);
177 let info = make_hygiene_info(db, macro_file, &loc); 177 let info = make_hygiene_info(db, macro_file, &loc);
178 match loc.def.kind { 178 match loc.def.kind {
179 MacroDefKind::Declarative => { 179 MacroDefKind::Declarative(_) => {
180 (info, Some(loc.def.krate), loc.def.local_inner) 180 (info, Some(loc.def.krate), loc.def.local_inner)
181 } 181 }
182 MacroDefKind::BuiltIn(_) => (info, Some(loc.def.krate), false), 182 MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false),
183 MacroDefKind::BuiltInDerive(_) => (info, None, false), 183 MacroDefKind::BuiltInDerive(..) => (info, None, false),
184 MacroDefKind::BuiltInEager(_) => (info, None, false), 184 MacroDefKind::BuiltInEager(..) => (info, None, false),
185 MacroDefKind::ProcMacro(_) => (info, None, false), 185 MacroDefKind::ProcMacro(..) => (info, None, false),
186 } 186 }
187 } 187 }
188 }, 188 },
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 7532d00b8..0a379651f 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -143,7 +143,7 @@ impl HirFileId {
143 143
144 let arg_tt = loc.kind.arg(db)?; 144 let arg_tt = loc.kind.arg(db)?;
145 145
146 let def = loc.def.ast_id.and_then(|id| { 146 let def = loc.def.ast_id().and_then(|id| {
147 let def_tt = match id.to_node(db) { 147 let def_tt = match id.to_node(db) {
148 ast::Macro::MacroRules(mac) => mac.token_tree()?, 148 ast::Macro::MacroRules(mac) => mac.token_tree()?,
149 ast::Macro::MacroDef(_) => return None, 149 ast::Macro::MacroDef(_) => return None,
@@ -180,7 +180,7 @@ impl HirFileId {
180 }; 180 };
181 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); 181 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
182 let item = match loc.def.kind { 182 let item = match loc.def.kind {
183 MacroDefKind::BuiltInDerive(_) => loc.kind.node(db), 183 MacroDefKind::BuiltInDerive(..) => loc.kind.node(db),
184 _ => return None, 184 _ => return None,
185 }; 185 };
186 Some(item.with_value(ast::Item::cast(item.value.clone())?)) 186 Some(item.with_value(ast::Item::cast(item.value.clone())?))
@@ -224,7 +224,6 @@ impl From<EagerMacroId> for MacroCallId {
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
225pub struct MacroDefId { 225pub struct MacroDefId {
226 pub krate: CrateId, 226 pub krate: CrateId,
227 pub ast_id: Option<AstId<ast::Macro>>,
228 pub kind: MacroDefKind, 227 pub kind: MacroDefKind,
229 228
230 pub local_inner: bool, 229 pub local_inner: bool,
@@ -239,16 +238,27 @@ impl MacroDefId {
239 ) -> LazyMacroId { 238 ) -> LazyMacroId {
240 db.intern_macro(MacroCallLoc { def: self, krate, kind }) 239 db.intern_macro(MacroCallLoc { def: self, krate, kind })
241 } 240 }
241
242 pub fn ast_id(&self) -> Option<AstId<ast::Macro>> {
243 let id = match &self.kind {
244 MacroDefKind::Declarative(id) => id,
245 MacroDefKind::BuiltIn(_, id) => id,
246 MacroDefKind::BuiltInDerive(_, id) => id,
247 MacroDefKind::BuiltInEager(_, id) => id,
248 MacroDefKind::ProcMacro(..) => return None,
249 };
250 Some(*id)
251 }
242} 252}
243 253
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 254#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
245pub enum MacroDefKind { 255pub enum MacroDefKind {
246 Declarative, 256 Declarative(AstId<ast::Macro>),
247 BuiltIn(BuiltinFnLikeExpander), 257 BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
248 // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander 258 // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
249 BuiltInDerive(BuiltinDeriveExpander), 259 BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
250 BuiltInEager(EagerExpander), 260 BuiltInEager(EagerExpander, AstId<ast::Macro>),
251 ProcMacro(ProcMacroExpander), 261 ProcMacro(ProcMacroExpander, AstId<ast::Fn>),
252} 262}
253 263
254#[derive(Debug, Clone, PartialEq, Eq, Hash)] 264#[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index bd2ff5d38..33b966026 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -12,10 +12,11 @@ use log::{info, warn};
12 12
13use crate::{ 13use crate::{
14 db::HirDatabase, 14 db::HirDatabase,
15 to_assoc_type_id, 15 to_assoc_type_id, to_chalk_trait_id,
16 traits::{InEnvironment, Solution}, 16 traits::{InEnvironment, Solution},
17 utils::generics, 17 utils::generics,
18 BoundVar, Canonical, DebruijnIndex, Interner, Obligation, Substitution, TraitRef, Ty, TyKind, 18 AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, Interner, Obligation, ProjectionTy,
19 Substitution, TraitRef, Ty, TyKind,
19}; 20};
20 21
21const AUTODEREF_RECURSION_LIMIT: usize = 10; 22const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -68,7 +69,8 @@ fn deref_by_trait(
68 Substitution::build_for_generics(&generic_params).push(ty.value.value.clone()).build(); 69 Substitution::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
69 70
70 // Check that the type implements Deref at all 71 // Check that the type implements Deref at all
71 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; 72 let trait_ref =
73 TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() };
72 let implements_goal = Canonical { 74 let implements_goal = Canonical {
73 kinds: ty.value.kinds.clone(), 75 kinds: ty.value.kinds.clone(),
74 value: InEnvironment { 76 value: InEnvironment {
@@ -81,16 +83,16 @@ fn deref_by_trait(
81 } 83 }
82 84
83 // Now do the assoc type projection 85 // Now do the assoc type projection
84 let projection = super::traits::ProjectionPredicate { 86 let projection = AliasEq {
85 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())) 87 alias: AliasTy::Projection(ProjectionTy {
86 .intern(&Interner),
87 projection_ty: super::ProjectionTy {
88 associated_ty_id: to_assoc_type_id(target), 88 associated_ty_id: to_assoc_type_id(target),
89 substitution: parameters, 89 substitution: parameters,
90 }, 90 }),
91 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len()))
92 .intern(&Interner),
91 }; 93 };
92 94
93 let obligation = super::Obligation::Projection(projection); 95 let obligation = super::Obligation::AliasEq(projection);
94 96
95 let in_env = InEnvironment { value: obligation, environment: ty.environment }; 97 let in_env = InEnvironment { value: obligation, environment: ty.environment };
96 98
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index bfe239793..33a0f4d7d 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -102,7 +102,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
102 let db = self.db; 102 let db = self.db;
103 for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { 103 for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
104 for (_, module) in block_def_map.modules() { 104 for (_, module) in block_def_map.modules() {
105 for (def_id, _) in module.scope.values() { 105 for def_id in module.scope.declarations() {
106 let mut validator = DeclValidator::new(self.db, self.krate, self.sink); 106 let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
107 validator.validate_item(def_id); 107 validator.validate_item(def_id);
108 } 108 }
@@ -902,4 +902,17 @@ extern {
902 "#, 902 "#,
903 ); 903 );
904 } 904 }
905
906 #[test]
907 fn infinite_loop_inner_items() {
908 check_diagnostics(
909 r#"
910fn qualify() {
911 mod foo {
912 use super::*;
913 }
914}
915 "#,
916 )
917 }
905} 918}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 7ce0f864c..59a1bd9b0 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -18,9 +18,9 @@ use hir_expand::name::Name;
18 18
19use crate::{ 19use crate::{
20 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, 20 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive,
21 to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasTy, CallableDefId, 21 to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
22 CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation, OpaqueTy, 22 CallableDefId, CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation,
23 ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind, 23 OpaqueTy, ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind,
24}; 24};
25 25
26pub struct HirFormatter<'a> { 26pub struct HirFormatter<'a> {
@@ -268,6 +268,16 @@ impl HirDisplay for ProjectionTy {
268 } 268 }
269} 269}
270 270
271impl HirDisplay for OpaqueTy {
272 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
273 if f.should_truncate() {
274 return write!(f, "{}", TYPE_HINT_TRUNCATION);
275 }
276
277 self.substitution[0].hir_fmt(f)
278 }
279}
280
271impl HirDisplay for Ty { 281impl HirDisplay for Ty {
272 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 282 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
273 if f.should_truncate() { 283 if f.should_truncate() {
@@ -344,7 +354,7 @@ impl HirDisplay for Ty {
344 }; 354 };
345 355
346 if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() { 356 if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
347 let trait_ = trait_ref.trait_; 357 let trait_ = trait_ref.hir_trait_id();
348 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) { 358 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
349 return write!(f, "{}", ty_display); 359 return write!(f, "{}", ty_display);
350 } 360 }
@@ -670,7 +680,7 @@ fn write_bounds_like_dyn_trait(
670 for p in predicates.iter() { 680 for p in predicates.iter() {
671 match p { 681 match p {
672 GenericPredicate::Implemented(trait_ref) => { 682 GenericPredicate::Implemented(trait_ref) => {
673 let trait_ = trait_ref.trait_; 683 let trait_ = trait_ref.hir_trait_id();
674 if !is_fn_trait { 684 if !is_fn_trait {
675 is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_); 685 is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
676 } 686 }
@@ -685,7 +695,7 @@ fn write_bounds_like_dyn_trait(
685 // existential) here, which is the only thing that's 695 // existential) here, which is the only thing that's
686 // possible in actual Rust, and hence don't print it 696 // possible in actual Rust, and hence don't print it
687 write!(f, "{}", f.db.trait_data(trait_).name)?; 697 write!(f, "{}", f.db.trait_data(trait_).name)?;
688 if let [_, params @ ..] = &*trait_ref.substs.0 { 698 if let [_, params @ ..] = &*trait_ref.substitution.0 {
689 if is_fn_trait { 699 if is_fn_trait {
690 if let Some(args) = params.first().and_then(|it| it.as_tuple()) { 700 if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
691 write!(f, "(")?; 701 write!(f, "(")?;
@@ -700,12 +710,12 @@ fn write_bounds_like_dyn_trait(
700 } 710 }
701 } 711 }
702 } 712 }
703 GenericPredicate::Projection(projection_pred) if is_fn_trait => { 713 GenericPredicate::AliasEq(alias_eq) if is_fn_trait => {
704 is_fn_trait = false; 714 is_fn_trait = false;
705 write!(f, " -> ")?; 715 write!(f, " -> ")?;
706 projection_pred.ty.hir_fmt(f)?; 716 alias_eq.ty.hir_fmt(f)?;
707 } 717 }
708 GenericPredicate::Projection(projection_pred) => { 718 GenericPredicate::AliasEq(AliasEq { ty, alias }) => {
709 // in types in actual Rust, these will always come 719 // in types in actual Rust, these will always come
710 // after the corresponding Implemented predicate 720 // after the corresponding Implemented predicate
711 if angle_open { 721 if angle_open {
@@ -714,11 +724,12 @@ fn write_bounds_like_dyn_trait(
714 write!(f, "<")?; 724 write!(f, "<")?;
715 angle_open = true; 725 angle_open = true;
716 } 726 }
717 let type_alias = f.db.type_alias_data(from_assoc_type_id( 727 if let AliasTy::Projection(proj) = alias {
718 projection_pred.projection_ty.associated_ty_id, 728 let type_alias =
719 )); 729 f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
720 write!(f, "{} = ", type_alias.name)?; 730 write!(f, "{} = ", type_alias.name)?;
721 projection_pred.ty.hir_fmt(f)?; 731 }
732 ty.hir_fmt(f)?;
722 } 733 }
723 GenericPredicate::Error => { 734 GenericPredicate::Error => {
724 if angle_open { 735 if angle_open {
@@ -745,16 +756,16 @@ impl TraitRef {
745 return write!(f, "{}", TYPE_HINT_TRUNCATION); 756 return write!(f, "{}", TYPE_HINT_TRUNCATION);
746 } 757 }
747 758
748 self.substs[0].hir_fmt(f)?; 759 self.substitution[0].hir_fmt(f)?;
749 if use_as { 760 if use_as {
750 write!(f, " as ")?; 761 write!(f, " as ")?;
751 } else { 762 } else {
752 write!(f, ": ")?; 763 write!(f, ": ")?;
753 } 764 }
754 write!(f, "{}", f.db.trait_data(self.trait_).name)?; 765 write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
755 if self.substs.len() > 1 { 766 if self.substitution.len() > 1 {
756 write!(f, "<")?; 767 write!(f, "<")?;
757 f.write_joined(&self.substs[1..], ", ")?; 768 f.write_joined(&self.substitution[1..], ", ")?;
758 write!(f, ">")?; 769 write!(f, ">")?;
759 } 770 }
760 Ok(()) 771 Ok(())
@@ -775,20 +786,20 @@ impl HirDisplay for GenericPredicate {
775 786
776 match self { 787 match self {
777 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 788 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
778 GenericPredicate::Projection(projection_pred) => { 789 GenericPredicate::AliasEq(AliasEq {
790 alias: AliasTy::Projection(projection_ty),
791 ty,
792 }) => {
779 write!(f, "<")?; 793 write!(f, "<")?;
780 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; 794 projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
781 write!( 795 write!(
782 f, 796 f,
783 ">::{} = ", 797 ">::{} = ",
784 f.db.type_alias_data(from_assoc_type_id( 798 f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
785 projection_pred.projection_ty.associated_ty_id
786 ))
787 .name,
788 )?; 799 )?;
789 projection_pred.ty.hir_fmt(f)?; 800 ty.hir_fmt(f)?;
790 } 801 }
791 GenericPredicate::Error => write!(f, "{{error}}")?, 802 GenericPredicate::AliasEq(_) | GenericPredicate::Error => write!(f, "{{error}}")?,
792 } 803 }
793 Ok(()) 804 Ok(())
794 } 805 }
@@ -815,11 +826,14 @@ impl HirDisplay for Obligation {
815 tr.hir_fmt(f)?; 826 tr.hir_fmt(f)?;
816 write!(f, ")") 827 write!(f, ")")
817 } 828 }
818 Obligation::Projection(proj) => { 829 Obligation::AliasEq(AliasEq { alias, ty }) => {
819 write!(f, "Normalize(")?; 830 write!(f, "Normalize(")?;
820 proj.projection_ty.hir_fmt(f)?; 831 match alias {
832 AliasTy::Projection(projection_ty) => projection_ty.hir_fmt(f)?,
833 AliasTy::Opaque(opaque) => opaque.hir_fmt(f)?,
834 }
821 write!(f, " => ")?; 835 write!(f, " => ")?;
822 proj.ty.hir_fmt(f)?; 836 ty.hir_fmt(f)?;
823 write!(f, ")") 837 write!(f, ")")
824 } 838 }
825 } 839 }
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 2610c9279..82186979a 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -37,12 +37,12 @@ use stdx::impl_from;
37use syntax::SmolStr; 37use syntax::SmolStr;
38 38
39use super::{ 39use super::{
40 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 40 traits::{Guidance, Obligation, Solution},
41 InEnvironment, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TypeWalk, 41 InEnvironment, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TypeWalk,
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, AliasTy, Interner, TyKind, 45 to_assoc_type_id, to_chalk_trait_id, AliasEq, AliasTy, Interner, TyKind,
46}; 46};
47 47
48pub(crate) use unify::unify; 48pub(crate) use unify::unify;
@@ -394,16 +394,17 @@ impl<'a> InferenceContext<'a> {
394 .push(inner_ty) 394 .push(inner_ty)
395 .fill(params.iter().cloned()) 395 .fill(params.iter().cloned())
396 .build(); 396 .build();
397 let trait_ref = TraitRef { trait_, substs: substs.clone() }; 397 let trait_ref =
398 let projection = ProjectionPredicate { 398 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() };
399 ty: ty.clone(), 399 let alias_eq = AliasEq {
400 projection_ty: ProjectionTy { 400 alias: AliasTy::Projection(ProjectionTy {
401 associated_ty_id: to_assoc_type_id(res_assoc_ty), 401 associated_ty_id: to_assoc_type_id(res_assoc_ty),
402 substitution: substs, 402 substitution: substs,
403 }, 403 }),
404 ty: ty.clone(),
404 }; 405 };
405 self.obligations.push(Obligation::Trait(trait_ref)); 406 self.obligations.push(Obligation::Trait(trait_ref));
406 self.obligations.push(Obligation::Projection(projection)); 407 self.obligations.push(Obligation::AliasEq(alias_eq));
407 self.resolve_ty_as_possible(ty) 408 self.resolve_ty_as_possible(ty)
408 } 409 }
409 None => self.err_ty(), 410 None => self.err_ty(),
@@ -428,8 +429,8 @@ impl<'a> InferenceContext<'a> {
428 429
429 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 430 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
430 let var = self.table.new_type_var(); 431 let var = self.table.new_type_var();
431 let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; 432 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
432 let obligation = Obligation::Projection(predicate); 433 let obligation = Obligation::AliasEq(alias_eq);
433 self.obligations.push(obligation); 434 self.obligations.push(obligation);
434 var 435 var
435 } 436 }
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index b1f98c507..b86474ed4 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -8,7 +8,8 @@ use chalk_ir::{Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9 9
10use crate::{ 10use crate::{
11 autoderef, traits::Solution, Interner, Obligation, Substitution, TraitRef, Ty, TyKind, 11 autoderef, to_chalk_trait_id, traits::Solution, Interner, Obligation, Substitution, TraitRef,
12 Ty, TyKind,
12}; 13};
13 14
14use super::{InEnvironment, InferenceContext}; 15use super::{InEnvironment, InferenceContext};
@@ -140,7 +141,8 @@ impl<'a> InferenceContext<'a> {
140 .push(from_ty.clone()) 141 .push(from_ty.clone())
141 .push(to_ty.clone()) 142 .push(to_ty.clone())
142 .build(); 143 .build();
143 let trait_ref = TraitRef { trait_: coerce_unsized_trait, substs }; 144 let trait_ref =
145 TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs };
144 let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref)); 146 let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref));
145 147
146 let canonicalizer = self.canonicalizer(); 148 let canonicalizer = self.canonicalizer();
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 0be8c5a90..93548b6c0 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -18,7 +18,7 @@ use crate::{
18 lower::lower_to_chalk_mutability, 18 lower::lower_to_chalk_mutability,
19 method_resolution, op, 19 method_resolution, op,
20 primitive::{self, UintTy}, 20 primitive::{self, UintTy},
21 to_assoc_type_id, 21 to_assoc_type_id, to_chalk_trait_id,
22 traits::{chalk::from_chalk, FnTrait, InEnvironment}, 22 traits::{chalk::from_chalk, FnTrait, InEnvironment},
23 utils::{generics, variant_data, Generics}, 23 utils::{generics, variant_data, Generics},
24 AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Obligation, Rawness, Scalar, 24 AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Obligation, Rawness, Scalar,
@@ -90,8 +90,10 @@ impl<'a> InferenceContext<'a> {
90 Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); 90 Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
91 91
92 let trait_env = Arc::clone(&self.trait_env); 92 let trait_env = Arc::clone(&self.trait_env);
93 let implements_fn_trait = 93 let implements_fn_trait = Obligation::Trait(TraitRef {
94 Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() }); 94 trait_id: to_chalk_trait_id(fn_once_trait),
95 substitution: substs.clone(),
96 });
95 let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { 97 let goal = self.canonicalizer().canonicalize_obligation(InEnvironment {
96 value: implements_fn_trait.clone(), 98 value: implements_fn_trait.clone(),
97 environment: trait_env, 99 environment: trait_env,
@@ -948,7 +950,10 @@ impl<'a> InferenceContext<'a> {
948 // construct a TraitDef 950 // construct a TraitDef
949 let substs = 951 let substs =
950 parameters.prefix(generics(self.db.upcast(), trait_.into()).len()); 952 parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
951 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); 953 self.obligations.push(Obligation::Trait(TraitRef {
954 trait_id: to_chalk_trait_id(trait_),
955 substitution: substs,
956 }));
952 } 957 }
953 } 958 }
954 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} 959 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index ea01d6238..e15135fc1 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -9,7 +9,9 @@ use hir_def::{
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::Name;
11 11
12use crate::{method_resolution, Interner, Substitution, Ty, TyKind, ValueTyDefId}; 12use crate::{
13 method_resolution, to_chalk_trait_id, Interner, Substitution, Ty, TyKind, ValueTyDefId,
14};
13 15
14use super::{ExprOrPatId, InferenceContext, TraitRef}; 16use super::{ExprOrPatId, InferenceContext, TraitRef};
15 17
@@ -165,7 +167,7 @@ impl<'a> InferenceContext<'a> {
165 segment: PathSegment<'_>, 167 segment: PathSegment<'_>,
166 id: ExprOrPatId, 168 id: ExprOrPatId,
167 ) -> Option<(ValueNs, Option<Substitution>)> { 169 ) -> Option<(ValueNs, Option<Substitution>)> {
168 let trait_ = trait_ref.trait_; 170 let trait_ = trait_ref.hir_trait_id();
169 let item = 171 let item =
170 self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| { 172 self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| {
171 match item { 173 match item {
@@ -200,7 +202,7 @@ impl<'a> InferenceContext<'a> {
200 }; 202 };
201 203
202 self.write_assoc_resolution(id, item); 204 self.write_assoc_resolution(id, item);
203 Some((def, Some(trait_ref.substs))) 205 Some((def, Some(trait_ref.substitution)))
204 } 206 }
205 207
206 fn resolve_ty_assoc_item( 208 fn resolve_ty_assoc_item(
@@ -255,8 +257,8 @@ impl<'a> InferenceContext<'a> {
255 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 257 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
256 .build(); 258 .build();
257 self.obligations.push(super::Obligation::Trait(TraitRef { 259 self.obligations.push(super::Obligation::Trait(TraitRef {
258 trait_, 260 trait_id: to_chalk_trait_id(trait_),
259 substs: trait_substs.clone(), 261 substitution: trait_substs.clone(),
260 })); 262 }));
261 Some(trait_substs) 263 Some(trait_substs)
262 } 264 }
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index b2d4f67b3..4738ec08a 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -7,8 +7,8 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 7
8use super::{InferenceContext, Obligation}; 8use super::{InferenceContext, Obligation};
9use crate::{ 9use crate::{
10 BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate, InEnvironment, InferenceVar, 10 AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate,
11 Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, 11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk,
12}; 12};
13 13
14impl<'a> InferenceContext<'a> { 14impl<'a> InferenceContext<'a> {
@@ -93,8 +93,8 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
93 Obligation::Trait(tr) => { 93 Obligation::Trait(tr) => {
94 Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST)) 94 Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST))
95 } 95 }
96 Obligation::Projection(pr) => { 96 Obligation::AliasEq(alias_eq) => {
97 Obligation::Projection(self.do_canonicalize(pr, DebruijnIndex::INNERMOST)) 97 Obligation::AliasEq(self.do_canonicalize(alias_eq, DebruijnIndex::INNERMOST))
98 } 98 }
99 }; 99 };
100 self.into_canonicalized(InEnvironment { 100 self.into_canonicalized(InEnvironment {
@@ -390,18 +390,29 @@ impl InferenceTable {
390 ) -> bool { 390 ) -> bool {
391 match (pred1, pred2) { 391 match (pred1, pred2) {
392 (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2)) 392 (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2))
393 if tr1.trait_ == tr2.trait_ => 393 if tr1.trait_id == tr2.trait_id =>
394 { 394 {
395 self.unify_substs(&tr1.substs, &tr2.substs, depth + 1) 395 self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1)
396 } 396 }
397 (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2)) 397 (
398 if proj1.projection_ty.associated_ty_id == proj2.projection_ty.associated_ty_id => 398 GenericPredicate::AliasEq(AliasEq { alias: alias1, ty: ty1 }),
399 { 399 GenericPredicate::AliasEq(AliasEq { alias: alias2, ty: ty2 }),
400 self.unify_substs( 400 ) => {
401 &proj1.projection_ty.substitution, 401 let (substitution1, substitution2) = match (alias1, alias2) {
402 &proj2.projection_ty.substitution, 402 (AliasTy::Projection(projection_ty1), AliasTy::Projection(projection_ty2))
403 depth + 1, 403 if projection_ty1.associated_ty_id == projection_ty2.associated_ty_id =>
404 ) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1) 404 {
405 (&projection_ty1.substitution, &projection_ty2.substitution)
406 }
407 (AliasTy::Opaque(opaque1), AliasTy::Opaque(opaque2))
408 if opaque1.opaque_ty_id == opaque2.opaque_ty_id =>
409 {
410 (&opaque1.substitution, &opaque2.substitution)
411 }
412 _ => return false,
413 };
414 self.unify_substs(&substitution1, &substitution2, depth + 1)
415 && self.unify_inner(&ty1, &ty2, depth + 1)
405 } 416 }
406 _ => false, 417 _ => false,
407 } 418 }
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 52b498ff7..2afcb5413 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -45,7 +45,7 @@ pub use lower::{
45 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 45 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
46 TyDefId, TyLoweringContext, ValueTyDefId, 46 TyDefId, TyLoweringContext, ValueTyDefId,
47}; 47};
48pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 48pub use traits::{AliasEq, InEnvironment, Obligation, TraitEnvironment};
49 49
50pub use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind}; 50pub use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind};
51 51
@@ -58,6 +58,8 @@ pub type ClosureId = chalk_ir::ClosureId<Interner>;
58pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 58pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
59pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; 59pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
60 60
61pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
62
61#[derive(Clone, PartialEq, Eq, Debug, Hash)] 63#[derive(Clone, PartialEq, Eq, Debug, Hash)]
62pub enum Lifetime { 64pub enum Lifetime {
63 Parameter(LifetimeParamId), 65 Parameter(LifetimeParamId),
@@ -70,6 +72,20 @@ pub struct OpaqueTy {
70 pub substitution: Substitution, 72 pub substitution: Substitution,
71} 73}
72 74
75impl TypeWalk for OpaqueTy {
76 fn walk(&self, f: &mut impl FnMut(&Ty)) {
77 self.substitution.walk(f);
78 }
79
80 fn walk_mut_binders(
81 &mut self,
82 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
83 binders: DebruijnIndex,
84 ) {
85 self.substitution.walk_mut_binders(f, binders);
86 }
87}
88
73/// A "projection" type corresponds to an (unnormalized) 89/// A "projection" type corresponds to an (unnormalized)
74/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the 90/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
75/// trait and all its parameters are fully known. 91/// trait and all its parameters are fully known.
@@ -81,7 +97,10 @@ pub struct ProjectionTy {
81 97
82impl ProjectionTy { 98impl ProjectionTy {
83 pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef { 99 pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
84 TraitRef { trait_: self.trait_(db), substs: self.substitution.clone() } 100 TraitRef {
101 trait_id: to_chalk_trait_id(self.trait_(db)),
102 substitution: self.substitution.clone(),
103 }
85 } 104 }
86 105
87 fn trait_(&self, db: &dyn HirDatabase) -> TraitId { 106 fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
@@ -128,6 +147,25 @@ pub enum AliasTy {
128 Opaque(OpaqueTy), 147 Opaque(OpaqueTy),
129} 148}
130 149
150impl TypeWalk for AliasTy {
151 fn walk(&self, f: &mut impl FnMut(&Ty)) {
152 match self {
153 AliasTy::Projection(it) => it.walk(f),
154 AliasTy::Opaque(it) => it.walk(f),
155 }
156 }
157
158 fn walk_mut_binders(
159 &mut self,
160 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
161 binders: DebruijnIndex,
162 ) {
163 match self {
164 AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
165 AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
166 }
167 }
168}
131/// A type. 169/// A type.
132/// 170///
133/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents 171/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
@@ -493,23 +531,25 @@ impl<T: TypeWalk> TypeWalk for Binders<T> {
493} 531}
494 532
495/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. 533/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
496/// Name to be bikeshedded: TraitBound? TraitImplements?
497#[derive(Clone, PartialEq, Eq, Debug, Hash)] 534#[derive(Clone, PartialEq, Eq, Debug, Hash)]
498pub struct TraitRef { 535pub struct TraitRef {
499 /// FIXME name? 536 pub trait_id: ChalkTraitId,
500 pub trait_: TraitId, 537 pub substitution: Substitution,
501 pub substs: Substitution,
502} 538}
503 539
504impl TraitRef { 540impl TraitRef {
505 pub fn self_ty(&self) -> &Ty { 541 pub fn self_type_parameter(&self) -> &Ty {
506 &self.substs[0] 542 &self.substitution[0]
543 }
544
545 pub fn hir_trait_id(&self) -> TraitId {
546 from_chalk_trait_id(self.trait_id)
507 } 547 }
508} 548}
509 549
510impl TypeWalk for TraitRef { 550impl TypeWalk for TraitRef {
511 fn walk(&self, f: &mut impl FnMut(&Ty)) { 551 fn walk(&self, f: &mut impl FnMut(&Ty)) {
512 self.substs.walk(f); 552 self.substitution.walk(f);
513 } 553 }
514 554
515 fn walk_mut_binders( 555 fn walk_mut_binders(
@@ -517,7 +557,7 @@ impl TypeWalk for TraitRef {
517 f: &mut impl FnMut(&mut Ty, DebruijnIndex), 557 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
518 binders: DebruijnIndex, 558 binders: DebruijnIndex,
519 ) { 559 ) {
520 self.substs.walk_mut_binders(f, binders); 560 self.substitution.walk_mut_binders(f, binders);
521 } 561 }
522} 562}
523 563
@@ -528,7 +568,7 @@ pub enum GenericPredicate {
528 /// The given trait needs to be implemented for its type parameters. 568 /// The given trait needs to be implemented for its type parameters.
529 Implemented(TraitRef), 569 Implemented(TraitRef),
530 /// An associated type bindings like in `Iterator<Item = T>`. 570 /// An associated type bindings like in `Iterator<Item = T>`.
531 Projection(ProjectionPredicate), 571 AliasEq(AliasEq),
532 /// We couldn't resolve the trait reference. (If some type parameters can't 572 /// We couldn't resolve the trait reference. (If some type parameters can't
533 /// be resolved, they will just be Unknown). 573 /// be resolved, they will just be Unknown).
534 Error, 574 Error,
@@ -546,8 +586,10 @@ impl GenericPredicate {
546 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> { 586 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
547 match self { 587 match self {
548 GenericPredicate::Implemented(tr) => Some(tr.clone()), 588 GenericPredicate::Implemented(tr) => Some(tr.clone()),
549 GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)), 589 GenericPredicate::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => {
550 GenericPredicate::Error => None, 590 Some(proj.trait_ref(db))
591 }
592 GenericPredicate::AliasEq(_) | GenericPredicate::Error => None,
551 } 593 }
552 } 594 }
553} 595}
@@ -556,7 +598,7 @@ impl TypeWalk for GenericPredicate {
556 fn walk(&self, f: &mut impl FnMut(&Ty)) { 598 fn walk(&self, f: &mut impl FnMut(&Ty)) {
557 match self { 599 match self {
558 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), 600 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
559 GenericPredicate::Projection(projection_pred) => projection_pred.walk(f), 601 GenericPredicate::AliasEq(alias_eq) => alias_eq.walk(f),
560 GenericPredicate::Error => {} 602 GenericPredicate::Error => {}
561 } 603 }
562 } 604 }
@@ -568,9 +610,7 @@ impl TypeWalk for GenericPredicate {
568 ) { 610 ) {
569 match self { 611 match self {
570 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders), 612 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
571 GenericPredicate::Projection(projection_pred) => { 613 GenericPredicate::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
572 projection_pred.walk_mut_binders(f, binders)
573 }
574 GenericPredicate::Error => {} 614 GenericPredicate::Error => {}
575 } 615 }
576 } 616 }
@@ -784,7 +824,7 @@ impl Ty {
784 824
785 /// If this is a `dyn Trait`, returns that trait. 825 /// If this is a `dyn Trait`, returns that trait.
786 pub fn dyn_trait(&self) -> Option<TraitId> { 826 pub fn dyn_trait(&self) -> Option<TraitId> {
787 self.dyn_trait_ref().map(|it| it.trait_) 827 self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
788 } 828 }
789 829
790 fn builtin_deref(&self) -> Option<Ty> { 830 fn builtin_deref(&self) -> Option<Ty> {
@@ -868,8 +908,8 @@ impl Ty {
868 // Parameters will be walked outside, and projection predicate is not used. 908 // Parameters will be walked outside, and projection predicate is not used.
869 // So just provide the Future trait. 909 // So just provide the Future trait.
870 let impl_bound = GenericPredicate::Implemented(TraitRef { 910 let impl_bound = GenericPredicate::Implemented(TraitRef {
871 trait_: future_trait, 911 trait_id: to_chalk_trait_id(future_trait),
872 substs: Substitution::empty(), 912 substitution: Substitution::empty(),
873 }); 913 });
874 Some(vec![impl_bound]) 914 Some(vec![impl_bound])
875 } else { 915 } else {
@@ -1158,3 +1198,11 @@ pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderI
1158 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(), 1198 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
1159 } 1199 }
1160} 1200}
1201
1202pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
1203 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
1204}
1205
1206pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
1207 salsa::InternKey::from_intern_id(id.0)
1208}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 462882b2b..7d22c3df5 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -27,14 +27,14 @@ use stdx::impl_from;
27 27
28use crate::{ 28use crate::{
29 db::HirDatabase, 29 db::HirDatabase,
30 to_assoc_type_id, to_placeholder_idx, 30 to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
31 traits::chalk::{Interner, ToChalk}, 31 traits::chalk::{Interner, ToChalk},
32 utils::{ 32 utils::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
34 variant_data, 34 variant_data,
35 }, 35 },
36 AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, GenericPredicate, 36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig,
37 ImplTraitId, OpaqueTy, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, 37 GenericPredicate, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, ReturnTypeImplTrait,
38 ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk, 38 ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk,
39}; 39};
40 40
@@ -360,7 +360,7 @@ impl<'a> TyLoweringContext<'a> {
360 // FIXME handle type parameters on the segment 360 // FIXME handle type parameters on the segment
361 TyKind::Alias(AliasTy::Projection(ProjectionTy { 361 TyKind::Alias(AliasTy::Projection(ProjectionTy {
362 associated_ty_id: to_assoc_type_id(associated_ty), 362 associated_ty_id: to_assoc_type_id(associated_ty),
363 substitution: super_trait_ref.substs, 363 substitution: super_trait_ref.substitution,
364 })) 364 }))
365 .intern(&Interner) 365 .intern(&Interner)
366 } 366 }
@@ -470,9 +470,9 @@ impl<'a> TyLoweringContext<'a> {
470 "there should be generics if there's a generic param", 470 "there should be generics if there's a generic param",
471 ), 471 ),
472 ); 472 );
473 t.substs.clone().subst_bound_vars(&s) 473 t.substitution.clone().subst_bound_vars(&s)
474 } 474 }
475 TypeParamLoweringMode::Variable => t.substs.clone(), 475 TypeParamLoweringMode::Variable => t.substitution.clone(),
476 }; 476 };
477 // We need to shift in the bound vars, since 477 // We need to shift in the bound vars, since
478 // associated_type_shorthand_candidates does not do that 478 // associated_type_shorthand_candidates does not do that
@@ -641,7 +641,7 @@ impl<'a> TyLoweringContext<'a> {
641 if let Some(self_ty) = explicit_self_ty { 641 if let Some(self_ty) = explicit_self_ty {
642 substs.0[0] = self_ty; 642 substs.0[0] = self_ty;
643 } 643 }
644 TraitRef { trait_: resolved, substs } 644 TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
645 } 645 }
646 646
647 fn lower_trait_ref( 647 fn lower_trait_ref(
@@ -743,16 +743,16 @@ impl<'a> TyLoweringContext<'a> {
743 }; 743 };
744 let projection_ty = ProjectionTy { 744 let projection_ty = ProjectionTy {
745 associated_ty_id: to_assoc_type_id(associated_ty), 745 associated_ty_id: to_assoc_type_id(associated_ty),
746 substitution: super_trait_ref.substs, 746 substitution: super_trait_ref.substitution,
747 }; 747 };
748 let mut preds = SmallVec::with_capacity( 748 let mut preds = SmallVec::with_capacity(
749 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), 749 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
750 ); 750 );
751 if let Some(type_ref) = &binding.type_ref { 751 if let Some(type_ref) = &binding.type_ref {
752 let ty = self.lower_ty(type_ref); 752 let ty = self.lower_ty(type_ref);
753 let projection_predicate = 753 let alias_eq =
754 ProjectionPredicate { projection_ty: projection_ty.clone(), ty }; 754 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
755 preds.push(GenericPredicate::Projection(projection_predicate)); 755 preds.push(GenericPredicate::AliasEq(alias_eq));
756 } 756 }
757 for bound in &binding.bounds { 757 for bound in &binding.bounds {
758 preds.extend(self.lower_type_bound( 758 preds.extend(self.lower_type_bound(
@@ -820,8 +820,8 @@ pub fn associated_type_shorthand_candidates<R>(
820 == TypeParamProvenance::TraitSelf 820 == TypeParamProvenance::TraitSelf
821 { 821 {
822 let trait_ref = TraitRef { 822 let trait_ref = TraitRef {
823 trait_: trait_id, 823 trait_id: to_chalk_trait_id(trait_id),
824 substs: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST), 824 substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST),
825 }; 825 };
826 traits_.push(trait_ref); 826 traits_.push(trait_ref);
827 } 827 }
@@ -832,7 +832,7 @@ pub fn associated_type_shorthand_candidates<R>(
832 }; 832 };
833 833
834 for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) { 834 for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
835 let data = db.trait_data(t.trait_); 835 let data = db.trait_data(t.hir_trait_id());
836 836
837 for (name, assoc_id) in &data.items { 837 for (name, assoc_id) in &data.items {
838 match assoc_id { 838 match assoc_id {
@@ -926,7 +926,7 @@ pub(crate) fn trait_environment_query(
926 continue; 926 continue;
927 } 927 }
928 if let GenericPredicate::Implemented(tr) = &pred { 928 if let GenericPredicate::Implemented(tr) = &pred {
929 traits_in_scope.push((tr.self_ty().clone(), tr.trait_)); 929 traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id()));
930 } 930 }
931 let program_clause: chalk_ir::ProgramClause<Interner> = 931 let program_clause: chalk_ir::ProgramClause<Interner> =
932 pred.clone().to_chalk(db).cast(&Interner); 932 pred.clone().to_chalk(db).cast(&Interner);
@@ -950,7 +950,7 @@ pub(crate) fn trait_environment_query(
950 // inside consts or type aliases) 950 // inside consts or type aliases)
951 cov_mark::hit!(trait_self_implements_self); 951 cov_mark::hit!(trait_self_implements_self);
952 let substs = Substitution::type_params(db, trait_id); 952 let substs = Substitution::type_params(db, trait_id);
953 let trait_ref = TraitRef { trait_: trait_id, substs }; 953 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
954 let pred = GenericPredicate::Implemented(trait_ref); 954 let pred = GenericPredicate::Implemented(trait_ref);
955 let program_clause: chalk_ir::ProgramClause<Interner> = 955 let program_clause: chalk_ir::ProgramClause<Interner> =
956 pred.clone().to_chalk(db).cast(&Interner); 956 pred.clone().to_chalk(db).cast(&Interner);
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 943d3339b..01b78fb44 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -19,6 +19,7 @@ use crate::{
19 db::HirDatabase, 19 db::HirDatabase,
20 from_foreign_def_id, 20 from_foreign_def_id,
21 primitive::{self, FloatTy, IntTy, UintTy}, 21 primitive::{self, FloatTy, IntTy, UintTy},
22 to_chalk_trait_id,
22 utils::all_super_traits, 23 utils::all_super_traits,
23 AdtId, Canonical, DebruijnIndex, FnPointer, FnSig, ForeignDefId, InEnvironment, Interner, 24 AdtId, Canonical, DebruijnIndex, FnPointer, FnSig, ForeignDefId, InEnvironment, Interner,
24 Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk, 25 Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk,
@@ -101,7 +102,7 @@ impl TraitImpls {
101 for (_module_id, module_data) in crate_def_map.modules() { 102 for (_module_id, module_data) in crate_def_map.modules() {
102 for impl_id in module_data.scope.impls() { 103 for impl_id in module_data.scope.impls() {
103 let target_trait = match db.impl_trait(impl_id) { 104 let target_trait = match db.impl_trait(impl_id) {
104 Some(tr) => tr.value.trait_, 105 Some(tr) => tr.value.hir_trait_id(),
105 None => continue, 106 None => continue,
106 }; 107 };
107 let self_ty = db.impl_self_ty(impl_id); 108 let self_ty = db.impl_self_ty(impl_id);
@@ -773,7 +774,7 @@ fn generic_implements_goal(
773 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) 774 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
774 .build(); 775 .build();
775 kinds.extend(iter::repeat(chalk_ir::TyVariableKind::General).take(substs.len() - 1)); 776 kinds.extend(iter::repeat(chalk_ir::TyVariableKind::General).take(substs.len() - 1));
776 let trait_ref = TraitRef { trait_, substs }; 777 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs };
777 let obligation = super::Obligation::Trait(trait_ref); 778 let obligation = super::Obligation::Trait(trait_ref);
778 Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) } 779 Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
779} 780}
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 40eb1034e..ac7de7605 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -8,10 +8,9 @@ use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
8use hir_def::{lang_item::LangItemTarget, TraitId}; 8use hir_def::{lang_item::LangItemTarget, TraitId};
9use stdx::panic_context; 9use stdx::panic_context;
10 10
11use crate::{db::HirDatabase, DebruijnIndex, Substitution}; 11use crate::{
12 12 db::HirDatabase, AliasTy, Canonical, DebruijnIndex, GenericPredicate, HirDisplay, Substitution,
13use super::{ 13 TraitRef, Ty, TyKind, TypeWalk,
14 Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TyKind, TypeWalk,
15}; 14};
16 15
17use self::chalk::{from_chalk, Interner, ToChalk}; 16use self::chalk::{from_chalk, Interner, ToChalk};
@@ -93,31 +92,32 @@ pub enum Obligation {
93 /// Prove that a certain type implements a trait (the type is the `Self` type 92 /// Prove that a certain type implements a trait (the type is the `Self` type
94 /// parameter to the `TraitRef`). 93 /// parameter to the `TraitRef`).
95 Trait(TraitRef), 94 Trait(TraitRef),
96 Projection(ProjectionPredicate), 95 AliasEq(AliasEq),
97} 96}
98 97
99impl Obligation { 98impl Obligation {
100 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { 99 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> {
101 match predicate { 100 match predicate {
102 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), 101 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)),
103 GenericPredicate::Projection(projection_pred) => { 102 GenericPredicate::AliasEq(alias_eq) => Some(Obligation::AliasEq(alias_eq)),
104 Some(Obligation::Projection(projection_pred))
105 }
106 GenericPredicate::Error => None, 103 GenericPredicate::Error => None,
107 } 104 }
108 } 105 }
109} 106}
110 107
111#[derive(Clone, Debug, PartialEq, Eq, Hash)] 108#[derive(Clone, Debug, PartialEq, Eq, Hash)]
112pub struct ProjectionPredicate { 109pub struct AliasEq {
113 pub projection_ty: ProjectionTy, 110 pub alias: AliasTy,
114 pub ty: Ty, 111 pub ty: Ty,
115} 112}
116 113
117impl TypeWalk for ProjectionPredicate { 114impl TypeWalk for AliasEq {
118 fn walk(&self, f: &mut impl FnMut(&Ty)) { 115 fn walk(&self, f: &mut impl FnMut(&Ty)) {
119 self.projection_ty.walk(f);
120 self.ty.walk(f); 116 self.ty.walk(f);
117 match &self.alias {
118 AliasTy::Projection(projection_ty) => projection_ty.walk(f),
119 AliasTy::Opaque(opaque) => opaque.walk(f),
120 }
121 } 121 }
122 122
123 fn walk_mut_binders( 123 fn walk_mut_binders(
@@ -125,8 +125,11 @@ impl TypeWalk for ProjectionPredicate {
125 f: &mut impl FnMut(&mut Ty, DebruijnIndex), 125 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
126 binders: DebruijnIndex, 126 binders: DebruijnIndex,
127 ) { 127 ) {
128 self.projection_ty.walk_mut_binders(f, binders);
129 self.ty.walk_mut_binders(f, binders); 128 self.ty.walk_mut_binders(f, binders);
129 match &mut self.alias {
130 AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
131 AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
132 }
130 } 133 }
131} 134}
132 135
@@ -137,13 +140,15 @@ pub(crate) fn trait_solve_query(
137 goal: Canonical<InEnvironment<Obligation>>, 140 goal: Canonical<InEnvironment<Obligation>>,
138) -> Option<Solution> { 141) -> Option<Solution> {
139 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value { 142 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value {
140 Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(), 143 Obligation::Trait(it) => db.trait_data(it.hir_trait_id()).name.to_string(),
141 Obligation::Projection(_) => "projection".to_string(), 144 Obligation::AliasEq(_) => "alias_eq".to_string(),
142 }); 145 });
143 log::info!("trait_solve_query({})", goal.value.value.display(db)); 146 log::info!("trait_solve_query({})", goal.value.value.display(db));
144 147
145 if let Obligation::Projection(pred) = &goal.value.value { 148 if let Obligation::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), .. }) =
146 if let TyKind::BoundVar(_) = &pred.projection_ty.substitution[0].interned(&Interner) { 149 &goal.value.value
150 {
151 if let TyKind::BoundVar(_) = &projection_ty.substitution[0].interned(&Interner) {
147 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible 152 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
148 return Some(Solution::Ambig(Guidance::Unknown)); 153 return Some(Solution::Ambig(Guidance::Unknown));
149 } 154 }
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index bef6e7e9c..080764e76 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -19,10 +19,10 @@ use crate::{
19 display::HirDisplay, 19 display::HirDisplay,
20 from_assoc_type_id, 20 from_assoc_type_id,
21 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 21 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
22 to_assoc_type_id, 22 to_assoc_type_id, to_chalk_trait_id,
23 utils::generics, 23 utils::generics,
24 BoundVar, CallableDefId, CallableSig, DebruijnIndex, FnDefId, GenericPredicate, 24 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, DebruijnIndex, FnDefId,
25 ProjectionPredicate, ProjectionTy, Substitution, TraitRef, Ty, TyKind, 25 GenericPredicate, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
26}; 26};
27use mapping::{ 27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, 28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
@@ -219,9 +219,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
219 // for<T> <Self> [Future<Self>, Future::Output<Self> = T] 219 // for<T> <Self> [Future<Self>, Future::Output<Self> = T]
220 // ^1 ^0 ^0 ^0 ^1 220 // ^1 ^0 ^0 ^0 ^1
221 let impl_bound = GenericPredicate::Implemented(TraitRef { 221 let impl_bound = GenericPredicate::Implemented(TraitRef {
222 trait_: future_trait, 222 trait_id: to_chalk_trait_id(future_trait),
223 // Self type as the first parameter. 223 // Self type as the first parameter.
224 substs: Substitution::single( 224 substitution: Substitution::single(
225 TyKind::BoundVar(BoundVar { 225 TyKind::BoundVar(BoundVar {
226 debruijn: DebruijnIndex::INNERMOST, 226 debruijn: DebruijnIndex::INNERMOST,
227 index: 0, 227 index: 0,
@@ -229,18 +229,18 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
229 .intern(&Interner), 229 .intern(&Interner),
230 ), 230 ),
231 }); 231 });
232 let proj_bound = GenericPredicate::Projection(ProjectionPredicate { 232 let proj_bound = GenericPredicate::AliasEq(AliasEq {
233 // The parameter of the opaque type. 233 alias: AliasTy::Projection(ProjectionTy {
234 ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 })
235 .intern(&Interner),
236 projection_ty: ProjectionTy {
237 associated_ty_id: to_assoc_type_id(future_output), 234 associated_ty_id: to_assoc_type_id(future_output),
238 // Self type as the first parameter. 235 // Self type as the first parameter.
239 substitution: Substitution::single( 236 substitution: Substitution::single(
240 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) 237 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
241 .intern(&Interner), 238 .intern(&Interner),
242 ), 239 ),
243 }, 240 }),
241 // The parameter of the opaque type.
242 ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 })
243 .intern(&Interner),
244 }); 244 });
245 let bound = OpaqueTyDatumBound { 245 let bound = OpaqueTyDatumBound {
246 bounds: make_binders( 246 bounds: make_binders(
@@ -546,7 +546,7 @@ fn impl_def_datum(
546 546
547 let generic_params = generics(db.upcast(), impl_id.into()); 547 let generic_params = generics(db.upcast(), impl_id.into());
548 let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 548 let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
549 let trait_ = trait_ref.trait_; 549 let trait_ = trait_ref.hir_trait_id();
550 let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate { 550 let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
551 rust_ir::ImplType::Local 551 rust_ir::ImplType::Local
552 } else { 552 } else {
@@ -614,7 +614,7 @@ fn type_alias_associated_ty_value(
614 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved 614 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved
615 615
616 let assoc_ty = db 616 let assoc_ty = db
617 .trait_data(trait_ref.trait_) 617 .trait_data(trait_ref.hir_trait_id())
618 .associated_type_by_name(&type_alias_data.name) 618 .associated_type_by_name(&type_alias_data.name)
619 .expect("assoc ty value should not exist"); // validated when building the impl data as well 619 .expect("assoc ty value should not exist"); // validated when building the impl data as well
620 let ty = db.ty(type_alias.into()); 620 let ty = db.ty(type_alias.into());
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index d969527dc..62b779008 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -14,8 +14,8 @@ use crate::{
14 from_assoc_type_id, 14 from_assoc_type_id,
15 primitive::UintTy, 15 primitive::UintTy,
16 traits::{Canonical, Obligation}, 16 traits::{Canonical, Obligation},
17 AliasTy, CallableDefId, FnPointer, GenericPredicate, InEnvironment, OpaqueTy, 17 AliasTy, CallableDefId, FnPointer, GenericPredicate, InEnvironment, OpaqueTy, ProjectionTy,
18 ProjectionPredicate, ProjectionTy, Scalar, Substitution, TraitRef, Ty, 18 Scalar, Substitution, TraitRef, Ty,
19}; 19};
20 20
21use super::interner::*; 21use super::interner::*;
@@ -239,15 +239,15 @@ impl ToChalk for TraitRef {
239 type Chalk = chalk_ir::TraitRef<Interner>; 239 type Chalk = chalk_ir::TraitRef<Interner>;
240 240
241 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { 241 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
242 let trait_id = self.trait_.to_chalk(db); 242 let trait_id = self.trait_id;
243 let substitution = self.substs.to_chalk(db); 243 let substitution = self.substitution.to_chalk(db);
244 chalk_ir::TraitRef { trait_id, substitution } 244 chalk_ir::TraitRef { trait_id, substitution }
245 } 245 }
246 246
247 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { 247 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
248 let trait_ = from_chalk(db, trait_ref.trait_id); 248 let trait_id = trait_ref.trait_id;
249 let substs = from_chalk(db, trait_ref.substitution); 249 let substs = from_chalk(db, trait_ref.substitution);
250 TraitRef { trait_, substs } 250 TraitRef { trait_id, substitution: substs }
251 } 251 }
252} 252}
253 253
@@ -314,12 +314,10 @@ impl ToChalk for GenericPredicate {
314 let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); 314 let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
315 make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) 315 make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
316 } 316 }
317 GenericPredicate::Projection(projection_pred) => { 317 GenericPredicate::AliasEq(alias_eq) => make_binders(
318 let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); 318 chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db).shifted_in(&Interner)),
319 let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); 319 0,
320 let alias = chalk_ir::AliasTy::Projection(projection); 320 ),
321 make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
322 }
323 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), 321 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
324 } 322 }
325 } 323 }
@@ -338,16 +336,8 @@ impl ToChalk for GenericPredicate {
338 chalk_ir::WhereClause::Implemented(tr) => { 336 chalk_ir::WhereClause::Implemented(tr) => {
339 GenericPredicate::Implemented(from_chalk(db, tr)) 337 GenericPredicate::Implemented(from_chalk(db, tr))
340 } 338 }
341 chalk_ir::WhereClause::AliasEq(projection_eq) => { 339 chalk_ir::WhereClause::AliasEq(alias_eq) => {
342 let projection_ty = from_chalk( 340 GenericPredicate::AliasEq(from_chalk(db, alias_eq))
343 db,
344 match projection_eq.alias {
345 chalk_ir::AliasTy::Projection(p) => p,
346 _ => unimplemented!(),
347 },
348 );
349 let ty = from_chalk(db, projection_eq.ty);
350 GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty })
351 } 341 }
352 342
353 chalk_ir::WhereClause::LifetimeOutlives(_) => { 343 chalk_ir::WhereClause::LifetimeOutlives(_) => {
@@ -383,19 +373,55 @@ impl ToChalk for ProjectionTy {
383 } 373 }
384 } 374 }
385} 375}
376impl ToChalk for OpaqueTy {
377 type Chalk = chalk_ir::OpaqueTy<Interner>;
378
379 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
380 chalk_ir::OpaqueTy {
381 opaque_ty_id: self.opaque_ty_id,
382 substitution: self.substitution.to_chalk(db),
383 }
384 }
385
386 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
387 OpaqueTy {
388 opaque_ty_id: chalk.opaque_ty_id,
389 substitution: from_chalk(db, chalk.substitution),
390 }
391 }
392}
393
394impl ToChalk for AliasTy {
395 type Chalk = chalk_ir::AliasTy<Interner>;
396
397 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
398 match self {
399 AliasTy::Projection(projection_ty) => {
400 chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
401 }
402 AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
403 }
404 }
405
406 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
407 match chalk {
408 chalk_ir::AliasTy::Projection(projection_ty) => {
409 AliasTy::Projection(from_chalk(db, projection_ty))
410 }
411 chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
412 }
413 }
414}
386 415
387impl ToChalk for ProjectionPredicate { 416impl ToChalk for AliasEq {
388 type Chalk = chalk_ir::AliasEq<Interner>; 417 type Chalk = chalk_ir::AliasEq<Interner>;
389 418
390 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { 419 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
391 chalk_ir::AliasEq { 420 chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
392 alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)),
393 ty: self.ty.to_chalk(db),
394 }
395 } 421 }
396 422
397 fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { 423 fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
398 unimplemented!() 424 AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
399 } 425 }
400} 426}
401 427
@@ -405,7 +431,7 @@ impl ToChalk for Obligation {
405 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { 431 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
406 match self { 432 match self {
407 Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), 433 Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner),
408 Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), 434 Obligation::AliasEq(alias_eq) => alias_eq.to_chalk(db).cast(&Interner),
409 } 435 }
410 } 436 }
411 437
@@ -515,42 +541,41 @@ pub(super) fn generic_predicate_to_inline_bound(
515 // We don't have a special type for this, but Chalk does. 541 // We don't have a special type for this, but Chalk does.
516 match pred { 542 match pred {
517 GenericPredicate::Implemented(trait_ref) => { 543 GenericPredicate::Implemented(trait_ref) => {
518 if &trait_ref.substs[0] != self_ty { 544 if &trait_ref.substitution[0] != self_ty {
519 // we can only convert predicates back to type bounds if they 545 // we can only convert predicates back to type bounds if they
520 // have the expected self type 546 // have the expected self type
521 return None; 547 return None;
522 } 548 }
523 let args_no_self = trait_ref.substs[1..] 549 let args_no_self = trait_ref.substitution[1..]
524 .iter() 550 .iter()
525 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 551 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
526 .collect(); 552 .collect();
527 let trait_bound = 553 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
528 rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
529 Some(rust_ir::InlineBound::TraitBound(trait_bound)) 554 Some(rust_ir::InlineBound::TraitBound(trait_bound))
530 } 555 }
531 GenericPredicate::Projection(proj) => { 556 GenericPredicate::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
532 if &proj.projection_ty.substitution[0] != self_ty { 557 if &projection_ty.substitution[0] != self_ty {
533 return None; 558 return None;
534 } 559 }
535 let trait_ = match from_assoc_type_id(proj.projection_ty.associated_ty_id) 560 let trait_ = match from_assoc_type_id(projection_ty.associated_ty_id)
536 .lookup(db.upcast()) 561 .lookup(db.upcast())
537 .container 562 .container
538 { 563 {
539 AssocContainerId::TraitId(t) => t, 564 AssocContainerId::TraitId(t) => t,
540 _ => panic!("associated type not in trait"), 565 _ => panic!("associated type not in trait"),
541 }; 566 };
542 let args_no_self = proj.projection_ty.substitution[1..] 567 let args_no_self = projection_ty.substitution[1..]
543 .iter() 568 .iter()
544 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 569 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
545 .collect(); 570 .collect();
546 let alias_eq_bound = rust_ir::AliasEqBound { 571 let alias_eq_bound = rust_ir::AliasEqBound {
547 value: proj.ty.clone().to_chalk(db), 572 value: ty.clone().to_chalk(db),
548 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, 573 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
549 associated_ty_id: proj.projection_ty.associated_ty_id, 574 associated_ty_id: projection_ty.associated_ty_id,
550 parameters: Vec::new(), // FIXME we don't support generic associated types yet 575 parameters: Vec::new(), // FIXME we don't support generic associated types yet
551 }; 576 };
552 Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) 577 Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
553 } 578 }
554 GenericPredicate::Error => None, 579 _ => None,
555 } 580 }
556} 581}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 7351e4e54..b66243d48 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -55,9 +55,9 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
55 // lifetime problems, but since there usually shouldn't be more than a 55 // lifetime problems, but since there usually shouldn't be more than a
56 // few direct traits this should be fine (we could even use some kind of 56 // few direct traits this should be fine (we could even use some kind of
57 // SmallVec if performance is a concern) 57 // SmallVec if performance is a concern)
58 let generic_params = db.generic_params(trait_ref.trait_.into()); 58 let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
59 let trait_self = match generic_params.find_trait_self_param() { 59 let trait_self = match generic_params.find_trait_self_param() {
60 Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p }, 60 Some(p) => TypeParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
61 None => return Vec::new(), 61 None => return Vec::new(),
62 }; 62 };
63 db.generic_predicates_for_param(trait_self) 63 db.generic_predicates_for_param(trait_self)
@@ -68,7 +68,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
68 _ => None, 68 _ => None,
69 }) 69 })
70 }) 70 })
71 .map(|pred| pred.subst(&trait_ref.substs)) 71 .map(|pred| pred.subst(&trait_ref.substitution))
72 .collect() 72 .collect()
73} 73}
74 74
@@ -108,7 +108,7 @@ pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) ->
108 // yeah this is quadratic, but trait hierarchies should be flat 108 // yeah this is quadratic, but trait hierarchies should be flat
109 // enough that this doesn't matter 109 // enough that this doesn't matter
110 for tt in direct_super_trait_refs(db, t) { 110 for tt in direct_super_trait_refs(db, t) {
111 if !result.iter().any(|tr| tr.trait_ == tt.trait_) { 111 if !result.iter().any(|tr| tr.trait_id == tt.trait_id) {
112 result.push(tt); 112 result.push(tt);
113 } 113 }
114 } 114 }
@@ -123,7 +123,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
123 name: &Name, 123 name: &Name,
124) -> Option<(TraitRef, TypeAliasId)> { 124) -> Option<(TraitRef, TypeAliasId)> {
125 all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| { 125 all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| {
126 let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?; 126 let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
127 Some((t, assoc_type)) 127 Some((t, assoc_type))
128 }) 128 })
129} 129}
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index c086de163..364be260c 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -339,10 +339,14 @@ impl TryToNav for hir::Field {
339impl TryToNav for hir::MacroDef { 339impl TryToNav for hir::MacroDef {
340 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 340 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
341 let src = self.source(db)?; 341 let src = self.source(db)?;
342 log::debug!("nav target {:#?}", src.value.syntax()); 342 let name_owner: &dyn ast::NameOwner = match &src.value {
343 Either::Left(it) => it,
344 Either::Right(it) => it,
345 };
346 log::debug!("nav target {:#?}", name_owner.syntax());
343 let mut res = NavigationTarget::from_named( 347 let mut res = NavigationTarget::from_named(
344 db, 348 db,
345 src.as_ref().map(|it| it as &dyn ast::NameOwner), 349 src.as_ref().with_value(name_owner),
346 SymbolKind::Macro, 350 SymbolKind::Macro,
347 ); 351 );
348 res.docs = self.docs(db); 352 res.docs = self.docs(db);
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 598b47e41..473d48c2f 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1176,4 +1176,21 @@ fn foo() { A { a$0: }; }
1176"#, 1176"#,
1177 ) 1177 )
1178 } 1178 }
1179
1180 #[test]
1181 fn goto_proc_macro() {
1182 check(
1183 r#"
1184//- /main.rs crate:main deps:mac
1185use mac::fn_macro;
1186
1187fn_macro$0!();
1188
1189//- /mac.rs crate:mac
1190#[proc_macro]
1191fn fn_macro() {}
1192 //^^^^^^^^
1193 "#,
1194 )
1195 }
1179} 1196}
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 15d309d7d..a3fb17c0a 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -331,10 +331,16 @@ fn hover_for_definition(
331) -> Option<Markup> { 331) -> Option<Markup> {
332 let mod_path = definition_mod_path(db, &def); 332 let mod_path = definition_mod_path(db, &def);
333 return match def { 333 return match def {
334 Definition::Macro(it) => { 334 Definition::Macro(it) => match &it.source(db)?.value {
335 let label = macro_label(&it.source(db)?.value); 335 Either::Left(mac) => {
336 from_def_source_labeled(db, it, Some(label), mod_path) 336 let label = macro_label(&mac);
337 } 337 from_def_source_labeled(db, it, Some(label), mod_path)
338 }
339 Either::Right(_) => {
340 // FIXME
341 None
342 }
343 },
338 Definition::Field(def) => from_hir_fmt(db, def, mod_path), 344 Definition::Field(def) => from_hir_fmt(db, def, mod_path),
339 Definition::ModuleDef(it) => match it { 345 Definition::ModuleDef(it) => match it {
340 ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), 346 ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path),
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index ba3447b3a..e25b698e0 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -12,7 +12,7 @@ mod html;
12#[cfg(test)] 12#[cfg(test)]
13mod tests; 13mod tests;
14 14
15use hir::{Name, Semantics}; 15use hir::{InFile, Name, Semantics};
16use ide_db::{RootDatabase, SymbolKind}; 16use ide_db::{RootDatabase, SymbolKind};
17use rustc_hash::FxHashMap; 17use rustc_hash::FxHashMap;
18use syntax::{ 18use syntax::{
@@ -73,14 +73,20 @@ pub(crate) fn highlight(
73 }; 73 };
74 74
75 let mut hl = highlights::Highlights::new(root.text_range()); 75 let mut hl = highlights::Highlights::new(root.text_range());
76 traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting); 76 traverse(
77 &mut hl,
78 &sema,
79 InFile::new(file_id.into(), &root),
80 range_to_highlight,
81 syntactic_name_ref_highlighting,
82 );
77 hl.to_vec() 83 hl.to_vec()
78} 84}
79 85
80fn traverse( 86fn traverse(
81 hl: &mut Highlights, 87 hl: &mut Highlights,
82 sema: &Semantics<RootDatabase>, 88 sema: &Semantics<RootDatabase>,
83 root: &SyntaxNode, 89 root: InFile<&SyntaxNode>,
84 range_to_highlight: TextRange, 90 range_to_highlight: TextRange,
85 syntactic_name_ref_highlighting: bool, 91 syntactic_name_ref_highlighting: bool,
86) { 92) {
@@ -93,7 +99,7 @@ fn traverse(
93 99
94 // Walk all nodes, keeping track of whether we are inside a macro or not. 100 // Walk all nodes, keeping track of whether we are inside a macro or not.
95 // If in macro, expand it first and highlight the expanded code. 101 // If in macro, expand it first and highlight the expanded code.
96 for event in root.preorder_with_tokens() { 102 for event in root.value.preorder_with_tokens() {
97 let event_range = match &event { 103 let event_range = match &event {
98 WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(), 104 WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(),
99 }; 105 };
@@ -150,7 +156,7 @@ fn traverse(
150 WalkEvent::Enter(it) => it, 156 WalkEvent::Enter(it) => it,
151 WalkEvent::Leave(it) => { 157 WalkEvent::Leave(it) => {
152 if let Some(node) = it.as_node() { 158 if let Some(node) = it.as_node() {
153 inject::doc_comment(hl, sema, node); 159 inject::doc_comment(hl, sema, root.with_value(node));
154 } 160 }
155 continue; 161 continue;
156 } 162 }
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 1d34731ab..5327af845 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -59,7 +59,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
59.label { color: #DFAF8F; font-style: italic; } 59.label { color: #DFAF8F; font-style: italic; }
60.comment { color: #7F9F7F; } 60.comment { color: #7F9F7F; }
61.documentation { color: #629755; } 61.documentation { color: #629755; }
62.intra_doc_link { color: #A9C577; } 62.intra_doc_link { font-style: italic; }
63.injected { opacity: 0.65 ; } 63.injected { opacity: 0.65 ; }
64.struct, .enum { color: #7CB8BB; } 64.struct, .enum { color: #7CB8BB; }
65.enum_variant { color: #BDE0F3; } 65.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 90feb6c18..5722dea3a 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -3,8 +3,8 @@
3use std::{mem, ops::Range}; 3use std::{mem, ops::Range};
4 4
5use either::Either; 5use either::Either;
6use hir::{HasAttrs, Semantics}; 6use hir::{HasAttrs, InFile, Semantics};
7use ide_db::{call_info::ActiveParameter, defs::Definition}; 7use ide_db::{call_info::ActiveParameter, defs::Definition, SymbolKind};
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode, AttrsOwner, DocCommentsOwner}, 9 ast::{self, AstNode, AttrsOwner, DocCommentsOwner},
10 match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 10 match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
@@ -148,8 +148,12 @@ fn doc_attributes<'node>(
148} 148}
149 149
150/// Injection of syntax highlighting of doctests. 150/// Injection of syntax highlighting of doctests.
151pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) { 151pub(super) fn doc_comment(
152 let (owner, attributes, def) = match doc_attributes(sema, node) { 152 hl: &mut Highlights,
153 sema: &Semantics<RootDatabase>,
154 node: InFile<&SyntaxNode>,
155) {
156 let (owner, attributes, def) = match doc_attributes(sema, node.value) {
153 Some(it) => it, 157 Some(it) => it,
154 None => return, 158 None => return,
155 }; 159 };
@@ -157,7 +161,12 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
157 let mut inj = Injector::default(); 161 let mut inj = Injector::default();
158 inj.add_unmapped("fn doctest() {\n"); 162 inj.add_unmapped("fn doctest() {\n");
159 163
160 let attrs_source_map = attributes.source_map(&owner); 164 let attrs_source_map = match def {
165 Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
166 attributes.source_map_for_module(sema.db, module.into())
167 }
168 _ => attributes.source_map(node.with_value(&owner)),
169 };
161 170
162 let mut is_codeblock = false; 171 let mut is_codeblock = false;
163 let mut is_doctest = false; 172 let mut is_doctest = false;
@@ -168,7 +177,10 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
168 let mut intra_doc_links = Vec::new(); 177 let mut intra_doc_links = Vec::new();
169 let mut string; 178 let mut string;
170 for attr in attributes.by_key("doc").attrs() { 179 for attr in attributes.by_key("doc").attrs() {
171 let src = attrs_source_map.source_of(&attr); 180 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr);
181 if file_id != node.file_id {
182 continue;
183 }
172 let (line, range, prefix) = match &src { 184 let (line, range, prefix) = match &src {
173 Either::Left(it) => { 185 Either::Left(it) => {
174 string = match find_doc_string_in_attr(attr, it) { 186 string = match find_doc_string_in_attr(attr, it) {
@@ -213,13 +225,16 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
213 intra_doc_links.extend( 225 intra_doc_links.extend(
214 extract_definitions_from_markdown(line) 226 extract_definitions_from_markdown(line)
215 .into_iter() 227 .into_iter()
216 .filter(|(link, ns, _)| { 228 .filter_map(|(link, ns, range)| {
217 validate_intra_doc_link(sema.db, &def, link, *ns) 229 validate_intra_doc_link(sema.db, &def, &link, ns).zip(Some(range))
218 }) 230 })
219 .map(|(.., Range { start, end })| { 231 .map(|(def, Range { start, end })| {
220 TextRange::at( 232 (
221 prev_range_start + TextSize::from(start as u32), 233 def,
222 TextSize::from((end - start) as u32), 234 TextRange::at(
235 prev_range_start + TextSize::from(start as u32),
236 TextSize::from((end - start) as u32),
237 ),
223 ) 238 )
224 }), 239 }),
225 ); 240 );
@@ -243,10 +258,13 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
243 } 258 }
244 } 259 }
245 260
246 for range in intra_doc_links { 261 for (def, range) in intra_doc_links {
247 hl.add(HlRange { 262 hl.add(HlRange {
248 range, 263 range,
249 highlight: HlTag::IntraDocLink | HlMod::Documentation, 264 highlight: module_def_to_hl_tag(def)
265 | HlMod::Documentation
266 | HlMod::Injected
267 | HlMod::IntraDocLink,
250 binding_hash: None, 268 binding_hash: None,
251 }); 269 });
252 } 270 }
@@ -306,7 +324,7 @@ fn validate_intra_doc_link(
306 def: &Definition, 324 def: &Definition,
307 link: &str, 325 link: &str,
308 ns: Option<hir::Namespace>, 326 ns: Option<hir::Namespace>,
309) -> bool { 327) -> Option<hir::ModuleDef> {
310 match def { 328 match def {
311 Definition::ModuleDef(def) => match def { 329 Definition::ModuleDef(def) => match def {
312 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), 330 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
@@ -326,5 +344,21 @@ fn validate_intra_doc_link(
326 | Definition::GenericParam(_) 344 | Definition::GenericParam(_)
327 | Definition::Label(_) => None, 345 | Definition::Label(_) => None,
328 } 346 }
329 .is_some() 347}
348
349fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag {
350 let symbol = match def {
351 hir::ModuleDef::Module(_) => SymbolKind::Module,
352 hir::ModuleDef::Function(_) => SymbolKind::Function,
353 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct,
354 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum,
355 hir::ModuleDef::Adt(hir::Adt::Union(_)) => SymbolKind::Union,
356 hir::ModuleDef::Variant(_) => SymbolKind::Variant,
357 hir::ModuleDef::Const(_) => SymbolKind::Const,
358 hir::ModuleDef::Static(_) => SymbolKind::Static,
359 hir::ModuleDef::Trait(_) => SymbolKind::Trait,
360 hir::ModuleDef::TypeAlias(_) => SymbolKind::TypeAlias,
361 hir::ModuleDef::BuiltinType(_) => return HlTag::BuiltinType,
362 };
363 HlTag::Symbol(symbol)
330} 364}
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index ce46e5127..93db79b89 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -26,7 +26,6 @@ pub enum HlTag {
26 Comment, 26 Comment,
27 EscapeSequence, 27 EscapeSequence,
28 FormatSpecifier, 28 FormatSpecifier,
29 IntraDocLink,
30 Keyword, 29 Keyword,
31 NumericLiteral, 30 NumericLiteral,
32 Operator, 31 Operator,
@@ -57,6 +56,8 @@ pub enum HlMod {
57 Static, 56 Static,
58 /// Used for items in impls&traits. 57 /// Used for items in impls&traits.
59 Associated, 58 Associated,
59 /// Used for intra doc links in doc injection.
60 IntraDocLink,
60 61
61 /// Keep this last! 62 /// Keep this last!
62 Unsafe, 63 Unsafe,
@@ -117,7 +118,6 @@ impl HlTag {
117 HlTag::Comment => "comment", 118 HlTag::Comment => "comment",
118 HlTag::EscapeSequence => "escape_sequence", 119 HlTag::EscapeSequence => "escape_sequence",
119 HlTag::FormatSpecifier => "format_specifier", 120 HlTag::FormatSpecifier => "format_specifier",
120 HlTag::IntraDocLink => "intra_doc_link",
121 HlTag::Keyword => "keyword", 121 HlTag::Keyword => "keyword",
122 HlTag::Punctuation(punct) => match punct { 122 HlTag::Punctuation(punct) => match punct {
123 HlPunct::Bracket => "bracket", 123 HlPunct::Bracket => "bracket",
@@ -151,6 +151,7 @@ impl HlMod {
151 HlMod::ControlFlow, 151 HlMod::ControlFlow,
152 HlMod::Definition, 152 HlMod::Definition,
153 HlMod::Documentation, 153 HlMod::Documentation,
154 HlMod::IntraDocLink,
154 HlMod::Injected, 155 HlMod::Injected,
155 HlMod::Mutable, 156 HlMod::Mutable,
156 HlMod::Consuming, 157 HlMod::Consuming,
@@ -162,17 +163,18 @@ impl HlMod {
162 163
163 fn as_str(self) -> &'static str { 164 fn as_str(self) -> &'static str {
164 match self { 165 match self {
166 HlMod::Associated => "associated",
165 HlMod::Attribute => "attribute", 167 HlMod::Attribute => "attribute",
168 HlMod::Callable => "callable",
169 HlMod::Consuming => "consuming",
166 HlMod::ControlFlow => "control", 170 HlMod::ControlFlow => "control",
167 HlMod::Definition => "declaration", 171 HlMod::Definition => "declaration",
168 HlMod::Documentation => "documentation", 172 HlMod::Documentation => "documentation",
169 HlMod::Injected => "injected", 173 HlMod::Injected => "injected",
174 HlMod::IntraDocLink => "intra_doc_link",
170 HlMod::Mutable => "mutable", 175 HlMod::Mutable => "mutable",
171 HlMod::Consuming => "consuming",
172 HlMod::Unsafe => "unsafe",
173 HlMod::Callable => "callable",
174 HlMod::Static => "static", 176 HlMod::Static => "static",
175 HlMod::Associated => "associated", 177 HlMod::Unsafe => "unsafe",
176 } 178 }
177 } 179 }
178 180
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 60c7518af..4635ea927 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 5d802a647..045162eb8 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
@@ -99,8 +99,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
99 <span class="brace">}</span> 99 <span class="brace">}</span>
100<span class="brace">}</span> 100<span class="brace">}</span>
101 101
102<span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> 102<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
103<span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span> 103<span class="comment documentation">/// </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span>
104<span class="comment documentation">/// [`noop`](noop) is a macro below</span> 104<span class="comment documentation">/// [`noop`](noop) is a macro below</span>
105<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 105<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
106 106
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index 4e312765c..ca9bb1e7d 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 57dfe7509..9215ddd9e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 75dbd0f14..e860d713e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 423256a20..6a6555208 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index fffe8c0f5..8b2dd3b70 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html
index 34d8deb68..9ab46d05c 100644
--- a/crates/ide/src/syntax_highlighting/test_data/injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/injection.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
index d9ca3a4c4..666b0b228 100644
--- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
@@ -7,7 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
7.label { color: #DFAF8F; font-style: italic; } 7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; } 8.comment { color: #7F9F7F; }
9.documentation { color: #629755; } 9.documentation { color: #629755; }
10.intra_doc_link { color: #A9C577; } 10.intra_doc_link { font-style: italic; }
11.injected { opacity: 0.65 ; } 11.injected { opacity: 0.65 ; }
12.struct, .enum { color: #7CB8BB; } 12.struct, .enum { color: #7CB8BB; }
13.enum_variant { color: #BDE0F3; } 13.enum_variant { color: #BDE0F3; }
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 30b23da6c..40571e52b 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -208,8 +208,10 @@ fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
208 format!("Qualify as `{}`", import.import_path) 208 format!("Qualify as `{}`", import.import_path)
209 } 209 }
210 } 210 }
211 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", import.import_path), 211 ImportCandidate::TraitAssocItem(_) => {
212 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", import.import_path), 212 format!("Qualify with `{}`", import.import_path)
213 }
214 ImportCandidate::TraitMethod(_) => format!("Qualify with `{}`", import.import_path),
213 } 215 }
214} 216}
215 217
@@ -544,6 +546,37 @@ fn main() {
544 } 546 }
545 547
546 #[test] 548 #[test]
549 fn associated_struct_const_unqualified() {
550 check_assist(
551 qualify_path,
552 r"
553 mod test_mod {
554 pub struct TestStruct {}
555 impl TestStruct {
556 const TEST_CONST: u8 = 42;
557 }
558 }
559
560 fn main() {
561 TEST_CONST$0
562 }
563 ",
564 r"
565 mod test_mod {
566 pub struct TestStruct {}
567 impl TestStruct {
568 const TEST_CONST: u8 = 42;
569 }
570 }
571
572 fn main() {
573 test_mod::TestStruct::TEST_CONST
574 }
575 ",
576 );
577 }
578
579 #[test]
547 fn associated_trait_function() { 580 fn associated_trait_function() {
548 check_assist( 581 check_assist(
549 qualify_path, 582 qualify_path,
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 3fa21ba7c..7578ad50b 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -91,7 +91,7 @@ impl<'a> MacroRender<'a> {
91 } 91 }
92 92
93 fn detail(&self) -> Option<String> { 93 fn detail(&self) -> Option<String> {
94 let ast_node = self.macro_.source(self.ctx.db())?.value; 94 let ast_node = self.macro_.source(self.ctx.db())?.value.left()?;
95 Some(macro_label(&ast_node)) 95 Some(macro_label(&ast_node))
96 } 96 }
97} 97}
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index e03ccd351..7c8844e95 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -304,7 +304,11 @@ fn path_applicable_imports(
304 return items_with_candidate_name 304 return items_with_candidate_name
305 .into_iter() 305 .into_iter()
306 .filter_map(|item| { 306 .filter_map(|item| {
307 Some(LocatedImport::new(mod_path(item)?, item, item, mod_path(item))) 307 let mut mod_path = mod_path(item)?;
308 if let Some(assoc_item) = item_as_assoc(db, item) {
309 mod_path.push_segment(assoc_item.name(db)?);
310 }
311 Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
308 }) 312 })
309 .collect(); 313 .collect();
310 } 314 }
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 0cb7d12a7..a3c5e9ccf 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -52,7 +52,6 @@ define_semantic_token_types![
52 (ESCAPE_SEQUENCE, "escapeSequence"), 52 (ESCAPE_SEQUENCE, "escapeSequence"),
53 (FORMAT_SPECIFIER, "formatSpecifier"), 53 (FORMAT_SPECIFIER, "formatSpecifier"),
54 (GENERIC, "generic"), 54 (GENERIC, "generic"),
55 (INTRA_DOC_LINK, "intraDocLink"),
56 (LABEL, "label"), 55 (LABEL, "label"),
57 (LIFETIME, "lifetime"), 56 (LIFETIME, "lifetime"),
58 (PARENTHESIS, "parenthesis"), 57 (PARENTHESIS, "parenthesis"),
@@ -90,6 +89,7 @@ define_semantic_token_modifiers![
90 (UNSAFE, "unsafe"), 89 (UNSAFE, "unsafe"),
91 (ATTRIBUTE_MODIFIER, "attribute"), 90 (ATTRIBUTE_MODIFIER, "attribute"),
92 (CALLABLE, "callable"), 91 (CALLABLE, "callable"),
92 (INTRA_DOC_LINK, "intraDocLink"),
93]; 93];
94 94
95#[derive(Default)] 95#[derive(Default)]
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 70501618e..1ddea9278 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -443,7 +443,6 @@ fn semantic_token_type_and_modifiers(
443 HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, 443 HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
444 HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, 444 HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
445 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, 445 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
446 HlTag::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
447 HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, 446 HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
448 HlTag::None => semantic_tokens::GENERIC, 447 HlTag::None => semantic_tokens::GENERIC,
449 HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, 448 HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
@@ -474,6 +473,7 @@ fn semantic_token_type_and_modifiers(
474 HlMod::Unsafe => semantic_tokens::UNSAFE, 473 HlMod::Unsafe => semantic_tokens::UNSAFE,
475 HlMod::Callable => semantic_tokens::CALLABLE, 474 HlMod::Callable => semantic_tokens::CALLABLE,
476 HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, 475 HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
476 HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
477 HlMod::Associated => continue, 477 HlMod::Associated => continue,
478 }; 478 };
479 mods |= modifier; 479 mods |= modifier;
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index f4c37353c..dba2197de 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -384,11 +384,9 @@ If the LSP binary is not available, GNOME Builder can install it when opening a
384 384
385=== Eclipse IDE 385=== Eclipse IDE
386 386
387Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
388
389Support for Rust development in the Eclipse IDE is provided by link:https://github.com/eclipse/corrosion[Eclipse Corrosion]. 387Support for Rust development in the Eclipse IDE is provided by link:https://github.com/eclipse/corrosion[Eclipse Corrosion].
390While it currently uses RLS as default, you can successfully configure it so the IDE will use `rust-analyzer` instead. 388If available in PATH or in some standard location, `rust-analyzer` is detected and powers editing of Rust files without further configuration.
391To do so, with an Eclipse IDE where Corrosion is installed, just go to __Window > Preferences > Rust__ and edit the __Path to Rust Language Server__ entry to reference the path to `rust-analyzer`. 389If `rust-analyzer` is not detected, Corrosion will prompt you for configuration of your Rust toolchain and language server with a link to the __Window > Preferences > Rust__ preference page; from here a button allows to download and configure `rust-analyzer`, but you can also reference another installation.
392You'll need to close and reopen all .rs and Cargo files, or to restart the IDE, for this change to take effect. 390You'll need to close and reopen all .rs and Cargo files, or to restart the IDE, for this change to take effect.
393 391
394== Configuration 392== Configuration