Skip to main content

simplicityhl/
ast.rs

1use std::collections::hash_map::Entry;
2use std::collections::{HashMap, HashSet};
3use std::num::NonZeroUsize;
4use std::sync::Arc;
5
6use either::Either;
7use miniscript::iter::{Tree, TreeLike};
8use simplicity::jet::{Core, Elements, Jet};
9
10use crate::debug::{CallTracker, DebugSymbols, TrackedCallName};
11use crate::driver::{CRATE_STR, MAIN_STR};
12use crate::error::{Diagnostic, Error, Span, WithSpan};
13use crate::jet::{source_type, target_type, JetHL};
14use crate::num::{NonZeroPow2Usize, Pow2Usize};
15use crate::parse::{MatchPattern, UseDecl, Visibility};
16use crate::pattern::Pattern;
17use crate::str::{AliasName, FunctionName, Identifier, ModuleName, SymbolName, WitnessName};
18use crate::types::{
19    AliasedType, EnumInfo, EnumVariantInfo, ResolvedType, StructuralType, TypeConstructible,
20    TypeDeconstructible, TypeInner, UIntType,
21};
22use crate::value::{UIntValue, Value};
23use crate::witness::{Parameters, WitnessTypes};
24use crate::{impl_eq_hash, parse};
25
26/// A program consists of the main function.
27///
28/// Other items such as custom functions or type aliases
29/// are resolved during the creation of the AST.
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub struct Program {
32    main: Expression,
33    parameters: Parameters,
34    witness_types: WitnessTypes,
35    call_tracker: Arc<CallTracker>,
36}
37
38impl Program {
39    /// Access the main function.
40    ///
41    /// There is exactly one main function for each program.
42    pub fn main(&self) -> &Expression {
43        &self.main
44    }
45
46    /// Access the parameters of the program.
47    pub fn parameters(&self) -> &Parameters {
48        &self.parameters
49    }
50
51    /// Access the witness types of the program.
52    pub fn witness_types(&self) -> &WitnessTypes {
53        &self.witness_types
54    }
55
56    /// Access the debug symbols of the program.
57    pub fn debug_symbols(&self, file: &str) -> DebugSymbols {
58        self.call_tracker.with_file(file)
59    }
60
61    /// Access the tracker of function calls.
62    pub(crate) fn call_tracker(&self) -> &Arc<CallTracker> {
63        &self.call_tracker
64    }
65}
66
67/// An item is a component of a program.
68///
69/// All items except for the main function are resolved during the creation of the AST.
70#[derive(Clone, Debug, Eq, PartialEq, Hash)]
71pub enum Item {
72    /// A type alias.
73    ///
74    /// A stub because the alias was resolved during the creation of the AST.
75    TypeAlias,
76    /// An enum declaration.
77    ///
78    /// A stub because the declaration was resolved into scope during the
79    /// creation of the AST.
80    EnumDeclaration,
81    /// A function.
82    Function(Function),
83    Use,
84    Module(Vec<Item>),
85    /// A placeholder used for error recovery during parsing.
86    Ignored,
87}
88
89/// Definition of a function.
90///
91/// All functions except for the main function are resolved during the creation of the AST.
92#[derive(Clone, Debug, Eq, PartialEq, Hash)]
93pub enum Function {
94    /// A custom function.
95    ///
96    /// A stub because the definition of the function was moved to its calls in the main function.
97    Custom,
98    /// The main function.
99    ///
100    /// An expression that takes no inputs (unit) and that produces no output (unit).
101    /// The expression may panic midway through, signalling failure.
102    /// Otherwise, the expression signals success.
103    ///
104    /// This expression is evaluated when the program is run.
105    Main(Expression),
106}
107
108/// A statement is a component of a block expression.
109///
110/// Statements can define variables or run validating expressions,
111/// but they never return values.
112#[derive(Clone, Debug, Eq, PartialEq, Hash)]
113pub enum Statement {
114    /// Variable assignment.
115    Assignment(Assignment),
116    /// Expression that returns nothing (the unit value).
117    Expression(Expression),
118}
119
120/// Assignment of a value to a variable identifier.
121#[derive(Clone, Debug)]
122pub struct Assignment {
123    pattern: Pattern,
124    expression: Expression,
125    span: Span,
126}
127
128impl Assignment {
129    /// Access the pattern of the assignment.
130    pub fn pattern(&self) -> &Pattern {
131        &self.pattern
132    }
133
134    /// Access the expression of the assignment.
135    pub fn expression(&self) -> &Expression {
136        &self.expression
137    }
138
139    /// Access the span of the assignment.
140    pub fn span(&self) -> &Span {
141        &self.span
142    }
143}
144
145impl_eq_hash!(Assignment; pattern, expression);
146
147/// An expression returns a value.
148#[derive(Clone, Debug)]
149pub struct Expression {
150    inner: ExpressionInner,
151    ty: ResolvedType,
152    span: Span,
153}
154
155impl_eq_hash!(Expression; inner, ty);
156
157impl Expression {
158    /// Access the inner expression.
159    pub fn inner(&self) -> &ExpressionInner {
160        &self.inner
161    }
162
163    /// Access the type of the expression.
164    pub fn ty(&self) -> &ResolvedType {
165        &self.ty
166    }
167
168    /// Access the span of the expression.
169    pub fn span(&self) -> &Span {
170        &self.span
171    }
172}
173
174/// Variant of an expression.
175#[derive(Clone, Debug, Eq, PartialEq, Hash)]
176pub enum ExpressionInner {
177    /// A single expression directly returns a value.
178    Single(SingleExpression),
179    /// A block expression first executes a series of statements inside a local scope.
180    /// Then, the block returns the value of its final expression.
181    /// The block returns nothing (unit) if there is no final expression.
182    Block(Arc<[Statement]>, Option<Arc<Expression>>),
183}
184
185/// A single expression directly returns its value.
186#[derive(Clone, Debug)]
187pub struct SingleExpression {
188    inner: SingleExpressionInner,
189    ty: ResolvedType,
190    span: Span,
191}
192
193impl SingleExpression {
194    /// Create a tuple expression from the given arguments and span.
195    pub fn tuple(args: Arc<[Expression]>, span: Span) -> Self {
196        let ty = ResolvedType::tuple(
197            args.iter()
198                .map(Expression::ty)
199                .cloned()
200                .collect::<Vec<ResolvedType>>(),
201        );
202        let inner = SingleExpressionInner::Tuple(args);
203        Self { inner, ty, span }
204    }
205
206    /// Access the inner expression.
207    pub fn inner(&self) -> &SingleExpressionInner {
208        &self.inner
209    }
210
211    /// Access the type of the expression.
212    pub fn ty(&self) -> &ResolvedType {
213        &self.ty
214    }
215
216    /// Access the span of the expression.
217    pub fn span(&self) -> &Span {
218        &self.span
219    }
220}
221
222impl_eq_hash!(SingleExpression; inner, ty);
223
224/// Variant of a single expression.
225#[derive(Clone, Debug, Eq, PartialEq, Hash)]
226pub enum SingleExpressionInner {
227    /// Constant value.
228    Constant(Value),
229    /// Witness value.
230    Witness(WitnessName),
231    /// Parameter value.
232    Parameter(WitnessName),
233    /// Variable that has been assigned a value.
234    Variable(Identifier),
235    /// Expression in parentheses.
236    Expression(Arc<Expression>),
237    /// Tuple expression.
238    Tuple(Arc<[Expression]>),
239    /// Array expression.
240    Array(Arc<[Expression]>),
241    /// Bounded list of expressions.
242    List(Arc<[Expression]>),
243    /// Either expression.
244    Either(Either<Arc<Expression>, Arc<Expression>>),
245    /// Option expression.
246    Option(Option<Arc<Expression>>),
247    /// Call expression.
248    Call(Call),
249    /// Match expression.
250    Match(Match),
251    /// Match expression over an enum's variants.
252    EnumMatch(EnumMatch),
253    /// Construction of an enum variant.
254    ///
255    /// The enum's definition lives in the type of the expression.
256    EnumConstruction(EnumConstruction),
257}
258
259/// Call of a user-defined or of a builtin function.
260#[derive(Clone, Debug)]
261pub struct Call {
262    name: CallName,
263    args: Arc<[Expression]>,
264    span: Span,
265}
266
267impl Call {
268    /// Access the name of the call.
269    pub fn name(&self) -> &CallName {
270        &self.name
271    }
272
273    /// Access the arguments of the call.
274    pub fn args(&self) -> &Arc<[Expression]> {
275        &self.args
276    }
277
278    /// Access the span of the call.
279    pub fn span(&self) -> &Span {
280        &self.span
281    }
282}
283
284impl_eq_hash!(Call; name, args);
285
286/// Name of a called function.
287#[derive(Clone, Debug, Eq, Hash)]
288#[allow(clippy::derived_hash_with_manual_eq)] // see comment on manual `PartialEq` impl below
289pub enum CallName {
290    /// Jet type.
291    Jet(Box<dyn JetHL>),
292    /// [`Either::unwrap_left`].
293    UnwrapLeft(ResolvedType),
294    /// [`Either::unwrap_right`].
295    UnwrapRight(ResolvedType),
296    /// [`Option::is_none`].
297    IsNone(ResolvedType),
298    /// [`Option::unwrap`].
299    Unwrap,
300    /// [`assert!`].
301    Assert,
302    /// [`panic!`] without error message.
303    Panic,
304    /// [`dbg!`].
305    Debug,
306    /// Cast from the given source type.
307    TypeCast(ResolvedType),
308    /// A custom function that was defined previously.
309    ///
310    /// We effectively copy the function body into every call of the function.
311    /// We use [`Arc`] for cheap clones during this process.
312    Custom(CustomFunction),
313    /// Fold of a bounded list with the given function.
314    Fold(CustomFunction, NonZeroPow2Usize),
315    /// Fold of an array with the given function.
316    ArrayFold(CustomFunction, NonZeroUsize),
317    /// Loop over the given function a bounded number of times until it returns success.
318    ForWhile(CustomFunction, Pow2Usize),
319}
320
321// Manually implemented because the 1.74 (MSRV) derive expands to a body that
322// moves out of the non-Copy `Box<dyn Jet>` field, later rustc versions are
323// fine.
324impl PartialEq for CallName {
325    fn eq(&self, other: &Self) -> bool {
326        match (self, other) {
327            (Self::Jet(a), Self::Jet(b)) => a == b,
328            (Self::UnwrapLeft(a), Self::UnwrapLeft(b)) => a == b,
329            (Self::UnwrapRight(a), Self::UnwrapRight(b)) => a == b,
330            (Self::IsNone(a), Self::IsNone(b)) => a == b,
331            (Self::Unwrap, Self::Unwrap) => true,
332            (Self::Assert, Self::Assert) => true,
333            (Self::Panic, Self::Panic) => true,
334            (Self::Debug, Self::Debug) => true,
335            (Self::TypeCast(a), Self::TypeCast(b)) => a == b,
336            (Self::Custom(a), Self::Custom(b)) => a == b,
337            (Self::Fold(a, b), Self::Fold(c, d)) => a == c && b == d,
338            (Self::ArrayFold(a, b), Self::ArrayFold(c, d)) => a == c && b == d,
339            (Self::ForWhile(a, b), Self::ForWhile(c, d)) => a == c && b == d,
340            _ => false,
341        }
342    }
343}
344
345/// Definition of a custom function.
346#[derive(Clone, Debug)]
347pub struct CustomFunction {
348    params: Arc<[FunctionParam]>,
349    body: Arc<Expression>,
350    span: Span,
351}
352
353impl CustomFunction {
354    /// Access the identifiers of the parameters of the function.
355    pub fn params(&self) -> &[FunctionParam] {
356        &self.params
357    }
358
359    /// Access the body of the function.
360    pub fn body(&self) -> &Expression {
361        &self.body
362    }
363
364    /// Access the span of the complete function declaration.
365    pub fn span(&self) -> &Span {
366        &self.span
367    }
368
369    /// Return a pattern for the parameters of the function.
370    pub fn params_pattern(&self) -> Pattern {
371        Pattern::tuple(
372            self.params()
373                .iter()
374                .map(FunctionParam::identifier)
375                .cloned()
376                .map(Pattern::Identifier),
377        )
378    }
379}
380
381impl_eq_hash!(CustomFunction; params, body);
382
383/// Parameter of a function.
384#[derive(Clone, Debug)]
385pub struct FunctionParam {
386    identifier: Identifier,
387    ty: ResolvedType,
388    span: Span,
389}
390
391impl FunctionParam {
392    /// Access the identifier of the parameter.
393    pub fn identifier(&self) -> &Identifier {
394        &self.identifier
395    }
396
397    /// Access the type of the parameter.
398    pub fn ty(&self) -> &ResolvedType {
399        &self.ty
400    }
401
402    /// Access the span of the complete parameter declaration.
403    pub fn span(&self) -> &Span {
404        &self.span
405    }
406}
407
408impl_eq_hash!(FunctionParam; identifier, ty);
409
410/// Match expression.
411#[derive(Clone, Debug)]
412pub struct Match {
413    scrutinee: Arc<Expression>,
414    left: MatchArm,
415    right: MatchArm,
416    span: Span,
417}
418
419impl Match {
420    /// Access the expression whose output is destructed in the match statement.
421    pub fn scrutinee(&self) -> &Expression {
422        &self.scrutinee
423    }
424
425    /// Access the branch that handles structural left values.
426    pub fn left(&self) -> &MatchArm {
427        &self.left
428    }
429
430    /// Access the branch that handles structural right values.
431    pub fn right(&self) -> &MatchArm {
432        &self.right
433    }
434
435    /// Access the span of the match statement.
436    pub fn span(&self) -> &Span {
437        &self.span
438    }
439}
440
441impl_eq_hash!(Match; scrutinee, left, right);
442
443/// Match expression over an enum's variants.
444#[derive(Clone, Debug)]
445pub struct EnumMatch {
446    scrutinee: Arc<Expression>,
447    /// Arms in variant order (declaration order).
448    ///
449    /// The order matches the leaf order of the enum's balanced sum.
450    arms: Arc<[EnumMatchArm]>,
451    span: Span,
452}
453
454impl EnumMatch {
455    /// Access the expression whose output is dispatched on in the match statement.
456    pub fn scrutinee(&self) -> &Expression {
457        &self.scrutinee
458    }
459
460    /// Access the arms in variant order (declaration order).
461    pub fn arms(&self) -> &[EnumMatchArm] {
462        &self.arms
463    }
464
465    /// Access the span of the match statement.
466    pub fn span(&self) -> &Span {
467        &self.span
468    }
469}
470
471impl_eq_hash!(EnumMatch; scrutinee, arms);
472
473/// Arm of an [`EnumMatch`] expression, ordered by variant.
474#[derive(Clone, Debug)]
475pub struct EnumMatchArm {
476    /// Pattern binding the variant's payload. [`Pattern::Ignore`] for unit
477    /// variants.
478    pattern: Pattern,
479    body: Arc<Expression>,
480    span: Span,
481}
482
483impl EnumMatchArm {
484    /// Access the pattern that binds the variant's payload.
485    pub fn pattern(&self) -> &Pattern {
486        &self.pattern
487    }
488
489    /// Access the expression that is executed in the match arm.
490    pub fn body(&self) -> &Expression {
491        &self.body
492    }
493
494    /// Access the span of the complete enum match arm.
495    pub fn span(&self) -> &Span {
496        &self.span
497    }
498}
499
500impl_eq_hash!(EnumMatchArm; pattern, body);
501
502/// Construction of an enum variant: the variant's position and its payload
503/// expressions. The enum's definition lives in the type of the enclosing
504/// [`SingleExpression`].
505#[derive(Clone, Debug)]
506pub struct EnumConstruction {
507    variant_index: usize,
508    payload: Arc<[Arc<Expression>]>,
509    span: Span,
510}
511
512impl EnumConstruction {
513    /// Access the constructed variant's position among the declared variants.
514    pub fn variant_index(&self) -> usize {
515        self.variant_index
516    }
517
518    /// Access the payload expressions. Empty for unit variants.
519    pub fn payload(&self) -> &[Arc<Expression>] {
520        &self.payload
521    }
522}
523
524impl_eq_hash!(EnumConstruction; variant_index, payload);
525
526impl AsRef<Span> for EnumConstruction {
527    fn as_ref(&self) -> &Span {
528        &self.span
529    }
530}
531
532impl AsRef<Span> for EnumMatch {
533    fn as_ref(&self) -> &Span {
534        &self.span
535    }
536}
537
538/// Arm of a [`Match`] expression.
539#[derive(Clone, Debug)]
540pub struct MatchArm {
541    pattern: MatchPattern,
542    expression: Arc<Expression>,
543    span: Span,
544}
545
546impl MatchArm {
547    /// Access the pattern of the match arm.
548    pub fn pattern(&self) -> &MatchPattern {
549        &self.pattern
550    }
551
552    /// Access the expression of the match arm.
553    pub fn expression(&self) -> &Expression {
554        &self.expression
555    }
556
557    /// Access the span of the complete match arm.
558    pub fn span(&self) -> &Span {
559        &self.span
560    }
561}
562
563impl_eq_hash!(MatchArm; pattern, expression);
564
565#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
566pub enum ExprTree<'a> {
567    Expression(&'a Expression),
568    Block(&'a [Statement], &'a Option<Arc<Expression>>),
569    Statement(&'a Statement),
570    Assignment(&'a Assignment),
571    Single(&'a SingleExpression),
572    Call(&'a Call),
573    Match(&'a Match),
574    EnumMatch(&'a EnumMatch),
575}
576
577impl TreeLike for ExprTree<'_> {
578    fn as_node(&self) -> Tree<Self> {
579        use SingleExpressionInner as S;
580
581        match self {
582            Self::Expression(expr) => match expr.inner() {
583                ExpressionInner::Block(statements, maybe_expr) => {
584                    Tree::Unary(Self::Block(statements, maybe_expr))
585                }
586                ExpressionInner::Single(single) => Tree::Unary(Self::Single(single)),
587            },
588            Self::Block(statements, maybe_expr) => Tree::Nary(
589                statements
590                    .iter()
591                    .map(Self::Statement)
592                    .chain(maybe_expr.iter().map(Arc::as_ref).map(Self::Expression))
593                    .collect(),
594            ),
595            Self::Statement(statement) => match statement {
596                Statement::Assignment(assignment) => Tree::Unary(Self::Assignment(assignment)),
597                Statement::Expression(expression) => Tree::Unary(Self::Expression(expression)),
598            },
599            Self::Assignment(assignment) => Tree::Unary(Self::Expression(assignment.expression())),
600            Self::Single(single) => match single.inner() {
601                S::Constant(_)
602                | S::Witness(_)
603                | S::Parameter(_)
604                | S::Variable(_)
605                | S::Option(None) => Tree::Nullary,
606                S::Expression(l)
607                | S::Either(Either::Left(l))
608                | S::Either(Either::Right(l))
609                | S::Option(Some(l)) => Tree::Unary(Self::Expression(l)),
610                S::Tuple(elements) | S::Array(elements) | S::List(elements) => {
611                    Tree::Nary(elements.iter().map(Self::Expression).collect())
612                }
613                S::Call(call) => Tree::Unary(Self::Call(call)),
614                S::Match(match_) => Tree::Unary(Self::Match(match_)),
615                S::EnumMatch(enum_match) => Tree::Unary(Self::EnumMatch(enum_match)),
616                S::EnumConstruction(construction) => Tree::Nary(
617                    construction
618                        .payload()
619                        .iter()
620                        .map(|arg| Self::Expression(arg))
621                        .collect(),
622                ),
623            },
624            Self::Call(call) => Tree::Nary(call.args().iter().map(Self::Expression).collect()),
625            Self::Match(match_) => Tree::Nary(Arc::new([
626                Self::Expression(match_.scrutinee()),
627                Self::Expression(match_.left().expression()),
628                Self::Expression(match_.right().expression()),
629            ])),
630            Self::EnumMatch(enum_match) => Tree::Nary(
631                std::iter::once(Self::Expression(enum_match.scrutinee()))
632                    .chain(
633                        enum_match
634                            .arms()
635                            .iter()
636                            .map(|arm| Self::Expression(arm.body())),
637                    )
638                    .collect(),
639            ),
640        }
641    }
642}
643
644/// Object which produces a specific kind of jet.
645///
646/// All methods return a `dyn Jet` rather than the specific jet so that the trait itself
647/// can be object-safe. However, implementors of this trait **must** ensure that
648/// all methods return the same kind of jet to avoid panics.
649///
650/// Users may rely on this property for correctness of their code, though since this
651/// is a safe trait, of course they may not rely on it for soundness.
652pub trait JetHinter: std::fmt::Debug + Send + Sync {
653    /// Attempts to parse a jet from a string.
654    fn parse_jet(&self, name: &str) -> Option<Box<dyn JetHL>>;
655    /// Constructs an instance of the `verify` jet.
656    fn construct_verify(&self) -> Box<dyn JetHL>;
657    /// Converts a runtime Simplicity jet back into this hinter's high-level jet.
658    fn conjure(&self, jet: &dyn Jet) -> Option<Box<dyn JetHL>>;
659
660    /// Clones the `JetHinter` into a boxed trait object.
661    fn clone_box(&self) -> Box<dyn JetHinter>;
662}
663
664macro_rules! impl_jet_hinter {
665    ($struct_name:ident, $jet_type:ident) => {
666        #[derive(Clone, Debug, Default)]
667        pub struct $struct_name;
668
669        impl $struct_name {
670            pub fn new() -> Self {
671                Self
672            }
673        }
674
675        impl JetHinter for $struct_name {
676            fn parse_jet(&self, name: &str) -> Option<Box<dyn JetHL>> {
677                $jet_type::parse(name)
678                    .ok()
679                    .map(|jet| -> Box<dyn JetHL> { Box::new(jet) })
680            }
681
682            fn construct_verify(&self) -> Box<dyn JetHL> {
683                Box::new($jet_type::Verify)
684            }
685
686            fn conjure(&self, jet: &dyn Jet) -> Option<Box<dyn JetHL>> {
687                jet.as_any()
688                    .downcast_ref::<$jet_type>()
689                    .map(|jet| Box::new(*jet) as Box<dyn JetHL>)
690            }
691
692            fn clone_box(&self) -> Box<dyn JetHinter> {
693                Box::new(Self)
694            }
695        }
696    };
697}
698
699impl_jet_hinter!(ElementsJetHinter, Elements);
700impl_jet_hinter!(CoreJetHinter, Core);
701
702/// A single module namespace. Handles arbitrary nesting via `submodules`.
703#[derive(Clone, Debug, Eq, PartialEq, Default)]
704struct ModuleScope {
705    aliases: HashMap<AliasName, (ResolvedType, Visibility)>,
706    functions: HashMap<FunctionName, (CustomFunction, Visibility)>,
707    /// Nested inling `mod` blocks, each becoming a child scope.
708    submodules: HashMap<ModuleName, (ModuleScope, Visibility)>,
709}
710
711/// Scope for generating the abstract syntax tree.
712///
713/// The scope is used for:
714/// 1. Assigning types to each variable
715/// 2. Resolving type aliases
716/// 3. Assigning types to each witness expression
717/// 4. Resolving calls to custom functions
718struct Scope {
719    /// Current position in the module tree. Push on `mod` enter, pop on exit.
720    /// Empty path means we are at the root (main file) scope.
721    module_path: Vec<ModuleName>,
722
723    /// Global scope where items from the main file that live at the root level.
724    root: ModuleScope,
725
726    /// Block-level variable scopes. Push on block enter, pop on block exit.
727    variables: Vec<HashMap<Identifier, ResolvedType>>,
728    parameters: HashMap<WitnessName, ResolvedType>,
729    witnesses: HashMap<WitnessName, ResolvedType>,
730    /// Allow enum constructions to name an enum by its declared name even
731    /// when that name is not an alias in scope. Enabled only for value
732    /// parsing (witness and argument files), which runs without a scope.
733    unscoped_enum_names: bool,
734    is_main: bool,
735    call_tracker: CallTracker,
736    jet_hinter: Box<dyn JetHinter>,
737}
738
739impl Default for Scope {
740    fn default() -> Self {
741        Self::new(
742            // TODO: Should be passed in global configuration
743            Box::new(ElementsJetHinter),
744        )
745    }
746}
747
748impl Scope {
749    pub fn new(jet_hinter: Box<dyn JetHinter>) -> Self {
750        Self {
751            module_path: Vec::new(),
752            root: ModuleScope::default(),
753            variables: Vec::new(),
754            parameters: HashMap::new(),
755            witnesses: HashMap::new(),
756            unscoped_enum_names: false,
757            is_main: false,
758            call_tracker: CallTracker::default(),
759            jet_hinter,
760        }
761    }
762
763    /// Scope for parsing values from witness and argument files: empty,
764    /// except that enum constructions may name an enum by its declared name.
765    fn for_value_parsing() -> Self {
766        Self {
767            unscoped_enum_names: true,
768            ..Self::default()
769        }
770    }
771
772    pub fn is_outside_function(&self) -> bool {
773        self.variables.is_empty()
774    }
775
776    /// Enter a new block inside the current function.
777    pub fn enter_block(&mut self) {
778        self.variables.push(HashMap::new());
779    }
780
781    /// Push the scope of the main function onto the stack.
782    ///
783    /// ## Panics
784    ///
785    /// - Already inside the main function.
786    /// - Already inside a function body.
787    pub fn enter_main(&mut self) {
788        assert!(!self.is_main, "Already inside main function");
789        assert!(self.is_outside_function(), "Already inside a function body");
790        self.enter_block();
791        self.is_main = true;
792    }
793
794    /// Exit the current block inside the curreent function.
795    ///
796    /// ## Panics
797    ///
798    /// - No acive block to exit.
799    pub fn exit_block(&mut self) {
800        self.variables.pop().expect("No active block to exit");
801    }
802
803    /// Pop the scope of the main function from the stack.
804    ///
805    /// ## Panics
806    ///
807    /// - Not inside the main function.
808    /// - Unclosed nested blocks remain.
809    pub fn exit_main(&mut self) {
810        assert!(self.is_main, "Current scope is not inside main function");
811        self.exit_block();
812        self.is_main = false;
813        assert!(
814            self.is_outside_function(),
815            "Current scope is not nested in topmost scope"
816        )
817    }
818
819    /// Enter a named module, pushing it onto the module path.
820    ///
821    /// ## Errors
822    ///
823    /// * [`Error::ModuleRedefined`] A module with this name is already defined in the current scope.
824    pub fn enter_module(&mut self, name: ModuleName, visibility: Visibility) -> Result<(), Error> {
825        let current = self.current_module_mut();
826        if current.submodules.contains_key(&name) {
827            return Err(Error::ModuleRedefined { name });
828        }
829
830        current
831            .submodules
832            .insert(name.clone(), (ModuleScope::default(), visibility));
833        self.module_path.push(name);
834        Ok(())
835    }
836
837    /// Exit the current module, popping it from the module path.
838    ///
839    /// ## Panics
840    ///
841    /// Not inside any module.
842    pub fn exit_module(&mut self) {
843        self.module_path.pop().expect("Not inside any module");
844    }
845
846    /// This allows us to perform read-only checks (like redefinitions) and
847    /// call `resolve` without taking a premature mutable borrow of `self`.
848    fn current_module(&self) -> &ModuleScope {
849        self.module_path.iter().fold(&self.root, |scope, segment| {
850            &scope.submodules.get(segment).expect("Module not found").0
851        })
852    }
853
854    /// We use iterations and `O(N)` algorithm, because nested block are not so deep.
855    /// It will be strange to see 100 nested blocks, so common `.fold()` will be enough for that.
856    fn current_module_mut(&mut self) -> &mut ModuleScope {
857        self.module_path
858            .iter()
859            .fold(&mut self.root, |scope, segment| {
860                &mut scope
861                    .submodules
862                    .get_mut(segment)
863                    .expect("Module not found")
864                    .0
865            })
866    }
867
868    // TODO: Consider to optimize it (we definitely can do it)
869    /// Resolves a `use` declaration by navigating the module tree, checking visibility,
870    /// and importing matching items into the current scope.
871    ///
872    /// ## Errors
873    ///
874    /// * [`Error::MissingCrateKeyword`] The import path does not start with the `crate` keyword.
875    /// * [`Error::ModuleNotFound`] A module segment in the target path does not exist.
876    /// * [`Error::ModuleIsPrivate`] Attempted to navigate into a private module from an unauthorized scope.
877    /// * [`Error::MainCannotBeAlias`] Attempted to alias an imported item to the reserved `main` identifier.
878    /// * May also return errors propagated from item collection and insertion, such as [`Error::PrivateItem`] or [`Error::RedefinedItem`].
879    pub fn resolve_use(&mut self, use_decl: &UseDecl) -> Result<(), Error> {
880        let path = use_decl.path();
881        if path.first().map(|id| id.as_inner()) != Some(CRATE_STR) {
882            return Err(Error::MissingCrateKeyword);
883        }
884
885        let use_vis = use_decl.visibility().clone();
886        let use_decl_items = match use_decl.items() {
887            parse::UseItems::Single(elem) => std::slice::from_ref(elem),
888            parse::UseItems::List(elems) => elems.as_slice(),
889        };
890
891        // Phase 1: navigate to target and collect items. Immutable borrow, dropped at end of block
892        // Vec<(ProcessedAlias, ProcessedFunction, ProcessedModule)>
893        // where each is Result<(Key, (Value, Visibility)), Error>
894        let collected: Vec<_> = {
895            // TODO: Part, that can be optimized
896            // How many segments do the caller's path and the target's path have in common?
897            let shared_prefix_len = self
898                .module_path
899                .iter()
900                .zip(&path[1..])
901                .take_while(|(curr, nav)| curr.as_inner() == nav.as_inner())
902                .count();
903
904            let mut target_scope = &self.root;
905
906            for (ind, segment) in path[1..].iter().enumerate() {
907                let name = ModuleName::from_str_unchecked(segment.as_inner());
908
909                let (inner, visibility) = target_scope
910                    .submodules
911                    .get(&name)
912                    .ok_or_else(|| Error::ModuleNotFound { name: name.clone() })?;
913
914                if matches!(visibility, Visibility::Private) && shared_prefix_len < ind {
915                    return Err(Error::ModuleIsPrivate { name });
916                }
917
918                target_scope = inner;
919            }
920
921            let mut collected = Vec::with_capacity(use_decl_items.len());
922            for (name, aliased) in use_decl_items {
923                if aliased.as_ref().is_some_and(|a| a.as_inner() == MAIN_STR) {
924                    return Err(Error::MainCannotBeAlias);
925                }
926
927                let local_name = aliased.as_ref().unwrap_or(name);
928
929                let alias_res =
930                    Self::try_collect_item(name, local_name, &target_scope.aliases, &use_vis);
931                let func_res =
932                    Self::try_collect_item(name, local_name, &target_scope.functions, &use_vis);
933                let mod_res =
934                    Self::try_collect_item(name, local_name, &target_scope.submodules, &use_vis);
935
936                collected.push((alias_res, func_res, mod_res));
937            }
938            collected
939        };
940
941        // Phase 2: insert into current scope
942        let current = self.current_module_mut();
943        for (alias_res, func_res, mod_res) in collected {
944            Self::resolve_processing_use_items_error(&[
945                Self::insert_collected(alias_res, &mut current.aliases),
946                Self::insert_collected(func_res, &mut current.functions),
947                Self::insert_collected(mod_res, &mut current.submodules),
948            ])?;
949        }
950
951        Ok(())
952    }
953
954    /// Attempts to find `name` in `target_map` and prepare it for import into another scope.
955    ///
956    /// ## Errors
957    ///
958    /// * [`Error::UnresolvedItem`] The requested `name` was not found in the `target_map`.
959    /// * [`Error::PrivateItem`] The requested item exists in the map, but its visibility is restricted to private.
960    fn try_collect_item<K, V>(
961        name: &SymbolName,
962        local_name: &SymbolName,
963        target_map: &HashMap<K, (V, Visibility)>,
964        use_vis: &Visibility,
965    ) -> Result<(K, (V, Visibility)), Error>
966    where
967        K: Eq + std::hash::Hash + From<SymbolName> + Clone,
968        V: Clone,
969    {
970        let (value, vis) =
971            target_map
972                .get(&K::from(name.clone()))
973                .ok_or_else(|| Error::UnresolvedItem {
974                    name: name.to_string(),
975                })?;
976
977        if matches!(vis, Visibility::Private) {
978            return Err(Error::PrivateItem {
979                name: name.to_string(),
980            });
981        }
982
983        Ok((
984            K::from(local_name.clone()),
985            (value.clone(), use_vis.clone()),
986        ))
987    }
988
989    /// Inserts a successfully collected item into the current scope's map.
990    ///
991    /// ## Errors
992    ///
993    /// * [`Error::RedefinedItem`] An item with the same name is already defined in the target scope.
994    /// * Propagates any upstream resolution error passed into the `res` argument.
995    fn insert_collected<K, V>(
996        res: Result<(K, (V, Visibility)), Error>,
997        map: &mut HashMap<K, (V, Visibility)>,
998    ) -> Result<(), Error>
999    where
1000        K: Eq + std::hash::Hash + std::fmt::Display,
1001    {
1002        res.and_then(|(k, v)| match map.entry(k) {
1003            Entry::Occupied(entry) => Err(Error::RedefinedItem {
1004                name: entry.key().to_string(),
1005            }),
1006            Entry::Vacant(entry) => {
1007                entry.insert(v);
1008                Ok(())
1009            }
1010        })
1011    }
1012
1013    // TODO: Consider to use better error handling
1014    /// Evaluates the results of attempting to collect an item from multiple namespaces
1015    /// (aliases, functions, submodules) and resolves the final error state.
1016    ///
1017    /// ## Errors
1018    ///
1019    /// * Returns a specific error (e.g., [`Error::PrivateItem`], [`Error::RedefinedItem`]) if one occurred.
1020    /// * Returns a fallback [`Error::UnresolvedItem`] if the item could not be found in any of the checked namespaces.
1021    fn resolve_processing_use_items_error(results: &[Result<(), Error>]) -> Result<(), Error> {
1022        if results.iter().any(|res| res.is_ok()) {
1023            return Ok(());
1024        }
1025
1026        let errors: Vec<&Error> = results
1027            .iter()
1028            .filter_map(|res| res.as_ref().err())
1029            .collect();
1030
1031        if let Some(&specific_err) = errors
1032            .iter()
1033            .find(|e| !matches!(e, Error::UnresolvedItem { .. }))
1034        {
1035            return Err(specific_err.clone());
1036        }
1037
1038        // Fallback to the first `UnresolvedItem` error
1039        Err(errors[0].clone())
1040    }
1041
1042    /// Insert a variable into the current block.
1043    ///
1044    /// ## Panics
1045    ///
1046    /// - No active block.
1047    pub fn insert_variable(&mut self, identifier: Identifier, ty: ResolvedType) {
1048        self.variables
1049            .last_mut()
1050            .expect("Stack is empty")
1051            .insert(identifier, ty);
1052    }
1053
1054    /// Get the type of the variable.
1055    pub fn get_variable(&self, identifier: &Identifier) -> Option<&ResolvedType> {
1056        self.variables
1057            .iter()
1058            .rev()
1059            .find_map(|scope| scope.get(identifier))
1060    }
1061
1062    /// Retrieves the resolved type of a type alias in the current module scope.
1063    ///
1064    /// ## Errors
1065    ///
1066    /// * [`Error::UndefinedAlias`]: The alias is not defined in the current scope.
1067    fn get_alias(&self, name: &AliasName) -> Result<ResolvedType, Error> {
1068        self.current_module()
1069            .aliases
1070            .get(name)
1071            .map(|(ty, _)| ty.clone())
1072            .ok_or_else(|| Error::UndefinedAlias { name: name.clone() })
1073    }
1074
1075    /// Resolve a type with aliases to a type without aliases.
1076    ///
1077    /// ## Errors
1078    ///
1079    /// * [`Error::UndefinedAlias`]: The alias is not found in the global registry.
1080    pub fn resolve(&self, ty: &AliasedType) -> Result<ResolvedType, Error> {
1081        ty.resolve(|name| self.get_alias(name))
1082    }
1083
1084    /// Error if `name` is already defined as an alias in the current module.
1085    fn check_alias_free(&self, name: &AliasName) -> Result<(), Error> {
1086        if self.current_module().aliases.contains_key(name) {
1087            return Err(Error::RedefinedAlias { name: name.clone() });
1088        }
1089
1090        Ok(())
1091    }
1092
1093    /// Insert a type alias into the current module scope.
1094    ///
1095    /// ## Errors
1096    ///
1097    /// * [`Error::RedefinedAlias`]: The alias name is already defined in the current scope.
1098    pub fn insert_alias(&mut self, alias: parse::TypeAlias) -> Result<(), Error> {
1099        self.check_alias_free(alias.name())?;
1100
1101        let resolved = self.resolve(alias.ty())?;
1102
1103        self.current_module_mut()
1104            .aliases
1105            .insert(alias.name().clone(), (resolved, alias.visibility().clone()));
1106
1107        Ok(())
1108    }
1109
1110    /// Insert an enum declaration into the current module.
1111    ///
1112    /// An enum is a type alias for a nominal enum type, so its name resolves as a type
1113    /// and its identity travels wherever the alias is imported.
1114    ///
1115    /// Enums may only be declared at the top level of the program's own files
1116    /// (the parser rejects declarations inside `mod` blocks, the driver rejects them in dependency files),
1117    /// so the bare name is unique program-wide and identifies the enum in the ABI.
1118    ///
1119    /// ## Errors
1120    ///
1121    /// * [`Error::RedefinedAlias`]: The name is already defined in the current module.
1122    pub fn insert_enum(
1123        &mut self,
1124        name: AliasName,
1125        visibility: Visibility,
1126        variants: Arc<[EnumVariantInfo]>,
1127    ) -> Result<(), Error> {
1128        self.check_alias_free(&name)?;
1129
1130        let info = EnumInfo::new(Arc::from(name.as_inner()), variants);
1131        let resolved = ResolvedType::enumeration(info);
1132
1133        self.current_module_mut()
1134            .aliases
1135            .insert(name, (resolved, visibility));
1136
1137        Ok(())
1138    }
1139
1140    /// Insert a parameter into the global map.
1141    ///
1142    /// ## Errors
1143    ///
1144    /// * [`Error::ExpressionTypeMismatch`] A parameter of the same name has already been defined as a different type.
1145    pub fn insert_parameter(&mut self, name: WitnessName, ty: ResolvedType) -> Result<(), Error> {
1146        match self.parameters.entry(name.clone()) {
1147            Entry::Occupied(entry) if entry.get() == &ty => Ok(()),
1148            Entry::Occupied(entry) => Err(Error::ExpressionTypeMismatch {
1149                expected: entry.get().clone(),
1150                found: ty,
1151            }),
1152            Entry::Vacant(entry) => {
1153                entry.insert(ty);
1154                Ok(())
1155            }
1156        }
1157    }
1158
1159    /// Insert a witness into the global map.
1160    ///
1161    /// ## Errors
1162    ///
1163    /// * [`Error::WitnessOutsideMain`] The current scope is not inside the main function.
1164    /// * [`Error::WitnessReused`] A witness with the same name has already been defined.
1165    pub fn insert_witness(&mut self, name: WitnessName, ty: ResolvedType) -> Result<(), Error> {
1166        if !self.is_main {
1167            return Err(Error::WitnessOutsideMain);
1168        }
1169
1170        match self.witnesses.entry(name.clone()) {
1171            Entry::Occupied(_) => Err(Error::WitnessReused { name }),
1172            Entry::Vacant(entry) => {
1173                entry.insert(ty);
1174                Ok(())
1175            }
1176        }
1177    }
1178
1179    /// Consume the scope and return its contents:
1180    ///
1181    /// 1. The map of parameter types.
1182    /// 2. The map of witness types.
1183    /// 3. The function call tracker.
1184    pub fn destruct(self) -> (Parameters, WitnessTypes, CallTracker) {
1185        (
1186            Parameters::from(self.parameters),
1187            WitnessTypes::from(self.witnesses),
1188            self.call_tracker,
1189        )
1190    }
1191
1192    /// Insert a custom function into the global map.
1193    ///
1194    /// ## Errors
1195    ///
1196    /// * [`Error::FunctionRedefined`] The function has already been defined.
1197    pub fn insert_function(
1198        &mut self,
1199        name: FunctionName,
1200        visibility: Visibility,
1201        function: CustomFunction,
1202    ) -> Result<(), Error> {
1203        if self.current_module().functions.contains_key(&name) {
1204            return Err(Error::FunctionRedefined { name });
1205        }
1206
1207        self.current_module_mut()
1208            .functions
1209            .insert(name, (function, visibility));
1210        Ok(())
1211    }
1212
1213    /// Retrieves the definition of a custom function, enforcing strict error prioritization.
1214    ///
1215    /// ## Errors
1216    ///
1217    /// * [`Error::FunctionUndefined`]: The function is not found in the global registry.
1218    pub fn get_function(&self, name: &FunctionName) -> Result<CustomFunction, Error> {
1219        self.current_module()
1220            .functions
1221            .get(name)
1222            .map(|(func, _)| func.clone())
1223            .ok_or_else(|| Error::FunctionUndefined { name: name.clone() })
1224    }
1225
1226    /// Track a call expression with its span.
1227    pub fn track_call<S: AsRef<Span>>(&mut self, span: &S, name: TrackedCallName) {
1228        self.call_tracker.track_call(*span.as_ref(), name);
1229    }
1230}
1231
1232/// Part of the abstract syntax tree that can be generated from a precursor in the parse tree.
1233trait AbstractSyntaxTree: Sized {
1234    /// Component of the parse tree.
1235    type From;
1236
1237    /// Analyze a component from the parse tree
1238    /// and convert it into a component of the abstract syntax tree.
1239    ///
1240    /// Check if the analyzed expression is of the expected type.
1241    /// Statements return no values so their expected type is always unit.
1242    fn analyze(from: &Self::From, ty: &ResolvedType, scope: &mut Scope)
1243        -> Result<Self, Diagnostic>;
1244}
1245
1246impl Program {
1247    pub fn analyze(
1248        from: &parse::Program,
1249        jet_hinter: Box<dyn JetHinter>,
1250    ) -> Result<Self, Diagnostic> {
1251        let unit = ResolvedType::unit();
1252        let mut scope = Scope::new(jet_hinter);
1253
1254        let items = from
1255            .items()
1256            .iter()
1257            .map(|s| Item::analyze(s, &unit, &mut scope))
1258            .collect::<Result<Vec<Item>, Diagnostic>>()?;
1259        debug_assert!(scope.is_outside_function());
1260        debug_assert!(
1261            scope.module_path.is_empty(),
1262            "Unclosed module scopes remain"
1263        );
1264
1265        let (parameters, witness_types, call_tracker) = scope.destruct();
1266        let main = Self::extract_single_main(&items)
1267            // If we find a duplicate of main function
1268            .map_err(|err| err.with_span(from.into()))?
1269            .ok_or(Error::MainRequired)
1270            .with_span(from)?;
1271
1272        Ok(Self {
1273            main,
1274            parameters,
1275            witness_types,
1276            call_tracker: Arc::new(call_tracker),
1277        })
1278    }
1279
1280    fn extract_single_main(items: &[Item]) -> Result<Option<Expression>, Error> {
1281        let mut main_expr = None;
1282
1283        for item in items {
1284            let extracted = match item {
1285                Item::Function(Function::Main(expr)) => Some(expr.clone()),
1286                Item::Module(items) => Self::extract_single_main(items)?,
1287                _ => None,
1288            };
1289
1290            let Some(expr) = extracted else {
1291                continue;
1292            };
1293
1294            if main_expr.replace(expr).is_some() {
1295                return Err(Error::FunctionRedefined {
1296                    name: FunctionName::main(),
1297                });
1298            }
1299        }
1300
1301        Ok(main_expr)
1302    }
1303}
1304
1305impl AbstractSyntaxTree for Item {
1306    type From = parse::Item;
1307
1308    fn analyze(
1309        from: &Self::From,
1310        ty: &ResolvedType,
1311        scope: &mut Scope,
1312    ) -> Result<Self, Diagnostic> {
1313        assert!(ty.is_unit(), "Items cannot return anything");
1314        assert!(
1315            scope.is_outside_function(),
1316            "Variables live only inside the function"
1317        );
1318
1319        match from {
1320            parse::Item::TypeAlias(alias) => {
1321                scope.insert_alias(alias.clone()).with_span(alias)?;
1322                Ok(Self::TypeAlias)
1323            }
1324            parse::Item::Function(function) => {
1325                Function::analyze(function, ty, scope).map(Self::Function)
1326            }
1327            parse::Item::Use(use_decl) => {
1328                scope.resolve_use(use_decl).with_span(use_decl)?;
1329                Ok(Self::Use)
1330            }
1331            parse::Item::EnumDeclaration(decl) => {
1332                if decl.variants().is_empty() {
1333                    // A sum of zero types would be uninhabited, which
1334                    // Simplicity's type algebra cannot express.
1335                    return Err(Error::Grammar {
1336                        msg: format!("enum '{}' must have at least one variant", decl.name()),
1337                    })
1338                    .with_span(decl);
1339                }
1340
1341                let mut seen_names = HashSet::new();
1342                for v in decl.variants() {
1343                    if !seen_names.insert(v.name()) {
1344                        return Err(Error::Grammar {
1345                            msg: format!(
1346                                "enum '{}' has duplicate variant name '{}'",
1347                                decl.name(),
1348                                v.name()
1349                            ),
1350                        })
1351                        .with_span(decl);
1352                    }
1353                }
1354
1355                let variants = decl
1356                    .variants()
1357                    .iter()
1358                    .map(|v| {
1359                        let payload = v
1360                            .payload()
1361                            .iter()
1362                            .map(|ty| scope.resolve(ty))
1363                            .collect::<Result<Arc<[ResolvedType]>, Error>>()
1364                            .with_span(v)?;
1365                        Ok(EnumVariantInfo::new(v.name().clone(), payload))
1366                    })
1367                    .collect::<Result<Arc<[EnumVariantInfo]>, Diagnostic>>()?;
1368                scope
1369                    .insert_enum(decl.name().clone(), decl.visibility().clone(), variants)
1370                    .with_span(decl)?;
1371
1372                Ok(Self::EnumDeclaration)
1373            }
1374            parse::Item::Module(module) => {
1375                scope
1376                    .enter_module(module.name().clone(), module.visibility().clone())
1377                    .with_span(module)?;
1378
1379                let mut analyzed_children = Vec::new();
1380                for item in module.items() {
1381                    analyzed_children.push(Item::analyze(item, ty, scope)?);
1382                }
1383                scope.exit_module();
1384                Ok(Self::Module(analyzed_children))
1385            }
1386            parse::Item::Ignored => Ok(Self::Ignored),
1387        }
1388    }
1389}
1390
1391impl AbstractSyntaxTree for Function {
1392    type From = parse::Function;
1393
1394    fn analyze(
1395        from: &Self::From,
1396        ty: &ResolvedType,
1397        scope: &mut Scope,
1398    ) -> Result<Self, Diagnostic> {
1399        assert!(ty.is_unit(), "Function definitions cannot return anything");
1400        assert!(
1401            scope.is_outside_function(),
1402            "Variables live only inside the function"
1403        );
1404
1405        if from.name().as_inner() != MAIN_STR {
1406            let params = from
1407                .params()
1408                .iter()
1409                .map(|param| {
1410                    let identifier = param.identifier().clone();
1411                    let ty = scope.resolve(param.ty())?;
1412                    Ok(FunctionParam {
1413                        identifier,
1414                        ty,
1415                        span: *param.span(),
1416                    })
1417                })
1418                .collect::<Result<Arc<[FunctionParam]>, Error>>()
1419                .with_span(from)?;
1420            let ret = from
1421                .ret()
1422                .as_ref()
1423                .map(|aliased| scope.resolve(aliased).with_span(from))
1424                .transpose()?
1425                .unwrap_or_else(ResolvedType::unit);
1426
1427            scope.enter_block();
1428            for param in params.iter() {
1429                scope.insert_variable(param.identifier().clone(), param.ty().clone());
1430            }
1431            let body = Expression::analyze(from.body(), &ret, scope).map(Arc::new)?;
1432            scope.exit_block();
1433
1434            debug_assert!(scope.is_outside_function());
1435            let function = CustomFunction {
1436                params,
1437                body,
1438                span: *from.span(),
1439            };
1440            scope
1441                .insert_function(from.name().clone(), from.visibility().clone(), function)
1442                .with_span(from)?;
1443
1444            return Ok(Self::Custom);
1445        }
1446
1447        if !from.params().is_empty() {
1448            return Err(Error::MainNoInputs).with_span(from);
1449        }
1450        if let Some(aliased) = from.ret() {
1451            let resolved = scope.resolve(aliased).with_span(from)?;
1452            if !resolved.is_unit() {
1453                return Err(Error::MainNoOutput).with_span(from);
1454            }
1455        }
1456
1457        if matches!(from.visibility(), Visibility::Public) {
1458            return Err(Error::MainCannotBePublic).with_span(from);
1459        }
1460
1461        scope.enter_main();
1462        let body = Expression::analyze(from.body(), ty, scope)?;
1463        scope.exit_main();
1464        Ok(Self::Main(body))
1465    }
1466}
1467
1468impl AbstractSyntaxTree for Statement {
1469    type From = parse::Statement;
1470
1471    fn analyze(
1472        from: &Self::From,
1473        ty: &ResolvedType,
1474        scope: &mut Scope,
1475    ) -> Result<Self, Diagnostic> {
1476        assert!(ty.is_unit(), "Statements cannot return anything");
1477        match from {
1478            parse::Statement::Assignment(assignment) => {
1479                Assignment::analyze(assignment, ty, scope).map(Self::Assignment)
1480            }
1481            parse::Statement::Expression(expression) => {
1482                Expression::analyze(expression, ty, scope).map(Self::Expression)
1483            }
1484        }
1485    }
1486}
1487
1488impl AbstractSyntaxTree for Assignment {
1489    type From = parse::Assignment;
1490
1491    fn analyze(
1492        from: &Self::From,
1493        ty: &ResolvedType,
1494        scope: &mut Scope,
1495    ) -> Result<Self, Diagnostic> {
1496        assert!(ty.is_unit(), "Assignments cannot return anything");
1497        // The assignment is a statement that returns nothing.
1498        //
1499        // However, the expression evaluated in the assignment does have a type,
1500        // namely the type specified in the assignment.
1501        let ty_expr = scope.resolve(from.ty()).with_span(from)?;
1502        let expression = Expression::analyze(from.expression(), &ty_expr, scope)?;
1503        let typed_variables = from.pattern().is_of_type(&ty_expr).with_span(from)?;
1504        for (identifier, ty) in typed_variables {
1505            scope.insert_variable(identifier, ty);
1506        }
1507
1508        Ok(Self {
1509            pattern: from.pattern().clone(),
1510            expression,
1511            span: *from.as_ref(),
1512        })
1513    }
1514}
1515
1516impl Expression {
1517    /// Analyze an expression from the parse tree in a const context without predefined variables.
1518    ///
1519    /// Check if the expression is of the given type.
1520    ///
1521    /// ## Const evaluation
1522    ///
1523    /// The returned expression might not be evaluable at compile time.
1524    /// The details depend on the current state of the SimplicityHL compiler.
1525    pub fn analyze_const(from: &parse::Expression, ty: &ResolvedType) -> Result<Self, Diagnostic> {
1526        // Value files carry no scope, so enum constructions may name the
1527        // enum by its declared name here — and only here.
1528        let mut empty_scope = Scope::for_value_parsing();
1529        Self::analyze(from, ty, &mut empty_scope)
1530    }
1531}
1532
1533/// Analyze the construction of an enum variant, e.g. `Action::Refresh(sig, 3)`.
1534///
1535/// Analysis is type-directed. The expected type must be an enum, and the written enum name must name it.
1536/// In program source that means an alias in lexical scope, the same rule
1537/// matches follow. In witness and argument files, which are parsed without
1538/// a scope ([`Scope::unscoped_enum_names`]), the enum's declared name
1539/// itself also matches.
1540fn analyze_enum_construction(
1541    construction: &parse::EnumConstruction,
1542    ty: &ResolvedType,
1543    scope: &mut Scope,
1544) -> Result<EnumConstruction, Diagnostic> {
1545    let span = *construction.span();
1546    let Some(info) = ty.as_enum() else {
1547        return Err(Error::ExpressionUnexpectedType { ty: ty.clone() }).with_span(span);
1548    };
1549
1550    // The written name must be the expected enum's.
1551    // Enums are declared at the top level, so only a single identifier can name one.
1552    // An alias in scope must resolve to the expected type.
1553    // Without a scope (witness and argument files) the declared name itself matches.
1554    let written = construction.enum_path_string();
1555    let names_expected_enum = match construction.enum_path() {
1556        [single] => {
1557            let alias = AliasName::from_str_unchecked(single.as_inner());
1558            match scope.get_alias(&alias) {
1559                Ok(resolved) if &resolved == ty => true,
1560                Ok(resolved) => {
1561                    return Err(Error::ExpressionTypeMismatch {
1562                        expected: ty.clone(),
1563                        found: resolved,
1564                    })
1565                    .with_span(span);
1566                }
1567                Err(_) => scope.unscoped_enum_names && written == info.name(),
1568            }
1569        }
1570        _ => false,
1571    };
1572    if !names_expected_enum {
1573        return Err(Error::Grammar {
1574            msg: format!("`{written}` does not name enum `{}`", info.name()),
1575        })
1576        .with_span(span);
1577    }
1578
1579    let (variant_index, variant) = info
1580        .variant(construction.variant())
1581        .ok_or_else(|| enum_variant_error(construction.variant().as_inner(), info))
1582        .with_span(span)?;
1583    if construction.args().len() != variant.payload().len() {
1584        return Err(Error::Grammar {
1585            msg: format!(
1586                "variant `{}` of enum `{}` carries {} payload value(s), found {}",
1587                construction.variant(),
1588                info.name(),
1589                variant.payload().len(),
1590                construction.args().len()
1591            ),
1592        })
1593        .with_span(span);
1594    }
1595
1596    let payload = construction
1597        .args()
1598        .iter()
1599        .zip(variant.payload())
1600        .map(|(arg, payload_ty)| Expression::analyze(arg, payload_ty, scope).map(Arc::new))
1601        .collect::<Result<Arc<[Arc<Expression>]>, Diagnostic>>()?;
1602
1603    Ok(EnumConstruction {
1604        variant_index,
1605        payload,
1606        span,
1607    })
1608}
1609
1610/// Do `a` and `b` carry the same enum at every corresponding position?
1611///
1612/// Casts prove structural equality, but enums are nominal: a cast may
1613/// freely reshape enum-free structure (`(u16, u16)` into `u32`), while
1614/// every enum must map to itself at its position — otherwise variants
1615/// would convert by ordinal position, silently bypassing declared
1616/// identity.
1617///
1618/// Conservative on shape changes: an enum aligned across a reshaped
1619/// subtree (such as an array-to-tuple conversion) is rejected even when
1620/// the enum itself is unchanged.
1621///
1622/// TODO(enums): this walk aligns high-level constructors, so casts that
1623/// reshape only the container around an enum are rejected even when the
1624/// enum keeps its structural position, e.g. `Option<E>` to
1625/// `Either<(), E>`. A provenance-aware comparison — structural skeletons
1626/// with nominal enum leaves — would accept those; keep `List` types
1627/// conservative either way, since their partition layout complicates
1628/// position alignment.
1629fn cast_preserves_enum_identity(source: &ResolvedType, target: &ResolvedType) -> bool {
1630    match (source.as_inner(), target.as_inner()) {
1631        (TypeInner::Enum(src), TypeInner::Enum(dst)) => src == dst,
1632        (TypeInner::Enum(_), _) | (_, TypeInner::Enum(_)) => false,
1633        (TypeInner::Option(src), TypeInner::Option(dst)) => cast_preserves_enum_identity(src, dst),
1634        (TypeInner::Either(src_l, src_r), TypeInner::Either(dst_l, dst_r)) => {
1635            cast_preserves_enum_identity(src_l, dst_l) && cast_preserves_enum_identity(src_r, dst_r)
1636        }
1637        (TypeInner::Tuple(src), TypeInner::Tuple(dst)) if src.len() == dst.len() => src
1638            .iter()
1639            .zip(dst.iter())
1640            .all(|(src_el, dst_el)| cast_preserves_enum_identity(src_el, dst_el)),
1641        (TypeInner::Array(src, src_len), TypeInner::Array(dst, dst_len)) if src_len == dst_len => {
1642            cast_preserves_enum_identity(src, dst)
1643        }
1644        (TypeInner::List(src, src_bound), TypeInner::List(dst, dst_bound))
1645            if src_bound == dst_bound =>
1646        {
1647            cast_preserves_enum_identity(src, dst)
1648        }
1649        // Differently shaped subtrees may convert freely as long as no
1650        // enum is involved on either side.
1651        _ => !source.contains_enum() && !target.contains_enum(),
1652    }
1653}
1654
1655/// The given string does not name a variant of the enum.
1656fn enum_variant_error(found: &str, info: &EnumInfo) -> Error {
1657    let variants = info
1658        .variants()
1659        .iter()
1660        .map(|variant| variant.name().to_string())
1661        .collect::<Vec<_>>()
1662        .join(", ");
1663    Error::Grammar {
1664        msg: format!(
1665            "`{found}` is not a variant of enum `{}`; expected one of: {variants}",
1666            info.name()
1667        ),
1668    }
1669}
1670
1671impl AbstractSyntaxTree for Expression {
1672    type From = parse::Expression;
1673
1674    fn analyze(
1675        from: &Self::From,
1676        ty: &ResolvedType,
1677        scope: &mut Scope,
1678    ) -> Result<Self, Diagnostic> {
1679        match from.inner() {
1680            parse::ExpressionInner::Single(single) => {
1681                let ast_single = SingleExpression::analyze(single, ty, scope)?;
1682                Ok(Self {
1683                    ty: ty.clone(),
1684                    inner: ExpressionInner::Single(ast_single),
1685                    span: *from.as_ref(),
1686                })
1687            }
1688            parse::ExpressionInner::Block(statements, expression) => {
1689                scope.enter_block();
1690                let ast_statements = statements
1691                    .iter()
1692                    .map(|s| Statement::analyze(s, &ResolvedType::unit(), scope))
1693                    .collect::<Result<Arc<[Statement]>, Diagnostic>>()?;
1694                let ast_expression = match expression {
1695                    Some(expression) => Expression::analyze(expression, ty, scope)
1696                        .map(Arc::new)
1697                        .map(Some),
1698                    None if ty.is_unit() => Ok(None),
1699                    None => Err(Error::ExpressionTypeMismatch {
1700                        expected: ty.clone(),
1701                        found: ResolvedType::unit(),
1702                    })
1703                    .with_span(from),
1704                }?;
1705                scope.exit_block();
1706
1707                Ok(Self {
1708                    ty: ty.clone(),
1709                    inner: ExpressionInner::Block(ast_statements, ast_expression),
1710                    span: *from.as_ref(),
1711                })
1712            }
1713        }
1714    }
1715}
1716
1717impl AbstractSyntaxTree for SingleExpression {
1718    type From = parse::SingleExpression;
1719
1720    fn analyze(
1721        from: &Self::From,
1722        ty: &ResolvedType,
1723        scope: &mut Scope,
1724    ) -> Result<Self, Diagnostic> {
1725        let inner = match from.inner() {
1726            parse::SingleExpressionInner::Boolean(bit) => {
1727                if !ty.is_boolean() {
1728                    return Err(Error::ExpressionTypeMismatch {
1729                        expected: ty.clone(),
1730                        found: ResolvedType::boolean(),
1731                    })
1732                    .with_span(from);
1733                }
1734                SingleExpressionInner::Constant(Value::from(*bit))
1735            }
1736            parse::SingleExpressionInner::Decimal(decimal) => {
1737                let ty = ty
1738                    .as_integer()
1739                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1740                    .with_span(from)?;
1741                UIntValue::parse_decimal(decimal, ty)
1742                    .with_span(from)
1743                    .map(Value::from)
1744                    .map(SingleExpressionInner::Constant)?
1745            }
1746            parse::SingleExpressionInner::Binary(bits) => {
1747                let ty = ty
1748                    .as_integer()
1749                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1750                    .with_span(from)?;
1751                let value = UIntValue::parse_binary(bits, ty).with_span(from)?;
1752                SingleExpressionInner::Constant(Value::from(value))
1753            }
1754            parse::SingleExpressionInner::Hexadecimal(bytes) => {
1755                let value = Value::parse_hexadecimal(bytes, ty).with_span(from)?;
1756                SingleExpressionInner::Constant(value)
1757            }
1758            parse::SingleExpressionInner::Witness(name) => {
1759                scope
1760                    .insert_witness(name.clone(), ty.clone())
1761                    .with_span(from)?;
1762                SingleExpressionInner::Witness(name.clone())
1763            }
1764            parse::SingleExpressionInner::Parameter(name) => {
1765                scope
1766                    .insert_parameter(name.shallow_clone(), ty.clone())
1767                    .with_span(from)?;
1768                SingleExpressionInner::Parameter(name.shallow_clone())
1769            }
1770            parse::SingleExpressionInner::Variable(identifier) => {
1771                let bound_ty = scope
1772                    .get_variable(identifier)
1773                    .ok_or(Error::UndefinedVariable {
1774                        identifier: identifier.clone(),
1775                    })
1776                    .with_span(from)?;
1777                if ty != bound_ty {
1778                    return Err(Error::ExpressionTypeMismatch {
1779                        expected: ty.clone(),
1780                        found: bound_ty.clone(),
1781                    })
1782                    .with_span(from);
1783                }
1784                scope.insert_variable(identifier.clone(), ty.clone());
1785                SingleExpressionInner::Variable(identifier.clone())
1786            }
1787            parse::SingleExpressionInner::Expression(parse) => {
1788                Expression::analyze(parse, ty, scope)
1789                    .map(Arc::new)
1790                    .map(SingleExpressionInner::Expression)?
1791            }
1792            parse::SingleExpressionInner::Tuple(tuple) => {
1793                let types = ty
1794                    .as_tuple()
1795                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1796                    .with_span(from)?;
1797                if tuple.len() != types.len() {
1798                    return Err(Error::ExpressionUnexpectedType { ty: ty.clone() }).with_span(from);
1799                }
1800                tuple
1801                    .iter()
1802                    .zip(types.iter())
1803                    .map(|(el_parse, el_ty)| Expression::analyze(el_parse, el_ty, scope))
1804                    .collect::<Result<Arc<[Expression]>, Diagnostic>>()
1805                    .map(SingleExpressionInner::Tuple)?
1806            }
1807            parse::SingleExpressionInner::Array(array) => {
1808                let (el_ty, size) = ty
1809                    .as_array()
1810                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1811                    .with_span(from)?;
1812                if array.len() != size {
1813                    return Err(Error::ExpressionUnexpectedType { ty: ty.clone() }).with_span(from);
1814                }
1815                array
1816                    .iter()
1817                    .map(|el_parse| Expression::analyze(el_parse, el_ty, scope))
1818                    .collect::<Result<Arc<[Expression]>, Diagnostic>>()
1819                    .map(SingleExpressionInner::Array)?
1820            }
1821            parse::SingleExpressionInner::List(list) => {
1822                let (el_ty, bound) = ty
1823                    .as_list()
1824                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1825                    .with_span(from)?;
1826                if bound.get() <= list.len() {
1827                    return Err(Error::ExpressionUnexpectedType { ty: ty.clone() }).with_span(from);
1828                }
1829                list.iter()
1830                    .map(|e| Expression::analyze(e, el_ty, scope))
1831                    .collect::<Result<Arc<[Expression]>, Diagnostic>>()
1832                    .map(SingleExpressionInner::List)?
1833            }
1834            parse::SingleExpressionInner::Either(either) => {
1835                let (ty_l, ty_r) = ty
1836                    .as_either()
1837                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1838                    .with_span(from)?;
1839                match either {
1840                    Either::Left(parse_l) => Expression::analyze(parse_l, ty_l, scope)
1841                        .map(Arc::new)
1842                        .map(Either::Left),
1843                    Either::Right(parse_r) => Expression::analyze(parse_r, ty_r, scope)
1844                        .map(Arc::new)
1845                        .map(Either::Right),
1846                }
1847                .map(SingleExpressionInner::Either)?
1848            }
1849            parse::SingleExpressionInner::Option(maybe_parse) => {
1850                let ty = ty
1851                    .as_option()
1852                    .ok_or(Error::ExpressionUnexpectedType { ty: ty.clone() })
1853                    .with_span(from)?;
1854                match maybe_parse {
1855                    Some(parse) => {
1856                        Some(Expression::analyze(parse, ty, scope).map(Arc::new)).transpose()
1857                    }
1858                    None => Ok(None),
1859                }
1860                .map(SingleExpressionInner::Option)?
1861            }
1862            parse::SingleExpressionInner::Call(call) => {
1863                Call::analyze(call, ty, scope).map(SingleExpressionInner::Call)?
1864            }
1865            parse::SingleExpressionInner::Match(match_) => {
1866                Match::analyze(match_, ty, scope).map(SingleExpressionInner::Match)?
1867            }
1868            parse::SingleExpressionInner::EnumConstruction(construction) => {
1869                analyze_enum_construction(construction, ty, scope)
1870                    .map(SingleExpressionInner::EnumConstruction)?
1871            }
1872            parse::SingleExpressionInner::EnumMatch(enum_match) => {
1873                EnumMatch::analyze(enum_match, ty, scope).map(SingleExpressionInner::EnumMatch)?
1874            }
1875        };
1876
1877        Ok(Self {
1878            inner,
1879            ty: ty.clone(),
1880            span: *from.as_ref(),
1881        })
1882    }
1883}
1884
1885impl AbstractSyntaxTree for EnumMatch {
1886    type From = parse::EnumMatch;
1887
1888    fn analyze(
1889        from: &Self::From,
1890        ty: &ResolvedType,
1891        scope: &mut Scope,
1892    ) -> Result<Self, Diagnostic> {
1893        let arms = from.arms();
1894        let span = *from.span();
1895        debug_assert!(!arms.is_empty(), "the parser rejects empty enum matches");
1896
1897        let enum_name = arms[0].enum_path_string();
1898        let [single] = arms[0].enum_path() else {
1899            return Err(Error::Grammar {
1900                msg: format!(
1901                    "`{enum_name}` does not name an enum; enums are declared at the \
1902                     top level, so match arms name them by a single identifier"
1903                ),
1904            })
1905            .with_span(span);
1906        };
1907        let alias = AliasName::from_str_unchecked(single.as_inner());
1908        let enum_ty = scope.get_alias(&alias).with_span(span)?;
1909        let info = match enum_ty.as_enum() {
1910            Some(info) => info.clone(),
1911            None => {
1912                return Err(Error::Grammar {
1913                    msg: format!(
1914                        "`{enum_name}` is not an enum, so match arms of the form \
1915                         `{enum_name}::Variant` cannot apply to it"
1916                    ),
1917                })
1918                .with_span(span)
1919            }
1920        };
1921
1922        // One slot per variant, in declaration order.
1923        // the order of the leaves of the enum's balanced sum.
1924        let mut arms_by_index: Vec<Option<&parse::EnumMatchArm>> =
1925            vec![None; info.variants().len()];
1926        for arm in arms {
1927            if arm.enum_path() != arms[0].enum_path() {
1928                return Err(Error::Grammar {
1929                    msg: format!(
1930                        "all match arms must use the same enum; expected '{}', found '{}'",
1931                        enum_name,
1932                        arm.enum_path_string()
1933                    ),
1934                })
1935                .with_span(span);
1936            }
1937            let (index, _) = info
1938                .variant(arm.variant())
1939                .ok_or_else(|| Error::Grammar {
1940                    msg: format!(
1941                        "variant '{}' is not defined in enum '{}'",
1942                        arm.variant(),
1943                        enum_name
1944                    ),
1945                })
1946                .with_span(span)?;
1947            let slot = &mut arms_by_index[index];
1948            if slot.is_some() {
1949                return Err(Error::Grammar {
1950                    msg: format!("duplicate arm for variant '{}'", arm.variant()),
1951                })
1952                .with_span(span);
1953            }
1954            *slot = Some(arm);
1955        }
1956
1957        // One collect: Some(arms) iff every variant is covered.
1958        let covered: Option<Vec<&parse::EnumMatchArm>> = arms_by_index.iter().copied().collect();
1959        let Some(covered) = covered else {
1960            let missing: Vec<String> = arms_by_index
1961                .iter()
1962                .zip(info.variants())
1963                .filter(|(slot, _)| slot.is_none())
1964                .map(|(_, variant)| format!("'{}'", variant.name()))
1965                .collect();
1966            return Err(Error::Grammar {
1967                msg: format!(
1968                    "enum match on '{}' must cover all {} variants; missing: {}",
1969                    enum_name,
1970                    info.variants().len(),
1971                    missing.join(", ")
1972                ),
1973            })
1974            .with_span(span);
1975        };
1976
1977        // Analyze the scrutinee against the nominal enum type, so that
1978        // matching a value of a different enum (or any other type) against
1979        // this enum's variants is a type error.
1980        let scrutinee = Expression::analyze(from.scrutinee(), &enum_ty, scope).map(Arc::new)?;
1981
1982        let arm_asts = covered
1983            .into_iter()
1984            .zip(info.variants())
1985            .map(|(arm, variant)| {
1986                let arm_span = *arm.span();
1987                let pattern = analyze_enum_arm_bindings(arm, variant, scope, arm_span)?;
1988                scope.enter_block();
1989                let payload_ty = variant.payload_type();
1990                let typed_variables = pattern.is_of_type(payload_ty).with_span(arm_span)?;
1991                for (identifier, variable_ty) in typed_variables {
1992                    scope.insert_variable(identifier, variable_ty);
1993                }
1994                let body = Expression::analyze(arm.expression(), ty, scope).map(Arc::new);
1995                scope.exit_block();
1996                Ok(EnumMatchArm {
1997                    pattern,
1998                    body: body?,
1999                    span: arm_span,
2000                })
2001            })
2002            .collect::<Result<Arc<[EnumMatchArm]>, Diagnostic>>()?;
2003
2004        Ok(Self {
2005            scrutinee,
2006            arms: arm_asts,
2007            span,
2008        })
2009    }
2010}
2011
2012/// Check an enum match arm's payload bindings against the variant's declared
2013/// payload types and combine them into one pattern for the variant's leaf.
2014///
2015/// Unit variants bind nothing ([`Pattern::Ignore`]); a single binding stands
2016/// alone; multiple bindings form a tuple pattern, matching the tuple that a
2017/// multi-payload variant carries at its leaf.
2018fn analyze_enum_arm_bindings(
2019    arm: &parse::EnumMatchArm,
2020    variant: &EnumVariantInfo,
2021    scope: &Scope,
2022    span: Span,
2023) -> Result<Pattern, Diagnostic> {
2024    if arm.bindings().len() != variant.payload().len() {
2025        return Err(Error::Grammar {
2026            msg: format!(
2027                "variant '{}' of enum '{}' carries {} payload value(s), \
2028                 but the arm binds {}",
2029                arm.variant(),
2030                arm.enum_path_string(),
2031                variant.payload().len(),
2032                arm.bindings().len()
2033            ),
2034        })
2035        .with_span(span);
2036    }
2037
2038    let mut patterns = Vec::with_capacity(arm.bindings().len());
2039    for ((pattern, declared), payload_ty) in arm.bindings().iter().zip(variant.payload()) {
2040        let declared = scope.resolve(declared).with_span(span)?;
2041        if &declared != payload_ty {
2042            return Err(Error::ExpressionTypeMismatch {
2043                expected: payload_ty.clone(),
2044                found: declared,
2045            })
2046            .with_span(span);
2047        }
2048        patterns.push(pattern.clone());
2049    }
2050
2051    let pattern = match patterns.len() {
2052        0 => Pattern::Ignore,
2053        1 => patterns[0].clone(),
2054        _ => Pattern::tuple(patterns),
2055    };
2056    Ok(pattern)
2057}
2058
2059impl AbstractSyntaxTree for Call {
2060    type From = parse::Call;
2061
2062    fn analyze(
2063        from: &Self::From,
2064        ty: &ResolvedType,
2065        scope: &mut Scope,
2066    ) -> Result<Self, Diagnostic> {
2067        fn check_argument_types(
2068            parse_args: &[parse::Expression],
2069            expected_tys: &[ResolvedType],
2070        ) -> Result<(), Error> {
2071            if parse_args.len() == expected_tys.len() {
2072                Ok(())
2073            } else {
2074                Err(Error::InvalidNumberOfArguments {
2075                    expected: expected_tys.len(),
2076                    found: parse_args.len(),
2077                })
2078            }
2079        }
2080
2081        fn check_output_type(
2082            observed_ty: &ResolvedType,
2083            expected_ty: &ResolvedType,
2084        ) -> Result<(), Error> {
2085            if observed_ty == expected_ty {
2086                Ok(())
2087            } else {
2088                Err(Error::ExpressionTypeMismatch {
2089                    expected: expected_ty.clone(),
2090                    found: observed_ty.clone(),
2091                })
2092            }
2093        }
2094
2095        fn analyze_arguments(
2096            parse_args: &[parse::Expression],
2097            args_tys: &[ResolvedType],
2098            scope: &mut Scope,
2099        ) -> Result<Arc<[Expression]>, Diagnostic> {
2100            let args = parse_args
2101                .iter()
2102                .zip(args_tys.iter())
2103                .map(|(arg_parse, arg_ty)| Expression::analyze(arg_parse, arg_ty, scope))
2104                .collect::<Result<Arc<[Expression]>, Diagnostic>>()?;
2105            Ok(args)
2106        }
2107
2108        let name = CallName::analyze(from, ty, scope)?;
2109        let args = match name.clone() {
2110            CallName::Jet(jet) => {
2111                let args_tys = source_type(&*jet)
2112                    .iter()
2113                    .map(AliasedType::resolve_builtin)
2114                    .collect::<Result<Vec<ResolvedType>, AliasName>>()
2115                    .map_err(|alias| Error::UndefinedAlias { name: alias })
2116                    .with_span(from)?;
2117                check_argument_types(from.args(), &args_tys).with_span(from)?;
2118                let out_ty = target_type(&*jet)
2119                    .resolve_builtin()
2120                    .map_err(|alias| Error::UndefinedAlias { name: alias })
2121                    .with_span(from)?;
2122                check_output_type(&out_ty, ty).with_span(from)?;
2123                scope.track_call(from, TrackedCallName::Jet);
2124                analyze_arguments(from.args(), &args_tys, scope)?
2125            }
2126            CallName::UnwrapLeft(right_ty) => {
2127                let args_tys = [ResolvedType::either(ty.clone(), right_ty)];
2128                check_argument_types(from.args(), &args_tys).with_span(from)?;
2129                let args = analyze_arguments(from.args(), &args_tys, scope)?;
2130                let [arg_ty] = args_tys;
2131                scope.track_call(from, TrackedCallName::UnwrapLeft(arg_ty));
2132                args
2133            }
2134            CallName::UnwrapRight(left_ty) => {
2135                let args_tys = [ResolvedType::either(left_ty, ty.clone())];
2136                check_argument_types(from.args(), &args_tys).with_span(from)?;
2137                let args = analyze_arguments(from.args(), &args_tys, scope)?;
2138                let [arg_ty] = args_tys;
2139                scope.track_call(from, TrackedCallName::UnwrapRight(arg_ty));
2140                args
2141            }
2142            CallName::IsNone(some_ty) => {
2143                let args_tys = [ResolvedType::option(some_ty)];
2144                check_argument_types(from.args(), &args_tys).with_span(from)?;
2145                let out_ty = ResolvedType::boolean();
2146                check_output_type(&out_ty, ty).with_span(from)?;
2147                analyze_arguments(from.args(), &args_tys, scope)?
2148            }
2149            CallName::Unwrap => {
2150                let args_tys = [ResolvedType::option(ty.clone())];
2151                check_argument_types(from.args(), &args_tys).with_span(from)?;
2152                scope.track_call(from, TrackedCallName::Unwrap);
2153                analyze_arguments(from.args(), &args_tys, scope)?
2154            }
2155            CallName::Assert => {
2156                let args_tys = [ResolvedType::boolean()];
2157                check_argument_types(from.args(), &args_tys).with_span(from)?;
2158                let out_ty = ResolvedType::unit();
2159                check_output_type(&out_ty, ty).with_span(from)?;
2160                scope.track_call(from, TrackedCallName::Assert);
2161                analyze_arguments(from.args(), &args_tys, scope)?
2162            }
2163            CallName::Panic => {
2164                let args_tys = [];
2165                check_argument_types(from.args(), &args_tys).with_span(from)?;
2166                // panic! allows every output type because it will never return anything
2167                scope.track_call(from, TrackedCallName::Panic);
2168                analyze_arguments(from.args(), &args_tys, scope)?
2169            }
2170            CallName::Debug => {
2171                let args_tys = [ty.clone()];
2172                check_argument_types(from.args(), &args_tys).with_span(from)?;
2173                let args = analyze_arguments(from.args(), &args_tys, scope)?;
2174                let [arg_ty] = args_tys;
2175                scope.track_call(from, TrackedCallName::Debug(arg_ty));
2176                args
2177            }
2178            CallName::TypeCast(source) => {
2179                // Casts prove structural equality, but enums are nominal:
2180                // every enum must map to itself at its structural position
2181                // (see `cast_preserves_enum_identity`), else same-shaped
2182                // enums would convert variants by ordinal position.
2183                if !cast_preserves_enum_identity(&source, ty)
2184                    || StructuralType::from(&source) != StructuralType::from(ty)
2185                {
2186                    return Err(Error::InvalidCast {
2187                        source,
2188                        target: ty.clone(),
2189                    })
2190                    .with_span(from);
2191                }
2192
2193                let args_tys = [source];
2194                check_argument_types(from.args(), &args_tys).with_span(from)?;
2195                analyze_arguments(from.args(), &args_tys, scope)?
2196            }
2197            CallName::Custom(function) => {
2198                let args_ty = function
2199                    .params()
2200                    .iter()
2201                    .map(FunctionParam::ty)
2202                    .cloned()
2203                    .collect::<Vec<ResolvedType>>();
2204                check_argument_types(from.args(), &args_ty).with_span(from)?;
2205                let out_ty = function.body().ty();
2206                check_output_type(out_ty, ty).with_span(from)?;
2207                analyze_arguments(from.args(), &args_ty, scope)?
2208            }
2209            CallName::Fold(function, bound) => {
2210                // A list fold has the signature:
2211                //   fold::<f, N>(list: List<E, N>, initial_accumulator: A) -> A
2212                // where
2213                //   fn f(element: E, accumulator: A) -> A
2214                let element_ty = function.params().first().expect("foldable function").ty();
2215                let list_ty = ResolvedType::list(element_ty.clone(), bound);
2216                let accumulator_ty = function
2217                    .params()
2218                    .get(1)
2219                    .expect("foldable function")
2220                    .ty()
2221                    .clone();
2222                let args_ty = [list_ty, accumulator_ty];
2223
2224                check_argument_types(from.args(), &args_ty).with_span(from)?;
2225                let out_ty = function.body().ty();
2226                check_output_type(out_ty, ty).with_span(from)?;
2227                analyze_arguments(from.args(), &args_ty, scope)?
2228            }
2229            CallName::ArrayFold(function, size) => {
2230                // An array fold has the signature:
2231                //   array_fold::<f, N>(array: [E; N], initial_accumulator: A) -> A
2232                // where
2233                //   fn f(element: E, accumulator: A) -> A
2234                let element_ty = function.params().first().expect("foldable function").ty();
2235                let array_ty = ResolvedType::array(element_ty.clone(), size.get());
2236                let accumulator_ty = function
2237                    .params()
2238                    .get(1)
2239                    .expect("foldable function")
2240                    .ty()
2241                    .clone();
2242                let args_ty = [array_ty, accumulator_ty];
2243
2244                check_argument_types(from.args(), &args_ty).with_span(from)?;
2245                let out_ty = function.body().ty();
2246                check_output_type(out_ty, ty).with_span(from)?;
2247                analyze_arguments(from.args(), &args_ty, scope)?
2248            }
2249            CallName::ForWhile(function, _bit_width) => {
2250                // A for-while loop has the signature:
2251                //   for_while::<f>(initial_accumulator: A, readonly_context: C) -> Either<B, A>
2252                // where
2253                //   fn f(accumulator: A, readonly_context: C, counter: u{N}) -> Either<B, A>
2254                //   N is a power of two
2255                let accumulator_ty = function
2256                    .params()
2257                    .first()
2258                    .expect("loopable function")
2259                    .ty()
2260                    .clone();
2261                let context_ty = function
2262                    .params()
2263                    .get(1)
2264                    .expect("loopable function")
2265                    .ty()
2266                    .clone();
2267                let args_ty = [accumulator_ty, context_ty];
2268
2269                check_argument_types(from.args(), &args_ty).with_span(from)?;
2270                let out_ty = function.body().ty();
2271                check_output_type(out_ty, ty).with_span(from)?;
2272                analyze_arguments(from.args(), &args_ty, scope)?
2273            }
2274        };
2275
2276        Ok(Self {
2277            name,
2278            args,
2279            span: *from.as_ref(),
2280        })
2281    }
2282}
2283
2284impl AbstractSyntaxTree for CallName {
2285    // Take parse::Call, so we have access to the span for pretty errors
2286    type From = parse::Call;
2287
2288    fn analyze(
2289        from: &Self::From,
2290        _ty: &ResolvedType,
2291        scope: &mut Scope,
2292    ) -> Result<Self, Diagnostic> {
2293        match from.name() {
2294            parse::CallName::Jet(name) => match scope.jet_hinter.parse_jet(name.as_inner()) {
2295                Some(jet) if !jet.is_disabled() => Ok(Self::Jet(jet)),
2296                _ => Err(Error::JetDoesNotExist { name: name.clone() }).with_span(from),
2297            },
2298            parse::CallName::UnwrapLeft(right_ty) => scope
2299                .resolve(right_ty)
2300                .map(Self::UnwrapLeft)
2301                .with_span(from),
2302            parse::CallName::UnwrapRight(left_ty) => scope
2303                .resolve(left_ty)
2304                .map(Self::UnwrapRight)
2305                .with_span(from),
2306            parse::CallName::IsNone(some_ty) => {
2307                scope.resolve(some_ty).map(Self::IsNone).with_span(from)
2308            }
2309            parse::CallName::Unwrap => Ok(Self::Unwrap),
2310            parse::CallName::Assert => Ok(Self::Assert),
2311            parse::CallName::Panic => Ok(Self::Panic),
2312            parse::CallName::Debug => Ok(Self::Debug),
2313            parse::CallName::TypeCast(target) => {
2314                scope.resolve(target).map(Self::TypeCast).with_span(from)
2315            }
2316            parse::CallName::Custom(name) => {
2317                scope.get_function(name).map(Self::Custom).with_span(from)
2318            }
2319            parse::CallName::ArrayFold(name, size) => {
2320                let function = scope.get_function(name).with_span(from)?;
2321                // A function that is used in a array fold has the signature:
2322                //   fn f(element: E, accumulator: A) -> A
2323                if function.params().len() != 2 || function.params()[1].ty() != function.body().ty()
2324                {
2325                    Err(Error::FunctionNotFoldable { name: name.clone() }).with_span(from)
2326                } else {
2327                    Ok(Self::ArrayFold(function, *size))
2328                }
2329            }
2330            parse::CallName::Fold(name, bound) => {
2331                let function = scope.get_function(name).with_span(from)?;
2332                // A function that is used in a list fold has the signature:
2333                //   fn f(element: E, accumulator: A) -> A
2334                if function.params().len() != 2 || function.params()[1].ty() != function.body().ty()
2335                {
2336                    Err(Error::FunctionNotFoldable { name: name.clone() }).with_span(from)
2337                } else {
2338                    Ok(Self::Fold(function, *bound))
2339                }
2340            }
2341            parse::CallName::ForWhile(name) => {
2342                let function = scope.get_function(name).with_span(from)?;
2343                // A function that is used in a for-while loop has the signature:
2344                //   fn f(accumulator: A, readonly_context: C, counter: u{N}) -> Either<B, A>
2345                // where
2346                //   N is a power of two
2347                if function.params().len() != 3 {
2348                    return Err(Error::FunctionNotLoopable { name: name.clone() }).with_span(from);
2349                }
2350                match function.body().ty().as_either() {
2351                    Some((_, out_r)) if out_r == function.params().first().unwrap().ty() => {}
2352                    _ => {
2353                        return Err(Error::FunctionNotLoopable { name: name.clone() })
2354                            .with_span(from);
2355                    }
2356                }
2357                // Disable loops for u32 or higher since no one will want to run
2358                // 2^32 = 4294967296 ≈ 4 billion iterations.
2359                // The resulting Simplicity program will not fit into a Bitcoin block.
2360                match function.params().get(2).unwrap().ty().as_integer() {
2361                    Some(
2362                        int_ty @ (UIntType::U1
2363                        | UIntType::U2
2364                        | UIntType::U4
2365                        | UIntType::U8
2366                        | UIntType::U16),
2367                    ) => Ok(Self::ForWhile(function, int_ty.bit_width())),
2368                    _ => Err(Error::FunctionNotLoopable { name: name.clone() }).with_span(from),
2369                }
2370            }
2371        }
2372    }
2373}
2374
2375impl AbstractSyntaxTree for Match {
2376    type From = parse::Match;
2377
2378    fn analyze(
2379        from: &Self::From,
2380        ty: &ResolvedType,
2381        scope: &mut Scope,
2382    ) -> Result<Self, Diagnostic> {
2383        let scrutinee_ty = from.scrutinee_type();
2384        let scrutinee_ty = scope.resolve(&scrutinee_ty).with_span(from)?;
2385        let scrutinee =
2386            Expression::analyze(from.scrutinee(), &scrutinee_ty, scope).map(Arc::new)?;
2387
2388        scope.enter_block();
2389        if let Some((pat_l, ty_l)) = from.left().pattern().as_typed_pattern() {
2390            let ty_l = scope.resolve(ty_l).with_span(from.left())?;
2391            let typed_variables = pat_l.is_of_type(&ty_l).with_span(from.left())?;
2392            for (identifier, ty) in typed_variables {
2393                scope.insert_variable(identifier, ty);
2394            }
2395        }
2396        let ast_l = Expression::analyze(from.left().expression(), ty, scope).map(Arc::new)?;
2397        scope.exit_block();
2398        scope.enter_block();
2399        if let Some((pat_r, ty_r)) = from.right().pattern().as_typed_pattern() {
2400            let ty_r = scope.resolve(ty_r).with_span(from.right())?;
2401            let typed_variables = pat_r.is_of_type(&ty_r).with_span(from.right())?;
2402            for (identifier, ty) in typed_variables {
2403                scope.insert_variable(identifier, ty);
2404            }
2405        }
2406        let ast_r = Expression::analyze(from.right().expression(), ty, scope).map(Arc::new)?;
2407        scope.exit_block();
2408
2409        Ok(Self {
2410            scrutinee,
2411            left: MatchArm {
2412                pattern: from.left().pattern().clone(),
2413                expression: ast_l,
2414                span: *from.left().span(),
2415            },
2416            right: MatchArm {
2417                pattern: from.right().pattern().clone(),
2418                expression: ast_r,
2419                span: *from.right().span(),
2420            },
2421            span: *from.as_ref(),
2422        })
2423    }
2424}
2425
2426impl AsRef<Span> for Assignment {
2427    fn as_ref(&self) -> &Span {
2428        &self.span
2429    }
2430}
2431
2432impl AsRef<Span> for FunctionParam {
2433    fn as_ref(&self) -> &Span {
2434        &self.span
2435    }
2436}
2437
2438impl AsRef<Span> for CustomFunction {
2439    fn as_ref(&self) -> &Span {
2440        &self.span
2441    }
2442}
2443
2444impl AsRef<Span> for Expression {
2445    fn as_ref(&self) -> &Span {
2446        &self.span
2447    }
2448}
2449
2450impl AsRef<Span> for SingleExpression {
2451    fn as_ref(&self) -> &Span {
2452        &self.span
2453    }
2454}
2455
2456impl AsRef<Span> for Call {
2457    fn as_ref(&self) -> &Span {
2458        &self.span
2459    }
2460}
2461
2462impl AsRef<Span> for Match {
2463    fn as_ref(&self) -> &Span {
2464        &self.span
2465    }
2466}
2467
2468impl AsRef<Span> for MatchArm {
2469    fn as_ref(&self) -> &Span {
2470        &self.span
2471    }
2472}
2473
2474impl AsRef<Span> for EnumMatchArm {
2475    fn as_ref(&self) -> &Span {
2476        &self.span
2477    }
2478}
2479
2480#[cfg(test)]
2481mod span_tests {
2482    use crate::parse::ParseFromStr;
2483
2484    use super::*;
2485
2486    #[test]
2487    fn analyzed_custom_function_preserves_declaration_and_parameter_spans() {
2488        let source = "fn helper(value: u8) -> u8 { value }";
2489        let parsed = parse::Function::parse_from_str(source).expect("function parses");
2490        let mut scope = Scope::new(Box::new(ElementsJetHinter));
2491
2492        Function::analyze(&parsed, &ResolvedType::unit(), &mut scope).expect("function analyzes");
2493        let function = scope
2494            .get_function(parsed.name())
2495            .expect("function is registered in scope");
2496
2497        assert_eq!(function.span().to_slice(source), Some(source));
2498        assert_eq!(
2499            function.params()[0].span().to_slice(source),
2500            Some("value: u8")
2501        );
2502    }
2503
2504    #[test]
2505    fn analyzed_match_arms_preserve_their_parsed_spans() {
2506        let source = r#"fn main() {
2507    let input: Either<u8, u8> = Left(1);
2508    match input {
2509        Left(left: u8) => {},
2510        Right(right: u8) => {},
2511    }
2512}"#;
2513        let parsed = parse::Program::parse_from_str(source).expect("program parses");
2514        let program =
2515            Program::analyze(&parsed, Box::new(ElementsJetHinter)).expect("program analyzes");
2516
2517        let ExpressionInner::Block(_, Some(last)) = program.main().inner() else {
2518            panic!("main body should end in a match");
2519        };
2520        let ExpressionInner::Single(single) = last.inner() else {
2521            panic!("match should be a single expression");
2522        };
2523        let SingleExpressionInner::Match(match_) = single.inner() else {
2524            panic!("expected a binary match");
2525        };
2526
2527        assert_eq!(
2528            match_.left().span().to_slice(source),
2529            Some("Left(left: u8) => {},")
2530        );
2531        assert_eq!(
2532            match_.right().span().to_slice(source),
2533            Some("Right(right: u8) => {},")
2534        );
2535    }
2536
2537    #[test]
2538    fn analyzed_enum_match_arms_preserve_their_parsed_spans() {
2539        let source = r#"enum Choice { First, Second, }
2540fn main() {
2541    let input: Choice = Choice::First;
2542    match input {
2543        Choice::First => {},
2544        Choice::Second => {},
2545    }
2546}"#;
2547        let parsed = parse::Program::parse_from_str(source).expect("program parses");
2548        let program =
2549            Program::analyze(&parsed, Box::new(ElementsJetHinter)).expect("program analyzes");
2550
2551        let ExpressionInner::Block(_, Some(last)) = program.main().inner() else {
2552            panic!("main body should end in an enum match");
2553        };
2554        let ExpressionInner::Single(single) = last.inner() else {
2555            panic!("enum match should be a single expression");
2556        };
2557        let SingleExpressionInner::EnumMatch(match_) = single.inner() else {
2558            panic!("expected an enum match");
2559        };
2560
2561        assert_eq!(
2562            match_.arms()[0].span().to_slice(source),
2563            Some("Choice::First => {},")
2564        );
2565        assert_eq!(
2566            match_.arms()[1].span().to_slice(source),
2567            Some("Choice::Second => {},")
2568        );
2569    }
2570}
2571
2572#[cfg(test)]
2573mod scope_resolution_tests {
2574    use super::{ElementsJetHinter, Program};
2575    use crate::driver::tests::setup_graph;
2576
2577    pub(super) fn analyze_multifile(files: Vec<(&str, &str)>) -> Result<(), String> {
2578        let (graph, _ids, _dir, mut diagnostics) = setup_graph(files);
2579
2580        let Some(driver_program) = graph.linearize_and_assemble(&mut diagnostics) else {
2581            return Err(diagnostics.render_to_string());
2582        };
2583
2584        Program::analyze(&driver_program, Box::new(ElementsJetHinter))
2585            .map(|_| ())
2586            .map_err(|e| e.to_string())
2587    }
2588
2589    #[test]
2590    fn private_type_alias_from_dependency_does_not_leak() {
2591        let result = analyze_multifile(vec![
2592            (
2593                "main.simf",
2594                "use lib::A::helper; fn main() { helper(); let x: Secret = 0; }",
2595            ),
2596            ("libs/lib/A.simf", "type Secret = u32; pub fn helper() {}"),
2597        ]);
2598
2599        assert!(
2600            result.is_err(),
2601            "private alias from another file leaked into root scope: {result:?}"
2602        );
2603    }
2604
2605    #[test]
2606    fn same_alias_name_in_different_modules_does_not_conflict_if_only_one_is_imported() {
2607        let result = analyze_multifile(vec![
2608            (
2609                "main.simf",
2610                "use lib::A::Word; use lib::B::id; fn main() { let x: Word = 0; assert!(jet::is_zero_32(id(x))); }",
2611            ),
2612            ("libs/lib/A.simf", "pub type Word = u32;"),
2613            ("libs/lib/B.simf", "pub type Word = u16; pub fn id(x: u32) -> u32 { x }"),
2614        ]);
2615
2616        assert!(
2617            result.is_ok(),
2618            "unimported alias from another module should not collide: {result:?}"
2619        );
2620    }
2621
2622    #[test]
2623    fn main_must_be_defined_once_per_project() {
2624        let result = analyze_multifile(vec![
2625            ("main.simf", "use lib::A::helper; fn main() { helper(); }"),
2626            ("libs/lib/A.simf", "fn main() {} pub fn helper() {}"),
2627        ]);
2628
2629        assert!(
2630            result.is_err(),
2631            "Main function must be inside an entry file: {result:?}"
2632        );
2633    }
2634
2635    #[test]
2636    fn test_local_definitions_visibility() {
2637        // main.simf defines a private function and a public function.
2638        // Expected: Both should be usable locally in main.
2639        let result = analyze_multifile(vec![(
2640            "main.simf",
2641            "fn private_fn() {} pub fn public_fn() {} fn main() { private_fn(); public_fn(); }",
2642        )]);
2643
2644        assert!(
2645            result.is_ok(),
2646            "Local definitions should be visible: {result:?}"
2647        );
2648    }
2649
2650    #[test]
2651    fn test_pub_use_propagation() {
2652        // Scenario: Re-exporting.
2653        let result = analyze_multifile(vec![
2654            ("libs/lib/A.simf", "pub fn foo() {}"),
2655            ("libs/lib/B.simf", "pub use crate::A::foo;"),
2656            ("main.simf", "use lib::B::foo; fn main() { foo(); }"),
2657        ]);
2658
2659        assert!(
2660            result.is_ok(),
2661            "Public re-exports must be visible: {result:?}"
2662        );
2663    }
2664
2665    #[test]
2666    fn test_private_import_encapsulation_error() {
2667        // Scenario: A private import cannot be re-exported.
2668        let result = analyze_multifile(vec![
2669            ("libs/lib/A.simf", "pub fn foo() {}"),
2670            ("libs/lib/B.simf", "use crate::A::foo;"), // <--- Private binding!
2671            ("main.simf", "use lib::B::foo; fn main() {}"),
2672        ]);
2673
2674        let err = result.expect_err("Private imports should not be accessible");
2675        assert!(err.contains("private") || err.contains("foo"));
2676    }
2677
2678    #[test]
2679    fn test_separated_type_aliases_and_functions() {
2680        let result = analyze_multifile(vec![
2681            ("libs/lib/A.simf", "pub type bar = u32; pub fn bar() {}"),
2682            (
2683                "main.simf",
2684                "use lib::A::bar; fn main() { bar(); let x: bar = 0; }",
2685            ),
2686        ]);
2687
2688        assert!(
2689            result.is_ok(),
2690            "AST should support separate namespaces for types and functions: {result:?}"
2691        );
2692    }
2693
2694    #[test]
2695    fn test_public_main_is_forbidden() {
2696        let result = analyze_multifile(vec![("main.simf", "pub fn main() {}")]);
2697
2698        let err = result.expect_err("Public main should be rejected");
2699        assert!(err.contains("Main") && err.contains("public"));
2700    }
2701
2702    #[test]
2703    fn test_aliasing_to_main_is_forbidden() {
2704        let result = analyze_multifile(vec![
2705            ("libs/lib/A.simf", "pub type bar = u32;"),
2706            ("main.simf", "use lib::A::bar as main; fn main() {}"),
2707        ]);
2708
2709        let err = result.expect_err("Aliasing to main should be rejected");
2710        assert!(err.contains("Main") && err.contains("alias"));
2711    }
2712
2713    #[test]
2714    fn test_renaming_with_use() {
2715        // Expected: "bar" is usable, "foo" is not.
2716        let result = analyze_multifile(vec![
2717            ("libs/lib/A.simf", "pub fn foo() {}"),
2718            (
2719                "main.simf",
2720                "use lib::A::foo as bar; fn main() { bar(); foo(); }",
2721            ),
2722        ]);
2723
2724        let err = result.expect_err("Using the original unaliased name 'foo' should fail");
2725        assert!(err.contains("foo") && (err.contains("not defined") || err.contains("unresolved")));
2726    }
2727
2728    #[test]
2729    fn test_multiple_aliases_in_list() {
2730        let result = analyze_multifile(vec![
2731            ("libs/lib/A.simf", "pub fn foo() {} pub fn baz() {}"),
2732            (
2733                "main.simf",
2734                "use lib::A::{foo as bar, baz as qux}; fn main() { bar(); qux(); }",
2735            ),
2736        ]);
2737
2738        assert!(
2739            result.is_ok(),
2740            "List aliases should be resolvable: {result:?}"
2741        );
2742    }
2743
2744    #[test]
2745    fn test_alias_private_item_fails() {
2746        let result = analyze_multifile(vec![
2747            ("libs/lib/A.simf", "fn secret() {}"),
2748            ("main.simf", "use lib::A::secret as my_secret; fn main() {}"),
2749        ]);
2750
2751        let err = result.expect_err("Aliasing a private item should fail");
2752        assert!(err.contains("secret") && err.contains("private"));
2753    }
2754
2755    #[test]
2756    fn test_deep_reexport_with_aliases() {
2757        let result = analyze_multifile(vec![
2758            ("libs/lib/A.simf", "pub fn original() {}"),
2759            ("libs/lib/B.simf", "pub use crate::A::original as middle;"),
2760            (
2761                "main.simf",
2762                "use lib::B::middle as final_name; fn main() { final_name(); }",
2763            ),
2764        ]);
2765
2766        assert!(
2767            result.is_ok(),
2768            "Deep alias re-exports should work: {result:?}"
2769        );
2770    }
2771
2772    #[test]
2773    fn test_deep_reexport_private_link_fails() {
2774        let result = analyze_multifile(vec![
2775            ("libs/lib/A.simf", "pub fn target() {}"),
2776            ("libs/lib/B.simf", "use crate::A::target as hidden_alias;"),
2777            ("main.simf", "use lib::B::hidden_alias; fn main() {}"),
2778        ]);
2779
2780        let err = result.expect_err("Private intermediate aliases should block resolution");
2781        assert!(err.contains("hidden_alias") && err.contains("private"));
2782    }
2783
2784    #[test]
2785    fn test_plain_import_and_alias_to_same_name_is_rejected() {
2786        let result = analyze_multifile(vec![
2787            ("libs/lib/A.simf", "pub fn foo() {}"),
2788            ("libs/lib/B.simf", "pub fn foo() {}"),
2789            (
2790                "main.simf",
2791                "use lib::A::foo; use lib::B::foo as foo; fn main() {}",
2792            ),
2793        ]);
2794
2795        let err = result.expect_err("Duplicate names in scope should fail");
2796        assert!(err.contains("foo") && err.contains("multiple times"));
2797    }
2798
2799    #[test]
2800    fn test_alias_cannot_reuse_local_definition_name() {
2801        let result = analyze_multifile(vec![
2802            ("libs/lib/A.simf", "pub fn bar() {}"),
2803            (
2804                "main.simf",
2805                "pub fn foo() {} use lib::A::bar as foo; fn main() {}",
2806            ),
2807        ]);
2808
2809        let err = result.expect_err("Alias reusing a local name should fail");
2810        assert!(err.contains("foo") && err.contains("multiple times"));
2811    }
2812
2813    #[test]
2814    #[ignore = "Pending better error handler:private item errors currently mask duplicate imports"]
2815    fn test_private_alias_error_does_not_mask_duplicate_function_import() {
2816        // Scenario: Loading a private item fails, but we must STILL catch if a
2817        // secondary import tries to bind to the same name.
2818        let result = analyze_multifile(vec![
2819            ("libs/lib/A.simf", "pub fn foo() {}"),
2820            ("libs/lib/B.simf", "pub fn foo() {} type foo = u32;"),
2821            (
2822                "main.simf",
2823                "use lib::A::foo; use lib::B::foo; fn main() {}",
2824            ),
2825        ]);
2826
2827        let err = result.expect_err("Duplicate function import should fail");
2828
2829        // It shouldn't just complain about the private type `foo`; it must also
2830        // complain that `foo` was imported twice!
2831        assert!(err.contains("foo") && err.contains("multiple times"));
2832    }
2833
2834    #[test]
2835    fn test_failed_alias_import_does_not_poison_following_imports() {
2836        let result = analyze_multifile(vec![
2837            ("libs/lib/A.simf", "pub fn nope() {}"),
2838            ("libs/lib/B.simf", "pub fn bar() {}"),
2839            (
2840                "main.simf",
2841                "use lib::A::missing as foo; use lib::B::bar as foo; fn main() {}",
2842            ),
2843        ]);
2844
2845        let err = result.expect_err("Build should fail on the unresolved import");
2846
2847        // It should complain about `missing`, but NOT about `foo` being duplicated,
2848        // because the first import failed and never actually reserved the name `foo`.
2849        assert!(err.contains("missing") || err.contains("not found"));
2850        assert!(!err.contains("multiple times"));
2851    }
2852
2853    #[test]
2854    fn test_local_function_cannot_reuse_alias_name() {
2855        let result = analyze_multifile(vec![
2856            ("libs/lib/A.simf", "pub fn bar() {}"),
2857            (
2858                "main.simf",
2859                "use lib::A::bar as foo; pub fn foo() {} fn main() {}",
2860            ),
2861        ]);
2862
2863        let err =
2864            result.expect_err("Build should fail when a local definition reuses an alias name");
2865        assert!(err.contains("foo") && err.contains("multiple times"));
2866    }
2867
2868    #[test]
2869    fn test_local_type_alias_cannot_reuse_alias_name() {
2870        let result = analyze_multifile(vec![
2871            ("libs/lib/A.simf", "pub type bar = u32;"),
2872            (
2873                "main.simf",
2874                "use lib::A::bar as foo; type foo = u64; fn main() {}",
2875            ),
2876        ]);
2877
2878        let err =
2879            result.expect_err("Build should fail when a local definition reuses an alias name");
2880        assert!(err.contains("foo") && err.contains("multiple times"));
2881    }
2882}
2883
2884#[cfg(test)]
2885mod module_tests {
2886    use crate::ast::scope_resolution_tests::analyze_multifile;
2887
2888    #[test]
2889    fn test_public_nested_modules_are_accessible() {
2890        let result = analyze_multifile(vec![
2891            (
2892                "libs/lib/A.simf",
2893                "pub mod outer { pub mod inner { pub fn target() {} } }",
2894            ),
2895            (
2896                "main.simf",
2897                "use lib::A::outer::inner::target; fn main() {}",
2898            ),
2899        ]);
2900
2901        assert!(
2902            result.is_ok(),
2903            "Deeply nested public modules should be accessible: {result:?}"
2904        );
2905    }
2906
2907    #[test]
2908    fn test_private_inner_module_blocks_external_access() {
2909        let result = analyze_multifile(vec![
2910            // `outer` is public, but `inner` is private
2911            // Even though `target` is public, the private wall at `inner` blocks it.
2912            (
2913                "libs/lib/A.simf",
2914                "pub mod outer { mod inner { pub fn target() {} } }",
2915            ),
2916            (
2917                "main.simf",
2918                "use lib::A::outer::inner::target; fn main() {}",
2919            ),
2920        ]);
2921
2922        let err = result.expect_err("Private inner module must block access");
2923        assert!(err.contains("inner") && err.contains("private"));
2924    }
2925
2926    #[test]
2927    #[ignore = "Not implemented now"]
2928    fn test_importing_a_whole_module_allows_path_traversal() {
2929        // Scenario: Instead of importing the function, the user imports the module itself,
2930        // and then uses the module name as a prefix.
2931        let result = analyze_multifile(vec![
2932            ("libs/lib/A.simf", "pub mod math { pub fn add() {} }"),
2933            ("main.simf", "use lib::A::math; fn main() { math::add(); }"),
2934        ]);
2935
2936        assert!(
2937            result.is_ok(),
2938            "Importing a module should bring its namespace into scope: {result:?}"
2939        );
2940    }
2941
2942    #[test]
2943    fn test_duplicate_module_blocks_are_rejected() {
2944        let result = analyze_multifile(vec![(
2945            "main.simf",
2946            "mod inner {} mod inner {} fn main() {}",
2947        )]);
2948
2949        let err = result.expect_err("Duplicate mod blocks must fail");
2950        assert!(err.contains("inner") && err.contains("multiple times"));
2951    }
2952
2953    #[test]
2954    fn test_sibling_modules_can_access_each_others_public_items() {
2955        // In Rust, sibling modules share the same parent, so they are allowed to see
2956        // each other (even if they are private to the outside world).
2957        let result = analyze_multifile(vec![(
2958            "main.simf",
2959            "
2960                mod brother { pub fn toy() {} }
2961                mod sister { use crate::brother::toy; }
2962                fn main() {}
2963            ",
2964        )]);
2965
2966        assert!(
2967            result.is_ok(),
2968            "Sibling modules should be able to import from each other: {result:?}"
2969        );
2970    }
2971
2972    #[test]
2973    fn test_inline_module_can_import_global_item() {
2974        // Scenario: A nested module needs to access a function defined at the very top of the file.
2975        // This proves `crate::` correctly points to the un-wrapped MAIN_MODULE root.
2976        let result = analyze_multifile(vec![(
2977            "main.simf",
2978            "
2979                pub fn global_func() {}
2980                mod inner { 
2981                    use crate::global_func; 
2982                    pub fn call_it() { global_func(); } 
2983                }
2984                fn main() {}
2985            ",
2986        )]);
2987
2988        assert!(
2989            result.is_ok(),
2990            "Nested modules must be able to import global items: {result:?}"
2991        );
2992    }
2993
2994    #[test]
2995    fn test_deeply_nested_inline_modules() {
2996        // Scenario: Traversing multiple inline module boundaries.
2997        let result = analyze_multifile(vec![(
2998            "main.simf",
2999            "
3000                mod level1 {
3001                    pub mod level2 {
3002                        pub fn treasure() {}
3003                    }
3004                }
3005                mod explorer {
3006                    use crate::level1::level2::treasure;
3007                }
3008                fn main() {}
3009            ",
3010        )]);
3011
3012        assert!(
3013            result.is_ok(),
3014            "Deeply nested inline modules must resolve correctly: {result:?}"
3015        );
3016    }
3017
3018    #[test]
3019    fn test_inline_module_privacy_is_enforced_between_siblings() {
3020        // Scenario: Sibling modules can see each other, but they CANNOT see each other's PRIVATE items.
3021        let result = analyze_multifile(vec![(
3022            "main.simf",
3023            "
3024                mod brother { 
3025                    fn secret_toy() {} // Missing 'pub'
3026                }
3027                mod sister { 
3028                    use crate::brother::secret_toy; 
3029                }
3030                fn main() {}
3031            ",
3032        )]);
3033
3034        let err = result.expect_err("Private inline items must remain hidden from siblings");
3035        assert!(err.contains("secret_toy") && err.contains("private"));
3036    }
3037
3038    #[test]
3039    fn test_main_scope_cannot_access_private_inline_items() {
3040        // Scenario: The root of the file tries to import a private item from its own child module.
3041        let result = analyze_multifile(vec![(
3042            "main.simf",
3043            "
3044                mod child { 
3045                    fn hidden() {} 
3046                }
3047                use crate::child::hidden;
3048                fn main() {}
3049            ",
3050        )]);
3051
3052        let err = result.expect_err("The root file scope must respect inline module privacy");
3053        assert!(err.contains("hidden") && err.contains("private"));
3054    }
3055
3056    #[test]
3057    fn test_inline_module_alias_import() {
3058        // Scenario: Importing an item from a sibling inline module and renaming it locally.
3059        let result = analyze_multifile(vec![(
3060            "main.simf",
3061            "
3062                mod supplier {
3063                    pub fn raw_material() {}
3064                }
3065                mod factory {
3066                    use crate::supplier::raw_material as finished_product;
3067                    pub fn produce() { finished_product(); }
3068                }
3069                fn main() {}
3070            ",
3071        )]);
3072
3073        assert!(
3074            result.is_ok(),
3075            "Inline imports must support aliasing: {result:?}"
3076        );
3077    }
3078}
3079
3080#[cfg(test)]
3081mod enum_tests {
3082    use crate::ast::ElementsJetHinter;
3083    use crate::{TemplateProgram, UnstableFeatures};
3084
3085    fn analyze(src: &str) -> Result<(), String> {
3086        TemplateProgram::new_with_unstable(
3087            src,
3088            &UnstableFeatures::all(),
3089            Box::new(ElementsJetHinter::new()),
3090        )
3091        .map(|_| ())
3092        .map_err(|e| e.to_string())
3093    }
3094
3095    #[test]
3096    fn enum_declaration_registers_type_alias() {
3097        let result = analyze(
3098            "enum Color { Red, Green }
3099             fn main() { let _x: Color = witness::C; }",
3100        );
3101        assert!(
3102            result.is_ok(),
3103            "enum name should resolve as a type: {result:?}"
3104        );
3105    }
3106
3107    #[test]
3108    fn enum_duplicate_variant_name_is_error() {
3109        let result = analyze("enum Color { Red, Red }\nfn main() {}");
3110        assert!(result.is_err());
3111        assert!(result.unwrap_err().contains("duplicate variant name"));
3112    }
3113
3114    #[test]
3115    fn enum_variant_named_after_builtin_pattern_is_ok() {
3116        // The written `Enum::Variant` form keeps `Action::None` distinct
3117        // from the built-in option literal, so variant names are
3118        // unrestricted.
3119        let result = analyze(
3120            "enum Action { None, Some, Other, }
3121             fn main() {
3122                 match witness::W {
3123                     Action::None => {},
3124                     Action::Some => {},
3125                     Action::Other => {},
3126                 }
3127             }",
3128        );
3129        assert!(
3130            result.is_ok(),
3131            "builtin-named variants should work: {result:?}"
3132        );
3133    }
3134
3135    #[test]
3136    fn enum_empty_is_error() {
3137        let result = analyze("enum Color { }\nfn main() {}");
3138        assert!(result.is_err());
3139        assert!(result.unwrap_err().contains("at least one variant"));
3140    }
3141
3142    #[test]
3143    fn enum_duplicate_name_is_error() {
3144        let result = analyze(
3145            "enum Color { Red, Green }
3146             enum Color { Blue, Cyan }
3147             fn main() {}",
3148        );
3149        assert!(result.is_err(), "redefined enum name should error");
3150    }
3151
3152    #[test]
3153    fn enum_declaration_inside_module_errors() {
3154        // FIXME: Enums may only be declared at the top level of a file.
3155        let result = analyze(
3156            "mod m {
3157                 pub enum Choice { X, Y, }
3158             }
3159             fn main() {}",
3160        );
3161        let err = result.expect_err("enum inside `mod` must be rejected");
3162        assert!(
3163            err.contains("top level"),
3164            "error should say enums are top-level only: {err}"
3165        );
3166    }
3167
3168    #[test]
3169    fn enum_declaration_in_dependency_errors() {
3170        use crate::ast::scope_resolution_tests::analyze_multifile;
3171
3172        // FIXME: An enum's declared name is its identity in the ABI, so enums may only be declared in the program's own files.
3173        let result = analyze_multifile(vec![
3174            (
3175                "main.simf",
3176                "use lib::A::helper;
3177                 fn main() { helper(); }",
3178            ),
3179            (
3180                "libs/lib/A.simf",
3181                "pub enum Status { On, Off, } pub fn helper() {}",
3182            ),
3183        ]);
3184        let err = result.expect_err("enums in dependency files must be rejected");
3185        assert!(
3186            err.contains("dependency"),
3187            "error should say enums cannot live in dependency files: {err}"
3188        );
3189    }
3190
3191    #[test]
3192    fn enum_payload_match_binds_payload() {
3193        let result = analyze(
3194            "enum Action { Refresh(u32, bool), Cold, }
3195             fn main() {
3196                 match witness::W {
3197                     Action::Refresh(n: u32, b: bool) => {
3198                         assert!(jet::is_zero_32(n));
3199                         assert!(b);
3200                     },
3201                     Action::Cold => {},
3202                 }
3203             }",
3204        );
3205        assert!(
3206            result.is_ok(),
3207            "payload bindings should analyze: {result:?}"
3208        );
3209    }
3210
3211    #[test]
3212    fn enum_payload_binding_type_mismatch_is_error() {
3213        let result = analyze(
3214            "enum Action { Refresh(u32), Cold, }
3215             fn main() {
3216                 match witness::W {
3217                     Action::Refresh(n: u16) => { assert!(jet::is_zero_16(n)); },
3218                     Action::Cold => {},
3219                 }
3220             }",
3221        );
3222        assert!(
3223            result.is_err(),
3224            "binding type must equal the declared payload type"
3225        );
3226    }
3227
3228    #[test]
3229    fn enum_payload_binding_arity_mismatch_is_error() {
3230        let result = analyze(
3231            "enum Action { Refresh(u32, bool), Cold, }
3232             fn main() {
3233                 match witness::W {
3234                     Action::Refresh(n: u32) => { assert!(jet::is_zero_32(n)); },
3235                     Action::Cold => {},
3236                 }
3237             }",
3238        );
3239        assert!(result.is_err());
3240        assert!(
3241            result.unwrap_err().contains("payload value"),
3242            "error should describe the arity mismatch"
3243        );
3244    }
3245
3246    #[test]
3247    fn enum_single_variant_matches() {
3248        // A single-variant enum is a named unit type; its match has one arm.
3249        let result = analyze(
3250            "enum Marker { Only }
3251             fn main() {
3252                 match witness::M {
3253                     Marker::Only => {},
3254                 }
3255             }",
3256        );
3257        assert!(
3258            result.is_ok(),
3259            "single-variant enum should work: {result:?}"
3260        );
3261    }
3262
3263    #[test]
3264    fn enum_match_undefined_enum_is_error() {
3265        let result = analyze(
3266            "fn main() {
3267                 match witness::P {
3268                     Unknown::A => {},
3269                     Unknown::B => {},
3270                 }
3271             }",
3272        );
3273        assert!(result.is_err(), "undefined enum should error");
3274    }
3275
3276    #[test]
3277    fn enum_match_mixed_enum_names_is_error() {
3278        let result = analyze(
3279            "enum A { X, Y }
3280             enum B { P, Q }
3281             fn main() {
3282                 match witness::W {
3283                     A::X => {},
3284                     B::Q => {},
3285                 }
3286             }",
3287        );
3288        assert!(result.is_err());
3289        assert!(result.unwrap_err().contains("same enum"));
3290    }
3291
3292    #[test]
3293    fn enum_match_unknown_variant_is_error() {
3294        let result = analyze(
3295            "enum A { X, Y }
3296             fn main() {
3297                 match witness::W {
3298                     A::X => {},
3299                     A::Z => {},
3300                 }
3301             }",
3302        );
3303        assert!(result.is_err());
3304        assert!(result.unwrap_err().contains("not defined"));
3305    }
3306
3307    #[test]
3308    fn enum_match_duplicate_arm_is_error() {
3309        let result = analyze(
3310            "enum A { X, Y }
3311             fn main() {
3312                 match witness::W {
3313                     A::X => {},
3314                     A::X => {},
3315                     A::Y => {},
3316                 }
3317             }",
3318        );
3319        assert!(result.is_err());
3320        assert!(result.unwrap_err().contains("duplicate arm"));
3321    }
3322
3323    #[test]
3324    fn enum_match_missing_arm_is_error() {
3325        let result = analyze(
3326            "enum A { X, Y, Z }
3327             fn main() {
3328                 match witness::W {
3329                     A::X => {},
3330                     A::Y => {},
3331                 }
3332             }",
3333        );
3334        assert!(result.is_err());
3335        assert!(result.unwrap_err().contains("must cover all 3 variants"));
3336    }
3337
3338    #[test]
3339    fn enum_match_rejects_scrutinee_of_different_enum() {
3340        let result = analyze(
3341            "enum A { X, Y, }
3342             enum B { P, Q, }
3343             fn main() {
3344                 let v: A = witness::V;
3345                 match v {
3346                     B::P => {},
3347                     B::Q => {},
3348                 }
3349             }",
3350        );
3351        assert!(
3352            result.is_err(),
3353            "matching a value of enum A against B's variants must be a type error"
3354        );
3355    }
3356
3357    #[test]
3358    fn enum_match_rejects_plain_u8_scrutinee() {
3359        let result = analyze(
3360            "enum Action { A, B, }
3361             fn main() {
3362                 let v: u8 = witness::V;
3363                 match v {
3364                     Action::A => {},
3365                     Action::B => {},
3366                 }
3367             }",
3368        );
3369        assert!(
3370            result.is_err(),
3371            "matching a u8 against enum variants must be a type error"
3372        );
3373    }
3374
3375    #[test]
3376    fn enum_match_rejects_same_shaped_enum() {
3377        // Identity is the declaration site: two enums with the same variants
3378        // are distinct types, so their values are not interchangeable.
3379        let result = analyze(
3380            "enum AChoice { X, Y, }
3381             enum BChoice { X, Y, }
3382             fn main() {
3383                 let v: AChoice = witness::V;
3384                 match v {
3385                     BChoice::X => {},
3386                     BChoice::Y => {},
3387                 }
3388             }",
3389        );
3390        assert!(
3391            result.is_err(),
3392            "structurally identical enums must not be interchangeable"
3393        );
3394    }
3395
3396    #[test]
3397    fn enum_match_on_non_enum_alias_is_error() {
3398        let result = analyze(
3399            "type Foo = u32;
3400             fn main() {
3401                 match witness::W {
3402                     Foo::A => {},
3403                     Foo::B => {},
3404                 }
3405             }",
3406        );
3407        assert!(result.is_err());
3408        assert!(
3409            result.unwrap_err().contains("not an enum"),
3410            "a defined non-enum alias should not report an undefined alias"
3411        );
3412    }
3413
3414    #[test]
3415    fn enum_cast_to_same_shaped_enum_is_rejected() {
3416        // Casts prove structural equality, but enums are nominal: a cast
3417        // between same-shaped enums would map variants by ordinal position
3418        // (Source::Allow -> Target::Deny), silently reversing semantics.
3419        let result = analyze(
3420            "enum Source { Allow, Deny, }
3421             enum Target { Deny, Allow, }
3422             fn main() {
3423                 let s: Source = Source::Allow;
3424                 let _t: Target = <Source>::into(s);
3425             }",
3426        );
3427        assert!(
3428            result.is_err(),
3429            "same-shaped enums must not cast into each other"
3430        );
3431    }
3432
3433    #[test]
3434    fn enum_cast_to_structural_sum_is_rejected() {
3435        let result = analyze(
3436            "enum Source { Allow, Deny, }
3437             fn main() {
3438                 let s: Source = Source::Allow;
3439                 let _e: Either<(), ()> = <Source>::into(s);
3440             }",
3441        );
3442        assert!(
3443            result.is_err(),
3444            "an enum must not cast to its structural sum"
3445        );
3446
3447        let result = analyze(
3448            "enum Source { Allow, Deny, }
3449             fn main() {
3450                 let e: Either<(), ()> = Left(());
3451                 let _s: Source = <Either<(), ()>>::into(e);
3452             }",
3453        );
3454        assert!(result.is_err(), "a structural sum must not cast to an enum");
3455    }
3456
3457    #[test]
3458    fn enum_cast_reshaping_enum_free_siblings_is_ok() {
3459        // Enum-free structure may reshape around an enum that stays put
3460        // at its position.
3461        let result = analyze(
3462            "enum E { A, B, }
3463             fn main() {
3464                 let x: (E, (u16, u16)) = (E::A, (1, 2));
3465                 let _y: (E, u32) = <(E, (u16, u16))>::into(x);
3466             }",
3467        );
3468        assert!(
3469            result.is_ok(),
3470            "reshaping enum-free siblings must stay castable: {result:?}"
3471        );
3472    }
3473
3474    #[test]
3475    fn enum_cast_to_itself_is_ok() {
3476        let result = analyze(
3477            "enum Source { Allow, Deny, }
3478             fn main() {
3479                 let s: Source = Source::Allow;
3480                 let _t: Source = <Source>::into(s);
3481             }",
3482        );
3483        assert!(
3484            result.is_ok(),
3485            "nominally identical cast should stay allowed: {result:?}"
3486        );
3487    }
3488
3489    #[test]
3490    fn enum_named_after_builtin_type_is_rejected() {
3491        // `enum Signature` would shadow the built-in alias: constructions
3492        // would name the enum while type annotations resolve to the
3493        // builtin, and the ABI would report the bare name ambiguously.
3494        for name in crate::str::ALIAS_RESERVED {
3495            let result = analyze(&format!("enum {name} {{ A, B, }}\nfn main() {{}}"));
3496            assert!(result.is_err(), "enum named `{name}` must be rejected");
3497        }
3498    }
3499
3500    #[test]
3501    fn enum_alias_named_after_pattern_is_matchable() {
3502        // `type Left = Action` shadows a built-in pattern name; the arm
3503        // parser distinguishes `Left::A` (enum path) from `Left(x)`
3504        // (built-in pattern) by the `::` that follows.
3505        let result = analyze(
3506            "enum Action { A, B, }
3507             type Left = Action;
3508             fn main() {
3509                 let v: Left = Action::A;
3510                 match v {
3511                     Left::A => {},
3512                     Left::B => {},
3513                 }
3514             }",
3515        );
3516        assert!(
3517            result.is_ok(),
3518            "an enum alias shadowing a pattern name must be matchable: {result:?}"
3519        );
3520    }
3521
3522    #[test]
3523    fn enum_alias_named_none_is_constructable() {
3524        // The nullary built-in `None` parses without parentheses, so the
3525        // expression parser must yield to enum construction when `::`
3526        // follows, like the arm parser does.
3527        let result = analyze(
3528            "enum Action { A, B, }
3529             type None = Action;
3530             fn main() {
3531                 let _x: None = None::A;
3532             }",
3533        );
3534        assert!(
3535            result.is_ok(),
3536            "`None::A` must parse as enum construction: {result:?}"
3537        );
3538    }
3539
3540    #[test]
3541    fn alias_named_after_pattern_stays_valid_without_enums() {
3542        // Stable programs may alias pattern names; the enums feature must
3543        // not retroactively reject them.
3544        let result = TemplateProgram::new_with_unstable(
3545            "type Left = u32;\nfn main() { let _x: Left = 1; }",
3546            &UnstableFeatures::none(),
3547            Box::new(ElementsJetHinter::new()),
3548        );
3549        assert!(
3550            result.is_ok(),
3551            "stable alias names must stay valid without -Z enums"
3552        );
3553    }
3554
3555    #[test]
3556    fn enum_construction_follows_lexical_scope_in_source() {
3557        // Inside a module the root's `E` is not in scope: only the local
3558        // import name may construct, exactly as matches require. The
3559        // declared-name fallback applies only to witness/argument files.
3560        let result = analyze(
3561            "pub enum E { A, B, }
3562             mod m {
3563                 use crate::E as Choice;
3564                 pub fn make() -> Choice {
3565                     E::A
3566                 }
3567             }
3568             use crate::m::make;
3569             fn main() {
3570                 let _x: E = make();
3571             }",
3572        );
3573        assert!(
3574            result.is_err(),
3575            "an out-of-scope declared name must not construct"
3576        );
3577
3578        let result = analyze(
3579            "pub enum E { A, B, }
3580             mod m {
3581                 use crate::E as Choice;
3582                 pub fn make() -> Choice {
3583                     Choice::A
3584                 }
3585             }
3586             use crate::m::make;
3587             fn main() {
3588                 let _x: E = make();
3589             }",
3590        );
3591        assert!(
3592            result.is_ok(),
3593            "the imported alias must construct: {result:?}"
3594        );
3595    }
3596
3597    #[test]
3598    fn enum_requires_unstable_feature() {
3599        let result = TemplateProgram::new_with_unstable(
3600            "enum Color { Red, Green }\nfn main() {}",
3601            &UnstableFeatures::none(),
3602            Box::new(ElementsJetHinter::new()),
3603        );
3604        assert!(result.is_err(), "enum syntax is gated behind -Z enums");
3605    }
3606}
3607
3608#[cfg(feature = "fmt")]
3609#[cfg(test)]
3610mod literal_tests {
3611    use crate::parse::ParseFromStr;
3612    use crate::value::{UIntValue, Value};
3613
3614    use super::*;
3615
3616    #[test]
3617    fn analyzed_numeric_literals_accept_digit_separators() {
3618        let cases = [
3619            ("1_337", UIntType::U16, Value::from(UIntValue::U16(1_337))),
3620            (
3621                "0b1010_0101",
3622                UIntType::U8,
3623                Value::from(UIntValue::U8(0b1010_0101)),
3624            ),
3625            (
3626                "0xDE_AD_BE_EF",
3627                UIntType::U32,
3628                Value::from(UIntValue::U32(0xdead_beef)),
3629            ),
3630        ];
3631
3632        for (source, integer_type, expected) in cases {
3633            let parsed = parse::Expression::parse_from_str(source).expect("literal parses");
3634            let analyzed =
3635                Expression::analyze_const(&parsed, &integer_type.into()).expect("literal analyzes");
3636
3637            let ExpressionInner::Single(single) = analyzed.inner() else {
3638                panic!("expected a single expression")
3639            };
3640            let SingleExpressionInner::Constant(value) = single.inner() else {
3641                panic!("expected a constant expression")
3642            };
3643
3644            assert_eq!(value, &expected, "unexpected value for {source:?}");
3645            assert_eq!(single.span().to_slice(source), Some(source));
3646        }
3647    }
3648}