aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/adt.rs2
-rw-r--r--crates/ra_hir/src/attr.rs80
-rw-r--r--crates/ra_hir/src/code_model.rs16
-rw-r--r--crates/ra_hir/src/code_model/docs.rs2
-rw-r--r--crates/ra_hir/src/code_model/src.rs4
-rw-r--r--crates/ra_hir/src/db.rs2
-rw-r--r--crates/ra_hir/src/diagnostics.rs2
-rw-r--r--crates/ra_hir/src/either.rs2
-rw-r--r--crates/ra_hir/src/expr.rs2
-rw-r--r--crates/ra_hir/src/expr/lower.rs23
-rw-r--r--crates/ra_hir/src/expr/scope.rs2
-rw-r--r--crates/ra_hir/src/expr/validation.rs2
-rw-r--r--crates/ra_hir/src/from_source.rs2
-rw-r--r--crates/ra_hir/src/generics.rs1
-rw-r--r--crates/ra_hir/src/ids.rs22
-rw-r--r--crates/ra_hir/src/impl_block.rs41
-rw-r--r--crates/ra_hir/src/lang_item.rs4
-rw-r--r--crates/ra_hir/src/lib.rs5
-rw-r--r--crates/ra_hir/src/marks.rs5
-rw-r--r--crates/ra_hir/src/mock.rs25
-rw-r--r--crates/ra_hir/src/name.rs159
-rw-r--r--crates/ra_hir/src/nameres.rs14
-rw-r--r--crates/ra_hir/src/nameres/collector.rs60
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs2
-rw-r--r--crates/ra_hir/src/nameres/raw.rs102
-rw-r--r--crates/ra_hir/src/nameres/tests.rs70
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs105
-rw-r--r--crates/ra_hir/src/path.rs66
-rw-r--r--crates/ra_hir/src/source_binder.rs16
-rw-r--r--crates/ra_hir/src/source_id.rs2
-rw-r--r--crates/ra_hir/src/ty.rs141
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs14
-rw-r--r--crates/ra_hir/src/ty/display.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs36
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs10
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs24
-rw-r--r--crates/ra_hir/src/ty/lower.rs20
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs18
-rw-r--r--crates/ra_hir/src/ty/op.rs2
-rw-r--r--crates/ra_hir/src/ty/primitive.rs2
-rw-r--r--crates/ra_hir/src/ty/tests.rs142
-rw-r--r--crates/ra_hir/src/ty/traits.rs12
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs80
-rw-r--r--crates/ra_hir/src/type_ref.rs2
44 files changed, 1038 insertions, 307 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index fbb4ff4d8..99d286215 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -133,7 +133,7 @@ impl VariantData {
133 .fields() 133 .fields()
134 .enumerate() 134 .enumerate()
135 .map(|(i, fd)| StructFieldData { 135 .map(|(i, fd)| StructFieldData {
136 name: Name::tuple_field_name(i), 136 name: Name::new_tuple_field(i),
137 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 137 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
138 }) 138 })
139 .collect(); 139 .collect();
diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs
new file mode 100644
index 000000000..f67e80bfd
--- /dev/null
+++ b/crates/ra_hir/src/attr.rs
@@ -0,0 +1,80 @@
1//! A higher level attributes based on TokenTree, with also some shortcuts.
2
3use std::sync::Arc;
4
5use mbe::ast_to_token_tree;
6use ra_cfg::CfgOptions;
7use ra_syntax::{
8 ast::{self, AstNode, AttrsOwner},
9 SmolStr,
10};
11use tt::Subtree;
12
13use crate::{db::AstDatabase, path::Path, HirFileId, Source};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub(crate) struct Attr {
17 pub(crate) path: Path,
18 pub(crate) input: Option<AttrInput>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum AttrInput {
23 Literal(SmolStr),
24 TokenTree(Subtree),
25}
26
27impl Attr {
28 pub(crate) fn from_src(
29 Source { file_id, ast }: Source<ast::Attr>,
30 db: &impl AstDatabase,
31 ) -> Option<Attr> {
32 let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?;
33 let input = match ast.input() {
34 None => None,
35 Some(ast::AttrInput::Literal(lit)) => {
36 // FIXME: escape? raw string?
37 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
38 Some(AttrInput::Literal(value))
39 }
40 Some(ast::AttrInput::TokenTree(tt)) => {
41 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
42 }
43 };
44
45 Some(Attr { path, input })
46 }
47
48 pub(crate) fn from_attrs_owner(
49 file_id: HirFileId,
50 owner: &dyn AttrsOwner,
51 db: &impl AstDatabase,
52 ) -> Option<Arc<[Attr]>> {
53 let mut attrs = owner.attrs().peekable();
54 if attrs.peek().is_none() {
55 // Avoid heap allocation
56 return None;
57 }
58 Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect())
59 }
60
61 pub(crate) fn is_simple_atom(&self, name: &str) -> bool {
62 // FIXME: Avoid cloning
63 self.path.as_ident().map_or(false, |s| s.to_string() == name)
64 }
65
66 pub(crate) fn as_cfg(&self) -> Option<&Subtree> {
67 if self.is_simple_atom("cfg") {
68 match &self.input {
69 Some(AttrInput::TokenTree(subtree)) => Some(subtree),
70 _ => None,
71 }
72 } else {
73 None
74 }
75 }
76
77 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> {
78 cfg_options.is_cfg_enabled(self.as_cfg()?)
79 }
80}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 20413cb3d..e3a7e8e3c 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1pub(crate) mod src; 3pub(crate) mod src;
2pub(crate) mod docs; 4pub(crate) mod docs;
3 5
@@ -339,10 +341,14 @@ pub struct Struct {
339} 341}
340 342
341impl Struct { 343impl Struct {
342 pub fn module(self, db: &impl HirDatabase) -> Module { 344 pub fn module(self, db: &impl DefDatabase) -> Module {
343 self.id.module(db) 345 self.id.module(db)
344 } 346 }
345 347
348 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
349 self.module(db).krate(db)
350 }
351
346 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 352 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
347 db.struct_data(self).name.clone() 353 db.struct_data(self).name.clone()
348 } 354 }
@@ -423,10 +429,14 @@ pub struct Enum {
423} 429}
424 430
425impl Enum { 431impl Enum {
426 pub fn module(self, db: &impl HirDatabase) -> Module { 432 pub fn module(self, db: &impl DefDatabase) -> Module {
427 self.id.module(db) 433 self.id.module(db)
428 } 434 }
429 435
436 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
437 self.module(db).krate(db)
438 }
439
430 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 440 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
431 db.enum_data(self).name.clone() 441 db.enum_data(self).name.clone()
432 } 442 }
@@ -514,7 +524,7 @@ impl Adt {
514 } 524 }
515 } 525 }
516 526
517 pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> { 527 pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
518 match self { 528 match self {
519 Adt::Struct(s) => s.module(db), 529 Adt::Struct(s) => s.module(db),
520 Adt::Union(s) => s.module(db), 530 Adt::Union(s) => s.module(db),
diff --git a/crates/ra_hir/src/code_model/docs.rs b/crates/ra_hir/src/code_model/docs.rs
index 99edc5814..9675e397f 100644
--- a/crates/ra_hir/src/code_model/docs.rs
+++ b/crates/ra_hir/src/code_model/docs.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_syntax::ast; 5use ra_syntax::ast;
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index c0cb27b47..fdae26906 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use ra_syntax::{ 3use ra_syntax::{
2 ast::{self, AstNode}, 4 ast::{self, AstNode},
3 SyntaxNode, 5 SyntaxNode,
@@ -119,7 +121,7 @@ impl HasSource for TypeAlias {
119impl HasSource for MacroDef { 121impl HasSource for MacroDef {
120 type Ast = ast::MacroCall; 122 type Ast = ast::MacroCall;
121 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> { 123 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> {
122 Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) } 124 Source { file_id: self.id.ast_id.file_id(), ast: self.id.ast_id.to_node(db) }
123 } 125 }
124} 126}
125 127
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index deed1c62f..73d7d6fb6 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_db::{salsa, SourceDatabase}; 5use ra_db::{salsa, SourceDatabase};
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 60da33695..9acdaf8ed 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::{any::Any, fmt}; 3use std::{any::Any, fmt};
2 4
3use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; 5use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange};
diff --git a/crates/ra_hir/src/either.rs b/crates/ra_hir/src/either.rs
index 439e6ec87..83583ef8b 100644
--- a/crates/ra_hir/src/either.rs
+++ b/crates/ra_hir/src/either.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2pub enum Either<A, B> { 4pub enum Either<A, B> {
3 A(A), 5 A(A),
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index b1bec2a68..d238741ba 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1pub(crate) mod lower; 3pub(crate) mod lower;
2pub(crate) mod scope; 4pub(crate) mod scope;
3pub(crate) mod validation; 5pub(crate) mod validation;
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
index 61535d24f..50ea429ea 100644
--- a/crates/ra_hir/src/expr/lower.rs
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use ra_arena::Arena; 3use ra_arena::Arena;
2use ra_syntax::{ 4use ra_syntax::{
3 ast::{ 5 ast::{
@@ -272,8 +274,11 @@ where
272 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) 274 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
273 } 275 }
274 ast::Expr::PathExpr(e) => { 276 ast::Expr::PathExpr(e) => {
275 let path = 277 let path = e
276 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing); 278 .path()
279 .and_then(|path| self.parse_path(path))
280 .map(Expr::Path)
281 .unwrap_or(Expr::Missing);
277 self.alloc_expr(path, syntax_ptr) 282 self.alloc_expr(path, syntax_ptr)
278 } 283 }
279 ast::Expr::ContinueExpr(_e) => { 284 ast::Expr::ContinueExpr(_e) => {
@@ -295,7 +300,7 @@ where
295 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 300 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
296 } 301 }
297 ast::Expr::RecordLit(e) => { 302 ast::Expr::RecordLit(e) => {
298 let path = e.path().and_then(Path::from_ast); 303 let path = e.path().and_then(|path| self.parse_path(path));
299 let mut field_ptrs = Vec::new(); 304 let mut field_ptrs = Vec::new();
300 let record_lit = if let Some(nfl) = e.record_field_list() { 305 let record_lit = if let Some(nfl) = e.record_field_list() {
301 let fields = nfl 306 let fields = nfl
@@ -459,7 +464,7 @@ where
459 .ast_id(&e) 464 .ast_id(&e)
460 .with_file_id(self.current_file_id); 465 .with_file_id(self.current_file_id);
461 466
462 if let Some(path) = e.path().and_then(Path::from_ast) { 467 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
463 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { 468 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
464 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); 469 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
465 let file_id = call_id.as_file(MacroFileKind::Expr); 470 let file_id = call_id.as_file(MacroFileKind::Expr);
@@ -529,7 +534,7 @@ where
529 Pat::Bind { name, mode: annotation, subpat } 534 Pat::Bind { name, mode: annotation, subpat }
530 } 535 }
531 ast::Pat::TupleStructPat(p) => { 536 ast::Pat::TupleStructPat(p) => {
532 let path = p.path().and_then(Path::from_ast); 537 let path = p.path().and_then(|path| self.parse_path(path));
533 let args = p.args().map(|p| self.collect_pat(p)).collect(); 538 let args = p.args().map(|p| self.collect_pat(p)).collect();
534 Pat::TupleStruct { path, args } 539 Pat::TupleStruct { path, args }
535 } 540 }
@@ -539,7 +544,7 @@ where
539 Pat::Ref { pat, mutability } 544 Pat::Ref { pat, mutability }
540 } 545 }
541 ast::Pat::PathPat(p) => { 546 ast::Pat::PathPat(p) => {
542 let path = p.path().and_then(Path::from_ast); 547 let path = p.path().and_then(|path| self.parse_path(path));
543 path.map(Pat::Path).unwrap_or(Pat::Missing) 548 path.map(Pat::Path).unwrap_or(Pat::Missing)
544 } 549 }
545 ast::Pat::TuplePat(p) => { 550 ast::Pat::TuplePat(p) => {
@@ -548,7 +553,7 @@ where
548 } 553 }
549 ast::Pat::PlaceholderPat(_) => Pat::Wild, 554 ast::Pat::PlaceholderPat(_) => Pat::Wild,
550 ast::Pat::RecordPat(p) => { 555 ast::Pat::RecordPat(p) => {
551 let path = p.path().and_then(Path::from_ast); 556 let path = p.path().and_then(|path| self.parse_path(path));
552 let record_field_pat_list = 557 let record_field_pat_list =
553 p.record_field_pat_list().expect("every struct should have a field list"); 558 p.record_field_pat_list().expect("every struct should have a field list");
554 let mut fields: Vec<_> = record_field_pat_list 559 let mut fields: Vec<_> = record_field_pat_list
@@ -589,6 +594,10 @@ where
589 self.missing_pat() 594 self.missing_pat()
590 } 595 }
591 } 596 }
597
598 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
599 Path::from_src(Source { ast: path, file_id: self.current_file_id }, self.db)
600 }
592} 601}
593 602
594impl From<ast::BinOp> for BinaryOp { 603impl From<ast::BinOp> for BinaryOp {
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index de0983a7e..5496822e7 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_arena::{impl_arena_id, Arena, RawId}; 5use ra_arena::{impl_arena_id, Arena, RawId};
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index f06e5ec07..1aa853c3e 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_syntax::ast; 5use ra_syntax::ast;
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 7b6d9b240..a012f33f7 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use ra_db::{FileId, FilePosition}; 3use ra_db::{FileId, FilePosition};
2use ra_syntax::{ 4use ra_syntax::{
3 algo::find_node_at_offset, 5 algo::find_node_at_offset,
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 6865d34ba..4ce7551c3 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -132,6 +132,7 @@ impl GenericParams {
132 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { 132 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
133 for (idx, type_param) in params.type_params().enumerate() { 133 for (idx, type_param) in params.type_params().enumerate() {
134 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 134 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
135 // FIXME: Use `Path::from_src`
135 let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); 136 let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast);
136 137
137 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; 138 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 9ea4e695d..a3b65cc79 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::{ 3use std::{
2 hash::{Hash, Hasher}, 4 hash::{Hash, Hasher},
3 sync::Arc, 5 sync::Arc,
@@ -10,7 +12,7 @@ use ra_syntax::{ast, AstNode, Parse, SyntaxNode};
10 12
11use crate::{ 13use crate::{
12 db::{AstDatabase, DefDatabase, InternDatabase}, 14 db::{AstDatabase, DefDatabase, InternDatabase},
13 AstId, FileAstId, Module, Source, 15 AstId, Crate, FileAstId, Module, Source,
14}; 16};
15 17
16/// hir makes heavy use of ids: integer (u32) handlers to various things. You 18/// hir makes heavy use of ids: integer (u32) handlers to various things. You
@@ -58,6 +60,17 @@ impl HirFileId {
58 } 60 }
59 } 61 }
60 62
63 /// Get the crate which the macro lives in, if it is a macro file.
64 pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
65 match self.0 {
66 HirFileIdRepr::File(_) => None,
67 HirFileIdRepr::Macro(macro_file) => {
68 let loc = macro_file.macro_call_id.loc(db);
69 Some(loc.def.krate)
70 }
71 }
72 }
73
61 pub(crate) fn parse_or_expand_query( 74 pub(crate) fn parse_or_expand_query(
62 db: &impl AstDatabase, 75 db: &impl AstDatabase,
63 file_id: HirFileId, 76 file_id: HirFileId,
@@ -121,10 +134,13 @@ impl From<FileId> for HirFileId {
121} 134}
122 135
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 136#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
124pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>); 137pub struct MacroDefId {
138 pub(crate) ast_id: AstId<ast::MacroCall>,
139 pub(crate) krate: Crate,
140}
125 141
126pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { 142pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
127 let macro_call = id.0.to_node(db); 143 let macro_call = id.ast_id.to_node(db);
128 let arg = macro_call.token_tree()?; 144 let arg = macro_call.token_tree()?;
129 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { 145 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
130 log::warn!("fail on macro_def to token tree: {:#?}", arg); 146 log::warn!("fail on macro_def to token tree: {:#?}", arg);
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index d830202bd..55dfc393b 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -1,13 +1,17 @@
1//! FIXME: write short doc here
2
1use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
2use std::sync::Arc; 4use std::sync::Arc;
3 5
4use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 6use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
7use ra_cfg::CfgOptions;
5use ra_syntax::{ 8use ra_syntax::{
6 ast::{self, AstNode}, 9 ast::{self, AstNode},
7 AstPtr, 10 AstPtr,
8}; 11};
9 12
10use crate::{ 13use crate::{
14 attr::Attr,
11 code_model::{Module, ModuleSource}, 15 code_model::{Module, ModuleSource},
12 db::{AstDatabase, DefDatabase, HirDatabase}, 16 db::{AstDatabase, DefDatabase, HirDatabase},
13 generics::HasGenericParams, 17 generics::HasGenericParams,
@@ -174,6 +178,7 @@ pub struct ModuleImplBlocks {
174impl ModuleImplBlocks { 178impl ModuleImplBlocks {
175 fn collect( 179 fn collect(
176 db: &(impl DefDatabase + AstDatabase), 180 db: &(impl DefDatabase + AstDatabase),
181 cfg_options: &CfgOptions,
177 module: Module, 182 module: Module,
178 source_map: &mut ImplSourceMap, 183 source_map: &mut ImplSourceMap,
179 ) -> Self { 184 ) -> Self {
@@ -186,11 +191,11 @@ impl ModuleImplBlocks {
186 let src = m.module.definition_source(db); 191 let src = m.module.definition_source(db);
187 match &src.ast { 192 match &src.ast {
188 ModuleSource::SourceFile(node) => { 193 ModuleSource::SourceFile(node) => {
189 m.collect_from_item_owner(db, source_map, node, src.file_id) 194 m.collect_from_item_owner(db, cfg_options, source_map, node, src.file_id)
190 } 195 }
191 ModuleSource::Module(node) => { 196 ModuleSource::Module(node) => {
192 let item_list = node.item_list().expect("inline module should have item list"); 197 let item_list = node.item_list().expect("inline module should have item list");
193 m.collect_from_item_owner(db, source_map, &item_list, src.file_id) 198 m.collect_from_item_owner(db, cfg_options, source_map, &item_list, src.file_id)
194 } 199 }
195 }; 200 };
196 m 201 m
@@ -199,6 +204,7 @@ impl ModuleImplBlocks {
199 fn collect_from_item_owner( 204 fn collect_from_item_owner(
200 &mut self, 205 &mut self,
201 db: &(impl DefDatabase + AstDatabase), 206 db: &(impl DefDatabase + AstDatabase),
207 cfg_options: &CfgOptions,
202 source_map: &mut ImplSourceMap, 208 source_map: &mut ImplSourceMap,
203 owner: &dyn ast::ModuleItemOwner, 209 owner: &dyn ast::ModuleItemOwner,
204 file_id: HirFileId, 210 file_id: HirFileId,
@@ -206,6 +212,13 @@ impl ModuleImplBlocks {
206 for item in owner.items_with_macros() { 212 for item in owner.items_with_macros() {
207 match item { 213 match item {
208 ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { 214 ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => {
215 let attrs = Attr::from_attrs_owner(file_id, &impl_block_ast, db);
216 if attrs.map_or(false, |attrs| {
217 attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false))
218 }) {
219 continue;
220 }
221
209 let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); 222 let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast);
210 let id = self.impls.alloc(impl_block); 223 let id = self.impls.alloc(impl_block);
211 for &impl_item in &self.impls[id].items { 224 for &impl_item in &self.impls[id].items {
@@ -216,9 +229,19 @@ impl ModuleImplBlocks {
216 } 229 }
217 ast::ItemOrMacro::Item(_) => (), 230 ast::ItemOrMacro::Item(_) => (),
218 ast::ItemOrMacro::Macro(macro_call) => { 231 ast::ItemOrMacro::Macro(macro_call) => {
232 let attrs = Attr::from_attrs_owner(file_id, &macro_call, db);
233 if attrs.map_or(false, |attrs| {
234 attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false))
235 }) {
236 continue;
237 }
238
219 //FIXME: we should really cut down on the boilerplate required to process a macro 239 //FIXME: we should really cut down on the boilerplate required to process a macro
220 let ast_id = db.ast_id_map(file_id).ast_id(&macro_call).with_file_id(file_id); 240 let ast_id = db.ast_id_map(file_id).ast_id(&macro_call).with_file_id(file_id);
221 if let Some(path) = macro_call.path().and_then(Path::from_ast) { 241 if let Some(path) = macro_call
242 .path()
243 .and_then(|path| Path::from_src(Source { ast: path, file_id }, db))
244 {
222 if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) 245 if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path)
223 { 246 {
224 let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); 247 let call_id = MacroCallLoc { def: def.id, ast_id }.id(db);
@@ -226,7 +249,13 @@ impl ModuleImplBlocks {
226 if let Some(item_list) = 249 if let Some(item_list) =
227 db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) 250 db.parse_or_expand(file_id).and_then(ast::MacroItems::cast)
228 { 251 {
229 self.collect_from_item_owner(db, source_map, &item_list, file_id) 252 self.collect_from_item_owner(
253 db,
254 cfg_options,
255 source_map,
256 &item_list,
257 file_id,
258 )
230 } 259 }
231 } 260 }
232 } 261 }
@@ -241,8 +270,10 @@ pub(crate) fn impls_in_module_with_source_map_query(
241 module: Module, 270 module: Module,
242) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { 271) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
243 let mut source_map = ImplSourceMap::default(); 272 let mut source_map = ImplSourceMap::default();
273 let crate_graph = db.crate_graph();
274 let cfg_options = crate_graph.cfg_options(module.krate.crate_id());
244 275
245 let result = ModuleImplBlocks::collect(db, module, &mut source_map); 276 let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map);
246 (Arc::new(result), Arc::new(source_map)) 277 (Arc::new(result), Arc::new(source_map))
247} 278}
248 279
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
index bcce314d8..6c4e8ffbd 100644
--- a/crates/ra_hir/src/lang_item.rs
+++ b/crates/ra_hir/src/lang_item.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
2use std::sync::Arc; 4use std::sync::Arc;
3 5
@@ -151,7 +153,7 @@ impl LangItems {
151 153
152fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> { 154fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> {
153 node.attrs() 155 node.attrs()
154 .filter_map(|a| a.as_key_value()) 156 .filter_map(|a| a.as_simple_key_value())
155 .filter(|(key, _)| key == "lang") 157 .filter(|(key, _)| key == "lang")
156 .map(|(_, val)| val) 158 .map(|(_, val)| val)
157 .nth(0) 159 .nth(0)
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index a9de9fb6b..4340e9d34 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -1,5 +1,3 @@
1#![recursion_limit = "512"]
2
3//! HIR (previously known as descriptors) provides a high-level object oriented 1//! HIR (previously known as descriptors) provides a high-level object oriented
4//! access to Rust code. 2//! access to Rust code.
5//! 3//!
@@ -7,6 +5,8 @@
7//! to a particular crate instance. That is, it has cfg flags and features 5//! to a particular crate instance. That is, it has cfg flags and features
8//! applied. So, the relation between syntax and HIR is many-to-one. 6//! applied. So, the relation between syntax and HIR is many-to-one.
9 7
8#![recursion_limit = "512"]
9
10macro_rules! impl_froms { 10macro_rules! impl_froms {
11 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { 11 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
12 $( 12 $(
@@ -44,6 +44,7 @@ mod traits;
44mod type_alias; 44mod type_alias;
45mod type_ref; 45mod type_ref;
46mod ty; 46mod ty;
47mod attr;
47mod impl_block; 48mod impl_block;
48mod expr; 49mod expr;
49mod lang_item; 50mod lang_item;
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index b2111be05..79af24b20 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -1,3 +1,5 @@
1//! See test_utils/src/marks.rs
2
1test_utils::marks!( 3test_utils::marks!(
2 bogus_paths 4 bogus_paths
3 name_res_works_for_broken_modules 5 name_res_works_for_broken_modules
@@ -9,9 +11,10 @@ test_utils::marks!(
9 glob_across_crates 11 glob_across_crates
10 std_prelude 12 std_prelude
11 match_ergonomics_ref 13 match_ergonomics_ref
12 trait_resolution_on_fn_type
13 infer_while_let 14 infer_while_let
14 macro_rules_from_other_crates_are_visible_with_macro_use 15 macro_rules_from_other_crates_are_visible_with_macro_use
15 prelude_is_macro_use 16 prelude_is_macro_use
16 coerce_merge_fail_fallback 17 coerce_merge_fail_fallback
18 macro_dollar_crate_self
19 macro_dollar_crate_other
17); 20);
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index cb405091e..f750986b8 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -1,6 +1,9 @@
1//! FIXME: write short doc here
2
1use std::{panic, sync::Arc}; 3use std::{panic, sync::Arc};
2 4
3use parking_lot::Mutex; 5use parking_lot::Mutex;
6use ra_cfg::CfgOptions;
4use ra_db::{ 7use ra_db::{
5 salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, 8 salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot,
6 SourceRootId, 9 SourceRootId,
@@ -72,13 +75,13 @@ impl MockDatabase {
72 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { 75 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
73 let mut ids = FxHashMap::default(); 76 let mut ids = FxHashMap::default();
74 let mut crate_graph = CrateGraph::default(); 77 let mut crate_graph = CrateGraph::default();
75 for (crate_name, (crate_root, edition, _)) in graph.0.iter() { 78 for (crate_name, (crate_root, edition, cfg_options, _)) in graph.0.iter() {
76 let crate_root = self.file_id_of(&crate_root); 79 let crate_root = self.file_id_of(&crate_root);
77 let crate_id = crate_graph.add_crate_root(crate_root, *edition); 80 let crate_id = crate_graph.add_crate_root(crate_root, *edition, cfg_options.clone());
78 Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone()); 81 Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone());
79 ids.insert(crate_name, crate_id); 82 ids.insert(crate_name, crate_id);
80 } 83 }
81 for (crate_name, (_, _, deps)) in graph.0.iter() { 84 for (crate_name, (_, _, _, deps)) in graph.0.iter() {
82 let from = ids[crate_name]; 85 let from = ids[crate_name];
83 for dep in deps { 86 for dep in deps {
84 let to = ids[dep]; 87 let to = ids[dep];
@@ -182,7 +185,7 @@ impl MockDatabase {
182 185
183 if is_crate_root { 186 if is_crate_root {
184 let mut crate_graph = CrateGraph::default(); 187 let mut crate_graph = CrateGraph::default();
185 crate_graph.add_crate_root(file_id, Edition::Edition2018); 188 crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default());
186 self.set_crate_graph(Arc::new(crate_graph)); 189 self.set_crate_graph(Arc::new(crate_graph));
187 } 190 }
188 file_id 191 file_id
@@ -266,19 +269,27 @@ impl MockDatabase {
266} 269}
267 270
268#[derive(Default)] 271#[derive(Default)]
269pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, Vec<String>))>); 272pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, CfgOptions, Vec<String>))>);
270 273
271#[macro_export] 274#[macro_export]
272macro_rules! crate_graph { 275macro_rules! crate_graph {
273 ($($crate_name:literal: ($crate_path:literal, $($edition:literal,)? [$($dep:literal),*]),)*) => {{ 276 ($(
277 $crate_name:literal: (
278 $crate_path:literal,
279 $($edition:literal,)?
280 [$($dep:literal),*]
281 $(,$cfg:expr)?
282 ),
283 )*) => {{
274 let mut res = $crate::mock::CrateGraphFixture::default(); 284 let mut res = $crate::mock::CrateGraphFixture::default();
275 $( 285 $(
276 #[allow(unused_mut, unused_assignments)] 286 #[allow(unused_mut, unused_assignments)]
277 let mut edition = ra_db::Edition::Edition2018; 287 let mut edition = ra_db::Edition::Edition2018;
278 $(edition = ra_db::Edition::from_string($edition);)? 288 $(edition = ra_db::Edition::from_string($edition);)?
289 let cfg_options = { ::ra_cfg::CfgOptions::default() $(; $cfg)? };
279 res.0.push(( 290 res.0.push((
280 $crate_name.to_string(), 291 $crate_name.to_string(),
281 ($crate_path.to_string(), edition, vec![$($dep.to_string()),*]) 292 ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*])
282 )); 293 ));
283 )* 294 )*
284 res 295 res
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 1bf993ffb..1e0b8c350 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::fmt; 3use std::fmt;
2 4
3use ra_syntax::{ast, SmolStr}; 5use ra_syntax::{ast, SmolStr};
@@ -5,20 +7,21 @@ use ra_syntax::{ast, SmolStr};
5/// `Name` is a wrapper around string, which is used in hir for both references 7/// `Name` is a wrapper around string, which is used in hir for both references
6/// and declarations. In theory, names should also carry hygiene info, but we are 8/// and declarations. In theory, names should also carry hygiene info, but we are
7/// not there yet! 9/// not there yet!
8#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 10#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub struct Name { 11pub struct Name(Repr);
10 text: SmolStr,
11}
12 12
13impl fmt::Display for Name { 13#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 14enum Repr {
15 fmt::Display::fmt(&self.text, f) 15 Text(SmolStr),
16 } 16 TupleField(usize),
17} 17}
18 18
19impl fmt::Debug for Name { 19impl fmt::Display for Name {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 fmt::Debug::fmt(&self.text, f) 21 match &self.0 {
22 Repr::Text(text) => fmt::Display::fmt(&text, f),
23 Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
24 }
22 } 25 }
23} 26}
24 27
@@ -26,29 +29,38 @@ impl Name {
26 /// Note: this is private to make creating name from random string hard. 29 /// Note: this is private to make creating name from random string hard.
27 /// Hopefully, this should allow us to integrate hygiene cleaner in the 30 /// Hopefully, this should allow us to integrate hygiene cleaner in the
28 /// future, and to switch to interned representation of names. 31 /// future, and to switch to interned representation of names.
29 const fn new(text: SmolStr) -> Name { 32 const fn new_text(text: SmolStr) -> Name {
30 Name { text } 33 Name(Repr::Text(text))
31 } 34 }
32 35
33 pub(crate) fn missing() -> Name { 36 pub(crate) fn new_tuple_field(idx: usize) -> Name {
34 Name::new("[missing name]".into()) 37 Name(Repr::TupleField(idx))
38 }
39
40 /// Shortcut to create inline plain text name
41 const fn new_inline_ascii(len: usize, text: &[u8]) -> Name {
42 Name::new_text(SmolStr::new_inline_from_ascii(len, text))
35 } 43 }
36 44
37 pub(crate) fn tuple_field_name(idx: usize) -> Name { 45 /// Resolve a name from the text of token.
38 Name::new(idx.to_string().into()) 46 fn resolve(raw_text: &SmolStr) -> Name {
47 let raw_start = "r#";
48 if raw_text.as_str().starts_with(raw_start) {
49 Name::new_text(SmolStr::new(&raw_text[raw_start.len()..]))
50 } else {
51 Name::new_text(raw_text.clone())
52 }
39 } 53 }
40 54
41 // There's should be no way to extract a string out of `Name`: `Name` in the 55 pub(crate) fn missing() -> Name {
42 // future, `Name` will include hygiene information, and you can't encode 56 Name::new_text("[missing name]".into())
43 // hygiene into a String. 57 }
44 // 58
45 // If you need to compare something with `Name`, compare `Name`s directly. 59 pub(crate) fn as_tuple_index(&self) -> Option<usize> {
46 // 60 match self.0 {
47 // If you need to render `Name` for the user, use the `Display` impl, but be 61 Repr::TupleField(idx) => Some(idx),
48 // aware that it strips hygiene info. 62 _ => None,
49 #[deprecated(note = "use to_string instead")] 63 }
50 pub fn as_smolstr(&self) -> &SmolStr {
51 &self.text
52 } 64 }
53} 65}
54 66
@@ -58,15 +70,16 @@ pub(crate) trait AsName {
58 70
59impl AsName for ast::NameRef { 71impl AsName for ast::NameRef {
60 fn as_name(&self) -> Name { 72 fn as_name(&self) -> Name {
61 let name = resolve_name(self.text()); 73 match self.as_tuple_field() {
62 Name::new(name) 74 Some(idx) => Name::new_tuple_field(idx),
75 None => Name::resolve(self.text()),
76 }
63 } 77 }
64} 78}
65 79
66impl AsName for ast::Name { 80impl AsName for ast::Name {
67 fn as_name(&self) -> Name { 81 fn as_name(&self) -> Name {
68 let name = resolve_name(self.text()); 82 Name::resolve(self.text())
69 Name::new(name)
70 } 83 }
71} 84}
72 85
@@ -74,66 +87,56 @@ impl AsName for ast::FieldKind {
74 fn as_name(&self) -> Name { 87 fn as_name(&self) -> Name {
75 match self { 88 match self {
76 ast::FieldKind::Name(nr) => nr.as_name(), 89 ast::FieldKind::Name(nr) => nr.as_name(),
77 ast::FieldKind::Index(idx) => Name::new(idx.text().clone()), 90 ast::FieldKind::Index(idx) => Name::new_tuple_field(idx.text().parse().unwrap()),
78 } 91 }
79 } 92 }
80} 93}
81 94
82impl AsName for ra_db::Dependency { 95impl AsName for ra_db::Dependency {
83 fn as_name(&self) -> Name { 96 fn as_name(&self) -> Name {
84 Name::new(self.name.clone()) 97 Name::new_text(self.name.clone())
85 } 98 }
86} 99}
87 100
88// Primitives 101// Primitives
89pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize")); 102pub(crate) const ISIZE: Name = Name::new_inline_ascii(5, b"isize");
90pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8")); 103pub(crate) const I8: Name = Name::new_inline_ascii(2, b"i8");
91pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16")); 104pub(crate) const I16: Name = Name::new_inline_ascii(3, b"i16");
92pub(crate) const I32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i32")); 105pub(crate) const I32: Name = Name::new_inline_ascii(3, b"i32");
93pub(crate) const I64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i64")); 106pub(crate) const I64: Name = Name::new_inline_ascii(3, b"i64");
94pub(crate) const I128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"i128")); 107pub(crate) const I128: Name = Name::new_inline_ascii(4, b"i128");
95pub(crate) const USIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"usize")); 108pub(crate) const USIZE: Name = Name::new_inline_ascii(5, b"usize");
96pub(crate) const U8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"u8")); 109pub(crate) const U8: Name = Name::new_inline_ascii(2, b"u8");
97pub(crate) const U16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u16")); 110pub(crate) const U16: Name = Name::new_inline_ascii(3, b"u16");
98pub(crate) const U32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u32")); 111pub(crate) const U32: Name = Name::new_inline_ascii(3, b"u32");
99pub(crate) const U64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u64")); 112pub(crate) const U64: Name = Name::new_inline_ascii(3, b"u64");
100pub(crate) const U128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"u128")); 113pub(crate) const U128: Name = Name::new_inline_ascii(4, b"u128");
101pub(crate) const F32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f32")); 114pub(crate) const F32: Name = Name::new_inline_ascii(3, b"f32");
102pub(crate) const F64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f64")); 115pub(crate) const F64: Name = Name::new_inline_ascii(3, b"f64");
103pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool")); 116pub(crate) const BOOL: Name = Name::new_inline_ascii(4, b"bool");
104pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char")); 117pub(crate) const CHAR: Name = Name::new_inline_ascii(4, b"char");
105pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str")); 118pub(crate) const STR: Name = Name::new_inline_ascii(3, b"str");
106 119
107// Special names 120// Special names
108pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self")); 121pub(crate) const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self");
109pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self")); 122pub(crate) const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self");
110pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules")); 123pub(crate) const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules");
111 124
112// Components of known path (value or mod name) 125// Components of known path (value or mod name)
113pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std")); 126pub(crate) const STD: Name = Name::new_inline_ascii(3, b"std");
114pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter")); 127pub(crate) const ITER: Name = Name::new_inline_ascii(4, b"iter");
115pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); 128pub(crate) const OPS: Name = Name::new_inline_ascii(3, b"ops");
116pub(crate) const FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); 129pub(crate) const FUTURE: Name = Name::new_inline_ascii(6, b"future");
117pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); 130pub(crate) const RESULT: Name = Name::new_inline_ascii(6, b"result");
118pub(crate) const BOXED: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); 131pub(crate) const BOXED: Name = Name::new_inline_ascii(5, b"boxed");
119 132
120// Components of known path (type name) 133// Components of known path (type name)
121pub(crate) const INTO_ITERATOR_TYPE: Name = 134pub(crate) const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator");
122 Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); 135pub(crate) const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item");
123pub(crate) const ITEM_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); 136pub(crate) const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try");
124pub(crate) const TRY_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); 137pub(crate) const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok");
125pub(crate) const OK_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); 138pub(crate) const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future");
126pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); 139pub(crate) const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result");
127pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); 140pub(crate) const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
128pub(crate) const OUTPUT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); 141pub(crate) const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
129pub(crate) const TARGET_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); 142pub(crate) const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
130pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box"));
131
132fn resolve_name(text: &SmolStr) -> SmolStr {
133 let raw_start = "r#";
134 if text.as_str().starts_with(raw_start) {
135 SmolStr::new(&text[raw_start.len()..])
136 } else {
137 text.clone()
138 }
139}
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index b808a0c36..67adcfa28 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -332,6 +332,20 @@ impl CrateDefMap {
332 ) -> ResolvePathResult { 332 ) -> ResolvePathResult {
333 let mut segments = path.segments.iter().enumerate(); 333 let mut segments = path.segments.iter().enumerate();
334 let mut curr_per_ns: PerNs = match path.kind { 334 let mut curr_per_ns: PerNs = match path.kind {
335 PathKind::DollarCrate(krate) => {
336 if krate == self.krate {
337 tested_by!(macro_dollar_crate_self);
338 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
339 } else {
340 match krate.root_module(db) {
341 Some(module) => {
342 tested_by!(macro_dollar_crate_other);
343 PerNs::types(module.into())
344 }
345 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
346 }
347 }
348 }
335 PathKind::Crate => { 349 PathKind::Crate => {
336 PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) 350 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
337 } 351 }
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index ef7dc6ebe..cef2dc9d2 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,3 +1,6 @@
1//! FIXME: write short doc here
2
3use ra_cfg::CfgOptions;
1use ra_db::FileId; 4use ra_db::FileId;
2use ra_syntax::{ast, SmolStr}; 5use ra_syntax::{ast, SmolStr};
3use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
@@ -33,6 +36,9 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
33 } 36 }
34 } 37 }
35 38
39 let crate_graph = db.crate_graph();
40 let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
41
36 let mut collector = DefCollector { 42 let mut collector = DefCollector {
37 db, 43 db,
38 def_map, 44 def_map,
@@ -40,6 +46,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
40 unresolved_imports: Vec::new(), 46 unresolved_imports: Vec::new(),
41 unexpanded_macros: Vec::new(), 47 unexpanded_macros: Vec::new(),
42 macro_stack_monitor: MacroStackMonitor::default(), 48 macro_stack_monitor: MacroStackMonitor::default(),
49 cfg_options,
43 }; 50 };
44 collector.collect(); 51 collector.collect();
45 collector.finish() 52 collector.finish()
@@ -74,8 +81,8 @@ impl MacroStackMonitor {
74} 81}
75 82
76/// Walks the tree of module recursively 83/// Walks the tree of module recursively
77struct DefCollector<DB> { 84struct DefCollector<'a, DB> {
78 db: DB, 85 db: &'a DB,
79 def_map: CrateDefMap, 86 def_map: CrateDefMap,
80 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 87 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
81 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 88 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
@@ -84,9 +91,11 @@ struct DefCollector<DB> {
84 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 91 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
85 /// To prevent stack overflow, we add a deep counter here for prevent that. 92 /// To prevent stack overflow, we add a deep counter here for prevent that.
86 macro_stack_monitor: MacroStackMonitor, 93 macro_stack_monitor: MacroStackMonitor,
94
95 cfg_options: &'a CfgOptions,
87} 96}
88 97
89impl<'a, DB> DefCollector<&'a DB> 98impl<DB> DefCollector<'_, DB>
90where 99where
91 DB: DefDatabase, 100 DB: DefDatabase,
92{ 101{
@@ -504,7 +513,7 @@ struct ModCollector<'a, D> {
504 parent_module: Option<ParentModule<'a>>, 513 parent_module: Option<ParentModule<'a>>,
505} 514}
506 515
507impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> 516impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
508where 517where
509 DB: DefDatabase, 518 DB: DefDatabase,
510{ 519{
@@ -521,24 +530,27 @@ where
521 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 530 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
522 // any other items. 531 // any other items.
523 for item in items { 532 for item in items {
524 if let raw::RawItem::Import(import_id) = *item { 533 if self.is_cfg_enabled(&item.attrs) {
525 let import = self.raw_items[import_id].clone(); 534 if let raw::RawItemKind::Import(import_id) = item.kind {
526 if import.is_extern_crate && import.is_macro_use { 535 let import = self.raw_items[import_id].clone();
527 self.def_collector.import_macros_from_extern_crate(self.module_id, &import); 536 if import.is_extern_crate && import.is_macro_use {
537 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
538 }
528 } 539 }
529 } 540 }
530 } 541 }
531 542
532 for item in items { 543 for item in items {
533 match *item { 544 if self.is_cfg_enabled(&item.attrs) {
534 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), 545 match item.kind {
535 raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( 546 raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]),
536 self.module_id, 547 raw::RawItemKind::Import(import_id) => self
537 import_id, 548 .def_collector
538 self.raw_items[import_id].clone(), 549 .unresolved_imports
539 )), 550 .push((self.module_id, import_id, self.raw_items[import_id].clone())),
540 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), 551 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]),
541 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 552 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
553 }
542 } 554 }
543 } 555 }
544 } 556 }
@@ -662,7 +674,10 @@ where
662 // Case 1: macro rules, define a macro in crate-global mutable scope 674 // Case 1: macro rules, define a macro in crate-global mutable scope
663 if is_macro_rules(&mac.path) { 675 if is_macro_rules(&mac.path) {
664 if let Some(name) = &mac.name { 676 if let Some(name) = &mac.name {
665 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); 677 let macro_id = MacroDefId {
678 ast_id: mac.ast_id.with_file_id(self.file_id),
679 krate: self.def_collector.def_map.krate,
680 };
666 let macro_ = MacroDef { id: macro_id }; 681 let macro_ = MacroDef { id: macro_id };
667 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); 682 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
668 } 683 }
@@ -698,6 +713,14 @@ where
698 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 713 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
699 } 714 }
700 } 715 }
716
717 fn is_cfg_enabled(&self, attrs: &raw::Attrs) -> bool {
718 attrs.as_ref().map_or(true, |attrs| {
719 attrs
720 .iter()
721 .all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false))
722 })
723 }
701} 724}
702 725
703fn is_macro_rules(path: &Path) -> bool { 726fn is_macro_rules(path: &Path) -> bool {
@@ -725,6 +748,7 @@ mod tests {
725 unresolved_imports: Vec::new(), 748 unresolved_imports: Vec::new(),
726 unexpanded_macros: Vec::new(), 749 unexpanded_macros: Vec::new(),
727 macro_stack_monitor: monitor, 750 macro_stack_monitor: monitor,
751 cfg_options: &CfgOptions::default(),
728 }; 752 };
729 collector.collect(); 753 collector.collect();
730 collector.finish() 754 collector.finish()
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
index 964da2794..0da6789de 100644
--- a/crates/ra_hir/src/nameres/per_ns.rs
+++ b/crates/ra_hir/src/nameres/per_ns.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use crate::{MacroDef, ModuleDef}; 3use crate::{MacroDef, ModuleDef};
2 4
3#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 29aaddbf1..623b343c4 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::{ops::Index, sync::Arc}; 3use std::{ops::Index, sync::Arc};
2 4
3use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
@@ -8,8 +10,9 @@ use ra_syntax::{
8use test_utils::tested_by; 10use test_utils::tested_by;
9 11
10use crate::{ 12use crate::{
13 attr::Attr,
11 db::{AstDatabase, DefDatabase}, 14 db::{AstDatabase, DefDatabase},
12 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, 15 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
13}; 16};
14 17
15/// `RawItems` is a set of top-level items in a file (except for impls). 18/// `RawItems` is a set of top-level items in a file (except for impls).
@@ -71,6 +74,8 @@ impl RawItems {
71 raw_items: RawItems::default(), 74 raw_items: RawItems::default(),
72 source_ast_id_map: db.ast_id_map(file_id), 75 source_ast_id_map: db.ast_id_map(file_id),
73 source_map: ImportSourceMap::default(), 76 source_map: ImportSourceMap::default(),
77 file_id,
78 db,
74 }; 79 };
75 if let Some(node) = db.parse_or_expand(file_id) { 80 if let Some(node) = db.parse_or_expand(file_id) {
76 if let Some(source_file) = ast::SourceFile::cast(node.clone()) { 81 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
@@ -115,8 +120,17 @@ impl Index<Macro> for RawItems {
115 } 120 }
116} 121}
117 122
123// Avoid heap allocation on items without attributes.
124pub(super) type Attrs = Option<Arc<[Attr]>>;
125
126#[derive(Debug, PartialEq, Eq, Clone)]
127pub(super) struct RawItem {
128 pub(super) attrs: Attrs,
129 pub(super) kind: RawItemKind,
130}
131
118#[derive(Debug, PartialEq, Eq, Clone, Copy)] 132#[derive(Debug, PartialEq, Eq, Clone, Copy)]
119pub(super) enum RawItem { 133pub(super) enum RawItemKind {
120 Module(Module), 134 Module(Module),
121 Import(ImportId), 135 Import(ImportId),
122 Def(Def), 136 Def(Def),
@@ -192,13 +206,15 @@ pub(super) struct MacroData {
192 pub(super) export: bool, 206 pub(super) export: bool,
193} 207}
194 208
195struct RawItemsCollector { 209struct RawItemsCollector<DB> {
196 raw_items: RawItems, 210 raw_items: RawItems,
197 source_ast_id_map: Arc<AstIdMap>, 211 source_ast_id_map: Arc<AstIdMap>,
198 source_map: ImportSourceMap, 212 source_map: ImportSourceMap,
213 file_id: HirFileId,
214 db: DB,
199} 215}
200 216
201impl RawItemsCollector { 217impl<DB: AstDatabase> RawItemsCollector<&DB> {
202 fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { 218 fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) {
203 for item_or_macro in body.items_with_macros() { 219 for item_or_macro in body.items_with_macros() {
204 match item_or_macro { 220 match item_or_macro {
@@ -209,6 +225,7 @@ impl RawItemsCollector {
209 } 225 }
210 226
211 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { 227 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) {
228 let attrs = self.parse_attrs(&item);
212 let (kind, name) = match item { 229 let (kind, name) = match item {
213 ast::ModuleItem::Module(module) => { 230 ast::ModuleItem::Module(module) => {
214 self.add_module(current_module, module); 231 self.add_module(current_module, module);
@@ -257,7 +274,7 @@ impl RawItemsCollector {
257 if let Some(name) = name { 274 if let Some(name) = name {
258 let name = name.as_name(); 275 let name = name.as_name();
259 let def = self.raw_items.defs.alloc(DefData { name, kind }); 276 let def = self.raw_items.defs.alloc(DefData { name, kind });
260 self.push_item(current_module, RawItem::Def(def)) 277 self.push_item(current_module, attrs, RawItemKind::Def(def));
261 } 278 }
262 } 279 }
263 280
@@ -266,8 +283,10 @@ impl RawItemsCollector {
266 Some(it) => it.as_name(), 283 Some(it) => it.as_name(),
267 None => return, 284 None => return,
268 }; 285 };
286 let attrs = self.parse_attrs(&module);
269 287
270 let ast_id = self.source_ast_id_map.ast_id(&module); 288 let ast_id = self.source_ast_id_map.ast_id(&module);
289 // FIXME: cfg_attr
271 let is_macro_use = module.has_atom_attr("macro_use"); 290 let is_macro_use = module.has_atom_attr("macro_use");
272 if module.has_semi() { 291 if module.has_semi() {
273 let attr_path = extract_mod_path_attribute(&module); 292 let attr_path = extract_mod_path_attribute(&module);
@@ -277,7 +296,7 @@ impl RawItemsCollector {
277 attr_path, 296 attr_path,
278 is_macro_use, 297 is_macro_use,
279 }); 298 });
280 self.push_item(current_module, RawItem::Module(item)); 299 self.push_item(current_module, attrs, RawItemKind::Module(item));
281 return; 300 return;
282 } 301 }
283 302
@@ -291,26 +310,37 @@ impl RawItemsCollector {
291 is_macro_use, 310 is_macro_use,
292 }); 311 });
293 self.process_module(Some(item), item_list); 312 self.process_module(Some(item), item_list);
294 self.push_item(current_module, RawItem::Module(item)); 313 self.push_item(current_module, attrs, RawItemKind::Module(item));
295 return; 314 return;
296 } 315 }
297 tested_by!(name_res_works_for_broken_modules); 316 tested_by!(name_res_works_for_broken_modules);
298 } 317 }
299 318
300 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { 319 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
320 // FIXME: cfg_attr
301 let is_prelude = use_item.has_atom_attr("prelude_import"); 321 let is_prelude = use_item.has_atom_attr("prelude_import");
302 322 let attrs = self.parse_attrs(&use_item);
303 Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { 323
304 let import_data = ImportData { 324 Path::expand_use_item(
305 path, 325 Source { ast: use_item, file_id: self.file_id },
306 alias, 326 self.db,
307 is_glob, 327 |path, use_tree, is_glob, alias| {
308 is_prelude, 328 let import_data = ImportData {
309 is_extern_crate: false, 329 path,
310 is_macro_use: false, 330 alias,
311 }; 331 is_glob,
312 self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); 332 is_prelude,
313 }) 333 is_extern_crate: false,
334 is_macro_use: false,
335 };
336 self.push_import(
337 current_module,
338 attrs.clone(),
339 import_data,
340 Either::A(AstPtr::new(use_tree)),
341 );
342 },
343 )
314 } 344 }
315 345
316 fn add_extern_crate_item( 346 fn add_extern_crate_item(
@@ -321,6 +351,8 @@ impl RawItemsCollector {
321 if let Some(name_ref) = extern_crate.name_ref() { 351 if let Some(name_ref) = extern_crate.name_ref() {
322 let path = Path::from_name_ref(&name_ref); 352 let path = Path::from_name_ref(&name_ref);
323 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 353 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
354 let attrs = self.parse_attrs(&extern_crate);
355 // FIXME: cfg_attr
324 let is_macro_use = extern_crate.has_atom_attr("macro_use"); 356 let is_macro_use = extern_crate.has_atom_attr("macro_use");
325 let import_data = ImportData { 357 let import_data = ImportData {
326 path, 358 path,
@@ -330,37 +362,47 @@ impl RawItemsCollector {
330 is_extern_crate: true, 362 is_extern_crate: true,
331 is_macro_use, 363 is_macro_use,
332 }; 364 };
333 self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); 365 self.push_import(
366 current_module,
367 attrs,
368 import_data,
369 Either::B(AstPtr::new(&extern_crate)),
370 );
334 } 371 }
335 } 372 }
336 373
337 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 374 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
338 let path = match m.path().and_then(Path::from_ast) { 375 let attrs = self.parse_attrs(&m);
376 let path = match m
377 .path()
378 .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db))
379 {
339 Some(it) => it, 380 Some(it) => it,
340 _ => return, 381 _ => return,
341 }; 382 };
342 383
343 let name = m.name().map(|it| it.as_name()); 384 let name = m.name().map(|it| it.as_name());
344 let ast_id = self.source_ast_id_map.ast_id(&m); 385 let ast_id = self.source_ast_id_map.ast_id(&m);
345 let export = m.has_atom_attr("macro_export") 386 // FIXME: cfg_attr
346 || m.attrs().filter_map(|x| x.as_call()).any(|(name, _)| name == "macro_export"); 387 let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
347 388
348 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); 389 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
349 self.push_item(current_module, RawItem::Macro(m)); 390 self.push_item(current_module, attrs, RawItemKind::Macro(m));
350 } 391 }
351 392
352 fn push_import( 393 fn push_import(
353 &mut self, 394 &mut self,
354 current_module: Option<Module>, 395 current_module: Option<Module>,
396 attrs: Attrs,
355 data: ImportData, 397 data: ImportData,
356 source: ImportSourcePtr, 398 source: ImportSourcePtr,
357 ) { 399 ) {
358 let import = self.raw_items.imports.alloc(data); 400 let import = self.raw_items.imports.alloc(data);
359 self.source_map.insert(import, source); 401 self.source_map.insert(import, source);
360 self.push_item(current_module, RawItem::Import(import)) 402 self.push_item(current_module, attrs, RawItemKind::Import(import))
361 } 403 }
362 404
363 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { 405 fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) {
364 match current_module { 406 match current_module {
365 Some(module) => match &mut self.raw_items.modules[module] { 407 Some(module) => match &mut self.raw_items.modules[module] {
366 ModuleData::Definition { items, .. } => items, 408 ModuleData::Definition { items, .. } => items,
@@ -368,13 +410,17 @@ impl RawItemsCollector {
368 }, 410 },
369 None => &mut self.raw_items.items, 411 None => &mut self.raw_items.items,
370 } 412 }
371 .push(item) 413 .push(RawItem { attrs, kind })
414 }
415
416 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
417 Attr::from_attrs_owner(self.file_id, item, self.db)
372 } 418 }
373} 419}
374 420
375fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> { 421fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> {
376 module.attrs().into_iter().find_map(|attr| { 422 module.attrs().into_iter().find_map(|attr| {
377 attr.as_key_value().and_then(|(name, value)| { 423 attr.as_simple_key_value().and_then(|(name, value)| {
378 let is_path = name == "path"; 424 let is_path = name == "path";
379 if is_path { 425 if is_path {
380 Some(value) 426 Some(value)
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index bc4b47b70..34dd79574 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -7,6 +7,7 @@ mod mod_resolution;
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use insta::assert_snapshot; 9use insta::assert_snapshot;
10use ra_cfg::CfgOptions;
10use ra_db::SourceDatabase; 11use ra_db::SourceDatabase;
11use test_utils::covers; 12use test_utils::covers;
12 13
@@ -507,3 +508,72 @@ fn values_dont_shadow_extern_crates() {
507 â‹®foo: v 508 â‹®foo: v
508 "###); 509 "###);
509} 510}
511
512#[test]
513fn cfg_not_test() {
514 let map = def_map_with_crate_graph(
515 r#"
516 //- /main.rs
517 use {Foo, Bar, Baz};
518 //- /lib.rs
519 #[prelude_import]
520 pub use self::prelude::*;
521 mod prelude {
522 #[cfg(test)]
523 pub struct Foo;
524 #[cfg(not(test))]
525 pub struct Bar;
526 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
527 pub struct Baz;
528 }
529 "#,
530 crate_graph! {
531 "main": ("/main.rs", ["std"]),
532 "std": ("/lib.rs", []),
533 },
534 );
535
536 assert_snapshot!(map, @r###"
537 â‹®crate
538 â‹®Bar: t v
539 â‹®Baz: _
540 â‹®Foo: _
541 "###);
542}
543
544#[test]
545fn cfg_test() {
546 let map = def_map_with_crate_graph(
547 r#"
548 //- /main.rs
549 use {Foo, Bar, Baz};
550 //- /lib.rs
551 #[prelude_import]
552 pub use self::prelude::*;
553 mod prelude {
554 #[cfg(test)]
555 pub struct Foo;
556 #[cfg(not(test))]
557 pub struct Bar;
558 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
559 pub struct Baz;
560 }
561 "#,
562 crate_graph! {
563 "main": ("/main.rs", ["std"]),
564 "std": ("/lib.rs", [], CfgOptions::default()
565 .atom("test".into())
566 .key_value("feature".into(), "foo".into())
567 .key_value("feature".into(), "bar".into())
568 .key_value("opt".into(), "42".into())
569 ),
570 },
571 );
572
573 assert_snapshot!(map, @r###"
574 â‹®crate
575 â‹®Bar: _
576 â‹®Baz: t v
577 â‹®Foo: t v
578 "###);
579}
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index bd60f4258..e4b408394 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -515,3 +515,108 @@ fn path_qualified_macros() {
515 â‹®not_found: _ 515 â‹®not_found: _
516 "###); 516 "###);
517} 517}
518
519#[test]
520fn macro_dollar_crate_is_correct_in_item() {
521 covers!(macro_dollar_crate_self);
522 covers!(macro_dollar_crate_other);
523 let map = def_map_with_crate_graph(
524 "
525 //- /main.rs
526 #[macro_use]
527 extern crate foo;
528
529 #[macro_use]
530 mod m {
531 macro_rules! current {
532 () => {
533 use $crate::Foo as FooSelf;
534 }
535 }
536 }
537
538 struct Foo;
539
540 current!();
541 not_current1!();
542 foo::not_current2!();
543
544 //- /lib.rs
545 mod m {
546 #[macro_export]
547 macro_rules! not_current1 {
548 () => {
549 use $crate::Bar;
550 }
551 }
552 }
553
554 #[macro_export]
555 macro_rules! not_current2 {
556 () => {
557 use $crate::Baz;
558 }
559 }
560
561 struct Bar;
562 struct Baz;
563 ",
564 crate_graph! {
565 "main": ("/main.rs", ["foo"]),
566 "foo": ("/lib.rs", []),
567 },
568 );
569 assert_snapshot!(map, @r###"
570 â‹®crate
571 â‹®Bar: t v
572 â‹®Baz: t v
573 â‹®Foo: t v
574 â‹®FooSelf: t v
575 â‹®foo: t
576 â‹®m: t
577 â‹®
578 â‹®crate::m
579 "###);
580}
581
582#[test]
583fn macro_dollar_crate_is_correct_in_indirect_deps() {
584 covers!(macro_dollar_crate_other);
585 // From std
586 let map = def_map_with_crate_graph(
587 r#"
588 //- /main.rs
589 foo!();
590
591 //- /std.rs
592 #[prelude_import]
593 use self::prelude::*;
594
595 pub use core::foo;
596
597 mod prelude {}
598
599 #[macro_use]
600 mod std_macros;
601
602 //- /core.rs
603 #[macro_export]
604 macro_rules! foo {
605 () => {
606 use $crate::bar;
607 }
608 }
609
610 pub struct bar;
611 "#,
612 crate_graph! {
613 "main": ("/main.rs", ["std"]),
614 "std": ("/std.rs", ["core"]),
615 "core": ("/core.rs", []),
616 },
617 );
618 assert_snapshot!(map, @r###"
619 â‹®crate
620 â‹®bar: t v
621 "###);
622}
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 39d1b7e46..394617e1a 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::{iter, sync::Arc}; 3use std::{iter, sync::Arc};
2 4
3use ra_syntax::{ 5use ra_syntax::{
@@ -5,7 +7,7 @@ use ra_syntax::{
5 AstNode, 7 AstNode,
6}; 8};
7 9
8use crate::{name, type_ref::TypeRef, AsName, Name}; 10use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source};
9 11
10#[derive(Debug, Clone, PartialEq, Eq, Hash)] 12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Path { 13pub struct Path {
@@ -52,16 +54,19 @@ pub enum PathKind {
52 Abs, 54 Abs,
53 // Type based path like `<T>::foo` 55 // Type based path like `<T>::foo`
54 Type(Box<TypeRef>), 56 Type(Box<TypeRef>),
57 // `$crate` from macro expansion
58 DollarCrate(Crate),
55} 59}
56 60
57impl Path { 61impl Path {
58 /// Calls `cb` with all paths, represented by this use item. 62 /// Calls `cb` with all paths, represented by this use item.
59 pub fn expand_use_item( 63 pub fn expand_use_item(
60 item: &ast::UseItem, 64 item_src: Source<ast::UseItem>,
65 db: &impl AstDatabase,
61 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), 66 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
62 ) { 67 ) {
63 if let Some(tree) = item.use_tree() { 68 if let Some(tree) = item_src.ast.use_tree() {
64 expand_use_tree(None, tree, &mut cb); 69 expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb);
65 } 70 }
66 } 71 }
67 72
@@ -76,7 +81,19 @@ impl Path {
76 } 81 }
77 82
78 /// Converts an `ast::Path` to `Path`. Works with use trees. 83 /// Converts an `ast::Path` to `Path`. Works with use trees.
79 pub fn from_ast(mut path: ast::Path) -> Option<Path> { 84 /// DEPRECATED: It does not handle `$crate` from macro call.
85 pub fn from_ast(path: ast::Path) -> Option<Path> {
86 Path::parse(path, &|| None)
87 }
88
89 /// Converts an `ast::Path` to `Path`. Works with use trees.
90 /// It correctly handles `$crate` based path from macro call.
91 pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> {
92 let file_id = source.file_id;
93 Path::parse(source.ast, &|| file_id.macro_crate(db))
94 }
95
96 fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> {
80 let mut kind = PathKind::Plain; 97 let mut kind = PathKind::Plain;
81 let mut segments = Vec::new(); 98 let mut segments = Vec::new();
82 loop { 99 loop {
@@ -88,6 +105,13 @@ impl Path {
88 105
89 match segment.kind()? { 106 match segment.kind()? {
90 ast::PathSegmentKind::Name(name) => { 107 ast::PathSegmentKind::Name(name) => {
108 if name.text() == "$crate" {
109 if let Some(macro_crate) = macro_crate() {
110 kind = PathKind::DollarCrate(macro_crate);
111 break;
112 }
113 }
114
91 let args = segment 115 let args = segment
92 .type_arg_list() 116 .type_arg_list()
93 .and_then(GenericArgs::from_ast) 117 .and_then(GenericArgs::from_ast)
@@ -113,7 +137,7 @@ impl Path {
113 } 137 }
114 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 138 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
115 Some(trait_ref) => { 139 Some(trait_ref) => {
116 let path = Path::from_ast(trait_ref.path()?)?; 140 let path = Path::parse(trait_ref.path()?, macro_crate)?;
117 kind = path.kind; 141 kind = path.kind;
118 let mut prefix_segments = path.segments; 142 let mut prefix_segments = path.segments;
119 prefix_segments.reverse(); 143 prefix_segments.reverse();
@@ -264,6 +288,7 @@ impl From<Name> for Path {
264fn expand_use_tree( 288fn expand_use_tree(
265 prefix: Option<Path>, 289 prefix: Option<Path>,
266 tree: ast::UseTree, 290 tree: ast::UseTree,
291 macro_crate: &impl Fn() -> Option<Crate>,
267 cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>), 292 cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
268) { 293) {
269 if let Some(use_tree_list) = tree.use_tree_list() { 294 if let Some(use_tree_list) = tree.use_tree_list() {
@@ -272,13 +297,13 @@ fn expand_use_tree(
272 None => prefix, 297 None => prefix,
273 // E.g. `use something::{inner}` (prefix is `None`, path is `something`) 298 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
274 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) 299 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
275 Some(path) => match convert_path(prefix, path) { 300 Some(path) => match convert_path(prefix, path, macro_crate) {
276 Some(it) => Some(it), 301 Some(it) => Some(it),
277 None => return, // FIXME: report errors somewhere 302 None => return, // FIXME: report errors somewhere
278 }, 303 },
279 }; 304 };
280 for child_tree in use_tree_list.use_trees() { 305 for child_tree in use_tree_list.use_trees() {
281 expand_use_tree(prefix.clone(), child_tree, cb); 306 expand_use_tree(prefix.clone(), child_tree, macro_crate, cb);
282 } 307 }
283 } else { 308 } else {
284 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); 309 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
@@ -295,7 +320,7 @@ fn expand_use_tree(
295 } 320 }
296 } 321 }
297 } 322 }
298 if let Some(path) = convert_path(prefix, ast_path) { 323 if let Some(path) = convert_path(prefix, ast_path, macro_crate) {
299 let is_glob = tree.has_star(); 324 let is_glob = tree.has_star();
300 cb(path, &tree, is_glob, alias) 325 cb(path, &tree, is_glob, alias)
301 } 326 }
@@ -305,12 +330,29 @@ fn expand_use_tree(
305 } 330 }
306} 331}
307 332
308fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { 333fn convert_path(
309 let prefix = 334 prefix: Option<Path>,
310 if let Some(qual) = path.qualifier() { Some(convert_path(prefix, qual)?) } else { prefix }; 335 path: ast::Path,
336 macro_crate: &impl Fn() -> Option<Crate>,
337) -> Option<Path> {
338 let prefix = if let Some(qual) = path.qualifier() {
339 Some(convert_path(prefix, qual, macro_crate)?)
340 } else {
341 prefix
342 };
343
311 let segment = path.segment()?; 344 let segment = path.segment()?;
312 let res = match segment.kind()? { 345 let res = match segment.kind()? {
313 ast::PathSegmentKind::Name(name) => { 346 ast::PathSegmentKind::Name(name) => {
347 if name.text() == "$crate" {
348 if let Some(krate) = macro_crate() {
349 return Some(Path::from_simple_segments(
350 PathKind::DollarCrate(krate),
351 iter::empty(),
352 ));
353 }
354 }
355
314 // no type args in use 356 // no type args in use
315 let mut res = prefix 357 let mut res = prefix
316 .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); 358 .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index bd4be8430..088335e66 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -1,10 +1,10 @@
1/// Lookup hir elements using positions in the source code. This is a lossy 1//! Lookup hir elements using positions in the source code. This is a lossy
2/// transformation: in general, a single source might correspond to several 2//! transformation: in general, a single source might correspond to several
3/// modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on 3//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
4/// modules. 4//! modules.
5/// 5//!
6/// So, this modules should not be used during hir construction, it exists 6//! So, this modules should not be used during hir construction, it exists
7/// purely for "IDE needs". 7//! purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use ra_db::FileId; 10use ra_db::FileId;
@@ -203,6 +203,7 @@ impl SourceAnalyzer {
203 db: &impl HirDatabase, 203 db: &impl HirDatabase,
204 macro_call: &ast::MacroCall, 204 macro_call: &ast::MacroCall,
205 ) -> Option<MacroDef> { 205 ) -> Option<MacroDef> {
206 // This must be a normal source file rather than macro file.
206 let path = macro_call.path().and_then(Path::from_ast)?; 207 let path = macro_call.path().and_then(Path::from_ast)?;
207 self.resolver.resolve_path_as_macro(db, &path) 208 self.resolver.resolve_path_as_macro(db, &path)
208 } 209 }
@@ -261,6 +262,7 @@ impl SourceAnalyzer {
261 return Some(PathResolution::AssocItem(assoc)); 262 return Some(PathResolution::AssocItem(assoc));
262 } 263 }
263 } 264 }
265 // This must be a normal source file rather than macro file.
264 let hir_path = crate::Path::from_ast(path.clone())?; 266 let hir_path = crate::Path::from_ast(path.clone())?;
265 self.resolve_hir_path(db, &hir_path) 267 self.resolve_hir_path(db, &hir_path)
266 } 268 }
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs
index 04574876d..a4dd99598 100644
--- a/crates/ra_hir/src/source_id.rs
+++ b/crates/ra_hir/src/source_id.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::{ 3use std::{
2 hash::{Hash, Hasher}, 4 hash::{Hash, Hasher},
3 marker::PhantomData, 5 marker::PhantomData,
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index fae9c1e22..d161735e8 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -14,11 +14,11 @@ pub(crate) mod display;
14 14
15use std::ops::Deref; 15use std::ops::Deref;
16use std::sync::Arc; 16use std::sync::Arc;
17use std::{fmt, mem}; 17use std::{fmt, iter, mem};
18 18
19use crate::{ 19use crate::{
20 db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, DefWithBody, GenericParams, Name, 20 db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, Crate, DefWithBody, GenericParams,
21 Trait, TypeAlias, 21 HasGenericParams, Name, Trait, TypeAlias,
22}; 22};
23use display::{HirDisplay, HirFormatter}; 23use display::{HirDisplay, HirFormatter};
24 24
@@ -111,6 +111,81 @@ pub enum TypeCtor {
111 Closure { def: DefWithBody, expr: ExprId }, 111 Closure { def: DefWithBody, expr: ExprId },
112} 112}
113 113
114impl TypeCtor {
115 pub fn num_ty_params(self, db: &impl HirDatabase) -> usize {
116 match self {
117 TypeCtor::Bool
118 | TypeCtor::Char
119 | TypeCtor::Int(_)
120 | TypeCtor::Float(_)
121 | TypeCtor::Str
122 | TypeCtor::Never => 0,
123 TypeCtor::Slice
124 | TypeCtor::Array
125 | TypeCtor::RawPtr(_)
126 | TypeCtor::Ref(_)
127 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure
128 => 1,
129 TypeCtor::Adt(adt) => {
130 let generic_params = adt.generic_params(db);
131 generic_params.count_params_including_parent()
132 }
133 TypeCtor::FnDef(callable) => {
134 let generic_params = callable.generic_params(db);
135 generic_params.count_params_including_parent()
136 }
137 TypeCtor::AssociatedType(type_alias) => {
138 let generic_params = type_alias.generic_params(db);
139 generic_params.count_params_including_parent()
140 }
141 TypeCtor::FnPtr { num_args } => num_args as usize + 1,
142 TypeCtor::Tuple { cardinality } => cardinality as usize,
143 }
144 }
145
146 pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
147 match self {
148 TypeCtor::Bool
149 | TypeCtor::Char
150 | TypeCtor::Int(_)
151 | TypeCtor::Float(_)
152 | TypeCtor::Str
153 | TypeCtor::Never
154 | TypeCtor::Slice
155 | TypeCtor::Array
156 | TypeCtor::RawPtr(_)
157 | TypeCtor::Ref(_)
158 | TypeCtor::FnPtr { .. }
159 | TypeCtor::Tuple { .. } => None,
160 TypeCtor::Closure { def, .. } => def.krate(db),
161 TypeCtor::Adt(adt) => adt.krate(db),
162 TypeCtor::FnDef(callable) => callable.krate(db),
163 TypeCtor::AssociatedType(type_alias) => type_alias.krate(db),
164 }
165 }
166
167 pub fn as_generic_def(self) -> Option<crate::generics::GenericDef> {
168 match self {
169 TypeCtor::Bool
170 | TypeCtor::Char
171 | TypeCtor::Int(_)
172 | TypeCtor::Float(_)
173 | TypeCtor::Str
174 | TypeCtor::Never
175 | TypeCtor::Slice
176 | TypeCtor::Array
177 | TypeCtor::RawPtr(_)
178 | TypeCtor::Ref(_)
179 | TypeCtor::FnPtr { .. }
180 | TypeCtor::Tuple { .. }
181 | TypeCtor::Closure { .. } => None,
182 TypeCtor::Adt(adt) => Some(adt.into()),
183 TypeCtor::FnDef(callable) => Some(callable.into()),
184 TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()),
185 }
186 }
187}
188
114/// A nominal type with (maybe 0) type parameters. This might be a primitive 189/// A nominal type with (maybe 0) type parameters. This might be a primitive
115/// type like `bool`, a struct, tuple, function pointer, reference or 190/// type like `bool`, a struct, tuple, function pointer, reference or
116/// several other things. 191/// several other things.
@@ -271,11 +346,65 @@ impl Substs {
271 .into(), 346 .into(),
272 ) 347 )
273 } 348 }
349
350 pub fn build_for_def(
351 db: &impl HirDatabase,
352 def: impl crate::HasGenericParams,
353 ) -> SubstsBuilder {
354 let params = def.generic_params(db);
355 let param_count = params.count_params_including_parent();
356 Substs::builder(param_count)
357 }
358
359 pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder {
360 Substs::builder(generic_params.count_params_including_parent())
361 }
362
363 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder {
364 Substs::builder(type_ctor.num_ty_params(db))
365 }
366
367 fn builder(param_count: usize) -> SubstsBuilder {
368 SubstsBuilder { vec: Vec::with_capacity(param_count), param_count }
369 }
370}
371
372#[derive(Debug, Clone)]
373pub struct SubstsBuilder {
374 vec: Vec<Ty>,
375 param_count: usize,
274} 376}
275 377
276impl From<Vec<Ty>> for Substs { 378impl SubstsBuilder {
277 fn from(v: Vec<Ty>) -> Self { 379 pub fn build(self) -> Substs {
278 Substs(v.into()) 380 assert_eq!(self.vec.len(), self.param_count);
381 Substs(self.vec.into())
382 }
383
384 pub fn push(mut self, ty: Ty) -> Self {
385 self.vec.push(ty);
386 self
387 }
388
389 fn remaining(&self) -> usize {
390 self.param_count - self.vec.len()
391 }
392
393 pub fn fill_with_bound_vars(mut self, starting_from: u32) -> Self {
394 self.vec.extend((starting_from..starting_from + self.remaining() as u32).map(Ty::Bound));
395 self
396 }
397
398 pub fn fill_with_unknown(mut self) -> Self {
399 self.vec.extend(iter::repeat(Ty::Unknown).take(self.remaining()));
400 self
401 }
402
403 pub fn use_parent_substs(mut self, parent_substs: &Substs) -> Self {
404 assert!(self.vec.is_empty());
405 assert!(parent_substs.len() <= self.param_count);
406 self.vec.extend(parent_substs.iter().cloned());
407 self
279 } 408 }
280} 409}
281 410
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 94f8ecdc9..02492ca14 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -7,7 +7,7 @@ use std::iter::successors;
7 7
8use log::{info, warn}; 8use log::{info, warn};
9 9
10use super::{traits::Solution, Canonical, Ty, TypeWalk}; 10use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
11use crate::{db::HirDatabase, name, HasGenericParams, Resolver}; 11use crate::{db::HirDatabase, name, HasGenericParams, Resolver};
12 12
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -44,7 +44,8 @@ fn deref_by_trait(
44 }; 44 };
45 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 45 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
46 46
47 if target.generic_params(db).count_params_including_parent() != 1 { 47 let generic_params = target.generic_params(db);
48 if generic_params.count_params_including_parent() != 1 {
48 // the Target type + Deref trait should only have one generic parameter, 49 // the Target type + Deref trait should only have one generic parameter,
49 // namely Deref's Self type 50 // namely Deref's Self type
50 return None; 51 return None;
@@ -54,12 +55,13 @@ fn deref_by_trait(
54 55
55 let env = super::lower::trait_env(db, resolver); 56 let env = super::lower::trait_env(db, resolver);
56 57
58 let parameters = Substs::build_for_generics(&generic_params)
59 .push(ty.value.clone().shift_bound_vars(1))
60 .build();
61
57 let projection = super::traits::ProjectionPredicate { 62 let projection = super::traits::ProjectionPredicate {
58 ty: Ty::Bound(0), 63 ty: Ty::Bound(0),
59 projection_ty: super::ProjectionTy { 64 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
60 associated_ty: target,
61 parameters: vec![ty.value.clone().shift_bound_vars(1)].into(),
62 },
63 }; 65 };
64 66
65 let obligation = super::Obligation::Projection(projection); 67 let obligation = super::Obligation::Projection(projection);
diff --git a/crates/ra_hir/src/ty/display.rs b/crates/ra_hir/src/ty/display.rs
index 63ec9d7e1..7910429d7 100644
--- a/crates/ra_hir/src/ty/display.rs
+++ b/crates/ra_hir/src/ty/display.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::fmt; 3use std::fmt;
2 4
3use crate::db::HirDatabase; 5use crate::db::HirDatabase;
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index db3377357..ca9aefc42 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -609,7 +609,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
609 609
610 for (i, &subpat) in subpats.iter().enumerate() { 610 for (i, &subpat) in subpats.iter().enumerate() {
611 let expected_ty = def 611 let expected_ty = def
612 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) 612 .and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
613 .map_or(Ty::Unknown, |field| field.ty(self.db)) 613 .map_or(Ty::Unknown, |field| field.ty(self.db))
614 .subst(&substs); 614 .subst(&substs);
615 let expected_ty = self.normalize_associated_types_in(expected_ty); 615 let expected_ty = self.normalize_associated_types_in(expected_ty);
@@ -688,14 +688,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
688 }; 688 };
689 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); 689 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
690 690
691 let inner_tys: Substs = args 691 let inner_tys = args
692 .iter() 692 .iter()
693 .zip(expectations_iter) 693 .zip(expectations_iter)
694 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) 694 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
695 .collect::<Vec<_>>() 695 .collect();
696 .into();
697 696
698 Ty::apply(TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, inner_tys) 697 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
699 } 698 }
700 Pat::Ref { pat, mutability } => { 699 Pat::Ref { pat, mutability } => {
701 let expectation = match expected.as_reference() { 700 let expectation = match expected.as_reference() {
@@ -1229,7 +1228,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1229 ty: pat_ty.clone(), 1228 ty: pat_ty.clone(),
1230 projection_ty: ProjectionTy { 1229 projection_ty: ProjectionTy {
1231 associated_ty: into_iter_item_alias, 1230 associated_ty: into_iter_item_alias,
1232 parameters: vec![iterable_ty].into(), 1231 parameters: Substs::single(iterable_ty),
1233 }, 1232 },
1234 }; 1233 };
1235 self.obligations.push(Obligation::Projection(projection)); 1234 self.obligations.push(Obligation::Projection(projection));
@@ -1262,7 +1261,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1262 sig_tys.push(ret_ty.clone()); 1261 sig_tys.push(ret_ty.clone());
1263 let sig_ty = Ty::apply( 1262 let sig_ty = Ty::apply(
1264 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 1263 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
1265 sig_tys.into(), 1264 Substs(sig_tys.into()),
1266 ); 1265 );
1267 let closure_ty = Ty::apply_one( 1266 let closure_ty = Ty::apply_one(
1268 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr }, 1267 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
@@ -1375,10 +1374,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1375 ) 1374 )
1376 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { 1375 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) {
1377 Ty::Apply(a_ty) => match a_ty.ctor { 1376 Ty::Apply(a_ty) => match a_ty.ctor {
1378 TypeCtor::Tuple { .. } => { 1377 TypeCtor::Tuple { .. } => name
1379 let i = name.to_string().parse::<usize>().ok(); 1378 .as_tuple_index()
1380 i.and_then(|i| a_ty.parameters.0.get(i).cloned()) 1379 .and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
1381 }
1382 TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| { 1380 TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
1383 self.write_field_resolution(tgt_expr, field); 1381 self.write_field_resolution(tgt_expr, field);
1384 field.ty(self.db).subst(&a_ty.parameters) 1382 field.ty(self.db).subst(&a_ty.parameters)
@@ -1400,7 +1398,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1400 ty: ty.clone(), 1398 ty: ty.clone(),
1401 projection_ty: ProjectionTy { 1399 projection_ty: ProjectionTy {
1402 associated_ty: future_future_output_alias, 1400 associated_ty: future_future_output_alias,
1403 parameters: vec![inner_ty].into(), 1401 parameters: Substs::single(inner_ty),
1404 }, 1402 },
1405 }; 1403 };
1406 self.obligations.push(Obligation::Projection(projection)); 1404 self.obligations.push(Obligation::Projection(projection));
@@ -1419,7 +1417,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1419 ty: ty.clone(), 1417 ty: ty.clone(),
1420 projection_ty: ProjectionTy { 1418 projection_ty: ProjectionTy {
1421 associated_ty: ops_try_ok_alias, 1419 associated_ty: ops_try_ok_alias,
1422 parameters: vec![inner_ty].into(), 1420 parameters: Substs::single(inner_ty),
1423 }, 1421 },
1424 }; 1422 };
1425 self.obligations.push(Obligation::Projection(projection)); 1423 self.obligations.push(Obligation::Projection(projection));
@@ -1604,6 +1602,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1604 tail: Option<ExprId>, 1602 tail: Option<ExprId>,
1605 expected: &Expectation, 1603 expected: &Expectation,
1606 ) -> Ty { 1604 ) -> Ty {
1605 let mut diverges = false;
1607 for stmt in statements { 1606 for stmt in statements {
1608 match stmt { 1607 match stmt {
1609 Statement::Let { pat, type_ref, initializer } => { 1608 Statement::Let { pat, type_ref, initializer } => {
@@ -1625,16 +1624,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1625 self.infer_pat(*pat, &ty, BindingMode::default()); 1624 self.infer_pat(*pat, &ty, BindingMode::default());
1626 } 1625 }
1627 Statement::Expr(expr) => { 1626 Statement::Expr(expr) => {
1628 self.infer_expr(*expr, &Expectation::none()); 1627 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) {
1628 diverges = true;
1629 }
1629 } 1630 }
1630 } 1631 }
1631 } 1632 }
1632 1633
1633 if let Some(expr) = tail { 1634 let ty = if let Some(expr) = tail {
1634 self.infer_expr_coerce(expr, expected) 1635 self.infer_expr_coerce(expr, expected)
1635 } else { 1636 } else {
1636 self.coerce(&Ty::unit(), &expected.ty); 1637 self.coerce(&Ty::unit(), &expected.ty);
1637 Ty::unit() 1638 Ty::unit()
1639 };
1640 if diverges {
1641 Ty::simple(TypeCtor::Never)
1642 } else {
1643 ty
1638 } 1644 }
1639 } 1645 }
1640 1646
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index feb7481b2..db979353a 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -158,13 +158,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
158 AssocItem::Const(c) => ValueNs::Const(c), 158 AssocItem::Const(c) => ValueNs::Const(c),
159 AssocItem::TypeAlias(_) => unreachable!(), 159 AssocItem::TypeAlias(_) => unreachable!(),
160 }; 160 };
161 let generics = item.generic_params(self.db); 161 let substs = Substs::build_for_def(self.db, item)
162 let mut substs = Vec::with_capacity(generics.count_params_including_parent()); 162 .use_parent_substs(&trait_ref.substs)
163 substs.extend(trait_ref.substs.iter().cloned()); 163 .fill_with_unknown()
164 substs.extend(std::iter::repeat(Ty::Unknown).take(generics.params.len())); 164 .build();
165 165
166 self.write_assoc_resolution(id, item); 166 self.write_assoc_resolution(id, item);
167 Some((def, Some(substs.into()))) 167 Some((def, Some(substs)))
168 } 168 }
169 169
170 fn resolve_ty_assoc_item( 170 fn resolve_ty_assoc_item(
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index b6ebee3b1..d161aa6b3 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -3,7 +3,8 @@
3use super::{InferenceContext, Obligation}; 3use super::{InferenceContext, Obligation};
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{ 5use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk, 6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty,
7 TypeWalk,
7}; 8};
8 9
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 10impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@@ -74,12 +75,9 @@ where
74 } 75 }
75 76
76 fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef { 77 fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef {
77 let substs = trait_ref 78 let substs =
78 .substs 79 trait_ref.substs.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
79 .iter() 80 TraitRef { trait_: trait_ref.trait_, substs: Substs(substs) }
80 .map(|ty| self.do_canonicalize_ty(ty.clone()))
81 .collect::<Vec<_>>();
82 TraitRef { trait_: trait_ref.trait_, substs: substs.into() }
83 } 81 }
84 82
85 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 83 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@@ -90,12 +88,9 @@ where
90 } 88 }
91 89
92 fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy { 90 fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy {
93 let params = projection_ty 91 let params =
94 .parameters 92 projection_ty.parameters.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
95 .iter() 93 ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: Substs(params) }
96 .map(|ty| self.do_canonicalize_ty(ty.clone()))
97 .collect::<Vec<_>>();
98 ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: params.into() }
99 } 94 }
100 95
101 fn do_canonicalize_projection_predicate( 96 fn do_canonicalize_projection_predicate(
@@ -153,8 +148,7 @@ impl<T> Canonicalized<T> {
153 solution: Canonical<Vec<Ty>>, 148 solution: Canonical<Vec<Ty>>,
154 ) { 149 ) {
155 // the solution may contain new variables, which we need to convert to new inference vars 150 // the solution may contain new variables, which we need to convert to new inference vars
156 let new_vars = 151 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect());
157 (0..solution.num_vars).map(|_| ctx.new_type_var()).collect::<Vec<_>>().into();
158 for (i, ty) in solution.value.into_iter().enumerate() { 152 for (i, ty) in solution.value.into_iter().enumerate() {
159 let var = self.free_vars[i]; 153 let var = self.free_vars[i];
160 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); 154 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars));
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index dd503d771..4b67c82e7 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -239,14 +239,10 @@ impl Ty {
239 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); 239 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db));
240 for t in traits { 240 for t in traits {
241 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { 241 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
242 let generics = t.generic_params(db); 242 let substs =
243 let mut substs = Vec::new(); 243 Substs::build_for_def(db, t).push(self_ty.clone()).fill_with_unknown().build();
244 substs.push(self_ty.clone());
245 substs.extend(
246 iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1),
247 );
248 // FIXME handle type parameters on the segment 244 // FIXME handle type parameters on the segment
249 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); 245 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
250 } 246 }
251 } 247 }
252 Ty::Unknown 248 Ty::Unknown
@@ -766,6 +762,16 @@ pub enum CallableDef {
766} 762}
767impl_froms!(CallableDef: Function, Struct, EnumVariant); 763impl_froms!(CallableDef: Function, Struct, EnumVariant);
768 764
765impl CallableDef {
766 pub fn krate(self, db: &impl HirDatabase) -> Option<crate::Crate> {
767 match self {
768 CallableDef::Function(f) => f.krate(db),
769 CallableDef::Struct(s) => s.krate(db),
770 CallableDef::EnumVariant(e) => e.parent_enum(db).krate(db),
771 }
772 }
773}
774
769impl From<CallableDef> for GenericDef { 775impl From<CallableDef> for GenericDef {
770 fn from(def: CallableDef) -> GenericDef { 776 fn from(def: CallableDef) -> GenericDef {
771 match def { 777 match def {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 4b71b376f..ad2ab560d 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -10,7 +10,6 @@ use rustc_hash::FxHashMap;
10use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; 10use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
11use crate::{ 11use crate::{
12 db::HirDatabase, 12 db::HirDatabase,
13 generics::HasGenericParams,
14 impl_block::{ImplBlock, ImplId}, 13 impl_block::{ImplBlock, ImplId},
15 nameres::CrateModuleId, 14 nameres::CrateModuleId,
16 resolve::Resolver, 15 resolve::Resolver,
@@ -331,20 +330,13 @@ fn generic_implements_goal(
331 trait_: Trait, 330 trait_: Trait,
332 self_ty: Canonical<Ty>, 331 self_ty: Canonical<Ty>,
333) -> Canonical<InEnvironment<super::Obligation>> { 332) -> Canonical<InEnvironment<super::Obligation>> {
334 let mut substs = Vec::new();
335 let generics = trait_.generic_params(db);
336 let num_vars = self_ty.num_vars; 333 let num_vars = self_ty.num_vars;
337 substs.push(self_ty.value); 334 let substs = super::Substs::build_for_def(db, trait_)
338 substs.extend( 335 .push(self_ty.value)
339 generics 336 .fill_with_bound_vars(num_vars as u32)
340 .params_including_parent() 337 .build();
341 .into_iter()
342 .skip(1)
343 .enumerate()
344 .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
345 );
346 let num_vars = substs.len() - 1 + self_ty.num_vars; 338 let num_vars = substs.len() - 1 + self_ty.num_vars;
347 let trait_ref = TraitRef { trait_, substs: substs.into() }; 339 let trait_ref = TraitRef { trait_, substs };
348 let obligation = super::Obligation::Trait(trait_ref); 340 let obligation = super::Obligation::Trait(trait_ref);
349 Canonical { num_vars, value: InEnvironment::new(env, obligation) } 341 Canonical { num_vars, value: InEnvironment::new(env, obligation) }
350} 342}
diff --git a/crates/ra_hir/src/ty/op.rs b/crates/ra_hir/src/ty/op.rs
index 1b30a5b9b..bcfa3a6a2 100644
--- a/crates/ra_hir/src/ty/op.rs
+++ b/crates/ra_hir/src/ty/op.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use super::{InferTy, Ty, TypeCtor}; 3use super::{InferTy, Ty, TypeCtor};
2use crate::{ 4use crate::{
3 expr::{BinaryOp, CmpOp}, 5 expr::{BinaryOp, CmpOp},
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 2c60fefd6..8966f9d1d 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::fmt; 3use std::fmt;
2 4
3#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 4362bb27a..25dad81eb 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3,6 +3,7 @@ use std::sync::Arc;
3 3
4use insta::assert_snapshot; 4use insta::assert_snapshot;
5 5
6use ra_cfg::CfgOptions;
6use ra_db::{salsa::Database, FilePosition, SourceDatabase}; 7use ra_db::{salsa::Database, FilePosition, SourceDatabase};
7use ra_syntax::{ 8use ra_syntax::{
8 algo, 9 algo,
@@ -24,6 +25,50 @@ mod never_type;
24mod coercion; 25mod coercion;
25 26
26#[test] 27#[test]
28fn cfg_impl_block() {
29 let (mut db, pos) = MockDatabase::with_position(
30 r#"
31//- /main.rs
32use foo::S as T;
33struct S;
34
35#[cfg(test)]
36impl S {
37 fn foo1(&self) -> i32 { 0 }
38}
39
40#[cfg(not(test))]
41impl S {
42 fn foo2(&self) -> i32 { 0 }
43}
44
45fn test() {
46 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
47 t<|>;
48}
49
50//- /foo.rs
51struct S;
52
53#[cfg(not(test))]
54impl S {
55 fn foo3(&self) -> i32 { 0 }
56}
57
58#[cfg(test)]
59impl S {
60 fn foo4(&self) -> i32 { 0 }
61}
62"#,
63 );
64 db.set_crate_graph_from_fixture(crate_graph! {
65 "main": ("/main.rs", ["foo"], CfgOptions::default().atom("test".into())),
66 "foo": ("/foo.rs", []),
67 });
68 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
69}
70
71#[test]
27fn infer_await() { 72fn infer_await() {
28 let (mut db, pos) = MockDatabase::with_position( 73 let (mut db, pos) = MockDatabase::with_position(
29 r#" 74 r#"
@@ -218,7 +263,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
218 [17; 18) 'b': isize 263 [17; 18) 'b': isize
219 [27; 28) 'c': ! 264 [27; 28) 'c': !
220 [33; 34) 'd': &str 265 [33; 34) 'd': &str
221 [42; 121) '{ ...f32; }': () 266 [42; 121) '{ ...f32; }': !
222 [48; 49) 'a': u32 267 [48; 49) 'a': u32
223 [55; 56) 'b': isize 268 [55; 56) 'b': isize
224 [62; 63) 'c': ! 269 [62; 63) 'c': !
@@ -981,6 +1026,67 @@ fn main(foo: Foo) {
981} 1026}
982 1027
983#[test] 1028#[test]
1029fn infer_if_match_with_return() {
1030 assert_snapshot!(
1031 infer(r#"
1032fn foo() {
1033 let _x1 = if true {
1034 1
1035 } else {
1036 return;
1037 };
1038 let _x2 = if true {
1039 2
1040 } else {
1041 return
1042 };
1043 let _x3 = match true {
1044 true => 3,
1045 _ => {
1046 return;
1047 }
1048 };
1049 let _x4 = match true {
1050 true => 4,
1051 _ => return
1052 };
1053}"#),
1054 @r###"
1055 [10; 323) '{ ... }; }': ()
1056 [20; 23) '_x1': i32
1057 [26; 80) 'if tru... }': i32
1058 [29; 33) 'true': bool
1059 [34; 51) '{ ... }': i32
1060 [44; 45) '1': i32
1061 [57; 80) '{ ... }': !
1062 [67; 73) 'return': !
1063 [90; 93) '_x2': i32
1064 [96; 149) 'if tru... }': i32
1065 [99; 103) 'true': bool
1066 [104; 121) '{ ... }': i32
1067 [114; 115) '2': i32
1068 [127; 149) '{ ... }': !
1069 [137; 143) 'return': !
1070 [159; 162) '_x3': i32
1071 [165; 247) 'match ... }': i32
1072 [171; 175) 'true': bool
1073 [186; 190) 'true': bool
1074 [194; 195) '3': i32
1075 [205; 206) '_': bool
1076 [210; 241) '{ ... }': !
1077 [224; 230) 'return': !
1078 [257; 260) '_x4': i32
1079 [263; 320) 'match ... }': i32
1080 [269; 273) 'true': bool
1081 [284; 288) 'true': bool
1082 [292; 293) '4': i32
1083 [303; 304) '_': bool
1084 [308; 314) 'return': !
1085 "###
1086 )
1087}
1088
1089#[test]
984fn infer_inherent_method() { 1090fn infer_inherent_method() {
985 assert_snapshot!( 1091 assert_snapshot!(
986 infer(r#" 1092 infer(r#"
@@ -3130,6 +3236,39 @@ fn test() { S.foo()<|>; }
3130 assert_eq!(t, "u128"); 3236 assert_eq!(t, "u128");
3131} 3237}
3132 3238
3239#[test]
3240fn infer_macro_with_dollar_crate_is_correct_in_expr() {
3241 covers!(macro_dollar_crate_other);
3242 let (mut db, pos) = MockDatabase::with_position(
3243 r#"
3244//- /main.rs
3245fn test() {
3246 let x = (foo::foo!(1), foo::foo!(2));
3247 x<|>;
3248}
3249
3250//- /lib.rs
3251#[macro_export]
3252macro_rules! foo {
3253 (1) => { $crate::bar!() };
3254 (2) => { 1 + $crate::baz() };
3255}
3256
3257#[macro_export]
3258macro_rules! bar {
3259 () => { 42 }
3260}
3261
3262pub fn baz() -> usize { 31usize }
3263"#,
3264 );
3265 db.set_crate_graph_from_fixture(crate_graph! {
3266 "main": ("/main.rs", ["foo"]),
3267 "foo": ("/lib.rs", []),
3268 });
3269 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
3270}
3271
3133#[ignore] 3272#[ignore]
3134#[test] 3273#[test]
3135fn method_resolution_trait_before_autoref() { 3274fn method_resolution_trait_before_autoref() {
@@ -3321,7 +3460,6 @@ fn test() { S2.into()<|>; }
3321 3460
3322#[test] 3461#[test]
3323fn method_resolution_encountering_fn_type() { 3462fn method_resolution_encountering_fn_type() {
3324 covers!(trait_resolution_on_fn_type);
3325 type_at( 3463 type_at(
3326 r#" 3464 r#"
3327//- /main.rs 3465//- /main.rs
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index d11dab294..b0f67ae50 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -1,9 +1,8 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::Arc; 2use std::sync::{Arc, Mutex};
3 3
4use chalk_ir::cast::Cast; 4use chalk_ir::cast::Cast;
5use log::debug; 5use log::debug;
6use parking_lot::Mutex;
7use ra_db::salsa; 6use ra_db::salsa;
8use ra_prof::profile; 7use ra_prof::profile;
9use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
@@ -38,7 +37,14 @@ impl TraitSolver {
38 ) -> Option<chalk_solve::Solution> { 37 ) -> Option<chalk_solve::Solution> {
39 let context = ChalkContext { db, krate: self.krate }; 38 let context = ChalkContext { db, krate: self.krate };
40 debug!("solve goal: {:?}", goal); 39 debug!("solve goal: {:?}", goal);
41 let solution = self.inner.lock().solve(&context, goal); 40 let mut solver = match self.inner.lock() {
41 Ok(it) => it,
42 // Our cancellation works via unwinding, but, as chalk is not
43 // panic-safe, we need to make sure to propagate the cancellation.
44 // Ideally, we should also make chalk panic-safe.
45 Err(_) => ra_db::Canceled::throw(),
46 };
47 let solution = solver.solve(&context, goal);
42 debug!("solve({:?}) => {:?}", goal, solution); 48 debug!("solve({:?}) => {:?}", goal, solution);
43 solution 49 solution
44 } 50 }
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 538b4d3ec..2642a54bf 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -10,17 +10,13 @@ use chalk_ir::{
10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
11 11
12use ra_db::salsa::{InternId, InternKey}; 12use ra_db::salsa::{InternId, InternKey};
13use test_utils::tested_by;
14 13
15use super::{Canonical, ChalkContext, Impl, Obligation}; 14use super::{Canonical, ChalkContext, Impl, Obligation};
16use crate::{ 15use crate::{
17 db::HirDatabase, 16 db::HirDatabase,
18 generics::GenericDef, 17 generics::GenericDef,
19 ty::display::HirDisplay, 18 ty::display::HirDisplay,
20 ty::{ 19 ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk},
21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
22 TypeWalk,
23 },
24 AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, 20 AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias,
25}; 21};
26 22
@@ -124,14 +120,15 @@ impl ToChalk for Substs {
124 } 120 }
125 121
126 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs { 122 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
127 parameters 123 let tys = parameters
128 .into_iter() 124 .into_iter()
129 .map(|p| match p { 125 .map(|p| match p {
130 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 126 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
131 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 127 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
132 }) 128 })
133 .collect::<Vec<_>>() 129 .collect::<Vec<_>>()
134 .into() 130 .into();
131 Substs(tys)
135 } 132 }
136} 133}
137 134
@@ -539,60 +536,18 @@ pub(crate) fn struct_datum_query(
539 struct_id: chalk_ir::StructId, 536 struct_id: chalk_ir::StructId,
540) -> Arc<StructDatum> { 537) -> Arc<StructDatum> {
541 debug!("struct_datum {:?}", struct_id); 538 debug!("struct_datum {:?}", struct_id);
542 let type_ctor = from_chalk(db, struct_id); 539 let type_ctor: TypeCtor = from_chalk(db, struct_id);
543 debug!("struct {:?} = {:?}", struct_id, type_ctor); 540 debug!("struct {:?} = {:?}", struct_id, type_ctor);
544 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor 541 let num_params = type_ctor.num_ty_params(db);
545 // FIXME extract this to a method on Ty 542 let upstream = type_ctor.krate(db) != Some(krate);
546 let (num_params, where_clauses, upstream) = match type_ctor { 543 let where_clauses = type_ctor
547 TypeCtor::Bool 544 .as_generic_def()
548 | TypeCtor::Char 545 .map(|generic_def| {
549 | TypeCtor::Int(_)
550 | TypeCtor::Float(_)
551 | TypeCtor::Never
552 | TypeCtor::Str => (0, vec![], true),
553 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
554 (1, vec![], true)
555 }
556 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
557 TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
558 TypeCtor::FnDef(callable) => {
559 tested_by!(trait_resolution_on_fn_type);
560 let upstream = match callable {
561 CallableDef::Function(f) => f.module(db).krate(db),
562 CallableDef::Struct(s) => s.module(db).krate(db),
563 CallableDef::EnumVariant(v) => v.parent_enum(db).module(db).krate(db),
564 } != Some(krate);
565 let generic_def: GenericDef = callable.into();
566 let generic_params = generic_def.generic_params(db); 546 let generic_params = generic_def.generic_params(db);
567 let bound_vars = Substs::bound_vars(&generic_params); 547 let bound_vars = Substs::bound_vars(&generic_params);
568 let where_clauses = convert_where_clauses(db, generic_def, &bound_vars); 548 convert_where_clauses(db, generic_def, &bound_vars)
569 (generic_params.count_params_including_parent(), where_clauses, upstream) 549 })
570 } 550 .unwrap_or_else(Vec::new);
571 TypeCtor::Adt(adt) => {
572 let generic_params = adt.generic_params(db);
573 let bound_vars = Substs::bound_vars(&generic_params);
574 let where_clauses = convert_where_clauses(db, adt.into(), &bound_vars);
575 (
576 generic_params.count_params_including_parent(),
577 where_clauses,
578 adt.krate(db) != Some(krate),
579 )
580 }
581 TypeCtor::AssociatedType(type_alias) => {
582 let generic_params = type_alias.generic_params(db);
583 let bound_vars = Substs::bound_vars(&generic_params);
584 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
585 (
586 generic_params.count_params_including_parent(),
587 where_clauses,
588 type_alias.krate(db) != Some(krate),
589 )
590 }
591 TypeCtor::Closure { def, .. } => {
592 let upstream = def.krate(db) != Some(krate);
593 (1, vec![], upstream)
594 }
595 };
596 let flags = chalk_rust_ir::StructFlags { 551 let flags = chalk_rust_ir::StructFlags {
597 upstream, 552 upstream,
598 // FIXME set fundamental flag correctly 553 // FIXME set fundamental flag correctly
@@ -729,17 +684,20 @@ fn closure_fn_trait_impl_datum(
729 684
730 let arg_ty = Ty::apply( 685 let arg_ty = Ty::apply(
731 TypeCtor::Tuple { cardinality: num_args }, 686 TypeCtor::Tuple { cardinality: num_args },
732 (0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), 687 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
733 ); 688 );
734 let output_ty = Ty::Bound(num_args.into()); 689 let output_ty = Ty::Bound(num_args.into());
735 let sig_ty = Ty::apply( 690 let sig_ty = Ty::apply(
736 TypeCtor::FnPtr { num_args }, 691 TypeCtor::FnPtr { num_args },
737 (0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), 692 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
738 ); 693 );
739 694
740 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); 695 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
741 696
742 let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() }; 697 let trait_ref = TraitRef {
698 trait_,
699 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
700 };
743 701
744 let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?; 702 let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?;
745 703
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index bc8acc7ee..2cf06b250 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -72,6 +72,7 @@ impl TypeRef {
72 } 72 }
73 ast::TypeRef::NeverType(..) => TypeRef::Never, 73 ast::TypeRef::NeverType(..) => TypeRef::Never,
74 ast::TypeRef::PathType(inner) => { 74 ast::TypeRef::PathType(inner) => {
75 // FIXME: Use `Path::from_src`
75 inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) 76 inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error)
76 } 77 }
77 ast::TypeRef::PointerType(inner) => { 78 ast::TypeRef::PointerType(inner) => {
@@ -141,6 +142,7 @@ impl TypeBound {
141 Some(p) => p, 142 Some(p) => p,
142 None => return TypeBound::Error, 143 None => return TypeBound::Error,
143 }; 144 };
145 // FIXME: Use `Path::from_src`
144 let path = match Path::from_ast(path) { 146 let path = match Path::from_ast(path) {
145 Some(p) => p, 147 Some(p) => p,
146 None => return TypeBound::Error, 148 None => return TypeBound::Error,