@samitouri / QOS-React-2 / commits / b133b6c0b4

[rust][sema] Visit imports as declarations

Teaches the semantic analyzer about import statements. We now treat imports as declarations, so that subsequent references to the imported value can be resolved.

Joe Savona committed Aug 15, 2023 at 09:30 UTC b133b6c0b47f2f124430cc2ab3d3bdee70c6c921
4 files changed +132 -127
compiler/forget/crates/forget_estree/src/generated_extensions.rs
+13 -2
@@ -1,7 +1,8 @@
1 // Manual extensions to generated types
2 use crate::{
3 - ArrowFunctionExpression, Function, FunctionDeclaration, FunctionExpression, JSXElementName,
4 - JSXMemberExpression, JSXMemberExpressionOrIdentifier, Pattern, SourceRange, SourceType,
3 + ArrowFunctionExpression, Function, FunctionDeclaration, FunctionExpression, ImportDeclaration,
4 + ImportDeclarationSpecifier, JSXElementName, JSXMemberExpression,
5 + JSXMemberExpressionOrIdentifier, Pattern, SourceRange, SourceType,
6 };
7
8 /// Sentinel trait to distinguish AST *node* types
@@ -25,6 +26,16 @@ impl Pattern {
26 }
27 }
28
29 +impl ImportDeclarationSpecifier {
30 + pub fn range(&self) -> Option<SourceRange> {
31 + match self {
32 + Self::ImportDefaultSpecifier(specifier) => specifier.range,
33 + Self::ImportNamespaceSpecifier(specifier) => specifier.range,
34 + Self::ImportSpecifier(specifier) => specifier.range,
35 + }
36 + }
37 +}
38 +
39 impl JSXElementName {
40 pub fn root_name(&self) -> &str {
41 match self {
compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs
+40 -2
@@ -1,8 +1,9 @@
1 use forget_diagnostics::Diagnostic;
2 use forget_estree::{
3 AssignmentOperator, AssignmentPropertyOrRestElement, AssignmentTarget, Expression,
4 - ExpressionOrSuper, ForInInit, ForInit, FunctionBody, Identifier, IntoFunction, JSXElementName,
5 - Pattern, Program, SourceRange, SourceType, Statement, VariableDeclarationKind, Visitor,
4 + ExpressionOrSuper, ForInInit, ForInit, FunctionBody, Identifier, ImportDeclarationSpecifier,
5 + IntoFunction, JSXElementName, Pattern, Program, SourceRange, SourceType, Statement,
6 + VariableDeclarationKind, Visitor,
7 };
8
9 use crate::{
@@ -280,6 +281,43 @@ impl Analyzer {
281 }
282
283 impl Visitor for Analyzer {
284 + fn visit_import_declaration_specifier(
285 + &mut self,
286 + ast: &forget_estree::ImportDeclarationSpecifier,
287 + ) {
288 + let kind = self.manager.scope(self.current).kind;
289 + if kind != ScopeKind::Module {
290 + self.manager.diagnostics.push(Diagnostic::invalid_syntax(
291 + "`import` declarations are only allowed at the top-level of a module",
292 + ast.range(),
293 + ))
294 + }
295 + match ast {
296 + ImportDeclarationSpecifier::ImportDefaultSpecifier(specifier) => {
297 + Analyzer::visit_declaration_identifier(
298 + self,
299 + &specifier.local,
300 + Some(DeclarationKind::Import),
301 + );
302 + }
303 + ImportDeclarationSpecifier::ImportSpecifier(specifier) => {
304 + // note: ignore the `imported` identifier
305 + Analyzer::visit_declaration_identifier(
306 + self,
307 + &specifier.local,
308 + Some(DeclarationKind::Import),
309 + );
310 + }
311 + ImportDeclarationSpecifier::ImportNamespaceSpecifier(specifier) => {
312 + Analyzer::visit_declaration_identifier(
313 + self,
314 + &specifier.local,
315 + Some(DeclarationKind::Import),
316 + );
317 + }
318 + }
319 + }
320 +
321 fn visit_function_declaration(&mut self, ast: &forget_estree::FunctionDeclaration) {
322 if let Some(id) = &ast.function.id {
323 let declaration = self.manager.add_declaration(
compiler/forget/crates/forget_semantic_analysis/src/scope_manager.rs
+2
@@ -248,6 +248,7 @@ impl ScopeManager {
248 fn get_scope_for_declaration(&self, scope: ScopeId, kind: DeclarationKind) -> ScopeId {
249 match kind {
250 DeclarationKind::Let
251 + | DeclarationKind::Import
252 | DeclarationKind::Const
253 | DeclarationKind::CatchClause
254 | DeclarationKind::For => scope,
@@ -401,6 +402,7 @@ pub enum DeclarationKind {
402 FunctionDeclaration,
403 For,
404 CatchClause,
405 + Import,
406 }
407
408 impl From<VariableDeclarationKind> for DeclarationKind {
compiler/forget/crates/forget_semantic_analysis/tests/snapshots/analysis_test__fixtures@globals-and-imports.js.snap
+77 -123
@@ -38,10 +38,37 @@ Scope {
38 ),
39 kind: Module,
40 declarations: {
41 - "Component": Declaration {
41 + "Foo": Declaration {
42 id: DeclarationId(
43 0,
44 ),
45 + kind: Import,
46 + scope: ScopeId(
47 + 1,
48 + ),
49 + },
50 + "Bar": Declaration {
51 + id: DeclarationId(
52 + 1,
53 + ),
54 + kind: Import,
55 + scope: ScopeId(
56 + 1,
57 + ),
58 + },
59 + "Baz": Declaration {
60 + id: DeclarationId(
61 + 2,
62 + ),
63 + kind: Import,
64 + scope: ScopeId(
65 + 1,
66 + ),
67 + },
68 + "Component": Declaration {
69 + id: DeclarationId(
70 + 3,
71 + ),
72 kind: FunctionDeclaration,
73 scope: ScopeId(
74 1,
@@ -58,7 +85,7 @@ Scope {
85 declarations: {
86 "props": Declaration {
87 id: DeclarationId(
61 - 1,
88 + 4,
89 ),
90 kind: FunctionDeclaration,
91 scope: ScopeId(
@@ -67,7 +94,7 @@ Scope {
94 },
95 "g": Declaration {
96 id: DeclarationId(
70 - 2,
97 + 5,
98 ),
99 kind: Let,
100 scope: ScopeId(
@@ -76,7 +103,7 @@ Scope {
103 },
104 "y": Declaration {
105 id: DeclarationId(
79 - 3,
106 + 6,
107 ),
108 kind: Let,
109 scope: ScopeId(
@@ -85,7 +112,7 @@ Scope {
112 },
113 "s": Declaration {
114 id: DeclarationId(
88 - 4,
115 + 7,
116 ),
117 kind: Let,
118 scope: ScopeId(
@@ -94,7 +121,7 @@ Scope {
121 },
122 "b": Declaration {
123 id: DeclarationId(
97 - 5,
124 + 8,
125 ),
126 kind: Let,
127 scope: ScopeId(
@@ -103,7 +130,7 @@ Scope {
130 },
131 "n": Declaration {
132 id: DeclarationId(
106 - 6,
133 + 9,
134 ),
135 kind: Let,
136 scope: ScopeId(
@@ -112,7 +139,7 @@ Scope {
139 },
140 "x": Declaration {
141 id: DeclarationId(
115 - 7,
142 + 10,
143 ),
144 kind: Let,
145 scope: ScopeId(
@@ -127,7 +154,7 @@ Scope {
154 ),
155 kind: Read,
156 declaration: DeclarationId(
130 - 1,
157 + 4,
158 ),
159 declaration (name): "props",
160 scope: ScopeId(
@@ -140,7 +167,7 @@ Scope {
167 ),
168 kind: Read,
169 declaration: DeclarationId(
143 - 1,
170 + 4,
171 ),
172 declaration (name): "props",
173 scope: ScopeId(
@@ -153,13 +180,52 @@ Scope {
180 ),
181 kind: Read,
182 declaration: DeclarationId(
156 - 1,
183 + 4,
184 ),
185 declaration (name): "props",
186 scope: ScopeId(
187 2,
188 ),
189 },
190 + Reference {
191 + id: ReferenceId(
192 + 3,
193 + ),
194 + kind: Read,
195 + declaration: DeclarationId(
196 + 0,
197 + ),
198 + declaration (name): "Foo",
199 + scope: ScopeId(
200 + 2,
201 + ),
202 + },
203 + Reference {
204 + id: ReferenceId(
205 + 4,
206 + ),
207 + kind: Read,
208 + declaration: DeclarationId(
209 + 1,
210 + ),
211 + declaration (name): "Bar",
212 + scope: ScopeId(
213 + 2,
214 + ),
215 + },
216 + Reference {
217 + id: ReferenceId(
218 + 5,
219 + ),
220 + kind: Read,
221 + declaration: DeclarationId(
222 + 2,
223 + ),
224 + declaration (name): "Baz",
225 + scope: ScopeId(
226 + 2,
227 + ),
228 + },
229 ],
230 children: [
231 Scope {
@@ -186,70 +252,6 @@ Scope {
252 },
253 ],
254 }
189 -Diagnostic(
190 - DiagnosticData {
191 - message: "Undefined variable",
192 - span: Some(
193 - SourceSpan {
194 - offset: SourceOffset(
195 - 7,
196 - ),
197 - length: 3,
198 - },
199 - ),
200 - related_information: [],
201 - severity: InvalidSyntax,
202 - data: [],
203 - },
204 -)
205 -Diagnostic(
206 - DiagnosticData {
207 - message: "Undefined variable",
208 - span: Some(
209 - SourceSpan {
210 - offset: SourceOffset(
211 - 35,
212 - ),
213 - length: 3,
214 - },
215 - ),
216 - related_information: [],
217 - severity: InvalidSyntax,
218 - data: [],
219 - },
220 -)
221 -Diagnostic(
222 - DiagnosticData {
223 - message: "Undefined variable",
224 - span: Some(
225 - SourceSpan {
226 - offset: SourceOffset(
227 - 60,
228 - ),
229 - length: 3,
230 - },
231 - ),
232 - related_information: [],
233 - severity: InvalidSyntax,
234 - data: [],
235 - },
236 -)
237 -Diagnostic(
238 - DiagnosticData {
239 - message: "Undefined variable",
240 - span: Some(
241 - SourceSpan {
242 - offset: SourceOffset(
243 - 60,
244 - ),
245 - length: 3,
246 - },
247 - ),
248 - related_information: [],
249 - severity: InvalidSyntax,
250 - data: [],
251 - },
252 -)
255 Diagnostic(
256 DiagnosticData {
257 message: "Undefined variable",
@@ -378,52 +380,4 @@ Diagnostic(
380 data: [],
381 },
382 )
381 -Diagnostic(
382 - DiagnosticData {
383 - message: "Undefined variable",
384 - span: Some(
385 - SourceSpan {
386 - offset: SourceOffset(
387 - 327,
388 - ),
389 - length: 3,
390 - },
391 - ),
392 - related_information: [],
393 - severity: InvalidSyntax,
394 - data: [],
395 - },
396 -)
397 -Diagnostic(
398 - DiagnosticData {
399 - message: "Undefined variable",
400 - span: Some(
401 - SourceSpan {
402 - offset: SourceOffset(
403 - 334,
404 - ),
405 - length: 3,
406 - },
407 - ),
408 - related_information: [],
409 - severity: InvalidSyntax,
410 - data: [],
411 - },
412 -)
413 -Diagnostic(
414 - DiagnosticData {
415 - message: "Undefined variable",
416 - span: Some(
417 - SourceSpan {
418 - offset: SourceOffset(
419 - 341,
420 - ),
421 - length: 3,
422 - },
423 - ),
424 - related_information: [],
425 - severity: InvalidSyntax,
426 - data: [],
427 - },
428 -)
383