swamp_analyzer/
constant.rs1use crate::types::TypeAnalyzeContext;
6use crate::{Analyzer, TypeContext};
7use swamp_semantic::err::ErrorKind;
8use swamp_semantic::{Constant, ConstantId, ConstantRef, Expression, ExpressionKind};
9use swamp_symbol::{Symbol, SymbolKind};
10
11impl Analyzer<'_> {
12 fn analyze_constant(&mut self, constant: &swamp_ast::ConstantInfo) {
13 let maybe_annotation_type = constant.annotation.as_ref().map(|found_ast_type| {
14 self.analyze_type(found_ast_type, &TypeAnalyzeContext::default())
15 });
16
17 let context = TypeContext::new_unsure_argument(maybe_annotation_type.as_ref(), true);
18
19 let resolved_expr = self.analyze_expression(&constant.expression, &context);
20
21 let actual_constant_type = if let Some(annotation_type) = maybe_annotation_type {
22 let extra_verification = false;
23 if extra_verification {
24 let debug_context = TypeContext::new_anything_argument(
25 annotation_type.collection_view_that_needs_explicit_storage(),
26 );
27 let worked_without_annotation =
28 self.analyze_expression(&constant.expression, &debug_context);
29 if self
30 .shared
31 .state
32 .types
33 .compatible_with(&annotation_type, &worked_without_annotation.ty)
34 {
35 let identifier_name = { self.get_text(&constant.constant_identifier.0) };
36 eprintln!(
37 "annotation was not needed for constant: {identifier_name} in {:?}",
38 self.module_path
39 );
40 }
41 }
42 annotation_type
43 } else {
44 resolved_expr.ty.clone()
45 };
46
47 if !actual_constant_type.can_be_stored_in_transient_field() {
49 self.add_err(ErrorKind::NeedStorage, &constant.constant_identifier.0);
50 return;
51 }
52 if !actual_constant_type.can_be_stored_in_field() {
53 self.add_hint(ErrorKind::NeedStorage, &constant.constant_identifier.0);
54 }
55
56 let name_node = self.to_node(&constant.constant_identifier.0);
59 let name_text = self.get_text_resolved(&name_node).to_string();
60 let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
61 self.shared.state.symbols.insert_top(
62 symbol_id,
63 Symbol {
64 id: symbol_id.into(),
65 kind: SymbolKind::Const,
66 source_map_node: name_node.clone(),
67 name: name_node.clone(),
68 },
69 );
70 let constant = Constant {
71 symbol_id,
72 name: name_node.clone(),
73 assigned_name: name_text,
74 id: ConstantId::from(self.shared.state.internal_function_id_allocator.alloc()),
75 expr: resolved_expr,
76 resolved_type: actual_constant_type,
77 function_scope_state: self.scope.total_scopes.clone(),
78 };
79
80 let const_ref = match self.shared.definition_table.add_constant(constant) {
81 Ok(c) => c,
82 Err(sem_err) => {
83 self.add_err_resolved(ErrorKind::SemanticError(sem_err), &name_node);
84 return;
85 }
86 };
87
88 match self
89 .shared
90 .lookup_table
91 .add_constant_link(const_ref.clone())
92 {
93 Ok(c) => c,
94 Err(sem_err) => {
95 self.add_err_resolved(ErrorKind::SemanticError(sem_err), &name_node);
96 return;
97 }
98 }
99
100 self.shared
102 .state
103 .constants_in_dependency_order
104 .push(const_ref);
105 }
106
107 pub(crate) fn analyze_constant_definition(&mut self, constant: &swamp_ast::ConstantInfo) {
108 self.analyze_constant(constant);
109 }
110
111 pub(crate) fn analyze_constant_access(
112 &mut self,
113 qualified_constant_identifier: &swamp_ast::QualifiedConstantIdentifier,
114 ) -> Expression {
115 match self
116 .try_find_constant(qualified_constant_identifier)
117 .cloned()
118 {
119 None => self.create_err(
120 ErrorKind::UnknownConstant,
121 &qualified_constant_identifier.name,
122 ),
123 Some(constant_ref) => {
124 let ty = constant_ref.resolved_type.clone();
125
126 let constant_reference_name_node =
127 self.to_node(&qualified_constant_identifier.name);
128 self.shared.state.refs.add(
129 constant_ref.symbol_id.into(),
130 constant_reference_name_node.clone(),
131 );
132 self.shared
133 .definition_table
134 .refs
135 .add(constant_ref.symbol_id.into(), constant_reference_name_node);
136
137 self.create_expr(
138 ExpressionKind::ConstantAccess(constant_ref),
139 ty,
140 &qualified_constant_identifier.name,
141 )
142 }
143 }
144 }
145
146 #[must_use]
147 pub fn try_find_constant(
148 &self,
149 qualified_constant_identifier: &swamp_ast::QualifiedConstantIdentifier,
150 ) -> Option<&ConstantRef> {
151 let path = self.get_module_path(qualified_constant_identifier.module_path.as_ref());
152 let constant_name = self.get_text(&qualified_constant_identifier.name);
153
154 let maybe_symbol_table = self.shared.get_definition_table(&path);
155 maybe_symbol_table.map_or_else(
156 || None,
157 |symbol_table| Some(symbol_table.get_constant(constant_name)),
158 )?
159 }
160}