Skip to main content

leo_ast/types/
canonicalize.rs

1// Copyright (C) 2019-2026 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17//! Scrubs `Span` and `NodeID` while preserving identity-bearing payloads (`Symbol`, `Location`).
18//! Applied by [`crate::TypeInterner::intern`] so structurally-equal values sharing only their
19//! positions collapse to one [`crate::Type`].
20//!
21//! Every impl fully destructures via `Self { ... }`, so adding a new field to any AST node is
22//! a compile error here — that's what stops a positional field from silently leaking through.
23
24use crate::{
25    ArrayAccess,
26    ArrayExpression,
27    ArrayType,
28    AssertStatement,
29    AssertVariant,
30    AssignStatement,
31    AsyncExpression,
32    BinaryExpression,
33    Block,
34    CallExpression,
35    CastExpression,
36    CompositeExpression,
37    CompositeFieldInitializer,
38    CompositeType,
39    ConditionalStatement,
40    ConstDeclaration,
41    DefinitionPlace,
42    DefinitionStatement,
43    DynamicOpExpression,
44    DynamicOpKind,
45    ErrExpression,
46    Expression,
47    ExpressionStatement,
48    FutureType,
49    Identifier,
50    IntrinsicExpression,
51    IterationStatement,
52    Literal,
53    MappingType,
54    MemberAccess,
55    NodeID,
56    OptionalType,
57    ProgramId,
58    RepeatExpression,
59    ReturnStatement,
60    Statement,
61    TernaryExpression,
62    TupleAccess,
63    TupleExpression,
64    TupleType,
65    TypeKind,
66    TypeNode,
67    UnaryExpression,
68    UnitExpression,
69    VectorType,
70};
71use leo_span::Span;
72
73pub trait Canonicalize: Sized {
74    #[must_use]
75    fn canonicalize(self) -> Self;
76}
77
78impl<T: Canonicalize> Canonicalize for Box<T> {
79    fn canonicalize(self) -> Self {
80        Box::new((*self).canonicalize())
81    }
82}
83
84impl<T: Canonicalize> Canonicalize for Vec<T> {
85    fn canonicalize(self) -> Self {
86        self.into_iter().map(Canonicalize::canonicalize).collect()
87    }
88}
89
90impl<T: Canonicalize> Canonicalize for Option<T> {
91    fn canonicalize(self) -> Self {
92        self.map(Canonicalize::canonicalize)
93    }
94}
95
96impl Canonicalize for Identifier {
97    fn canonicalize(self) -> Self {
98        let Self { name, span: _, id: _ } = self;
99        Self { name, span: Span::default(), id: NodeID::default() }
100    }
101}
102
103impl Canonicalize for ProgramId {
104    fn canonicalize(self) -> Self {
105        let Self { name, network } = self;
106        Self { name: name.canonicalize(), network: network.canonicalize() }
107    }
108}
109
110// `Canonicalize for Path` is implemented in `common/path.rs` so it can see Path's private fields.
111
112impl Canonicalize for TypeNode {
113    fn canonicalize(self) -> Self {
114        // Canonicalizing `kind` doesn't change its interner key, so `type_` stays valid and we
115        // can rebuild via `from_parts` without another intern lookup.
116        let (kind, _, type_) = self.into_parts();
117        TypeNode::from_parts(kind.canonicalize(), Span::default(), type_)
118    }
119}
120
121impl Canonicalize for TypeKind {
122    fn canonicalize(self) -> Self {
123        match self {
124            TypeKind::Array(a) => TypeKind::Array(a.canonicalize()),
125            TypeKind::Composite(c) => TypeKind::Composite(c.canonicalize()),
126            TypeKind::Future(f) => TypeKind::Future(f.canonicalize()),
127            TypeKind::Ident(i) => TypeKind::Ident(i.canonicalize()),
128            TypeKind::Mapping(m) => TypeKind::Mapping(m.canonicalize()),
129            TypeKind::Optional(o) => TypeKind::Optional(o.canonicalize()),
130            TypeKind::Tuple(t) => TypeKind::Tuple(t.canonicalize()),
131            TypeKind::Vector(v) => TypeKind::Vector(v.canonicalize()),
132            t @ (TypeKind::Address
133            | TypeKind::Boolean
134            | TypeKind::Field
135            | TypeKind::Group
136            | TypeKind::Integer(_)
137            | TypeKind::Identifier
138            | TypeKind::DynRecord
139            | TypeKind::Scalar
140            | TypeKind::Signature
141            | TypeKind::String
142            | TypeKind::Numeric
143            | TypeKind::Unit
144            | TypeKind::Err) => t,
145        }
146    }
147}
148
149impl Canonicalize for ArrayType {
150    fn canonicalize(self) -> Self {
151        let Self { element_type, length } = self;
152        Self { element_type: element_type.canonicalize(), length: length.canonicalize() }
153    }
154}
155
156impl Canonicalize for CompositeType {
157    fn canonicalize(self) -> Self {
158        let Self { path, const_arguments } = self;
159        Self { path: path.canonicalize(), const_arguments: const_arguments.canonicalize() }
160    }
161}
162
163impl Canonicalize for FutureType {
164    fn canonicalize(self) -> Self {
165        let Self { inputs, location, is_explicit } = self;
166        Self { inputs: inputs.canonicalize(), location, is_explicit }
167    }
168}
169
170impl Canonicalize for MappingType {
171    fn canonicalize(self) -> Self {
172        let Self { key, value } = self;
173        Self { key: key.canonicalize(), value: value.canonicalize() }
174    }
175}
176
177impl Canonicalize for OptionalType {
178    fn canonicalize(self) -> Self {
179        let Self { inner } = self;
180        Self { inner: inner.canonicalize() }
181    }
182}
183
184impl Canonicalize for TupleType {
185    fn canonicalize(self) -> Self {
186        let Self { elements } = self;
187        Self { elements: elements.canonicalize() }
188    }
189}
190
191impl Canonicalize for VectorType {
192    fn canonicalize(self) -> Self {
193        let Self { element_type } = self;
194        Self { element_type: element_type.canonicalize() }
195    }
196}
197
198impl Canonicalize for Expression {
199    fn canonicalize(self) -> Self {
200        match self {
201            Expression::ArrayAccess(n) => Expression::ArrayAccess(n.canonicalize()),
202            Expression::Async(n) => Expression::Async(n.canonicalize()),
203            Expression::Array(n) => Expression::Array(n.canonicalize()),
204            Expression::Binary(n) => Expression::Binary(n.canonicalize()),
205            Expression::Intrinsic(n) => Expression::Intrinsic(n.canonicalize()),
206            Expression::Call(n) => Expression::Call(n.canonicalize()),
207            Expression::DynamicOp(n) => Expression::DynamicOp(n.canonicalize()),
208            Expression::Cast(n) => Expression::Cast(n.canonicalize()),
209            Expression::Composite(n) => Expression::Composite(n.canonicalize()),
210            Expression::Err(n) => Expression::Err(n.canonicalize()),
211            Expression::Path(n) => Expression::Path(n.canonicalize()),
212            Expression::Literal(n) => Expression::Literal(n.canonicalize()),
213            Expression::MemberAccess(n) => Expression::MemberAccess(n.canonicalize()),
214            Expression::Repeat(n) => Expression::Repeat(n.canonicalize()),
215            Expression::Ternary(n) => Expression::Ternary(n.canonicalize()),
216            Expression::Tuple(n) => Expression::Tuple(n.canonicalize()),
217            Expression::TupleAccess(n) => Expression::TupleAccess(n.canonicalize()),
218            Expression::Unary(n) => Expression::Unary(n.canonicalize()),
219            Expression::Unit(n) => Expression::Unit(n.canonicalize()),
220        }
221    }
222}
223
224impl Canonicalize for ArrayAccess {
225    fn canonicalize(self) -> Self {
226        let Self { array, index, span: _, id: _ } = self;
227        Self { array: array.canonicalize(), index: index.canonicalize(), span: Span::default(), id: NodeID::default() }
228    }
229}
230
231impl Canonicalize for AsyncExpression {
232    fn canonicalize(self) -> Self {
233        let Self { block, span: _, id: _ } = self;
234        Self { block: block.canonicalize(), span: Span::default(), id: NodeID::default() }
235    }
236}
237
238impl Canonicalize for ArrayExpression {
239    fn canonicalize(self) -> Self {
240        let Self { elements, span: _, id: _ } = self;
241        Self { elements: elements.canonicalize(), span: Span::default(), id: NodeID::default() }
242    }
243}
244
245impl Canonicalize for BinaryExpression {
246    fn canonicalize(self) -> Self {
247        let Self { left, right, op, span: _, id: _ } = self;
248        Self {
249            left: left.canonicalize(),
250            right: right.canonicalize(),
251            op,
252            span: Span::default(),
253            id: NodeID::default(),
254        }
255    }
256}
257
258impl Canonicalize for IntrinsicExpression {
259    fn canonicalize(self) -> Self {
260        let Self { name, type_parameters, input_types, return_types, arguments, span: _, id: _ } = self;
261        Self {
262            name,
263            type_parameters: type_parameters.into_iter().map(|(ty, _)| (ty.canonicalize(), Span::default())).collect(),
264            input_types: input_types
265                .into_iter()
266                .map(|(mode, ty, _)| (mode, ty.canonicalize(), Span::default()))
267                .collect(),
268            return_types: return_types
269                .into_iter()
270                .map(|(mode, ty, _)| (mode, ty.canonicalize(), Span::default()))
271                .collect(),
272            arguments: arguments.canonicalize(),
273            span: Span::default(),
274            id: NodeID::default(),
275        }
276    }
277}
278
279impl Canonicalize for CallExpression {
280    fn canonicalize(self) -> Self {
281        let Self { function, const_arguments, arguments, span: _, id: _ } = self;
282        Self {
283            function: function.canonicalize(),
284            const_arguments: const_arguments.canonicalize(),
285            arguments: arguments.canonicalize(),
286            span: Span::default(),
287            id: NodeID::default(),
288        }
289    }
290}
291
292impl Canonicalize for DynamicOpExpression {
293    fn canonicalize(self) -> Self {
294        let Self { interface, target_program, network, kind, span: _, id: _ } = self;
295        Self {
296            interface: interface.canonicalize(),
297            target_program: target_program.canonicalize(),
298            network: network.canonicalize(),
299            kind: kind.canonicalize(),
300            span: Span::default(),
301            id: NodeID::default(),
302        }
303    }
304}
305
306impl Canonicalize for DynamicOpKind {
307    fn canonicalize(self) -> Self {
308        match self {
309            DynamicOpKind::Call { function, arguments } => {
310                DynamicOpKind::Call { function: function.canonicalize(), arguments: arguments.canonicalize() }
311            }
312            DynamicOpKind::Read { storage } => DynamicOpKind::Read { storage: storage.canonicalize() },
313            DynamicOpKind::Op { member, op, arguments } => DynamicOpKind::Op {
314                member: member.canonicalize(),
315                op: op.canonicalize(),
316                arguments: arguments.canonicalize(),
317            },
318        }
319    }
320}
321
322impl Canonicalize for CastExpression {
323    fn canonicalize(self) -> Self {
324        let Self { expression, type_, span: _, id: _ } = self;
325        Self {
326            expression: expression.canonicalize(),
327            type_: type_.canonicalize(),
328            span: Span::default(),
329            id: NodeID::default(),
330        }
331    }
332}
333
334impl Canonicalize for CompositeExpression {
335    fn canonicalize(self) -> Self {
336        let Self { path, const_arguments, members, base, span: _, id: _ } = self;
337        Self {
338            path: path.canonicalize(),
339            const_arguments: const_arguments.canonicalize(),
340            members: members.canonicalize(),
341            base: base.canonicalize(),
342            span: Span::default(),
343            id: NodeID::default(),
344        }
345    }
346}
347
348impl Canonicalize for CompositeFieldInitializer {
349    fn canonicalize(self) -> Self {
350        let Self { identifier, expression, span: _, id: _ } = self;
351        Self {
352            identifier: identifier.canonicalize(),
353            expression: expression.canonicalize(),
354            span: Span::default(),
355            id: NodeID::default(),
356        }
357    }
358}
359
360impl Canonicalize for ErrExpression {
361    fn canonicalize(self) -> Self {
362        let Self { span: _, id: _ } = self;
363        Self { span: Span::default(), id: NodeID::default() }
364    }
365}
366
367impl Canonicalize for Literal {
368    fn canonicalize(self) -> Self {
369        let Self { variant, span: _, id: _ } = self;
370        // `variant: LiteralVariant` carries the identity (Address(String), Integer(IntegerType, String), …).
371        Self { variant, span: Span::default(), id: NodeID::default() }
372    }
373}
374
375impl Canonicalize for MemberAccess {
376    fn canonicalize(self) -> Self {
377        let Self { inner, name, span: _, id: _ } = self;
378        Self { inner: inner.canonicalize(), name: name.canonicalize(), span: Span::default(), id: NodeID::default() }
379    }
380}
381
382impl Canonicalize for RepeatExpression {
383    fn canonicalize(self) -> Self {
384        let Self { expr, count, span: _, id: _ } = self;
385        Self { expr: expr.canonicalize(), count: count.canonicalize(), span: Span::default(), id: NodeID::default() }
386    }
387}
388
389impl Canonicalize for TernaryExpression {
390    fn canonicalize(self) -> Self {
391        let Self { condition, if_true, if_false, span: _, id: _ } = self;
392        Self {
393            condition: condition.canonicalize(),
394            if_true: if_true.canonicalize(),
395            if_false: if_false.canonicalize(),
396            span: Span::default(),
397            id: NodeID::default(),
398        }
399    }
400}
401
402impl Canonicalize for TupleExpression {
403    fn canonicalize(self) -> Self {
404        let Self { elements, span: _, id: _ } = self;
405        Self { elements: elements.canonicalize(), span: Span::default(), id: NodeID::default() }
406    }
407}
408
409impl Canonicalize for TupleAccess {
410    fn canonicalize(self) -> Self {
411        let Self { tuple, index, span: _, id: _ } = self;
412        Self { tuple: tuple.canonicalize(), index, span: Span::default(), id: NodeID::default() }
413    }
414}
415
416impl Canonicalize for UnaryExpression {
417    fn canonicalize(self) -> Self {
418        let Self { receiver, op, span: _, id: _ } = self;
419        Self { receiver: receiver.canonicalize(), op, span: Span::default(), id: NodeID::default() }
420    }
421}
422
423impl Canonicalize for UnitExpression {
424    fn canonicalize(self) -> Self {
425        let Self { span: _, id: _ } = self;
426        Self { span: Span::default(), id: NodeID::default() }
427    }
428}
429
430impl Canonicalize for Block {
431    fn canonicalize(self) -> Self {
432        let Self { statements, span: _, id: _ } = self;
433        Self { statements: statements.canonicalize(), span: Span::default(), id: NodeID::default() }
434    }
435}
436
437impl Canonicalize for Statement {
438    fn canonicalize(self) -> Self {
439        match self {
440            Statement::Assert(s) => Statement::Assert(s.canonicalize()),
441            Statement::Assign(s) => Statement::Assign(s.canonicalize()),
442            Statement::Block(s) => Statement::Block(s.canonicalize()),
443            Statement::Conditional(s) => Statement::Conditional(s.canonicalize()),
444            Statement::Const(s) => Statement::Const(s.canonicalize()),
445            Statement::Definition(s) => Statement::Definition(s.canonicalize()),
446            Statement::Expression(s) => Statement::Expression(s.canonicalize()),
447            Statement::Iteration(s) => Statement::Iteration(s.canonicalize()),
448            Statement::Return(s) => Statement::Return(s.canonicalize()),
449        }
450    }
451}
452
453impl Canonicalize for AssertStatement {
454    fn canonicalize(self) -> Self {
455        let Self { variant, span: _, id: _ } = self;
456        Self { variant: variant.canonicalize(), span: Span::default(), id: NodeID::default() }
457    }
458}
459
460impl Canonicalize for AssertVariant {
461    fn canonicalize(self) -> Self {
462        match self {
463            AssertVariant::Assert(e) => AssertVariant::Assert(e.canonicalize()),
464            AssertVariant::AssertEq(a, b) => AssertVariant::AssertEq(a.canonicalize(), b.canonicalize()),
465            AssertVariant::AssertNeq(a, b) => AssertVariant::AssertNeq(a.canonicalize(), b.canonicalize()),
466        }
467    }
468}
469
470impl Canonicalize for AssignStatement {
471    fn canonicalize(self) -> Self {
472        let Self { place, value, span: _, id: _ } = self;
473        Self { place: place.canonicalize(), value: value.canonicalize(), span: Span::default(), id: NodeID::default() }
474    }
475}
476
477impl Canonicalize for ConditionalStatement {
478    fn canonicalize(self) -> Self {
479        let Self { condition, then, otherwise, span: _, id: _ } = self;
480        Self {
481            condition: condition.canonicalize(),
482            then: then.canonicalize(),
483            otherwise: otherwise.canonicalize(),
484            span: Span::default(),
485            id: NodeID::default(),
486        }
487    }
488}
489
490impl Canonicalize for ConstDeclaration {
491    fn canonicalize(self) -> Self {
492        let Self { is_exported, place, type_, value, span: _, id: _ } = self;
493        Self {
494            is_exported,
495            place: place.canonicalize(),
496            type_: type_.canonicalize(),
497            value: value.canonicalize(),
498            span: Span::default(),
499            id: NodeID::default(),
500        }
501    }
502}
503
504impl Canonicalize for DefinitionStatement {
505    fn canonicalize(self) -> Self {
506        let Self { place, type_, value, span: _, id: _ } = self;
507        Self {
508            place: place.canonicalize(),
509            type_: type_.canonicalize(),
510            value: value.canonicalize(),
511            span: Span::default(),
512            id: NodeID::default(),
513        }
514    }
515}
516
517impl Canonicalize for DefinitionPlace {
518    fn canonicalize(self) -> Self {
519        match self {
520            DefinitionPlace::Single(id) => DefinitionPlace::Single(id.canonicalize()),
521            DefinitionPlace::Multiple(ids) => DefinitionPlace::Multiple(ids.canonicalize()),
522        }
523    }
524}
525
526impl Canonicalize for ExpressionStatement {
527    fn canonicalize(self) -> Self {
528        let Self { expression, span: _, id: _ } = self;
529        Self { expression: expression.canonicalize(), span: Span::default(), id: NodeID::default() }
530    }
531}
532
533impl Canonicalize for IterationStatement {
534    fn canonicalize(self) -> Self {
535        let Self { variable, type_, start, stop, inclusive, block, span: _, id: _ } = self;
536        Self {
537            variable: variable.canonicalize(),
538            type_: type_.canonicalize(),
539            start: start.canonicalize(),
540            stop: stop.canonicalize(),
541            inclusive,
542            block: block.canonicalize(),
543            span: Span::default(),
544            id: NodeID::default(),
545        }
546    }
547}
548
549impl Canonicalize for ReturnStatement {
550    fn canonicalize(self) -> Self {
551        let Self { expression, span: _, id: _ } = self;
552        Self { expression: expression.canonicalize(), span: Span::default(), id: NodeID::default() }
553    }
554}