1use crate::{
2 decl_engine::*,
3 engine_threading::*,
4 has_changes,
5 language::ty::*,
6 semantic_analysis::{
7 TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
8 TypeCheckFinalizationContext,
9 },
10 type_system::*,
11};
12use serde::{Deserialize, Serialize};
13use std::{
14 borrow::Cow,
15 hash::{Hash, Hasher},
16};
17use sway_error::handler::{ErrorEmitted, Handler};
18use sway_types::{Ident, Span, Spanned};
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21pub struct TyReassignment {
22 pub lhs: TyReassignmentTarget,
23 pub rhs: TyExpression,
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
27pub enum TyReassignmentTarget {
28 ElementAccess {
34 base_name: Ident,
37 base_type: TypeId,
39 indices: Vec<ProjectionKind>,
43 },
44 Deref(Box<TyExpression>),
52}
53
54impl EqWithEngines for TyReassignmentTarget {}
55impl PartialEqWithEngines for TyReassignmentTarget {
56 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
57 let type_engine = ctx.engines().te();
58 match (self, other) {
59 (TyReassignmentTarget::Deref(l), TyReassignmentTarget::Deref(r)) => (*l).eq(r, ctx),
60 (
61 TyReassignmentTarget::ElementAccess {
62 base_name: l_name,
63 base_type: l_type,
64 indices: l_indices,
65 },
66 TyReassignmentTarget::ElementAccess {
67 base_name: r_name,
68 base_type: r_type,
69 indices: r_indices,
70 },
71 ) => {
72 l_name == r_name
73 && (l_type == r_type
74 || type_engine.get(*l_type).eq(&type_engine.get(*r_type), ctx))
75 && l_indices.eq(r_indices, ctx)
76 }
77 _ => false,
78 }
79 }
80}
81
82impl EqWithEngines for TyReassignment {}
83impl PartialEqWithEngines for TyReassignment {
84 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
85 self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
86 }
87}
88
89impl HashWithEngines for TyReassignmentTarget {
90 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
91 let type_engine = engines.te();
92 match self {
93 TyReassignmentTarget::Deref(exp) => exp.hash(state, engines),
94 TyReassignmentTarget::ElementAccess {
95 base_name,
96 base_type,
97 indices,
98 } => {
99 base_name.hash(state);
100 type_engine.get(*base_type).hash(state, engines);
101 indices.hash(state, engines);
102 }
103 };
104 }
105}
106
107impl HashWithEngines for TyReassignment {
108 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
109 let TyReassignment { lhs, rhs } = self;
110
111 lhs.hash(state, engines);
112 rhs.hash(state, engines);
113 }
114}
115
116impl SubstTypes for TyReassignmentTarget {
117 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
118 has_changes! {
119 match self {
120 TyReassignmentTarget::Deref(exp) => exp.subst(ctx),
121 TyReassignmentTarget::ElementAccess { base_type, indices, .. } => {
122 has_changes! {
123 base_type.subst(ctx);
124 indices.subst(ctx);
125 }
126 }
127 };
128 }
129 }
130}
131
132impl SubstTypes for TyReassignment {
133 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
134 has_changes! {
135 self.lhs.subst(ctx);
136 self.rhs.subst(ctx);
137 }
138 }
139}
140
141impl ReplaceDecls for TyReassignmentTarget {
142 fn replace_decls_inner(
143 &mut self,
144 decl_mapping: &DeclMapping,
145 handler: &Handler,
146 ctx: &mut TypeCheckContext,
147 ) -> Result<bool, ErrorEmitted> {
148 Ok(match self {
149 TyReassignmentTarget::Deref(exp) => exp.replace_decls(decl_mapping, handler, ctx)?,
150 TyReassignmentTarget::ElementAccess { indices, .. } => indices
151 .iter_mut()
152 .map(|i| i.replace_decls(decl_mapping, handler, ctx))
153 .collect::<Result<Vec<bool>, _>>()?
154 .iter()
155 .any(|is_changed| *is_changed),
156 })
157 }
158}
159
160impl ReplaceDecls for TyReassignment {
161 fn replace_decls_inner(
162 &mut self,
163 decl_mapping: &DeclMapping,
164 handler: &Handler,
165 ctx: &mut TypeCheckContext,
166 ) -> Result<bool, ErrorEmitted> {
167 let lhs_changed = self.lhs.replace_decls(decl_mapping, handler, ctx)?;
168 let rhs_changed = self.rhs.replace_decls(decl_mapping, handler, ctx)?;
169
170 Ok(lhs_changed || rhs_changed)
171 }
172}
173
174impl TypeCheckAnalysis for TyReassignmentTarget {
175 fn type_check_analyze(
176 &self,
177 handler: &Handler,
178 ctx: &mut TypeCheckAnalysisContext,
179 ) -> Result<(), ErrorEmitted> {
180 match self {
181 TyReassignmentTarget::Deref(exp) => exp.type_check_analyze(handler, ctx)?,
182 TyReassignmentTarget::ElementAccess { indices, .. } => indices
183 .iter()
184 .map(|i| i.type_check_analyze(handler, ctx))
185 .collect::<Result<Vec<()>, _>>()
186 .map(|_| ())?,
187 };
188 Ok(())
189 }
190}
191
192impl TypeCheckAnalysis for TyReassignment {
193 fn type_check_analyze(
194 &self,
195 handler: &Handler,
196 ctx: &mut TypeCheckAnalysisContext,
197 ) -> Result<(), ErrorEmitted> {
198 self.lhs.type_check_analyze(handler, ctx)?;
199 self.rhs.type_check_analyze(handler, ctx)?;
200
201 Ok(())
202 }
203}
204
205impl TypeCheckFinalization for TyReassignmentTarget {
206 fn type_check_finalize(
207 &mut self,
208 handler: &Handler,
209 ctx: &mut TypeCheckFinalizationContext,
210 ) -> Result<(), ErrorEmitted> {
211 match self {
212 TyReassignmentTarget::Deref(exp) => exp.type_check_finalize(handler, ctx)?,
213 TyReassignmentTarget::ElementAccess { indices, .. } => indices
214 .iter_mut()
215 .map(|i| i.type_check_finalize(handler, ctx))
216 .collect::<Result<Vec<()>, _>>()
217 .map(|_| ())?,
218 };
219 Ok(())
220 }
221}
222
223impl TypeCheckFinalization for TyReassignment {
224 fn type_check_finalize(
225 &mut self,
226 handler: &Handler,
227 ctx: &mut TypeCheckFinalizationContext,
228 ) -> Result<(), ErrorEmitted> {
229 self.lhs.type_check_finalize(handler, ctx)?;
230 self.rhs.type_check_finalize(handler, ctx)?;
231
232 Ok(())
233 }
234}
235
236impl UpdateConstantExpression for TyReassignmentTarget {
237 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
238 match self {
239 TyReassignmentTarget::Deref(exp) => {
240 exp.update_constant_expression(engines, implementing_type)
241 }
242 TyReassignmentTarget::ElementAccess { indices, .. } => {
243 indices
244 .iter_mut()
245 .for_each(|i| i.update_constant_expression(engines, implementing_type));
246 }
247 };
248 }
249}
250
251impl UpdateConstantExpression for TyReassignment {
252 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
253 self.lhs
254 .update_constant_expression(engines, implementing_type);
255 self.rhs
256 .update_constant_expression(engines, implementing_type);
257 }
258}
259
260#[derive(Clone, Debug, Serialize, Deserialize)]
261pub enum ProjectionKind {
262 StructField {
263 name: Ident,
264 },
265 TupleField {
266 index: usize,
267 index_span: Span,
268 },
269 ArrayIndex {
270 index: Box<TyExpression>,
271 index_span: Span,
272 },
273}
274
275impl EqWithEngines for ProjectionKind {}
276impl PartialEqWithEngines for ProjectionKind {
277 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
278 match (self, other) {
279 (
280 ProjectionKind::StructField { name: l_name },
281 ProjectionKind::StructField { name: r_name },
282 ) => l_name == r_name,
283 (
284 ProjectionKind::TupleField {
285 index: l_index,
286 index_span: l_index_span,
287 },
288 ProjectionKind::TupleField {
289 index: r_index,
290 index_span: r_index_span,
291 },
292 ) => l_index == r_index && l_index_span == r_index_span,
293 (
294 ProjectionKind::ArrayIndex {
295 index: l_index,
296 index_span: l_index_span,
297 },
298 ProjectionKind::ArrayIndex {
299 index: r_index,
300 index_span: r_index_span,
301 },
302 ) => l_index.eq(r_index, ctx) && l_index_span == r_index_span,
303 _ => false,
304 }
305 }
306}
307
308impl HashWithEngines for ProjectionKind {
309 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
310 use ProjectionKind::*;
311 std::mem::discriminant(self).hash(state);
312 match self {
313 StructField { name } => name.hash(state),
314 TupleField {
315 index,
316 index_span: _,
319 } => index.hash(state),
320 ArrayIndex {
321 index,
322 index_span: _,
325 } => {
326 index.hash(state, engines);
327 }
328 }
329 }
330}
331
332impl SubstTypes for ProjectionKind {
333 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
334 use ProjectionKind::*;
335 match self {
336 ArrayIndex { index, .. } => index.subst(ctx),
337 _ => HasChanges::No,
338 }
339 }
340}
341
342impl ReplaceDecls for ProjectionKind {
343 fn replace_decls_inner(
344 &mut self,
345 decl_mapping: &DeclMapping,
346 handler: &Handler,
347 ctx: &mut TypeCheckContext,
348 ) -> Result<bool, ErrorEmitted> {
349 use ProjectionKind::*;
350 match self {
351 ArrayIndex { index, .. } => index.replace_decls(decl_mapping, handler, ctx),
352 _ => Ok(false),
353 }
354 }
355}
356
357impl TypeCheckAnalysis for ProjectionKind {
358 fn type_check_analyze(
359 &self,
360 handler: &Handler,
361 ctx: &mut TypeCheckAnalysisContext,
362 ) -> Result<(), ErrorEmitted> {
363 use ProjectionKind::*;
364 match self {
365 ArrayIndex { index, .. } => index.type_check_analyze(handler, ctx),
366 _ => Ok(()),
367 }
368 }
369}
370
371impl TypeCheckFinalization for ProjectionKind {
372 fn type_check_finalize(
373 &mut self,
374 handler: &Handler,
375 ctx: &mut TypeCheckFinalizationContext,
376 ) -> Result<(), ErrorEmitted> {
377 use ProjectionKind::*;
378 match self {
379 ArrayIndex { index, .. } => index.type_check_finalize(handler, ctx),
380 _ => Ok(()),
381 }
382 }
383}
384
385impl UpdateConstantExpression for ProjectionKind {
386 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
387 use ProjectionKind::*;
388 #[allow(clippy::single_match)]
389 match self {
391 ArrayIndex { index, .. } => {
392 index.update_constant_expression(engines, implementing_type)
393 }
394 _ => (),
395 }
396 }
397}
398
399impl Spanned for ProjectionKind {
400 fn span(&self) -> Span {
401 match self {
402 ProjectionKind::StructField { name } => name.span(),
403 ProjectionKind::TupleField { index_span, .. } => index_span.clone(),
404 ProjectionKind::ArrayIndex { index_span, .. } => index_span.clone(),
405 }
406 }
407}
408
409impl ProjectionKind {
410 pub(crate) fn pretty_print(&self) -> Cow<str> {
411 match self {
412 ProjectionKind::StructField { name } => Cow::Borrowed(name.as_str()),
413 ProjectionKind::TupleField { index, .. } => Cow::Owned(index.to_string()),
414 ProjectionKind::ArrayIndex { index, .. } => Cow::Owned(format!("{index:#?}")),
415 }
416 }
417}