diff options
Diffstat (limited to 'crates/hir')
-rw-r--r-- | crates/hir/src/diagnostics.rs | 256 | ||||
-rw-r--r-- | crates/hir/src/display.rs | 6 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 226 | ||||
-rw-r--r-- | crates/hir/src/semantics.rs | 29 | ||||
-rw-r--r-- | crates/hir/src/source_analyzer.rs | 15 |
5 files changed, 456 insertions, 76 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 414c3f35e..2cdbd172a 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -3,13 +3,251 @@ | |||
3 | //! | 3 | //! |
4 | //! This probably isn't the best way to do this -- ideally, diagnistics should | 4 | //! This probably isn't the best way to do this -- ideally, diagnistics should |
5 | //! be expressed in terms of hir types themselves. | 5 | //! be expressed in terms of hir types themselves. |
6 | pub use hir_def::diagnostics::{ | 6 | use std::any::Any; |
7 | InactiveCode, UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | 7 | |
8 | }; | 8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; |
9 | pub use hir_expand::diagnostics::{ | 9 | use hir_def::path::ModPath; |
10 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, | 10 | use hir_expand::{HirFileId, InFile}; |
11 | }; | 11 | use stdx::format_to; |
12 | pub use hir_ty::diagnostics::{ | 12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
13 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | 13 | |
14 | NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | 14 | pub use hir_ty::{ |
15 | diagnostics::{ | ||
16 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, | ||
17 | MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon, | ||
18 | ReplaceFilterMapNextWithFindMap, | ||
19 | }, | ||
20 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, | ||
15 | }; | 21 | }; |
22 | |||
23 | // Diagnostic: unresolved-module | ||
24 | // | ||
25 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. | ||
26 | #[derive(Debug)] | ||
27 | pub struct UnresolvedModule { | ||
28 | pub file: HirFileId, | ||
29 | pub decl: AstPtr<ast::Module>, | ||
30 | pub candidate: String, | ||
31 | } | ||
32 | |||
33 | impl Diagnostic for UnresolvedModule { | ||
34 | fn code(&self) -> DiagnosticCode { | ||
35 | DiagnosticCode("unresolved-module") | ||
36 | } | ||
37 | fn message(&self) -> String { | ||
38 | "unresolved module".to_string() | ||
39 | } | ||
40 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
41 | InFile::new(self.file, self.decl.clone().into()) | ||
42 | } | ||
43 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
44 | self | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // Diagnostic: unresolved-extern-crate | ||
49 | // | ||
50 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. | ||
51 | #[derive(Debug)] | ||
52 | pub struct UnresolvedExternCrate { | ||
53 | pub file: HirFileId, | ||
54 | pub item: AstPtr<ast::ExternCrate>, | ||
55 | } | ||
56 | |||
57 | impl Diagnostic for UnresolvedExternCrate { | ||
58 | fn code(&self) -> DiagnosticCode { | ||
59 | DiagnosticCode("unresolved-extern-crate") | ||
60 | } | ||
61 | fn message(&self) -> String { | ||
62 | "unresolved extern crate".to_string() | ||
63 | } | ||
64 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
65 | InFile::new(self.file, self.item.clone().into()) | ||
66 | } | ||
67 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
68 | self | ||
69 | } | ||
70 | } | ||
71 | |||
72 | #[derive(Debug)] | ||
73 | pub struct UnresolvedImport { | ||
74 | pub file: HirFileId, | ||
75 | pub node: AstPtr<ast::UseTree>, | ||
76 | } | ||
77 | |||
78 | impl Diagnostic for UnresolvedImport { | ||
79 | fn code(&self) -> DiagnosticCode { | ||
80 | DiagnosticCode("unresolved-import") | ||
81 | } | ||
82 | fn message(&self) -> String { | ||
83 | "unresolved import".to_string() | ||
84 | } | ||
85 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
86 | InFile::new(self.file, self.node.clone().into()) | ||
87 | } | ||
88 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
89 | self | ||
90 | } | ||
91 | fn is_experimental(&self) -> bool { | ||
92 | // This currently results in false positives in the following cases: | ||
93 | // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly) | ||
94 | // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly) | ||
95 | // - proc macros and/or proc macro generated code | ||
96 | true | ||
97 | } | ||
98 | } | ||
99 | |||
100 | // Diagnostic: unresolved-macro-call | ||
101 | // | ||
102 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path to a | ||
103 | // macro in a macro invocation. | ||
104 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
105 | pub struct UnresolvedMacroCall { | ||
106 | pub file: HirFileId, | ||
107 | pub node: AstPtr<ast::MacroCall>, | ||
108 | pub path: ModPath, | ||
109 | } | ||
110 | |||
111 | impl Diagnostic for UnresolvedMacroCall { | ||
112 | fn code(&self) -> DiagnosticCode { | ||
113 | DiagnosticCode("unresolved-macro-call") | ||
114 | } | ||
115 | fn message(&self) -> String { | ||
116 | format!("unresolved macro `{}!`", self.path) | ||
117 | } | ||
118 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
119 | InFile::new(self.file, self.node.clone().into()) | ||
120 | } | ||
121 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
122 | self | ||
123 | } | ||
124 | fn is_experimental(&self) -> bool { | ||
125 | true | ||
126 | } | ||
127 | } | ||
128 | |||
129 | // Diagnostic: inactive-code | ||
130 | // | ||
131 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | ||
132 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
133 | pub struct InactiveCode { | ||
134 | pub file: HirFileId, | ||
135 | pub node: SyntaxNodePtr, | ||
136 | pub cfg: CfgExpr, | ||
137 | pub opts: CfgOptions, | ||
138 | } | ||
139 | |||
140 | impl Diagnostic for InactiveCode { | ||
141 | fn code(&self) -> DiagnosticCode { | ||
142 | DiagnosticCode("inactive-code") | ||
143 | } | ||
144 | fn message(&self) -> String { | ||
145 | let inactive = DnfExpr::new(self.cfg.clone()).why_inactive(&self.opts); | ||
146 | let mut buf = "code is inactive due to #[cfg] directives".to_string(); | ||
147 | |||
148 | if let Some(inactive) = inactive { | ||
149 | format_to!(buf, ": {}", inactive); | ||
150 | } | ||
151 | |||
152 | buf | ||
153 | } | ||
154 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
155 | InFile::new(self.file, self.node.clone()) | ||
156 | } | ||
157 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
158 | self | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // Diagnostic: unresolved-proc-macro | ||
163 | // | ||
164 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | ||
165 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | ||
166 | // but can also indicate project setup problems. | ||
167 | // | ||
168 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
169 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
170 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
171 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
172 | pub struct UnresolvedProcMacro { | ||
173 | pub file: HirFileId, | ||
174 | pub node: SyntaxNodePtr, | ||
175 | /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` | ||
176 | /// to use instead. | ||
177 | pub precise_location: Option<TextRange>, | ||
178 | pub macro_name: Option<String>, | ||
179 | } | ||
180 | |||
181 | impl Diagnostic for UnresolvedProcMacro { | ||
182 | fn code(&self) -> DiagnosticCode { | ||
183 | DiagnosticCode("unresolved-proc-macro") | ||
184 | } | ||
185 | |||
186 | fn message(&self) -> String { | ||
187 | match &self.macro_name { | ||
188 | Some(name) => format!("proc macro `{}` not expanded", name), | ||
189 | None => "proc macro not expanded".to_string(), | ||
190 | } | ||
191 | } | ||
192 | |||
193 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
194 | InFile::new(self.file, self.node.clone()) | ||
195 | } | ||
196 | |||
197 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
198 | self | ||
199 | } | ||
200 | } | ||
201 | |||
202 | // Diagnostic: macro-error | ||
203 | // | ||
204 | // This diagnostic is shown for macro expansion errors. | ||
205 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
206 | pub struct MacroError { | ||
207 | pub file: HirFileId, | ||
208 | pub node: SyntaxNodePtr, | ||
209 | pub message: String, | ||
210 | } | ||
211 | |||
212 | impl Diagnostic for MacroError { | ||
213 | fn code(&self) -> DiagnosticCode { | ||
214 | DiagnosticCode("macro-error") | ||
215 | } | ||
216 | fn message(&self) -> String { | ||
217 | self.message.clone() | ||
218 | } | ||
219 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
220 | InFile::new(self.file, self.node.clone()) | ||
221 | } | ||
222 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
223 | self | ||
224 | } | ||
225 | fn is_experimental(&self) -> bool { | ||
226 | // Newly added and not very well-tested, might contain false positives. | ||
227 | true | ||
228 | } | ||
229 | } | ||
230 | |||
231 | #[derive(Debug)] | ||
232 | pub struct UnimplementedBuiltinMacro { | ||
233 | pub file: HirFileId, | ||
234 | pub node: SyntaxNodePtr, | ||
235 | } | ||
236 | |||
237 | impl Diagnostic for UnimplementedBuiltinMacro { | ||
238 | fn code(&self) -> DiagnosticCode { | ||
239 | DiagnosticCode("unimplemented-builtin-macro") | ||
240 | } | ||
241 | |||
242 | fn message(&self) -> String { | ||
243 | "unimplemented built-in macro".to_string() | ||
244 | } | ||
245 | |||
246 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
247 | InFile::new(self.file, self.node.clone()) | ||
248 | } | ||
249 | |||
250 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
251 | self | ||
252 | } | ||
253 | } | ||
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 508ac37c2..72f0d9b5f 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs | |||
@@ -92,7 +92,7 @@ impl HirDisplay for Function { | |||
92 | &data.ret_type | 92 | &data.ret_type |
93 | } else { | 93 | } else { |
94 | match &*data.ret_type { | 94 | match &*data.ret_type { |
95 | TypeRef::ImplTrait(bounds) => match &bounds[0] { | 95 | TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() { |
96 | TypeBound::Path(path) => { | 96 | TypeBound::Path(path) => { |
97 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings | 97 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings |
98 | [0] | 98 | [0] |
@@ -427,10 +427,6 @@ impl HirDisplay for Trait { | |||
427 | write!(f, "trait {}", data.name)?; | 427 | write!(f, "trait {}", data.name)?; |
428 | let def_id = GenericDefId::TraitId(self.id); | 428 | let def_id = GenericDefId::TraitId(self.id); |
429 | write_generic_params(def_id, f)?; | 429 | write_generic_params(def_id, f)?; |
430 | if !data.bounds.is_empty() { | ||
431 | write!(f, ": ")?; | ||
432 | f.write_joined(&*data.bounds, " + ")?; | ||
433 | } | ||
434 | write_where_clause(def_id, f)?; | 430 | write_where_clause(def_id, f)?; |
435 | Ok(()) | 431 | Ok(()) |
436 | } | 432 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a7c42ca1e..d3ef29db4 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -35,12 +35,18 @@ use std::{iter, sync::Arc}; | |||
35 | 35 | ||
36 | use arrayvec::ArrayVec; | 36 | use arrayvec::ArrayVec; |
37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
38 | use diagnostics::{ | ||
39 | InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, | ||
40 | UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | ||
41 | }; | ||
38 | use either::Either; | 42 | use either::Either; |
39 | use hir_def::{ | 43 | use hir_def::{ |
40 | adt::{ReprKind, VariantData}, | 44 | adt::{ReprKind, VariantData}, |
45 | body::BodyDiagnostic, | ||
41 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 46 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
42 | item_tree::ItemTreeNode, | 47 | item_tree::ItemTreeNode, |
43 | lang_item::LangItemTarget, | 48 | lang_item::LangItemTarget, |
49 | nameres, | ||
44 | per_ns::PerNs, | 50 | per_ns::PerNs, |
45 | resolver::{HasResolver, Resolver}, | 51 | resolver::{HasResolver, Resolver}, |
46 | src::HasSource as _, | 52 | src::HasSource as _, |
@@ -50,11 +56,12 @@ use hir_def::{ | |||
50 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | 56 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, |
51 | TypeParamId, UnionId, | 57 | TypeParamId, UnionId, |
52 | }; | 58 | }; |
53 | use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | 59 | use hir_expand::{name::name, MacroCallKind, MacroDefKind}; |
54 | use hir_ty::{ | 60 | use hir_ty::{ |
55 | autoderef, | 61 | autoderef, |
56 | consteval::ConstExt, | 62 | consteval::ConstExt, |
57 | could_unify, | 63 | could_unify, |
64 | diagnostics_sink::DiagnosticSink, | ||
58 | method_resolution::{self, def_crates, TyFingerprint}, | 65 | method_resolution::{self, def_crates, TyFingerprint}, |
59 | primitive::UintTy, | 66 | primitive::UintTy, |
60 | subst_prefix, | 67 | subst_prefix, |
@@ -65,11 +72,12 @@ use hir_ty::{ | |||
65 | WhereClause, | 72 | WhereClause, |
66 | }; | 73 | }; |
67 | use itertools::Itertools; | 74 | use itertools::Itertools; |
75 | use nameres::diagnostics::DefDiagnosticKind; | ||
68 | use rustc_hash::FxHashSet; | 76 | use rustc_hash::FxHashSet; |
69 | use stdx::{format_to, impl_from}; | 77 | use stdx::{format_to, impl_from}; |
70 | use syntax::{ | 78 | use syntax::{ |
71 | ast::{self, AttrsOwner, NameOwner}, | 79 | ast::{self, AttrsOwner, NameOwner}, |
72 | AstNode, SmolStr, | 80 | AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr, |
73 | }; | 81 | }; |
74 | use tt::{Ident, Leaf, Literal, TokenTree}; | 82 | use tt::{Ident, Leaf, Literal, TokenTree}; |
75 | 83 | ||
@@ -442,7 +450,131 @@ impl Module { | |||
442 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 450 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
443 | }); | 451 | }); |
444 | let def_map = self.id.def_map(db.upcast()); | 452 | let def_map = self.id.def_map(db.upcast()); |
445 | def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); | 453 | for diag in def_map.diagnostics() { |
454 | if diag.in_module != self.id.local_id { | ||
455 | // FIXME: This is accidentally quadratic. | ||
456 | continue; | ||
457 | } | ||
458 | match &diag.kind { | ||
459 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { | ||
460 | let decl = declaration.to_node(db.upcast()); | ||
461 | sink.push(UnresolvedModule { | ||
462 | file: declaration.file_id, | ||
463 | decl: AstPtr::new(&decl), | ||
464 | candidate: candidate.clone(), | ||
465 | }) | ||
466 | } | ||
467 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { | ||
468 | let item = ast.to_node(db.upcast()); | ||
469 | sink.push(UnresolvedExternCrate { | ||
470 | file: ast.file_id, | ||
471 | item: AstPtr::new(&item), | ||
472 | }); | ||
473 | } | ||
474 | |||
475 | DefDiagnosticKind::UnresolvedImport { id, index } => { | ||
476 | let file_id = id.file_id(); | ||
477 | let item_tree = id.item_tree(db.upcast()); | ||
478 | let import = &item_tree[id.value]; | ||
479 | |||
480 | let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); | ||
481 | sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) }); | ||
482 | } | ||
483 | |||
484 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { | ||
485 | let item = ast.to_node(db.upcast()); | ||
486 | sink.push(InactiveCode { | ||
487 | file: ast.file_id, | ||
488 | node: AstPtr::new(&item).into(), | ||
489 | cfg: cfg.clone(), | ||
490 | opts: opts.clone(), | ||
491 | }); | ||
492 | } | ||
493 | |||
494 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { | ||
495 | let mut precise_location = None; | ||
496 | let (file, ast, name) = match ast { | ||
497 | MacroCallKind::FnLike { ast_id, .. } => { | ||
498 | let node = ast_id.to_node(db.upcast()); | ||
499 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) | ||
500 | } | ||
501 | MacroCallKind::Derive { ast_id, derive_name, .. } => { | ||
502 | let node = ast_id.to_node(db.upcast()); | ||
503 | |||
504 | // Compute the precise location of the macro name's token in the derive | ||
505 | // list. | ||
506 | // FIXME: This does not handle paths to the macro, but neither does the | ||
507 | // rest of r-a. | ||
508 | let derive_attrs = | ||
509 | node.attrs().filter_map(|attr| match attr.as_simple_call() { | ||
510 | Some((name, args)) if name == "derive" => Some(args), | ||
511 | _ => None, | ||
512 | }); | ||
513 | 'outer: for attr in derive_attrs { | ||
514 | let tokens = | ||
515 | attr.syntax().children_with_tokens().filter_map(|elem| { | ||
516 | match elem { | ||
517 | syntax::NodeOrToken::Node(_) => None, | ||
518 | syntax::NodeOrToken::Token(tok) => Some(tok), | ||
519 | } | ||
520 | }); | ||
521 | for token in tokens { | ||
522 | if token.kind() == SyntaxKind::IDENT | ||
523 | && token.text() == derive_name.as_str() | ||
524 | { | ||
525 | precise_location = Some(token.text_range()); | ||
526 | break 'outer; | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | |||
531 | ( | ||
532 | ast_id.file_id, | ||
533 | SyntaxNodePtr::from(AstPtr::new(&node)), | ||
534 | Some(derive_name.clone()), | ||
535 | ) | ||
536 | } | ||
537 | }; | ||
538 | sink.push(UnresolvedProcMacro { | ||
539 | file, | ||
540 | node: ast, | ||
541 | precise_location, | ||
542 | macro_name: name, | ||
543 | }); | ||
544 | } | ||
545 | |||
546 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { | ||
547 | let node = ast.to_node(db.upcast()); | ||
548 | sink.push(UnresolvedMacroCall { | ||
549 | file: ast.file_id, | ||
550 | node: AstPtr::new(&node), | ||
551 | path: path.clone(), | ||
552 | }); | ||
553 | } | ||
554 | |||
555 | DefDiagnosticKind::MacroError { ast, message } => { | ||
556 | let (file, ast) = match ast { | ||
557 | MacroCallKind::FnLike { ast_id, .. } => { | ||
558 | let node = ast_id.to_node(db.upcast()); | ||
559 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | ||
560 | } | ||
561 | MacroCallKind::Derive { ast_id, .. } => { | ||
562 | let node = ast_id.to_node(db.upcast()); | ||
563 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | ||
564 | } | ||
565 | }; | ||
566 | sink.push(MacroError { file, node: ast, message: message.clone() }); | ||
567 | } | ||
568 | |||
569 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { | ||
570 | let node = ast.to_node(db.upcast()); | ||
571 | // Must have a name, otherwise we wouldn't emit it. | ||
572 | let name = node.name().expect("unimplemented builtin macro with no name"); | ||
573 | let ptr = SyntaxNodePtr::from(AstPtr::new(&name)); | ||
574 | sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr }); | ||
575 | } | ||
576 | } | ||
577 | } | ||
446 | for decl in self.declarations(db) { | 578 | for decl in self.declarations(db) { |
447 | match decl { | 579 | match decl { |
448 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 580 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), |
@@ -513,9 +645,8 @@ impl Field { | |||
513 | } | 645 | } |
514 | 646 | ||
515 | /// Returns the type as in the signature of the struct (i.e., with | 647 | /// Returns the type as in the signature of the struct (i.e., with |
516 | /// placeholder types for type parameters). This is good for showing | 648 | /// placeholder types for type parameters). Only use this in the context of |
517 | /// signature help, but not so good to actually get the type of the field | 649 | /// the field definition. |
518 | /// when you actually have a variable of the struct. | ||
519 | pub fn ty(&self, db: &dyn HirDatabase) -> Type { | 650 | pub fn ty(&self, db: &dyn HirDatabase) -> Type { |
520 | let var_id = self.parent.into(); | 651 | let var_id = self.parent.into(); |
521 | let generic_def_id: GenericDefId = match self.parent { | 652 | let generic_def_id: GenericDefId = match self.parent { |
@@ -552,10 +683,6 @@ impl Struct { | |||
552 | Module { id: self.id.lookup(db.upcast()).container } | 683 | Module { id: self.id.lookup(db.upcast()).container } |
553 | } | 684 | } |
554 | 685 | ||
555 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
556 | Some(self.module(db).krate()) | ||
557 | } | ||
558 | |||
559 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 686 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
560 | db.struct_data(self.id).name.clone() | 687 | db.struct_data(self.id).name.clone() |
561 | } | 688 | } |
@@ -640,10 +767,6 @@ impl Enum { | |||
640 | Module { id: self.id.lookup(db.upcast()).container } | 767 | Module { id: self.id.lookup(db.upcast()).container } |
641 | } | 768 | } |
642 | 769 | ||
643 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
644 | Some(self.module(db).krate()) | ||
645 | } | ||
646 | |||
647 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 770 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
648 | db.enum_data(self.id).name.clone() | 771 | db.enum_data(self.id).name.clone() |
649 | } | 772 | } |
@@ -673,6 +796,7 @@ impl Variant { | |||
673 | pub fn module(self, db: &dyn HirDatabase) -> Module { | 796 | pub fn module(self, db: &dyn HirDatabase) -> Module { |
674 | self.parent.module(db) | 797 | self.parent.module(db) |
675 | } | 798 | } |
799 | |||
676 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { | 800 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { |
677 | self.parent | 801 | self.parent |
678 | } | 802 | } |
@@ -729,10 +853,6 @@ impl Adt { | |||
729 | } | 853 | } |
730 | } | 854 | } |
731 | 855 | ||
732 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
733 | self.module(db).krate() | ||
734 | } | ||
735 | |||
736 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 856 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
737 | match self { | 857 | match self { |
738 | Adt::Struct(s) => s.name(db), | 858 | Adt::Struct(s) => s.name(db), |
@@ -821,10 +941,6 @@ impl Function { | |||
821 | self.id.lookup(db.upcast()).module(db.upcast()).into() | 941 | self.id.lookup(db.upcast()).module(db.upcast()).into() |
822 | } | 942 | } |
823 | 943 | ||
824 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
825 | Some(self.module(db).krate()) | ||
826 | } | ||
827 | |||
828 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 944 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
829 | db.function_data(self.id).name.clone() | 945 | db.function_data(self.id).name.clone() |
830 | } | 946 | } |
@@ -881,7 +997,37 @@ impl Function { | |||
881 | 997 | ||
882 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 998 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { |
883 | let krate = self.module(db).id.krate(); | 999 | let krate = self.module(db).id.krate(); |
884 | hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); | 1000 | |
1001 | let source_map = db.body_with_source_map(self.id.into()).1; | ||
1002 | for diag in source_map.diagnostics() { | ||
1003 | match diag { | ||
1004 | BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode { | ||
1005 | file: node.file_id, | ||
1006 | node: node.value.clone(), | ||
1007 | cfg: cfg.clone(), | ||
1008 | opts: opts.clone(), | ||
1009 | }), | ||
1010 | BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { | ||
1011 | file: node.file_id, | ||
1012 | node: node.value.clone().into(), | ||
1013 | message: message.to_string(), | ||
1014 | }), | ||
1015 | BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro { | ||
1016 | file: node.file_id, | ||
1017 | node: node.value.clone().into(), | ||
1018 | precise_location: None, | ||
1019 | macro_name: None, | ||
1020 | }), | ||
1021 | BodyDiagnostic::UnresolvedMacroCall { node, path } => { | ||
1022 | sink.push(UnresolvedMacroCall { | ||
1023 | file: node.file_id, | ||
1024 | node: node.value.clone(), | ||
1025 | path: path.clone(), | ||
1026 | }) | ||
1027 | } | ||
1028 | } | ||
1029 | } | ||
1030 | |||
885 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1031 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); |
886 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | 1032 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); |
887 | } | 1033 | } |
@@ -1014,10 +1160,6 @@ impl Const { | |||
1014 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1160 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1015 | } | 1161 | } |
1016 | 1162 | ||
1017 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
1018 | Some(self.module(db).krate()) | ||
1019 | } | ||
1020 | |||
1021 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 1163 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
1022 | db.const_data(self.id).name.clone() | 1164 | db.const_data(self.id).name.clone() |
1023 | } | 1165 | } |
@@ -1045,10 +1187,6 @@ impl Static { | |||
1045 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1187 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1046 | } | 1188 | } |
1047 | 1189 | ||
1048 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
1049 | Some(self.module(db).krate()) | ||
1050 | } | ||
1051 | |||
1052 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 1190 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
1053 | db.static_data(self.id).name.clone() | 1191 | db.static_data(self.id).name.clone() |
1054 | } | 1192 | } |
@@ -1112,10 +1250,6 @@ impl TypeAlias { | |||
1112 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1250 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1113 | } | 1251 | } |
1114 | 1252 | ||
1115 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1116 | self.module(db).krate() | ||
1117 | } | ||
1118 | |||
1119 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1253 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { |
1120 | db.type_alias_data(self.id).type_ref.as_deref().cloned() | 1254 | db.type_alias_data(self.id).type_ref.as_deref().cloned() |
1121 | } | 1255 | } |
@@ -1156,10 +1290,16 @@ impl BuiltinType { | |||
1156 | 1290 | ||
1157 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1291 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1158 | pub enum MacroKind { | 1292 | pub enum MacroKind { |
1293 | /// `macro_rules!` or Macros 2.0 macro. | ||
1159 | Declarative, | 1294 | Declarative, |
1160 | ProcMacro, | 1295 | /// A built-in or custom derive. |
1161 | Derive, | 1296 | Derive, |
1297 | /// A built-in function-like macro. | ||
1162 | BuiltIn, | 1298 | BuiltIn, |
1299 | /// A procedural attribute macro. | ||
1300 | Attr, | ||
1301 | /// A function-like procedural macro. | ||
1302 | ProcMacro, | ||
1163 | } | 1303 | } |
1164 | 1304 | ||
1165 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1305 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -1189,11 +1329,13 @@ impl MacroDef { | |||
1189 | pub fn kind(&self) -> MacroKind { | 1329 | pub fn kind(&self) -> MacroKind { |
1190 | match self.id.kind { | 1330 | match self.id.kind { |
1191 | MacroDefKind::Declarative(_) => MacroKind::Declarative, | 1331 | MacroDefKind::Declarative(_) => MacroKind::Declarative, |
1192 | MacroDefKind::BuiltIn(_, _) => MacroKind::BuiltIn, | 1332 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, |
1193 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, | 1333 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, |
1194 | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, | 1334 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { |
1195 | // FIXME might be a derive | 1335 | MacroKind::Derive |
1196 | MacroDefKind::ProcMacro(_, _) => MacroKind::ProcMacro, | 1336 | } |
1337 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::Attr, _) => MacroKind::Attr, | ||
1338 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, | ||
1197 | } | 1339 | } |
1198 | } | 1340 | } |
1199 | } | 1341 | } |
@@ -1667,10 +1809,6 @@ impl Impl { | |||
1667 | self.id.lookup(db.upcast()).container.into() | 1809 | self.id.lookup(db.upcast()).container.into() |
1668 | } | 1810 | } |
1669 | 1811 | ||
1670 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1671 | Crate { id: self.module(db).id.krate() } | ||
1672 | } | ||
1673 | |||
1674 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | 1812 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { |
1675 | let src = self.source(db)?; | 1813 | let src = self.source(db)?; |
1676 | let item = src.file_id.is_builtin_derive(db.upcast())?; | 1814 | let item = src.file_id.is_builtin_derive(db.upcast())?; |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1b5064b5a..c7f2c02e4 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -11,7 +11,7 @@ use hir_def::{ | |||
11 | AsMacroCall, FunctionId, TraitId, VariantId, | 11 | AsMacroCall, FunctionId, TraitId, VariantId, |
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, ExpansionInfo}; | 13 | use hir_expand::{name::AsName, ExpansionInfo}; |
14 | use hir_ty::associated_type_shorthand_candidates; | 14 | use hir_ty::{associated_type_shorthand_candidates, Interner}; |
15 | use itertools::Itertools; | 15 | use itertools::Itertools; |
16 | use rustc_hash::{FxHashMap, FxHashSet}; | 16 | use rustc_hash::{FxHashMap, FxHashSet}; |
17 | use syntax::{ | 17 | use syntax::{ |
@@ -120,10 +120,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
120 | pub fn speculative_expand( | 120 | pub fn speculative_expand( |
121 | &self, | 121 | &self, |
122 | actual_macro_call: &ast::MacroCall, | 122 | actual_macro_call: &ast::MacroCall, |
123 | hypothetical_args: &ast::TokenTree, | 123 | speculative_args: &ast::TokenTree, |
124 | token_to_map: SyntaxToken, | 124 | token_to_map: SyntaxToken, |
125 | ) -> Option<(SyntaxNode, SyntaxToken)> { | 125 | ) -> Option<(SyntaxNode, SyntaxToken)> { |
126 | self.imp.speculative_expand(actual_macro_call, hypothetical_args, token_to_map) | 126 | self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map) |
127 | } | 127 | } |
128 | 128 | ||
129 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | 129 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { |
@@ -227,7 +227,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
227 | pub fn resolve_record_field( | 227 | pub fn resolve_record_field( |
228 | &self, | 228 | &self, |
229 | field: &ast::RecordExprField, | 229 | field: &ast::RecordExprField, |
230 | ) -> Option<(Field, Option<Local>)> { | 230 | ) -> Option<(Field, Option<Local>, Type)> { |
231 | self.imp.resolve_record_field(field) | 231 | self.imp.resolve_record_field(field) |
232 | } | 232 | } |
233 | 233 | ||
@@ -335,7 +335,7 @@ impl<'db> SemanticsImpl<'db> { | |||
335 | fn speculative_expand( | 335 | fn speculative_expand( |
336 | &self, | 336 | &self, |
337 | actual_macro_call: &ast::MacroCall, | 337 | actual_macro_call: &ast::MacroCall, |
338 | hypothetical_args: &ast::TokenTree, | 338 | speculative_args: &ast::TokenTree, |
339 | token_to_map: SyntaxToken, | 339 | token_to_map: SyntaxToken, |
340 | ) -> Option<(SyntaxNode, SyntaxToken)> { | 340 | ) -> Option<(SyntaxNode, SyntaxToken)> { |
341 | let sa = self.analyze(actual_macro_call.syntax()); | 341 | let sa = self.analyze(actual_macro_call.syntax()); |
@@ -344,10 +344,10 @@ impl<'db> SemanticsImpl<'db> { | |||
344 | let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { | 344 | let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { |
345 | sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) | 345 | sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) |
346 | })?; | 346 | })?; |
347 | hir_expand::db::expand_hypothetical( | 347 | hir_expand::db::expand_speculative( |
348 | self.db.upcast(), | 348 | self.db.upcast(), |
349 | macro_call_id, | 349 | macro_call_id, |
350 | hypothetical_args, | 350 | speculative_args, |
351 | token_to_map, | 351 | token_to_map, |
352 | ) | 352 | ) |
353 | } | 353 | } |
@@ -361,7 +361,7 @@ impl<'db> SemanticsImpl<'db> { | |||
361 | let sa = self.analyze(&parent); | 361 | let sa = self.analyze(&parent); |
362 | 362 | ||
363 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { | 363 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { |
364 | self.db.check_canceled(); | 364 | self.db.unwind_if_cancelled(); |
365 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | 365 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; |
366 | let tt = macro_call.token_tree()?; | 366 | let tt = macro_call.token_tree()?; |
367 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { | 367 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { |
@@ -501,14 +501,12 @@ impl<'db> SemanticsImpl<'db> { | |||
501 | } | 501 | } |
502 | 502 | ||
503 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { | 503 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { |
504 | self.analyze(call.syntax()).resolve_method_call(self.db, call) | 504 | self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id) |
505 | } | 505 | } |
506 | 506 | ||
507 | fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { | 507 | fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { |
508 | // FIXME: this erases Substs, we should instead record the correct | 508 | let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?; |
509 | // substitution during inference and use that | 509 | let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst); |
510 | let func = self.resolve_method_call(call)?; | ||
511 | let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build(); | ||
512 | let resolver = self.analyze(call.syntax()).resolver; | 510 | let resolver = self.analyze(call.syntax()).resolver; |
513 | let ty = Type::new_with_resolver(self.db, &resolver, ty)?; | 511 | let ty = Type::new_with_resolver(self.db, &resolver, ty)?; |
514 | let mut res = ty.as_callable(self.db)?; | 512 | let mut res = ty.as_callable(self.db)?; |
@@ -520,7 +518,10 @@ impl<'db> SemanticsImpl<'db> { | |||
520 | self.analyze(field.syntax()).resolve_field(self.db, field) | 518 | self.analyze(field.syntax()).resolve_field(self.db, field) |
521 | } | 519 | } |
522 | 520 | ||
523 | fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> { | 521 | fn resolve_record_field( |
522 | &self, | ||
523 | field: &ast::RecordExprField, | ||
524 | ) -> Option<(Field, Option<Local>, Type)> { | ||
524 | self.analyze(field.syntax()).resolve_record_field(self.db, field) | 525 | self.analyze(field.syntax()).resolve_record_field(self.db, field) |
525 | } | 526 | } |
526 | 527 | ||
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 20753314d..37a050415 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -143,7 +143,7 @@ impl SourceAnalyzer { | |||
143 | &self, | 143 | &self, |
144 | db: &dyn HirDatabase, | 144 | db: &dyn HirDatabase, |
145 | call: &ast::MethodCallExpr, | 145 | call: &ast::MethodCallExpr, |
146 | ) -> Option<FunctionId> { | 146 | ) -> Option<(FunctionId, Substitution)> { |
147 | let expr_id = self.expr_id(db, &call.clone().into())?; | 147 | let expr_id = self.expr_id(db, &call.clone().into())?; |
148 | self.infer.as_ref()?.method_resolution(expr_id) | 148 | self.infer.as_ref()?.method_resolution(expr_id) |
149 | } | 149 | } |
@@ -161,7 +161,7 @@ impl SourceAnalyzer { | |||
161 | &self, | 161 | &self, |
162 | db: &dyn HirDatabase, | 162 | db: &dyn HirDatabase, |
163 | field: &ast::RecordExprField, | 163 | field: &ast::RecordExprField, |
164 | ) -> Option<(Field, Option<Local>)> { | 164 | ) -> Option<(Field, Option<Local>, Type)> { |
165 | let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; | 165 | let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; |
166 | let expr = ast::Expr::from(record_expr); | 166 | let expr = ast::Expr::from(record_expr); |
167 | let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; | 167 | let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; |
@@ -178,10 +178,13 @@ impl SourceAnalyzer { | |||
178 | _ => None, | 178 | _ => None, |
179 | } | 179 | } |
180 | }; | 180 | }; |
181 | let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?; | ||
181 | let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; | 182 | let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; |
182 | let variant_data = variant.variant_data(db.upcast()); | 183 | let variant_data = variant.variant_data(db.upcast()); |
183 | let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; | 184 | let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; |
184 | Some((field.into(), local)) | 185 | let field_ty = |
186 | db.field_types(variant).get(field.local_id)?.clone().substitute(&Interner, subst); | ||
187 | Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)?)) | ||
185 | } | 188 | } |
186 | 189 | ||
187 | pub(crate) fn resolve_record_pat_field( | 190 | pub(crate) fn resolve_record_pat_field( |
@@ -305,7 +308,11 @@ impl SourceAnalyzer { | |||
305 | } | 308 | } |
306 | } | 309 | } |
307 | 310 | ||
308 | resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) | 311 | if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { |
312 | resolve_hir_path_qualifier(db, &self.resolver, &hir_path) | ||
313 | } else { | ||
314 | resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) | ||
315 | } | ||
309 | } | 316 | } |
310 | 317 | ||
311 | pub(crate) fn record_literal_missing_fields( | 318 | pub(crate) fn record_literal_missing_fields( |