Fork of daniellemaywood.uk/gleam — Wasm codegen work
36 kB
1055 lines
1use std::collections::{HashMap, HashSet};
2
3use ecow::EcoString;
4use lsp_types::Location;
5
6use gleam_core::{
7 analyse,
8 ast::{
9 self, ArgNames, AssignName, BitArraySize, ClauseGuard, CustomType, Function,
10 ModuleConstant, Pattern, RecordConstructor, SrcSpan, TypeAstConstructorName, TypedExpr,
11 TypedModule, visit::Visit,
12 },
13 build::Located,
14 type_::{
15 ModuleInterface, ModuleValueConstructor, Type, ValueConstructor, ValueConstructorVariant,
16 error::{Named, VariableOrigin},
17 },
18};
19
20use super::{
21 compiler::ModuleSourceInformation, rename::RenameTarget, src_span_to_lsp_range, url_from_path,
22};
23
24#[derive(Debug)]
25pub enum Referenced {
26 LocalVariable {
27 definition_location: SrcSpan,
28 location: SrcSpan,
29 origin: Option<VariableOrigin>,
30 name: EcoString,
31 },
32 ModuleName {
33 module_name: EcoString,
34 module_alias: EcoString,
35 location: SrcSpan,
36 },
37 ModuleValue {
38 module: EcoString,
39 name: EcoString,
40 location: SrcSpan,
41 name_kind: Named,
42 target_kind: RenameTarget,
43 },
44 ModuleType {
45 module: EcoString,
46 name: EcoString,
47 location: SrcSpan,
48 target_kind: RenameTarget,
49 },
50}
51
52pub fn reference_for_ast_node(
53 found: Located<'_>,
54 current_module: &EcoString,
55) -> Option<Referenced> {
56 match found {
57 Located::Expression {
58 expression:
59 TypedExpr::Var {
60 constructor:
61 ValueConstructor {
62 variant:
63 ValueConstructorVariant::LocalVariable {
64 location: definition_location,
65 origin,
66 },
67 ..
68 },
69 location,
70 name,
71 },
72 ..
73 } => Some(Referenced::LocalVariable {
74 definition_location: *definition_location,
75 location: *location,
76 origin: Some(origin.clone()),
77 name: name.clone(),
78 }),
79 Located::Pattern(Pattern::Variable {
80 location,
81 origin,
82 name,
83 ..
84 }) => Some(Referenced::LocalVariable {
85 definition_location: *location,
86 location: *location,
87 origin: Some(origin.clone()),
88 name: name.clone(),
89 }),
90 Located::Pattern(Pattern::BitArraySize(BitArraySize::Variable {
91 constructor,
92 location,
93 name,
94 ..
95 })) => constructor
96 .as_ref()
97 .and_then(|constructor| match &constructor.variant {
98 ValueConstructorVariant::LocalVariable {
99 location: definition_location,
100 origin,
101 } => Some(Referenced::LocalVariable {
102 definition_location: *definition_location,
103 location: *location,
104 origin: Some(origin.clone()),
105 name: name.clone(),
106 }),
107 ValueConstructorVariant::ModuleConstant { .. }
108 | ValueConstructorVariant::ModuleFn { .. }
109 | ValueConstructorVariant::Record { .. } => None,
110 }),
111 Located::Pattern(Pattern::Assign { location, name, .. }) => {
112 Some(Referenced::LocalVariable {
113 definition_location: *location,
114 location: *location,
115 origin: None,
116 name: name.clone(),
117 })
118 }
119 Located::Arg(arg) => match &arg.names {
120 ArgNames::Named { location, name }
121 | ArgNames::NamedLabelled {
122 name_location: location,
123 name,
124 ..
125 } => Some(Referenced::LocalVariable {
126 definition_location: *location,
127 location: *location,
128 origin: None,
129 name: name.clone(),
130 }),
131 ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None,
132 },
133 Located::Expression {
134 expression:
135 TypedExpr::Var {
136 constructor:
137 ValueConstructor {
138 variant:
139 ValueConstructorVariant::ModuleConstant { module, name, .. }
140 | ValueConstructorVariant::ModuleFn { module, name, .. },
141 ..
142 },
143 location,
144 ..
145 },
146 ..
147 } => Some(Referenced::ModuleValue {
148 module: module.clone(),
149 name: name.clone(),
150 location: *location,
151 name_kind: Named::Function,
152 target_kind: RenameTarget::Unqualified,
153 }),
154
155 Located::Expression {
156 expression:
157 TypedExpr::ModuleSelect {
158 module_name,
159 label,
160 constructor:
161 ModuleValueConstructor::Fn { .. } | ModuleValueConstructor::Constant { .. },
162 location,
163 field_start,
164 ..
165 },
166 ..
167 } => Some(Referenced::ModuleValue {
168 module: module_name.clone(),
169 name: label.clone(),
170 location: SrcSpan::new(*field_start, location.end),
171 name_kind: Named::Function,
172 target_kind: RenameTarget::Qualified,
173 }),
174
175 Located::ModuleFunction(Function {
176 name: Some((location, name)),
177 ..
178 })
179 | Located::ModuleConstant(ModuleConstant {
180 name,
181 name_location: location,
182 ..
183 }) => Some(Referenced::ModuleValue {
184 module: current_module.clone(),
185 name: name.clone(),
186 location: *location,
187 name_kind: Named::Function,
188 target_kind: RenameTarget::Definition,
189 }),
190 Located::Expression {
191 expression:
192 TypedExpr::Var {
193 constructor:
194 ValueConstructor {
195 variant: ValueConstructorVariant::Record { module, name, .. },
196 ..
197 },
198 location,
199 ..
200 },
201 ..
202 } => Some(Referenced::ModuleValue {
203 module: module.clone(),
204 name: name.clone(),
205 location: *location,
206 name_kind: Named::CustomTypeVariant,
207 target_kind: RenameTarget::Unqualified,
208 }),
209 Located::Expression {
210 expression:
211 TypedExpr::ModuleSelect {
212 module_name,
213 label,
214 constructor: ModuleValueConstructor::Record { .. },
215 location,
216 field_start,
217 ..
218 },
219 ..
220 } => Some(Referenced::ModuleValue {
221 module: module_name.clone(),
222 name: label.clone(),
223 location: SrcSpan::new(*field_start, location.end),
224 name_kind: Named::CustomTypeVariant,
225 target_kind: RenameTarget::Qualified,
226 }),
227 Located::VariantConstructorDefinition(RecordConstructor {
228 name,
229 name_location,
230 ..
231 }) => Some(Referenced::ModuleValue {
232 module: current_module.clone(),
233 name: name.clone(),
234 location: *name_location,
235 name_kind: Named::CustomTypeVariant,
236 target_kind: RenameTarget::Definition,
237 }),
238 Located::Pattern(Pattern::Constructor {
239 constructor: analyse::Inferred::Known(constructor),
240 module: module_select,
241 name_location: location,
242 ..
243 }) => Some(Referenced::ModuleValue {
244 module: constructor.module.clone(),
245 name: constructor.name.clone(),
246 location: *location,
247 name_kind: Named::CustomTypeVariant,
248 target_kind: if module_select.is_some() {
249 RenameTarget::Qualified
250 } else {
251 RenameTarget::Unqualified
252 },
253 }),
254 Located::StringPrefixPatternVariable { location, name, .. } => {
255 Some(Referenced::LocalVariable {
256 definition_location: location,
257 location,
258 origin: None,
259 name: name.clone(),
260 })
261 }
262 Located::Annotation { ast, type_ } => match type_.named_type_name() {
263 Some((module, name)) => {
264 let (target_kind, location) = match ast {
265 ast::TypeAst::Constructor(constructor) => {
266 let kind = if constructor.name.is_qualified() {
267 RenameTarget::Qualified
268 } else {
269 RenameTarget::Unqualified
270 };
271 let name_location = constructor.name.name_location()?;
272 (kind, name_location)
273 }
274 ast::TypeAst::Fn(_)
275 | ast::TypeAst::Var(_)
276 | ast::TypeAst::Tuple(_)
277 | ast::TypeAst::Hole(_) => (RenameTarget::Unqualified, ast.location()),
278 };
279 Some(Referenced::ModuleType {
280 module,
281 name,
282 location,
283 target_kind,
284 })
285 }
286 None => None,
287 },
288 Located::ModuleCustomType(CustomType {
289 name,
290 name_location,
291 ..
292 }) => Some(Referenced::ModuleType {
293 module: current_module.clone(),
294 name: name.clone(),
295 location: *name_location,
296 target_kind: RenameTarget::Definition,
297 }),
298 Located::ModuleName {
299 location,
300 module_name,
301 module_alias,
302 ..
303 } => Some(Referenced::ModuleName {
304 module_name,
305 module_alias,
306 location,
307 }),
308 Located::ModuleImport(import) => {
309 let module_name = match &import.as_name {
310 Some((
311 AssignName::Variable(module_alias) | AssignName::Discard(module_alias),
312 alias_location,
313 )) => Referenced::ModuleName {
314 module_name: import.module.clone(),
315 module_alias: module_alias.clone(),
316 location: SrcSpan {
317 start: alias_location.end - (module_alias.len() as u32),
318 end: alias_location.end,
319 },
320 },
321 None => Referenced::ModuleName {
322 module_name: import.module.clone(),
323 module_alias: import
324 .module
325 .split('/')
326 .next_back()
327 .map(EcoString::from)
328 .unwrap_or_else(|| import.module.clone()),
329 location: import.module_location,
330 },
331 };
332
333 Some(module_name)
334 }
335
336 Located::ClauseGuard(ClauseGuard::Var {
337 location,
338 type_: _,
339 name,
340 definition_location,
341 origin,
342 }) => Some(Referenced::LocalVariable {
343 definition_location: *definition_location,
344 location: *location,
345 origin: Some(origin.clone()),
346 name: name.clone(),
347 }),
348
349 Located::ClauseGuard(ClauseGuard::ModuleSelect {
350 location,
351 field_start,
352 label,
353 module_name,
354 ..
355 }) => Some(Referenced::ModuleValue {
356 module: module_name.clone(),
357 name: label.clone(),
358 location: SrcSpan::new(*field_start, location.end),
359 name_kind: Named::Function,
360 target_kind: RenameTarget::Qualified,
361 }),
362
363 Located::Pattern(_)
364 | Located::ClauseGuard(_)
365 | Located::PatternSpread { .. }
366 | Located::Statement(_)
367 | Located::Expression { .. }
368 | Located::FunctionBody(_)
369 | Located::UnqualifiedImport(_)
370 | Located::Label(..)
371 | Located::Constant(_)
372 | Located::ModuleFunction(_)
373 | Located::ModuleTypeAlias(_) => None,
374 }
375}
376
377pub fn find_module_references(
378 module_name: EcoString,
379 name: EcoString,
380 modules: &im::HashMap<EcoString, ModuleInterface>,
381 sources: &HashMap<EcoString, ModuleSourceInformation>,
382 layer: ast::Layer,
383) -> Vec<Location> {
384 let mut reference_locations = Vec::new();
385
386 for module in modules.values() {
387 if module.name == module_name || module.references.imported_modules.contains(&module_name) {
388 let Some(source_information) = sources.get(&module.name) else {
389 continue;
390 };
391
392 find_references_in_module(
393 &module_name,
394 &name,
395 module,
396 source_information,
397 &mut reference_locations,
398 layer,
399 );
400 }
401 }
402
403 reference_locations
404}
405
406fn find_references_in_module(
407 module_name: &EcoString,
408 name: &EcoString,
409 module: &ModuleInterface,
410 source_information: &ModuleSourceInformation,
411 reference_locations: &mut Vec<Location>,
412 layer: ast::Layer,
413) {
414 let reference_map = match layer {
415 ast::Layer::Value => &module.references.value_references,
416 ast::Layer::Type => &module.references.type_references,
417 };
418
419 let Some(references) = reference_map.get(&(module_name.clone(), name.clone())) else {
420 return;
421 };
422
423 let Some(uri) = url_from_path(source_information.path.as_str()) else {
424 return;
425 };
426
427 for reference in references {
428 reference_locations.push(Location {
429 uri: uri.clone(),
430 range: src_span_to_lsp_range(reference.location, &source_information.line_numbers),
431 });
432 }
433}
434
435#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
436pub struct VariableReference {
437 pub location: SrcSpan,
438 pub kind: VariableReferenceKind,
439}
440
441#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
442pub enum VariableReferenceKind {
443 Variable,
444 LabelShorthand,
445}
446
447/// How to treat variables defined in alternative patterns
448enum AlternativeVariable {
449 Track,
450 Ignore,
451}
452
453pub struct FindVariableReferences {
454 // Due to the structure of some AST nodes (for example, record updates),
455 // when we traverse the AST it is possible to accidentally duplicate references.
456 // To avoid this, we use a `HashSet` instead of a `Vec` here.
457 // See: https://github.com/gleam-lang/gleam/issues/4859 and the linked PR.
458 references: HashSet<VariableReference>,
459 definition_location: DefinitionLocation,
460 alternative_variable: AlternativeVariable,
461 name: EcoString,
462}
463
464/// Where the variable we're finding references for is defined.
465///
466enum DefinitionLocation {
467 /// This is the location where the variable is defined, nothing special is
468 /// going on here. For example:
469 ///
470 /// ```gleam
471 /// let wibble = 1
472 /// // ^^^^^^ Definition location for `wibble`
473 /// wibble + 1
474 /// ^^^^^^
475 /// // `wibble` used here, defined earlier
476 /// ```
477 ///
478 Regular { location: SrcSpan },
479
480 /// When dealing with alternative patterns and aliases we need special care:
481 /// each usage wil always reference the first alternative where a variable
482 /// is defined and not the following ones. For example:
483 ///
484 /// ```gleam
485 /// case wibble {
486 /// [] as var | [_] as var -> var
487 /// // ^^^ ^^^ If we look where `var` thinks it's defined
488 /// // It will say it's defined here!
489 /// }
490 /// ```
491 ///
492 /// This poses a problem if we start the renaming from the second
493 /// alternative pattern:
494 ///
495 /// ```gleam
496 /// case wibble {
497 /// [] as var | [_] as var -> var
498 /// // ^^^ Since `var` uses the first alternative as its
499 /// // definition location, this would not be considered
500 /// // a reference to that same var.
501 /// }
502 /// ```
503 ///
504 /// So we keep track of the location of this definition, but we also need
505 /// to store the location of the first definition in the alternative case
506 /// (that's `first_alternative_location`), so that when we look for
507 /// references we can check against this one that is canonically used by
508 /// expressions in the AST
509 ///
510 Alternative {
511 location: SrcSpan,
512 first_alternative_location: SrcSpan,
513 },
514}
515
516impl FindVariableReferences {
517 pub fn new(variable_definition_location: SrcSpan, variable_name: EcoString) -> Self {
518 Self {
519 references: HashSet::new(),
520 definition_location: DefinitionLocation::Regular {
521 location: variable_definition_location,
522 },
523 alternative_variable: AlternativeVariable::Ignore,
524 name: variable_name,
525 }
526 }
527
528 /// Where the definition for which we're accumulating references is
529 /// originally defined. In case of alternative patterns this will point to
530 /// the first occurrence of that name! Look at the docs for
531 /// `DefinitionLocation` to learn more on why this is needed.
532 ///
533 fn definition_origin_location(&self) -> SrcSpan {
534 match self.definition_location {
535 DefinitionLocation::Regular { location }
536 | DefinitionLocation::Alternative {
537 first_alternative_location: location,
538 ..
539 } => location,
540 }
541 }
542
543 /// This is the location of the definition for which we're accumulating
544 /// references. In most cases you'll want to use `definition_origin_location`.
545 /// The difference between the two is explained in greater detail in the docs
546 /// for `DefinitionLocation`.
547 ///
548 fn definition_location(&self) -> SrcSpan {
549 match self.definition_location {
550 DefinitionLocation::Regular { location }
551 | DefinitionLocation::Alternative { location, .. } => location,
552 }
553 }
554
555 fn update_alternative_origin(&mut self, alternative_location: SrcSpan) {
556 match self.definition_location {
557 // We've found the location of the origin of an alternative pattern.
558 DefinitionLocation::Regular { location } if alternative_location < location => {
559 self.definition_location = DefinitionLocation::Alternative {
560 location,
561 first_alternative_location: alternative_location,
562 };
563 }
564
565 // Since the new alternative location we've found is smaller, that
566 // is the actual first one for the alternative pattern!
567 DefinitionLocation::Alternative {
568 location,
569 first_alternative_location,
570 } if alternative_location < first_alternative_location => {
571 self.definition_location = DefinitionLocation::Alternative {
572 location,
573 first_alternative_location: alternative_location,
574 };
575 }
576
577 DefinitionLocation::Regular { .. } | DefinitionLocation::Alternative { .. } => (),
578 };
579 }
580
581 pub fn find_in_module(mut self, module: &TypedModule) -> HashSet<VariableReference> {
582 self.visit_typed_module(module);
583 self.references
584 }
585
586 pub fn find(mut self, expression: &TypedExpr) -> HashSet<VariableReference> {
587 self.visit_typed_expr(expression);
588 self.references
589 }
590
591 fn register_alternative_definition(&mut self, name: &EcoString, location: &SrcSpan) {
592 match self.alternative_variable {
593 // If we are inside the same alternative pattern as the target
594 // variable and the name is the same, this is an alternative definition
595 // of the same variable. We don't register the reference if this is
596 // the exact variable though, as that would result in a duplicated
597 // reference.
598 AlternativeVariable::Track
599 if *name == self.name && *location != self.definition_location() =>
600 {
601 self.update_alternative_origin(*location);
602
603 _ = self.references.insert(VariableReference {
604 location: *location,
605 kind: VariableReferenceKind::Variable,
606 });
607 }
608 AlternativeVariable::Track | AlternativeVariable::Ignore => {}
609 }
610 }
611}
612
613impl<'ast> Visit<'ast> for FindVariableReferences {
614 fn visit_typed_function(&mut self, fun: &'ast ast::TypedFunction) {
615 if fun
616 .full_location()
617 .contains(self.definition_origin_location().start)
618 {
619 ast::visit::visit_typed_function(self, fun);
620 }
621 }
622
623 fn visit_typed_expr_var(
624 &mut self,
625 location: &'ast SrcSpan,
626 constructor: &'ast ValueConstructor,
627 _name: &'ast EcoString,
628 ) {
629 match constructor.variant {
630 ValueConstructorVariant::LocalVariable {
631 location: definition_location,
632 ..
633 } if definition_location == self.definition_origin_location() => {
634 _ = self.references.insert(VariableReference {
635 location: *location,
636 kind: VariableReferenceKind::Variable,
637 });
638 }
639 ValueConstructorVariant::LocalVariable { .. }
640 | ValueConstructorVariant::ModuleConstant { .. }
641 | ValueConstructorVariant::ModuleFn { .. }
642 | ValueConstructorVariant::Record { .. } => {}
643 }
644 }
645
646 fn visit_typed_clause_guard_var(
647 &mut self,
648 location: &'ast SrcSpan,
649 _name: &'ast EcoString,
650 _type_: &'ast std::sync::Arc<Type>,
651 definition_location: &'ast SrcSpan,
652 _origin: &'ast VariableOrigin,
653 ) {
654 if *definition_location == self.definition_origin_location() {
655 _ = self.references.insert(VariableReference {
656 location: *location,
657 kind: VariableReferenceKind::Variable,
658 });
659 }
660 }
661
662 fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {
663 // If this alternative pattern contains the variable we are finding
664 // references for, we track that so we can find alternative definitions
665 // of the target variable.
666 if clause
667 .pattern_location()
668 .contains(self.definition_origin_location().start)
669 {
670 self.alternative_variable = AlternativeVariable::Track;
671 }
672
673 for pattern in clause.pattern.iter() {
674 self.visit_typed_pattern(pattern);
675 }
676 for patterns in clause.alternative_patterns.iter() {
677 for pattern in patterns {
678 self.visit_typed_pattern(pattern);
679 }
680 }
681
682 self.alternative_variable = AlternativeVariable::Ignore;
683
684 if let Some(guard) = &clause.guard {
685 self.visit_typed_clause_guard(guard);
686 }
687 self.visit_typed_expr(&clause.then);
688 }
689
690 fn visit_typed_pattern_variable(
691 &mut self,
692 location: &'ast SrcSpan,
693 name: &'ast EcoString,
694 _type_: &'ast std::sync::Arc<Type>,
695 _origin: &'ast VariableOrigin,
696 ) {
697 self.register_alternative_definition(name, location);
698 }
699
700 fn visit_typed_pattern_assign(
701 &mut self,
702 location: &'ast SrcSpan,
703 name: &'ast EcoString,
704 pattern: &'ast ast::TypedPattern,
705 ) {
706 self.register_alternative_definition(name, location);
707
708 ast::visit::visit_typed_pattern_assign(self, location, name, pattern);
709 }
710
711 fn visit_typed_bit_array_size_variable(
712 &mut self,
713 location: &'ast SrcSpan,
714 _name: &'ast EcoString,
715 constructor: &'ast Option<Box<ValueConstructor>>,
716 _type_: &'ast std::sync::Arc<Type>,
717 ) {
718 let variant = match constructor {
719 Some(constructor) => &constructor.variant,
720 None => return,
721 };
722 match variant {
723 ValueConstructorVariant::LocalVariable {
724 location: definition_location,
725 ..
726 } if *definition_location == self.definition_origin_location() => {
727 _ = self.references.insert(VariableReference {
728 location: *location,
729 kind: VariableReferenceKind::Variable,
730 });
731 }
732 ValueConstructorVariant::LocalVariable { .. }
733 | ValueConstructorVariant::ModuleConstant { .. }
734 | ValueConstructorVariant::ModuleFn { .. }
735 | ValueConstructorVariant::Record { .. } => {}
736 }
737 }
738
739 fn visit_typed_call_arg(&mut self, arg: &'ast gleam_core::type_::TypedCallArg) {
740 if let TypedExpr::Var {
741 location,
742 constructor,
743 ..
744 } = &arg.value
745 {
746 match &constructor.variant {
747 ValueConstructorVariant::LocalVariable {
748 location: definition_location,
749 ..
750 } if arg.uses_label_shorthand()
751 && *definition_location == self.definition_origin_location() =>
752 {
753 _ = self.references.insert(VariableReference {
754 location: *location,
755 kind: VariableReferenceKind::LabelShorthand,
756 });
757 return;
758 }
759 ValueConstructorVariant::LocalVariable { .. }
760 | ValueConstructorVariant::ModuleConstant { .. }
761 | ValueConstructorVariant::ModuleFn { .. }
762 | ValueConstructorVariant::Record { .. } => {}
763 }
764 }
765
766 ast::visit::visit_typed_call_arg(self, arg);
767 }
768
769 fn visit_typed_pattern_string_prefix(
770 &mut self,
771 location: &'ast SrcSpan,
772 left_location: &'ast SrcSpan,
773 left_side_assignment: &'ast Option<(EcoString, SrcSpan)>,
774 right_location: &'ast SrcSpan,
775 left_side_string: &'ast EcoString,
776 right_side_assignment: &'ast AssignName,
777 ) {
778 // Handle the prefix alias in alternative pattern: "prefix" as name | "other_prefix" as name
779 if let Some((name, left_side_assignment_location)) = left_side_assignment {
780 self.register_alternative_definition(name, left_side_assignment_location);
781 }
782
783 // Handle the suffix in alternative pattern: "prefix" <> name | "other_prefix" <> name
784 match right_side_assignment {
785 AssignName::Variable(name) => {
786 self.register_alternative_definition(name, right_location)
787 }
788 AssignName::Discard(_) => {}
789 }
790
791 ast::visit::visit_typed_pattern_string_prefix(
792 self,
793 location,
794 left_location,
795 left_side_assignment,
796 right_location,
797 left_side_string,
798 right_side_assignment,
799 );
800 }
801}
802
803pub struct ModuleNameReference {
804 pub location: SrcSpan,
805 pub kind: ModuleNameReferenceKind,
806}
807
808pub enum ModuleNameReferenceKind {
809 Import,
810 AliasedImport,
811 ModuleSelect,
812}
813
814pub struct FindModuleNameReferences<'a> {
815 pub references: Vec<ModuleNameReference>,
816 pub module_name: &'a EcoString,
817 pub module_alias: &'a EcoString,
818}
819
820impl<'ast> Visit<'ast> for FindModuleNameReferences<'_> {
821 fn visit_typed_module(&mut self, module: &'ast TypedModule) {
822 ast::visit::visit_typed_module(self, module);
823 }
824
825 fn visit_typed_clause_guard(&mut self, guard: &'ast ast::TypedClauseGuard) {
826 ast::visit::visit_typed_clause_guard(self, guard);
827 }
828
829 fn visit_typed_import(&mut self, import: &'ast ast::TypedImport) {
830 match import.as_name.as_ref() {
831 None => {
832 if import.module == *self.module_name {
833 self.references.push(ModuleNameReference {
834 location: import.location,
835 kind: ModuleNameReferenceKind::Import,
836 })
837 }
838 }
839 Some((AssignName::Variable(alias) | AssignName::Discard(alias), alias_location)) => {
840 if alias == self.module_alias {
841 self.references.push(ModuleNameReference {
842 location: *alias_location,
843 kind: ModuleNameReferenceKind::AliasedImport,
844 })
845 }
846 }
847 }
848
849 ast::visit::visit_typed_import(self, import);
850 }
851
852 fn visit_typed_clause_guard_module_select(
853 &mut self,
854 location: &'ast SrcSpan,
855 field_start: &'ast u32,
856 definition_location: &'ast SrcSpan,
857 type_: &'ast std::sync::Arc<Type>,
858 label: &'ast EcoString,
859 module_name: &'ast EcoString,
860 module_alias: &'ast EcoString,
861 literal: &'ast ast::TypedConstant,
862 ) {
863 if module_alias == self.module_alias {
864 self.references.push(ModuleNameReference {
865 location: SrcSpan::new(
866 location.start,
867 location.start + (module_alias.len() as u32),
868 ),
869 kind: ModuleNameReferenceKind::ModuleSelect,
870 });
871 }
872
873 ast::visit::visit_typed_clause_guard_module_select(
874 self,
875 location,
876 field_start,
877 definition_location,
878 type_,
879 label,
880 module_name,
881 module_alias,
882 literal,
883 );
884 }
885
886 fn visit_typed_expr_module_select(
887 &mut self,
888 location: &'ast SrcSpan,
889 field_start: &'ast u32,
890 type_: &'ast std::sync::Arc<Type>,
891 label: &'ast EcoString,
892 module_name: &'ast EcoString,
893 module_alias: &'ast EcoString,
894 constructor: &'ast ModuleValueConstructor,
895 ) {
896 if module_alias == self.module_alias {
897 self.references.push(ModuleNameReference {
898 location: SrcSpan::new(
899 location.start,
900 location.start + (module_alias.len() as u32),
901 ),
902 kind: ModuleNameReferenceKind::ModuleSelect,
903 });
904 }
905
906 ast::visit::visit_typed_expr_module_select(
907 self,
908 location,
909 field_start,
910 type_,
911 label,
912 module_name,
913 module_alias,
914 constructor,
915 );
916 }
917
918 fn visit_type_ast_constructor(
919 &mut self,
920 location: &'ast SrcSpan,
921 name: &'ast TypeAstConstructorName,
922 arguments: &'ast [ast::TypeAst],
923 arguments_types: Option<Vec<std::sync::Arc<Type>>>,
924 ) {
925 if let TypeAstConstructorName::Qualified {
926 module: module_alias,
927 module_location,
928 ..
929 } = name
930 && module_alias == self.module_alias
931 {
932 self.references.push(ModuleNameReference {
933 location: *module_location,
934 kind: ModuleNameReferenceKind::ModuleSelect,
935 })
936 }
937
938 ast::visit::visit_type_ast_constructor(self, location, name, arguments, arguments_types);
939 }
940
941 fn visit_typed_constant_record(
942 &mut self,
943 location: &'ast SrcSpan,
944 module: &'ast Option<(EcoString, SrcSpan)>,
945 name: &'ast EcoString,
946 arguments: &'ast Vec<ast::CallArg<ast::TypedConstant>>,
947 type_: &'ast std::sync::Arc<Type>,
948 field_map: &'ast analyse::Inferred<gleam_core::type_::FieldMap>,
949 record_constructor: &'ast Option<Box<ValueConstructor>>,
950 ) {
951 if let Some((module_alias, module_location)) = module
952 && module_alias == self.module_alias
953 {
954 self.references.push(ModuleNameReference {
955 location: *module_location,
956 kind: ModuleNameReferenceKind::ModuleSelect,
957 })
958 }
959
960 ast::visit::visit_typed_constant_record(
961 self,
962 location,
963 module,
964 name,
965 arguments,
966 type_,
967 field_map,
968 record_constructor,
969 );
970 }
971
972 fn visit_typed_constant_record_update(
973 &mut self,
974 location: &'ast SrcSpan,
975 constructor_location: &'ast SrcSpan,
976 module: &'ast Option<(EcoString, SrcSpan)>,
977 name: &'ast EcoString,
978 record: &'ast ast::RecordBeingUpdated<ast::TypedConstant>,
979 arguments: &'ast [ast::RecordUpdateArg<ast::TypedConstant>],
980 type_: &'ast std::sync::Arc<Type>,
981 field_map: &'ast analyse::Inferred<gleam_core::type_::FieldMap>,
982 ) {
983 if let Some((module_alias, module_location)) = module
984 && module_alias == self.module_alias
985 {
986 self.references.push(ModuleNameReference {
987 location: *module_location,
988 kind: ModuleNameReferenceKind::ModuleSelect,
989 })
990 }
991
992 ast::visit::visit_typed_constant_record_update(
993 self,
994 location,
995 constructor_location,
996 module,
997 name,
998 record,
999 arguments,
1000 type_,
1001 field_map,
1002 )
1003 }
1004
1005 fn visit_typed_constant_var(
1006 &mut self,
1007 _location: &'ast SrcSpan,
1008 module: &'ast Option<(EcoString, SrcSpan)>,
1009 _name: &'ast EcoString,
1010 _constructor: &'ast Option<Box<ValueConstructor>>,
1011 _type_: &'ast std::sync::Arc<Type>,
1012 ) {
1013 if let Some((module_alias, module_location)) = module
1014 && module_alias == self.module_alias
1015 {
1016 self.references.push(ModuleNameReference {
1017 location: *module_location,
1018 kind: ModuleNameReferenceKind::ModuleSelect,
1019 })
1020 }
1021 }
1022
1023 fn visit_typed_pattern_constructor(
1024 &mut self,
1025 location: &'ast SrcSpan,
1026 name_location: &'ast SrcSpan,
1027 name: &'ast EcoString,
1028 arguments: &'ast Vec<ast::CallArg<ast::TypedPattern>>,
1029 module: &'ast Option<(EcoString, SrcSpan)>,
1030 constructor: &'ast analyse::Inferred<gleam_core::type_::PatternConstructor>,
1031 spread: &'ast Option<SrcSpan>,
1032 type_: &'ast std::sync::Arc<Type>,
1033 ) {
1034 if let Some((module_alias, module_location)) = module
1035 && module_alias == self.module_alias
1036 {
1037 self.references.push(ModuleNameReference {
1038 location: *module_location,
1039 kind: ModuleNameReferenceKind::ModuleSelect,
1040 });
1041 }
1042
1043 ast::visit::visit_typed_pattern_constructor(
1044 self,
1045 location,
1046 name_location,
1047 name,
1048 arguments,
1049 module,
1050 constructor,
1051 spread,
1052 type_,
1053 );
1054 }
1055}