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<HasChanges, ErrorEmitted> {
256 let has_changes = match self {
257 TyReassignmentTarget::DerefAccess { exp, indices } => {
258 let mut has_changes = exp.type_check_finalize(handler, ctx)?;
259 for index in indices.iter_mut() {
260 has_changes |= index.type_check_finalize(handler, ctx)?;
261 }
262 has_changes
263 }
264 TyReassignmentTarget::ElementAccess { indices, .. } => {
265 let mut has_changes = HasChanges::No;
266 for index in indices.iter_mut() {
267 has_changes |= index.type_check_finalize(handler, ctx)?;
268 }
269 has_changes
270 }
271 };
272 Ok(has_changes)
273 }
274}
275
276impl TypeCheckFinalization for TyReassignment {
277 fn type_check_finalize(
278 &mut self,
279 handler: &Handler,
280 ctx: &mut TypeCheckFinalizationContext,
281 ) -> Result<HasChanges, ErrorEmitted> {
282 Ok(has_changes! {
283 self.lhs.type_check_finalize(handler, ctx)?;
284 self.rhs.type_check_finalize(handler, ctx)?;
285 })
286 }
287}
288
289impl UpdateConstantExpression for TyReassignmentTarget {
290 fn update_constant_expression(
291 &mut self,
292 engines: &Engines,
293 implementing_type: &TyDecl,
294 ) -> HasChanges {
295 match self {
296 TyReassignmentTarget::DerefAccess { exp, indices } => has_changes! {
297 exp.update_constant_expression(engines, implementing_type);
298 indices
299 .iter_mut()
300 .fold(HasChanges::No, |acc, i| {
301 acc | i.update_constant_expression(engines, implementing_type)
302 });
303 },
304 TyReassignmentTarget::ElementAccess { indices, .. } => {
305 indices.iter_mut().fold(HasChanges::No, |acc, i| {
306 acc | i.update_constant_expression(engines, implementing_type)
307 })
308 }
309 }
310 }
311}
312
313impl UpdateConstantExpression for TyReassignment {
314 fn update_constant_expression(
315 &mut self,
316 engines: &Engines,
317 implementing_type: &TyDecl,
318 ) -> HasChanges {
319 has_changes! {
320 self.lhs.update_constant_expression(engines, implementing_type);
321 self.rhs.update_constant_expression(engines, implementing_type);
322 }
323 }
324}
325
326#[derive(Clone, Debug, Serialize, Deserialize)]
327pub enum ProjectionKind {
328 StructField {
329 name: Ident,
330 field_to_access: Option<Box<TyStructField>>,
331 },
332 TupleField {
333 index: usize,
334 index_span: Span,
335 },
336 ArrayIndex {
337 index: Box<TyExpression>,
338 index_span: Span,
339 },
340}
341
342impl EqWithEngines for ProjectionKind {}
343impl PartialEqWithEngines for ProjectionKind {
344 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
345 match (self, other) {
346 (
347 ProjectionKind::StructField {
348 name: l_name,
349 field_to_access: _,
350 },
351 ProjectionKind::StructField {
352 name: r_name,
353 field_to_access: _,
354 },
355 ) => l_name == r_name,
356 (
357 ProjectionKind::TupleField {
358 index: l_index,
359 index_span: l_index_span,
360 },
361 ProjectionKind::TupleField {
362 index: r_index,
363 index_span: r_index_span,
364 },
365 ) => l_index == r_index && l_index_span == r_index_span,
366 (
367 ProjectionKind::ArrayIndex {
368 index: l_index,
369 index_span: l_index_span,
370 },
371 ProjectionKind::ArrayIndex {
372 index: r_index,
373 index_span: r_index_span,
374 },
375 ) => l_index.eq(r_index, ctx) && l_index_span == r_index_span,
376 _ => false,
377 }
378 }
379}
380
381impl HashWithEngines for ProjectionKind {
382 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
383 use ProjectionKind::*;
384 std::mem::discriminant(self).hash(state);
385 match self {
386 StructField {
387 name,
388 field_to_access: _,
389 } => name.hash(state),
390 TupleField {
391 index,
392 index_span: _,
395 } => index.hash(state),
396 ArrayIndex {
397 index,
398 index_span: _,
401 } => {
402 index.hash(state, engines);
403 }
404 }
405 }
406}
407
408impl SubstTypes for ProjectionKind {
409 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
410 use ProjectionKind::*;
411 match self {
412 ArrayIndex { index, .. } => index.subst(ctx),
413 _ => HasChanges::No,
414 }
415 }
416}
417
418impl ReplaceDecls for ProjectionKind {
419 fn replace_decls_inner(
420 &mut self,
421 decl_mapping: &DeclMapping,
422 handler: &Handler,
423 ctx: &mut TypeCheckContext,
424 ) -> Result<HasChanges, ErrorEmitted> {
425 use ProjectionKind::*;
426 match self {
427 ArrayIndex { index, .. } => index.replace_decls(decl_mapping, handler, ctx),
428 _ => Ok(HasChanges::No),
429 }
430 }
431}
432
433impl TypeCheckAnalysis for ProjectionKind {
434 fn type_check_analyze(
435 &self,
436 handler: &Handler,
437 ctx: &mut TypeCheckAnalysisContext,
438 ) -> Result<(), ErrorEmitted> {
439 use ProjectionKind::*;
440 match self {
441 ArrayIndex { index, .. } => index.type_check_analyze(handler, ctx),
442 _ => Ok(()),
443 }
444 }
445}
446
447impl TypeCheckFinalization for ProjectionKind {
448 fn type_check_finalize(
449 &mut self,
450 handler: &Handler,
451 ctx: &mut TypeCheckFinalizationContext,
452 ) -> Result<HasChanges, ErrorEmitted> {
453 use ProjectionKind::*;
454 match self {
455 ArrayIndex { index, .. } => index.type_check_finalize(handler, ctx),
456 _ => Ok(HasChanges::No),
457 }
458 }
459}
460
461impl UpdateConstantExpression for ProjectionKind {
462 fn update_constant_expression(
463 &mut self,
464 engines: &Engines,
465 implementing_type: &TyDecl,
466 ) -> HasChanges {
467 use ProjectionKind::*;
468 match self {
469 ArrayIndex { index, .. } => {
470 index.update_constant_expression(engines, implementing_type)
471 }
472 _ => HasChanges::No,
473 }
474 }
475}
476
477impl Spanned for ProjectionKind {
478 fn span(&self) -> Span {
479 match self {
480 ProjectionKind::StructField {
481 name,
482 field_to_access: _,
483 } => name.span(),
484 ProjectionKind::TupleField { index_span, .. } => index_span.clone(),
485 ProjectionKind::ArrayIndex { index_span, .. } => index_span.clone(),
486 }
487 }
488}
489
490impl ProjectionKind {
491 pub(crate) fn pretty_print(&self) -> Cow<'_, str> {
492 match self {
493 ProjectionKind::StructField {
494 name,
495 field_to_access: _,
496 } => Cow::Borrowed(name.as_str()),
497 ProjectionKind::TupleField { index, .. } => Cow::Owned(index.to_string()),
498 ProjectionKind::ArrayIndex { index, .. } => Cow::Owned(format!("{index:#?}")),
499 }
500 }
501}