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 DerefAccess {
54 exp: Box<TyExpression>,
56 indices: Vec<ProjectionKind>,
60 },
61}
62
63impl EqWithEngines for TyReassignmentTarget {}
64impl PartialEqWithEngines for TyReassignmentTarget {
65 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
66 let type_engine = ctx.engines().te();
67 match (self, other) {
68 (
69 TyReassignmentTarget::DerefAccess {
70 exp: l,
71 indices: l_indices,
72 },
73 TyReassignmentTarget::DerefAccess {
74 exp: r,
75 indices: r_indices,
76 },
77 ) => (*l).eq(r, ctx) && l_indices.eq(r_indices, ctx),
78 (
79 TyReassignmentTarget::ElementAccess {
80 base_name: l_name,
81 base_type: l_type,
82 indices: l_indices,
83 },
84 TyReassignmentTarget::ElementAccess {
85 base_name: r_name,
86 base_type: r_type,
87 indices: r_indices,
88 },
89 ) => {
90 l_name == r_name
91 && (l_type == r_type
92 || type_engine.get(*l_type).eq(&type_engine.get(*r_type), ctx))
93 && l_indices.eq(r_indices, ctx)
94 }
95 _ => false,
96 }
97 }
98}
99
100impl EqWithEngines for TyReassignment {}
101impl PartialEqWithEngines for TyReassignment {
102 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
103 self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
104 }
105}
106
107impl HashWithEngines for TyReassignmentTarget {
108 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
109 let type_engine = engines.te();
110 match self {
111 TyReassignmentTarget::DerefAccess { exp, indices } => {
112 exp.hash(state, engines);
113 indices.hash(state, engines);
114 }
115 TyReassignmentTarget::ElementAccess {
116 base_name,
117 base_type,
118 indices,
119 } => {
120 base_name.hash(state);
121 type_engine.get(*base_type).hash(state, engines);
122 indices.hash(state, engines);
123 }
124 };
125 }
126}
127
128impl HashWithEngines for TyReassignment {
129 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
130 let TyReassignment { lhs, rhs } = self;
131
132 lhs.hash(state, engines);
133 rhs.hash(state, engines);
134 }
135}
136
137impl SubstTypes for TyReassignmentTarget {
138 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
139 has_changes! {
140 match self {
141 TyReassignmentTarget::DerefAccess{exp, indices} => {
142 has_changes! {
143 exp.subst(ctx);
144 indices.subst(ctx);
145 }
146 },
147 TyReassignmentTarget::ElementAccess { base_type, indices, .. } => {
148 has_changes! {
149 base_type.subst(ctx);
150 indices.subst(ctx);
151 }
152 }
153 };
154 }
155 }
156}
157
158impl SubstTypes for TyReassignment {
159 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
160 has_changes! {
161 self.lhs.subst(ctx);
162 self.rhs.subst(ctx);
163 }
164 }
165}
166
167impl ReplaceDecls for TyReassignmentTarget {
168 fn replace_decls_inner(
169 &mut self,
170 decl_mapping: &DeclMapping,
171 handler: &Handler,
172 ctx: &mut TypeCheckContext,
173 ) -> Result<bool, ErrorEmitted> {
174 Ok(match self {
175 TyReassignmentTarget::DerefAccess { exp, indices } => {
176 let mut changed = exp.replace_decls(decl_mapping, handler, ctx)?;
177 changed |= indices
178 .iter_mut()
179 .map(|i| i.replace_decls(decl_mapping, handler, ctx))
180 .collect::<Result<Vec<bool>, _>>()?
181 .iter()
182 .any(|is_changed| *is_changed);
183 changed
184 }
185 TyReassignmentTarget::ElementAccess { indices, .. } => indices
186 .iter_mut()
187 .map(|i| i.replace_decls(decl_mapping, handler, ctx))
188 .collect::<Result<Vec<bool>, _>>()?
189 .iter()
190 .any(|is_changed| *is_changed),
191 })
192 }
193}
194
195impl ReplaceDecls for TyReassignment {
196 fn replace_decls_inner(
197 &mut self,
198 decl_mapping: &DeclMapping,
199 handler: &Handler,
200 ctx: &mut TypeCheckContext,
201 ) -> Result<bool, ErrorEmitted> {
202 let lhs_changed = self.lhs.replace_decls(decl_mapping, handler, ctx)?;
203 let rhs_changed = self.rhs.replace_decls(decl_mapping, handler, ctx)?;
204
205 Ok(lhs_changed || rhs_changed)
206 }
207}
208
209impl TypeCheckAnalysis for TyReassignmentTarget {
210 fn type_check_analyze(
211 &self,
212 handler: &Handler,
213 ctx: &mut TypeCheckAnalysisContext,
214 ) -> Result<(), ErrorEmitted> {
215 match self {
216 TyReassignmentTarget::DerefAccess { exp, indices } => {
217 exp.type_check_analyze(handler, ctx)?;
218 indices
219 .iter()
220 .map(|i| i.type_check_analyze(handler, ctx))
221 .collect::<Result<Vec<()>, _>>()
222 .map(|_| ())?
223 }
224 TyReassignmentTarget::ElementAccess { indices, .. } => indices
225 .iter()
226 .map(|i| i.type_check_analyze(handler, ctx))
227 .collect::<Result<Vec<()>, _>>()
228 .map(|_| ())?,
229 };
230 Ok(())
231 }
232}
233
234impl TypeCheckAnalysis for TyReassignment {
235 fn type_check_analyze(
236 &self,
237 handler: &Handler,
238 ctx: &mut TypeCheckAnalysisContext,
239 ) -> Result<(), ErrorEmitted> {
240 self.lhs.type_check_analyze(handler, ctx)?;
241 self.rhs.type_check_analyze(handler, ctx)?;
242
243 Ok(())
244 }
245}
246
247impl TypeCheckFinalization for TyReassignmentTarget {
248 fn type_check_finalize(
249 &mut self,
250 handler: &Handler,
251 ctx: &mut TypeCheckFinalizationContext,
252 ) -> Result<(), ErrorEmitted> {
253 match self {
254 TyReassignmentTarget::DerefAccess { exp, indices } => {
255 exp.type_check_finalize(handler, ctx)?;
256 indices
257 .iter_mut()
258 .map(|i| i.type_check_finalize(handler, ctx))
259 .collect::<Result<Vec<()>, _>>()
260 .map(|_| ())?;
261 }
262 TyReassignmentTarget::ElementAccess { indices, .. } => indices
263 .iter_mut()
264 .map(|i| i.type_check_finalize(handler, ctx))
265 .collect::<Result<Vec<()>, _>>()
266 .map(|_| ())?,
267 };
268 Ok(())
269 }
270}
271
272impl TypeCheckFinalization for TyReassignment {
273 fn type_check_finalize(
274 &mut self,
275 handler: &Handler,
276 ctx: &mut TypeCheckFinalizationContext,
277 ) -> Result<(), ErrorEmitted> {
278 self.lhs.type_check_finalize(handler, ctx)?;
279 self.rhs.type_check_finalize(handler, ctx)?;
280
281 Ok(())
282 }
283}
284
285impl UpdateConstantExpression for TyReassignmentTarget {
286 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
287 match self {
288 TyReassignmentTarget::DerefAccess { exp, indices } => {
289 exp.update_constant_expression(engines, implementing_type);
290 indices
291 .iter_mut()
292 .for_each(|i| i.update_constant_expression(engines, implementing_type));
293 }
294 TyReassignmentTarget::ElementAccess { indices, .. } => {
295 indices
296 .iter_mut()
297 .for_each(|i| i.update_constant_expression(engines, implementing_type));
298 }
299 };
300 }
301}
302
303impl UpdateConstantExpression for TyReassignment {
304 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
305 self.lhs
306 .update_constant_expression(engines, implementing_type);
307 self.rhs
308 .update_constant_expression(engines, implementing_type);
309 }
310}
311
312#[derive(Clone, Debug, Serialize, Deserialize)]
313pub enum ProjectionKind {
314 StructField {
315 name: Ident,
316 field_to_access: Option<Box<TyStructField>>,
317 },
318 TupleField {
319 index: usize,
320 index_span: Span,
321 },
322 ArrayIndex {
323 index: Box<TyExpression>,
324 index_span: Span,
325 },
326}
327
328impl EqWithEngines for ProjectionKind {}
329impl PartialEqWithEngines for ProjectionKind {
330 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
331 match (self, other) {
332 (
333 ProjectionKind::StructField {
334 name: l_name,
335 field_to_access: _,
336 },
337 ProjectionKind::StructField {
338 name: r_name,
339 field_to_access: _,
340 },
341 ) => l_name == r_name,
342 (
343 ProjectionKind::TupleField {
344 index: l_index,
345 index_span: l_index_span,
346 },
347 ProjectionKind::TupleField {
348 index: r_index,
349 index_span: r_index_span,
350 },
351 ) => l_index == r_index && l_index_span == r_index_span,
352 (
353 ProjectionKind::ArrayIndex {
354 index: l_index,
355 index_span: l_index_span,
356 },
357 ProjectionKind::ArrayIndex {
358 index: r_index,
359 index_span: r_index_span,
360 },
361 ) => l_index.eq(r_index, ctx) && l_index_span == r_index_span,
362 _ => false,
363 }
364 }
365}
366
367impl HashWithEngines for ProjectionKind {
368 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
369 use ProjectionKind::*;
370 std::mem::discriminant(self).hash(state);
371 match self {
372 StructField {
373 name,
374 field_to_access: _,
375 } => name.hash(state),
376 TupleField {
377 index,
378 index_span: _,
381 } => index.hash(state),
382 ArrayIndex {
383 index,
384 index_span: _,
387 } => {
388 index.hash(state, engines);
389 }
390 }
391 }
392}
393
394impl SubstTypes for ProjectionKind {
395 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
396 use ProjectionKind::*;
397 match self {
398 ArrayIndex { index, .. } => index.subst(ctx),
399 _ => HasChanges::No,
400 }
401 }
402}
403
404impl ReplaceDecls for ProjectionKind {
405 fn replace_decls_inner(
406 &mut self,
407 decl_mapping: &DeclMapping,
408 handler: &Handler,
409 ctx: &mut TypeCheckContext,
410 ) -> Result<bool, ErrorEmitted> {
411 use ProjectionKind::*;
412 match self {
413 ArrayIndex { index, .. } => index.replace_decls(decl_mapping, handler, ctx),
414 _ => Ok(false),
415 }
416 }
417}
418
419impl TypeCheckAnalysis for ProjectionKind {
420 fn type_check_analyze(
421 &self,
422 handler: &Handler,
423 ctx: &mut TypeCheckAnalysisContext,
424 ) -> Result<(), ErrorEmitted> {
425 use ProjectionKind::*;
426 match self {
427 ArrayIndex { index, .. } => index.type_check_analyze(handler, ctx),
428 _ => Ok(()),
429 }
430 }
431}
432
433impl TypeCheckFinalization for ProjectionKind {
434 fn type_check_finalize(
435 &mut self,
436 handler: &Handler,
437 ctx: &mut TypeCheckFinalizationContext,
438 ) -> Result<(), ErrorEmitted> {
439 use ProjectionKind::*;
440 match self {
441 ArrayIndex { index, .. } => index.type_check_finalize(handler, ctx),
442 _ => Ok(()),
443 }
444 }
445}
446
447impl UpdateConstantExpression for ProjectionKind {
448 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
449 use ProjectionKind::*;
450 #[allow(clippy::single_match)]
451 match self {
453 ArrayIndex { index, .. } => {
454 index.update_constant_expression(engines, implementing_type)
455 }
456 _ => (),
457 }
458 }
459}
460
461impl Spanned for ProjectionKind {
462 fn span(&self) -> Span {
463 match self {
464 ProjectionKind::StructField {
465 name,
466 field_to_access: _,
467 } => name.span(),
468 ProjectionKind::TupleField { index_span, .. } => index_span.clone(),
469 ProjectionKind::ArrayIndex { index_span, .. } => index_span.clone(),
470 }
471 }
472}
473
474impl ProjectionKind {
475 pub(crate) fn pretty_print(&self) -> Cow<str> {
476 match self {
477 ProjectionKind::StructField {
478 name,
479 field_to_access: _,
480 } => Cow::Borrowed(name.as_str()),
481 ProjectionKind::TupleField { index, .. } => Cow::Owned(index.to_string()),
482 ProjectionKind::ArrayIndex { index, .. } => Cow::Owned(format!("{index:#?}")),
483 }
484 }
485}