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