cranelift_isle/
sema.rs

1//! Semantic analysis.
2//!
3//! This module primarily contains the type environment and term environment.
4//!
5//! The type environment is constructed by analyzing an input AST. The type
6//! environment records the types used in the input source and the types of our
7//! various rules and symbols. ISLE's type system is intentionally easy to
8//! check, only requires a single pass over the AST, and doesn't require any
9//! unification or anything like that.
10//!
11//! The term environment is constructed from both the AST and type
12//! environment. It is sort of a typed and reorganized AST that more directly
13//! reflects ISLE semantics than the input ISLE source code (where as the AST is
14//! the opposite).
15
16use crate::ast;
17use crate::error::*;
18use crate::lexer::Pos;
19use crate::log;
20use crate::stablemapset::{StableMap, StableSet};
21use std::collections::hash_map::Entry;
22use std::collections::BTreeMap;
23use std::collections::BTreeSet;
24use std::collections::HashMap;
25use std::fmt;
26
27declare_id!(
28    /// The id of an interned symbol.
29    Sym
30);
31declare_id!(
32    /// The id of an interned type inside the `TypeEnv`.
33    TypeId
34);
35declare_id!(
36    /// The id of a variant inside an enum.
37    VariantId
38);
39declare_id!(
40    /// The id of a field inside a variant.
41    FieldId
42);
43declare_id!(
44    /// The id of an interned term inside the `TermEnv`.
45    TermId
46);
47declare_id!(
48    /// The id of an interned rule inside the `TermEnv`.
49    RuleId
50);
51declare_id!(
52    /// The id of a bound variable inside a `Bindings`.
53    VarId
54);
55
56/// The type environment.
57///
58/// Keeps track of which symbols and rules have which types.
59#[derive(Debug)]
60pub struct TypeEnv {
61    /// Arena of interned symbol names.
62    ///
63    /// Referred to indirectly via `Sym` indices.
64    pub syms: Vec<String>,
65
66    /// Map of already-interned symbol names to their `Sym` ids.
67    pub sym_map: StableMap<String, Sym>,
68
69    /// Arena of type definitions.
70    ///
71    /// Referred to indirectly via `TypeId`s.
72    pub types: Vec<Type>,
73
74    /// A map from a type name symbol to its `TypeId`.
75    pub type_map: StableMap<Sym, TypeId>,
76
77    /// The types of constant symbols.
78    pub const_types: StableMap<Sym, TypeId>,
79
80    /// Type errors that we've found so far during type checking.
81    pub errors: Vec<Error>,
82}
83
84/// A built-in type.
85#[derive(Copy, Clone, Debug, PartialEq, Eq)]
86#[repr(u8)]
87pub enum BuiltinType {
88    /// The type of booleans, with values `true` and `false`.
89    Bool,
90    /// The types of fixed-width integers.
91    Int(IntType),
92}
93
94/// A built-in fixed-width integer type.
95#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub enum IntType {
97    /// Unsigned, 8 bits.
98    U8,
99    /// Unsigned, 16 bits.
100    U16,
101    /// Unsigned, 32 bits.
102    U32,
103    /// Unsigned, 64 bits.
104    U64,
105    /// Unsigned, 128 bits.
106    U128,
107    /// Unsigned, enough bits to hold a pointer.
108    USize,
109    /// Signed, 8 bits.
110    I8,
111    /// Signed, 16 bits.
112    I16,
113    /// Signed, 32 bits.
114    I32,
115    /// Signed, 64 bits.
116    I64,
117    /// Signed, 128 bits.
118    I128,
119    /// Unsigned, enough bits to hold a pointer.
120    ISize,
121}
122
123impl IntType {
124    /// Get the integer type's name.
125    pub fn name(&self) -> &'static str {
126        match self {
127            IntType::U8 => "u8",
128            IntType::U16 => "u16",
129            IntType::U32 => "u32",
130            IntType::U64 => "u64",
131            IntType::U128 => "u128",
132            IntType::USize => "usize",
133            IntType::I8 => "i8",
134            IntType::I16 => "i16",
135            IntType::I32 => "i32",
136            IntType::I64 => "i64",
137            IntType::I128 => "i128",
138            IntType::ISize => "isize",
139        }
140    }
141
142    /// Is this integer type signed?
143    pub fn is_signed(&self) -> bool {
144        match self {
145            IntType::U8
146            | IntType::U16
147            | IntType::U32
148            | IntType::U64
149            | IntType::U128
150            | IntType::USize => false,
151
152            IntType::I8
153            | IntType::I16
154            | IntType::I32
155            | IntType::I64
156            | IntType::I128
157            | IntType::ISize => true,
158        }
159    }
160}
161
162impl fmt::Display for IntType {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        write!(f, "{}", self.name())
165    }
166}
167
168impl BuiltinType {
169    /// All the built-in types.
170    pub const ALL: &'static [Self] = &[
171        Self::Bool,
172        Self::Int(IntType::U8),
173        Self::Int(IntType::U16),
174        Self::Int(IntType::U32),
175        Self::Int(IntType::U64),
176        Self::Int(IntType::U128),
177        Self::Int(IntType::USize),
178        Self::Int(IntType::I8),
179        Self::Int(IntType::I16),
180        Self::Int(IntType::I32),
181        Self::Int(IntType::I64),
182        Self::Int(IntType::I128),
183        Self::Int(IntType::ISize),
184    ];
185
186    /// Get the built-in type's name.
187    pub fn name(&self) -> &'static str {
188        match self {
189            BuiltinType::Bool => "bool",
190            BuiltinType::Int(it) => it.name(),
191        }
192    }
193
194    const fn to_usize(&self) -> usize {
195        match self {
196            Self::Bool => 0,
197            Self::Int(ty) => *ty as usize + 1,
198        }
199    }
200}
201
202impl TypeId {
203    const fn builtin(builtin: BuiltinType) -> Self {
204        Self(builtin.to_usize())
205    }
206
207    /// TypeId for `bool`.
208    pub const BOOL: Self = Self::builtin(BuiltinType::Bool);
209
210    /// TypeId for `u8`.
211    pub const U8: Self = Self::builtin(BuiltinType::Int(IntType::U8));
212    /// TypeId for `u16`.
213    pub const U16: Self = Self::builtin(BuiltinType::Int(IntType::U16));
214    /// TypeId for `u32`.
215    pub const U32: Self = Self::builtin(BuiltinType::Int(IntType::U32));
216    /// TypeId for `u64`.
217    pub const U64: Self = Self::builtin(BuiltinType::Int(IntType::U64));
218    /// TypeId for `u128`.
219    pub const U128: Self = Self::builtin(BuiltinType::Int(IntType::U128));
220    /// TypeId for `usize`.
221    pub const USIZE: Self = Self::builtin(BuiltinType::Int(IntType::USize));
222
223    /// TypeId for `i8`.
224    pub const I8: Self = Self::builtin(BuiltinType::Int(IntType::I8));
225    /// TypeId for `i16`.
226    pub const I16: Self = Self::builtin(BuiltinType::Int(IntType::I16));
227    /// TypeId for `i32`.
228    pub const I32: Self = Self::builtin(BuiltinType::Int(IntType::I32));
229    /// TypeId for `i64`.
230    pub const I64: Self = Self::builtin(BuiltinType::Int(IntType::I64));
231    /// TypeId for `i128`.
232    pub const I128: Self = Self::builtin(BuiltinType::Int(IntType::I128));
233    /// TypeId for `isize`.
234    pub const ISIZE: Self = Self::builtin(BuiltinType::Int(IntType::ISize));
235}
236
237/// A type.
238#[derive(Clone, Debug, PartialEq, Eq)]
239pub enum Type {
240    /// Built-in types. Always in scope, not defined anywhere in source.
241    Builtin(BuiltinType),
242
243    /// A primitive, `Copy` type.
244    ///
245    /// These are always defined externally, and we allow literals of these
246    /// types to pass through from ISLE source code to the emitted Rust code.
247    Primitive(TypeId, Sym, Pos),
248
249    /// A sum type.
250    ///
251    /// Note that enums with only one variant are equivalent to a "struct".
252    Enum {
253        /// The name of this enum.
254        name: Sym,
255        /// This `enum`'s type id.
256        id: TypeId,
257        /// Is this `enum` defined in external Rust code?
258        ///
259        /// If so, ISLE will not emit a definition for it. If not, then it will
260        /// emit a Rust definition for it.
261        is_extern: bool,
262        /// Whether this type should *not* derive `Debug`.
263        ///
264        /// Incompatible with `is_extern`.
265        is_nodebug: bool,
266        /// The different variants for this enum.
267        variants: Vec<Variant>,
268        /// The ISLE source position where this `enum` is defined.
269        pos: Pos,
270    },
271}
272
273impl Type {
274    /// Get the name of this `Type`.
275    pub fn name<'a>(&self, tyenv: &'a TypeEnv) -> &'a str {
276        match self {
277            Self::Builtin(ty) => ty.name(),
278            Self::Primitive(_, name, _) | Self::Enum { name, .. } => &tyenv.syms[name.index()],
279        }
280    }
281
282    /// Get the position where this type was defined.
283    pub fn pos(&self) -> Option<Pos> {
284        match self {
285            Self::Builtin(..) => None,
286            Self::Primitive(_, _, pos) | Self::Enum { pos, .. } => Some(*pos),
287        }
288    }
289
290    /// Is this a primitive type?
291    pub fn is_prim(&self) -> bool {
292        matches!(self, Type::Primitive(..))
293    }
294
295    /// Is this a built-in integer type?
296    pub fn is_int(&self) -> bool {
297        matches!(self, Self::Builtin(BuiltinType::Int(_)))
298    }
299}
300
301/// A variant of an enum.
302#[derive(Clone, Debug, PartialEq, Eq)]
303pub struct Variant {
304    /// The name of this variant.
305    pub name: Sym,
306
307    /// The full, prefixed-with-the-enum's-name name of this variant.
308    ///
309    /// E.g. if the enum is `Foo` and this variant is `Bar`, then the
310    /// `fullname` is `Foo.Bar`.
311    pub fullname: Sym,
312
313    /// The id of this variant, i.e. the index of this variant within its
314    /// enum's `Type::Enum::variants`.
315    pub id: VariantId,
316
317    /// The data fields of this enum variant.
318    pub fields: Vec<Field>,
319}
320
321/// A field of a `Variant`.
322#[derive(Clone, Debug, PartialEq, Eq)]
323pub struct Field {
324    /// The name of this field.
325    pub name: Sym,
326    /// This field's id.
327    pub id: FieldId,
328    /// The type of this field.
329    pub ty: TypeId,
330}
331
332/// The term environment.
333///
334/// This is sort of a typed and reorganized AST that more directly reflects ISLE
335/// semantics than the input ISLE source code (where as the AST is the
336/// opposite).
337#[derive(Clone, Debug)]
338pub struct TermEnv {
339    /// Arena of interned terms defined in this ISLE program.
340    ///
341    /// This is indexed by `TermId`.
342    pub terms: Vec<Term>,
343
344    /// A map from am interned `Term`'s name to its `TermId`.
345    pub term_map: StableMap<Sym, TermId>,
346
347    /// Arena of interned rules defined in this ISLE program.
348    ///
349    /// This is indexed by `RuleId`.
350    pub rules: Vec<Rule>,
351
352    /// Map from (inner_ty, outer_ty) pairs to term IDs, giving the
353    /// defined implicit type-converter terms we can try to use to fit
354    /// types together.
355    pub converters: StableMap<(TypeId, TypeId), TermId>,
356
357    /// Flag for whether to expand internal extractors in the
358    /// translation from the AST to sema.
359    pub expand_internal_extractors: bool,
360}
361
362/// A term.
363///
364/// Maps parameter types to result types if this is a constructor term, or
365/// result types to parameter types if this is an extractor term. Or both if
366/// this term can be either a constructor or an extractor.
367#[derive(Clone, Debug, PartialEq, Eq)]
368pub struct Term {
369    /// This term's id.
370    pub id: TermId,
371    /// The source position where this term was declared.
372    pub decl_pos: Pos,
373    /// The name of this term.
374    pub name: Sym,
375    /// The parameter types to this term.
376    pub arg_tys: Vec<TypeId>,
377    /// The result types of this term.
378    pub ret_ty: TypeId,
379    /// The kind of this term.
380    pub kind: TermKind,
381}
382
383/// Flags from a term's declaration with `(decl ...)`.
384#[derive(Copy, Clone, Debug, PartialEq, Eq)]
385pub struct TermFlags {
386    /// Whether the term is marked as `pure`.
387    pub pure: bool,
388    /// Whether the term is marked as `multi`.
389    pub multi: bool,
390    /// Whether the term is marked as `partial`.
391    pub partial: bool,
392}
393
394impl TermFlags {
395    /// Return a new `TermFlags` suitable for a term on the LHS of a rule.
396    pub fn on_lhs(mut self) -> Self {
397        self.pure = true;
398        self.partial = true;
399        self
400    }
401}
402
403/// The kind of a term.
404#[derive(Clone, Debug, PartialEq, Eq)]
405pub enum TermKind {
406    /// An enum variant constructor or extractor.
407    EnumVariant {
408        /// Which variant of the enum: e.g. for enum type `A` if a term is
409        /// `(A.A1 ...)` then the variant ID corresponds to `A1`.
410        variant: VariantId,
411    },
412    /// A term declared via a `(decl ...)` form.
413    Decl {
414        /// Flags from the term's declaration.
415        flags: TermFlags,
416        /// The kind of this term's constructor, if any.
417        constructor_kind: Option<ConstructorKind>,
418        /// The kind of this term's extractor, if any.
419        extractor_kind: Option<ExtractorKind>,
420    },
421}
422
423/// The kind of a constructor for a term.
424#[derive(Clone, Debug, PartialEq, Eq)]
425pub enum ConstructorKind {
426    /// A term with "internal" rules that work in the forward direction. Becomes
427    /// a compiled Rust function in the generated code.
428    InternalConstructor,
429    /// A term defined solely by an external constructor function.
430    ExternalConstructor {
431        /// The external name of the constructor function.
432        name: Sym,
433    },
434}
435
436/// The kind of an extractor for a term.
437#[derive(Clone, Debug, PartialEq, Eq)]
438pub enum ExtractorKind {
439    /// A term that defines an "extractor macro" in the LHS of a pattern. Its
440    /// arguments take patterns and are simply substituted with the given
441    /// patterns when used.
442    InternalExtractor {
443        /// This extractor's pattern.
444        template: ast::Pattern,
445    },
446    /// A term defined solely by an external extractor function.
447    ExternalExtractor {
448        /// The external name of the extractor function.
449        name: Sym,
450        /// Is the external extractor infallible?
451        infallible: bool,
452        /// The position where this external extractor was declared.
453        pos: Pos,
454    },
455}
456
457/// How many values a function can return.
458#[derive(Clone, Copy, Debug, Eq, PartialEq)]
459pub enum ReturnKind {
460    /// Exactly one return value.
461    Plain,
462    /// Zero or one return values.
463    Option,
464    /// Zero or more return values.
465    Iterator,
466}
467
468/// An external function signature.
469#[derive(Clone, Debug)]
470pub struct ExternalSig {
471    /// The name of the external function.
472    pub func_name: String,
473    /// The name of the external function, prefixed with the context trait.
474    pub full_name: String,
475    /// The types of this function signature's parameters.
476    pub param_tys: Vec<TypeId>,
477    /// The types of this function signature's results.
478    pub ret_tys: Vec<TypeId>,
479    /// How many values can this function return?
480    pub ret_kind: ReturnKind,
481}
482
483impl Term {
484    /// Get this term's type.
485    pub fn ty(&self) -> TypeId {
486        self.ret_ty
487    }
488
489    fn check_args_count<T>(&self, args: &[T], tyenv: &mut TypeEnv, pos: Pos, sym: &ast::Ident) {
490        if self.arg_tys.len() != args.len() {
491            tyenv.report_error(
492                pos,
493                format!(
494                    "Incorrect argument count for term '{}': got {}, expect {}",
495                    sym.0,
496                    args.len(),
497                    self.arg_tys.len()
498                ),
499            );
500        }
501    }
502
503    /// Is this term an enum variant?
504    pub fn is_enum_variant(&self) -> bool {
505        matches!(self.kind, TermKind::EnumVariant { .. })
506    }
507
508    /// Is this term partial?
509    pub fn is_partial(&self) -> bool {
510        matches!(
511            self.kind,
512            TermKind::Decl {
513                flags: TermFlags { partial: true, .. },
514                ..
515            }
516        )
517    }
518
519    /// Does this term have a constructor?
520    pub fn has_constructor(&self) -> bool {
521        matches!(
522            self.kind,
523            TermKind::EnumVariant { .. }
524                | TermKind::Decl {
525                    constructor_kind: Some(_),
526                    ..
527                }
528        )
529    }
530
531    /// Does this term have an extractor?
532    pub fn has_extractor(&self) -> bool {
533        matches!(
534            self.kind,
535            TermKind::EnumVariant { .. }
536                | TermKind::Decl {
537                    extractor_kind: Some(_),
538                    ..
539                }
540        )
541    }
542
543    /// Is this term's extractor external?
544    pub fn has_external_extractor(&self) -> bool {
545        matches!(
546            self.kind,
547            TermKind::Decl {
548                extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
549                ..
550            }
551        )
552    }
553
554    /// Is this term's constructor external?
555    pub fn has_external_constructor(&self) -> bool {
556        matches!(
557            self.kind,
558            TermKind::Decl {
559                constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
560                ..
561            }
562        )
563    }
564
565    /// Get this term's extractor's external function signature, if any.
566    pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
567        match &self.kind {
568            TermKind::Decl {
569                flags,
570                extractor_kind:
571                    Some(ExtractorKind::ExternalExtractor {
572                        name, infallible, ..
573                    }),
574                ..
575            } => {
576                let ret_kind = if flags.multi {
577                    ReturnKind::Iterator
578                } else if *infallible {
579                    ReturnKind::Plain
580                } else {
581                    ReturnKind::Option
582                };
583                Some(ExternalSig {
584                    func_name: tyenv.syms[name.index()].clone(),
585                    full_name: format!("C::{}", tyenv.syms[name.index()]),
586                    param_tys: vec![self.ret_ty],
587                    ret_tys: self.arg_tys.clone(),
588                    ret_kind,
589                })
590            }
591            _ => None,
592        }
593    }
594
595    /// Get this term's constructor's external function signature, if any.
596    pub fn constructor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
597        match &self.kind {
598            TermKind::Decl {
599                constructor_kind: Some(kind),
600                flags,
601                ..
602            } => {
603                let (func_name, full_name) = match kind {
604                    ConstructorKind::InternalConstructor => {
605                        let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
606                        (name.clone(), name)
607                    }
608                    ConstructorKind::ExternalConstructor { name } => (
609                        tyenv.syms[name.index()].clone(),
610                        format!("C::{}", tyenv.syms[name.index()]),
611                    ),
612                };
613                let ret_kind = if flags.multi {
614                    ReturnKind::Iterator
615                } else if flags.partial {
616                    ReturnKind::Option
617                } else {
618                    ReturnKind::Plain
619                };
620                Some(ExternalSig {
621                    func_name,
622                    full_name,
623                    param_tys: self.arg_tys.clone(),
624                    ret_tys: vec![self.ret_ty],
625                    ret_kind,
626                })
627            }
628            _ => None,
629        }
630    }
631}
632
633/// A term rewrite rule.
634#[derive(Clone, Debug)]
635pub struct Rule {
636    /// This rule's id.
637    pub id: RuleId,
638    /// The left-hand side pattern that this rule matches.
639    pub root_term: TermId,
640    /// Patterns to test against the root term's arguments.
641    pub args: Vec<Pattern>,
642    /// Any subpattern "if-let" clauses.
643    pub iflets: Vec<IfLet>,
644    /// The right-hand side expression that this rule evaluates upon successful
645    /// match.
646    pub rhs: Expr,
647    /// Variable names used in this rule, indexed by [VarId].
648    pub vars: Vec<BoundVar>,
649    /// The priority of this rule, defaulted to 0 if it was missing in the source.
650    pub prio: i64,
651    /// The source position where this rule is defined.
652    pub pos: Pos,
653    /// The optional name for this rule.
654    pub name: Option<Sym>,
655}
656
657/// A name bound in a pattern or let-expression.
658#[derive(Clone, Debug)]
659pub struct BoundVar {
660    /// The identifier used for this variable within the scope of the current [Rule].
661    pub id: VarId,
662    /// The variable's name.
663    pub name: Sym,
664    /// The type of the value this variable is bound to.
665    pub ty: TypeId,
666    /// A counter used to check whether this variable is still in scope during
667    /// semantic analysis. Not meaningful afterward.
668    scope: usize,
669}
670
671/// An `if-let` clause with a subpattern match on an expr after the
672/// main LHS matches.
673#[derive(Clone, Debug)]
674pub struct IfLet {
675    /// The left-hand side pattern that this `if-let` clause matches
676    /// against the expression below.
677    pub lhs: Pattern,
678    /// The right-hand side expression that this pattern
679    /// evaluates. Must be pure.
680    pub rhs: Expr,
681}
682
683/// A left-hand side pattern of some rule.
684#[derive(Clone, Debug, PartialEq, Eq)]
685pub enum Pattern {
686    /// Bind a variable of the given type from the current value.
687    ///
688    /// Keep matching on the value with the subpattern.
689    BindPattern(TypeId, VarId, Box<Pattern>),
690
691    /// Match the current value against an already bound variable with the given
692    /// type.
693    Var(TypeId, VarId),
694
695    /// Match the current value against a constant boolean.
696    ConstBool(TypeId, bool),
697
698    /// Match the current value against a constant integer of the given integer
699    /// type.
700    ConstInt(TypeId, i128),
701
702    /// Match the current value against a constant primitive value of the given
703    /// primitive type.
704    ConstPrim(TypeId, Sym),
705
706    /// Match the current value against the given extractor term with the given
707    /// arguments.
708    Term(TypeId, TermId, Vec<Pattern>),
709
710    /// Match anything of the given type successfully.
711    Wildcard(TypeId),
712
713    /// Match all of the following patterns of the given type.
714    And(TypeId, Vec<Pattern>),
715}
716
717/// A right-hand side expression of some rule.
718#[derive(Clone, Debug, PartialEq, Eq)]
719pub enum Expr {
720    /// Invoke this term constructor with the given arguments.
721    Term(TypeId, TermId, Vec<Expr>),
722    /// Get the value of a variable that was bound in the left-hand side.
723    Var(TypeId, VarId),
724    /// Get a constant boolean.
725    ConstBool(TypeId, bool),
726    /// Get a constant integer.
727    ConstInt(TypeId, i128),
728    /// Get a constant primitive.
729    ConstPrim(TypeId, Sym),
730    /// Evaluate the nested expressions and bind their results to the given
731    /// variables, then evaluate the body expression.
732    Let {
733        /// The type of the result of this let expression.
734        ty: TypeId,
735        /// The expressions that are evaluated and bound to the given variables.
736        bindings: Vec<(VarId, TypeId, Box<Expr>)>,
737        /// The body expression that is evaluated after the bindings.
738        body: Box<Expr>,
739    },
740}
741
742/// Visitor interface for [Pattern]s. Visitors can assign an arbitrary identifier to each
743/// subpattern, which is threaded through to subsequent calls into the visitor.
744pub trait PatternVisitor {
745    /// The type of subpattern identifiers.
746    type PatternId: Copy;
747
748    /// Match if `a` and `b` have equal values.
749    fn add_match_equal(&mut self, a: Self::PatternId, b: Self::PatternId, ty: TypeId);
750    /// Match if `input` is the given boolean constant.
751    fn add_match_bool(&mut self, input: Self::PatternId, ty: TypeId, bool_val: bool);
752    /// Match if `input` is the given integer constant.
753    fn add_match_int(&mut self, input: Self::PatternId, ty: TypeId, int_val: i128);
754    /// Match if `input` is the given primitive constant.
755    fn add_match_prim(&mut self, input: Self::PatternId, ty: TypeId, val: Sym);
756
757    /// Match if `input` is the given enum variant. Returns an identifier for each field within the
758    /// enum variant. The length of the return list must equal the length of `arg_tys`.
759    fn add_match_variant(
760        &mut self,
761        input: Self::PatternId,
762        input_ty: TypeId,
763        arg_tys: &[TypeId],
764        variant: VariantId,
765    ) -> Vec<Self::PatternId>;
766
767    /// Match if the given external extractor succeeds on `input`. Returns an identifier for each
768    /// return value from the external extractor. The length of the return list must equal the
769    /// length of `output_tys`.
770    fn add_extract(
771        &mut self,
772        input: Self::PatternId,
773        input_ty: TypeId,
774        output_tys: Vec<TypeId>,
775        term: TermId,
776        infallible: bool,
777        multi: bool,
778    ) -> Vec<Self::PatternId>;
779}
780
781impl Pattern {
782    /// Get this pattern's type.
783    pub fn ty(&self) -> TypeId {
784        match *self {
785            Self::BindPattern(t, ..) => t,
786            Self::Var(t, ..) => t,
787            Self::ConstBool(t, ..) => t,
788            Self::ConstInt(t, ..) => t,
789            Self::ConstPrim(t, ..) => t,
790            Self::Term(t, ..) => t,
791            Self::Wildcard(t, ..) => t,
792            Self::And(t, ..) => t,
793        }
794    }
795
796    /// Recursively visit every sub-pattern.
797    pub fn visit<V: PatternVisitor>(
798        &self,
799        visitor: &mut V,
800        input: V::PatternId,
801        termenv: &TermEnv,
802        vars: &mut HashMap<VarId, V::PatternId>,
803    ) {
804        match *self {
805            Pattern::BindPattern(_ty, var, ref subpat) => {
806                // Bind the appropriate variable and recurse.
807                assert!(!vars.contains_key(&var));
808                vars.insert(var, input);
809                subpat.visit(visitor, input, termenv, vars);
810            }
811            Pattern::Var(ty, var) => {
812                // Assert that the value matches the existing bound var.
813                let var_val = vars
814                    .get(&var)
815                    .copied()
816                    .expect("Variable should already be bound");
817                visitor.add_match_equal(input, var_val, ty);
818            }
819            Pattern::ConstBool(ty, value) => visitor.add_match_bool(input, ty, value),
820            Pattern::ConstInt(ty, value) => visitor.add_match_int(input, ty, value),
821            Pattern::ConstPrim(ty, value) => visitor.add_match_prim(input, ty, value),
822            Pattern::Term(ty, term, ref args) => {
823                // Determine whether the term has an external extractor or not.
824                let termdata = &termenv.terms[term.index()];
825                let arg_values = match &termdata.kind {
826                    TermKind::EnumVariant { variant } => {
827                        visitor.add_match_variant(input, ty, &termdata.arg_tys, *variant)
828                    }
829                    TermKind::Decl {
830                        extractor_kind: None,
831                        ..
832                    } => {
833                        panic!("Pattern invocation of undefined term body")
834                    }
835                    TermKind::Decl {
836                        extractor_kind: Some(ExtractorKind::InternalExtractor { .. }),
837                        ..
838                    } => {
839                        panic!("Should have been expanded away")
840                    }
841                    TermKind::Decl {
842                        flags,
843                        extractor_kind: Some(ExtractorKind::ExternalExtractor { infallible, .. }),
844                        ..
845                    } => {
846                        // Evaluate all `input` args.
847                        let output_tys = args.iter().map(|arg| arg.ty()).collect();
848
849                        // Invoke the extractor.
850                        visitor.add_extract(
851                            input,
852                            termdata.ret_ty,
853                            output_tys,
854                            term,
855                            *infallible && !flags.multi,
856                            flags.multi,
857                        )
858                    }
859                };
860                for (pat, val) in args.iter().zip(arg_values) {
861                    pat.visit(visitor, val, termenv, vars);
862                }
863            }
864            Pattern::And(_ty, ref children) => {
865                for child in children {
866                    child.visit(visitor, input, termenv, vars);
867                }
868            }
869            Pattern::Wildcard(_ty) => {
870                // Nothing!
871            }
872        }
873    }
874}
875
876/// Visitor interface for [Expr]s. Visitors can return an arbitrary identifier for each
877/// subexpression, which is threaded through to subsequent calls into the visitor.
878pub trait ExprVisitor {
879    /// The type of subexpression identifiers.
880    type ExprId: Copy;
881
882    /// Construct a constant boolean.
883    fn add_const_bool(&mut self, ty: TypeId, val: bool) -> Self::ExprId;
884    /// Construct a constant integer.
885    fn add_const_int(&mut self, ty: TypeId, val: i128) -> Self::ExprId;
886    /// Construct a primitive constant.
887    fn add_const_prim(&mut self, ty: TypeId, val: Sym) -> Self::ExprId;
888
889    /// Construct an enum variant with the given `inputs` assigned to the variant's fields in order.
890    fn add_create_variant(
891        &mut self,
892        inputs: Vec<(Self::ExprId, TypeId)>,
893        ty: TypeId,
894        variant: VariantId,
895    ) -> Self::ExprId;
896
897    /// Call an external constructor with the given `inputs` as arguments.
898    fn add_construct(
899        &mut self,
900        inputs: Vec<(Self::ExprId, TypeId)>,
901        ty: TypeId,
902        term: TermId,
903        pure: bool,
904        infallible: bool,
905        multi: bool,
906    ) -> Self::ExprId;
907}
908
909impl Expr {
910    /// Get this expression's type.
911    pub fn ty(&self) -> TypeId {
912        match *self {
913            Self::Term(t, ..) => t,
914            Self::Var(t, ..) => t,
915            Self::ConstBool(t, ..) => t,
916            Self::ConstInt(t, ..) => t,
917            Self::ConstPrim(t, ..) => t,
918            Self::Let { ty: t, .. } => t,
919        }
920    }
921
922    /// Recursively visit every subexpression.
923    pub fn visit<V: ExprVisitor>(
924        &self,
925        visitor: &mut V,
926        termenv: &TermEnv,
927        vars: &HashMap<VarId, V::ExprId>,
928    ) -> V::ExprId {
929        log!("Expr::visit: expr {:?}", self);
930        match *self {
931            Expr::ConstBool(ty, val) => visitor.add_const_bool(ty, val),
932            Expr::ConstInt(ty, val) => visitor.add_const_int(ty, val),
933            Expr::ConstPrim(ty, val) => visitor.add_const_prim(ty, val),
934            Expr::Let {
935                ty: _ty,
936                ref bindings,
937                ref body,
938            } => {
939                let mut vars = vars.clone();
940                for &(var, _var_ty, ref var_expr) in bindings {
941                    let var_value = var_expr.visit(visitor, termenv, &vars);
942                    vars.insert(var, var_value);
943                }
944                body.visit(visitor, termenv, &vars)
945            }
946            Expr::Var(_ty, var_id) => *vars.get(&var_id).unwrap(),
947            Expr::Term(ty, term, ref arg_exprs) => {
948                let termdata = &termenv.terms[term.index()];
949                let arg_values_tys = arg_exprs
950                    .iter()
951                    .map(|arg_expr| arg_expr.visit(visitor, termenv, vars))
952                    .zip(termdata.arg_tys.iter().copied())
953                    .collect();
954                match &termdata.kind {
955                    TermKind::EnumVariant { variant } => {
956                        visitor.add_create_variant(arg_values_tys, ty, *variant)
957                    }
958                    TermKind::Decl {
959                        constructor_kind: Some(_),
960                        flags,
961                        ..
962                    } => {
963                        visitor.add_construct(
964                            arg_values_tys,
965                            ty,
966                            term,
967                            flags.pure,
968                            /* infallible = */ !flags.partial,
969                            flags.multi,
970                        )
971                    }
972                    TermKind::Decl {
973                        constructor_kind: None,
974                        ..
975                    } => panic!("Should have been caught by typechecking"),
976                }
977            }
978        }
979    }
980
981    fn visit_in_rule<V: RuleVisitor>(
982        &self,
983        visitor: &mut V,
984        termenv: &TermEnv,
985        vars: &HashMap<VarId, <V::PatternVisitor as PatternVisitor>::PatternId>,
986    ) -> V::Expr {
987        let var_exprs = vars
988            .iter()
989            .map(|(&var, &val)| (var, visitor.pattern_as_expr(val)))
990            .collect();
991        visitor.add_expr(|visitor| VisitedExpr {
992            ty: self.ty(),
993            value: self.visit(visitor, termenv, &var_exprs),
994        })
995    }
996}
997
998/// Information about an expression after it has been fully visited in [RuleVisitor::add_expr].
999#[derive(Clone, Copy)]
1000pub struct VisitedExpr<V: ExprVisitor> {
1001    /// The type of the top-level expression.
1002    pub ty: TypeId,
1003    /// The identifier returned by the visitor for the top-level expression.
1004    pub value: V::ExprId,
1005}
1006
1007/// Visitor interface for [Rule]s. Visitors must be able to visit patterns by implementing
1008/// [PatternVisitor], and to visit expressions by providing a type that implements [ExprVisitor].
1009pub trait RuleVisitor {
1010    /// The type of pattern visitors constructed by [RuleVisitor::add_pattern].
1011    type PatternVisitor: PatternVisitor;
1012    /// The type of expression visitors constructed by [RuleVisitor::add_expr].
1013    type ExprVisitor: ExprVisitor;
1014    /// The type returned from [RuleVisitor::add_expr], which may be exchanged for a subpattern
1015    /// identifier using [RuleVisitor::expr_as_pattern].
1016    type Expr;
1017
1018    /// Visit one of the arguments to the top-level pattern.
1019    fn add_arg(
1020        &mut self,
1021        index: usize,
1022        ty: TypeId,
1023    ) -> <Self::PatternVisitor as PatternVisitor>::PatternId;
1024
1025    /// Visit a pattern, used once for the rule's left-hand side and once for each if-let. You can
1026    /// determine which part of the rule the pattern comes from based on whether the `PatternId`
1027    /// passed to the first call to this visitor came from `add_arg` or `expr_as_pattern`.
1028    fn add_pattern<F>(&mut self, visitor: F)
1029    where
1030        F: FnOnce(&mut Self::PatternVisitor);
1031
1032    /// Visit an expression, used once for each if-let and once for the rule's right-hand side.
1033    fn add_expr<F>(&mut self, visitor: F) -> Self::Expr
1034    where
1035        F: FnOnce(&mut Self::ExprVisitor) -> VisitedExpr<Self::ExprVisitor>;
1036
1037    /// Given an expression from [RuleVisitor::add_expr], return an identifier that can be used with
1038    /// a pattern visitor in [RuleVisitor::add_pattern].
1039    fn expr_as_pattern(
1040        &mut self,
1041        expr: Self::Expr,
1042    ) -> <Self::PatternVisitor as PatternVisitor>::PatternId;
1043
1044    /// Given an identifier from the pattern visitor, return an identifier that can be used with
1045    /// the expression visitor.
1046    fn pattern_as_expr(
1047        &mut self,
1048        pattern: <Self::PatternVisitor as PatternVisitor>::PatternId,
1049    ) -> <Self::ExprVisitor as ExprVisitor>::ExprId;
1050}
1051
1052impl Rule {
1053    /// Recursively visit every pattern and expression in this rule. Returns the [RuleVisitor::Expr]
1054    /// that was returned from [RuleVisitor::add_expr] when that function was called on the rule's
1055    /// right-hand side.
1056    pub fn visit<V: RuleVisitor>(&self, visitor: &mut V, termenv: &TermEnv) -> V::Expr {
1057        let mut vars = HashMap::new();
1058
1059        // Visit the pattern, starting from the root input value.
1060        let termdata = &termenv.terms[self.root_term.index()];
1061        for (i, (subpat, &arg_ty)) in self.args.iter().zip(termdata.arg_tys.iter()).enumerate() {
1062            let value = visitor.add_arg(i, arg_ty);
1063            visitor.add_pattern(|visitor| subpat.visit(visitor, value, termenv, &mut vars));
1064        }
1065
1066        // Visit the `if-let` clauses, using `V::ExprVisitor` for the sub-exprs (right-hand sides).
1067        for iflet in self.iflets.iter() {
1068            let subexpr = iflet.rhs.visit_in_rule(visitor, termenv, &vars);
1069            let value = visitor.expr_as_pattern(subexpr);
1070            visitor.add_pattern(|visitor| iflet.lhs.visit(visitor, value, termenv, &mut vars));
1071        }
1072
1073        // Visit the rule's right-hand side, making use of the bound variables from the pattern.
1074        self.rhs.visit_in_rule(visitor, termenv, &vars)
1075    }
1076}
1077
1078/// Given an `Option<T>`, unwrap the inner `T` value, or `continue` if it is
1079/// `None`.
1080///
1081/// Useful for when we encountered an error earlier in our analysis but kept
1082/// going to find more errors, and now we've run into some missing data that
1083/// would have been filled in if we didn't hit that original error, but we want
1084/// to keep going to find more errors.
1085macro_rules! unwrap_or_continue {
1086    ($e:expr) => {
1087        match $e {
1088            Some(x) => x,
1089            None => continue,
1090        }
1091    };
1092}
1093
1094impl Default for TypeEnv {
1095    fn default() -> Self {
1096        Self {
1097            syms: BuiltinType::ALL
1098                .iter()
1099                .map(|bt| String::from(bt.name()))
1100                .collect(),
1101            sym_map: BuiltinType::ALL
1102                .iter()
1103                .enumerate()
1104                .map(|(idx, bt)| (String::from(bt.name()), Sym(idx)))
1105                .collect(),
1106            types: BuiltinType::ALL
1107                .iter()
1108                .map(|bt| Type::Builtin(*bt))
1109                .collect(),
1110            type_map: BuiltinType::ALL
1111                .iter()
1112                .enumerate()
1113                .map(|(idx, _)| (Sym(idx), TypeId(idx)))
1114                .collect(),
1115            const_types: StableMap::new(),
1116            errors: vec![],
1117        }
1118    }
1119}
1120
1121impl TypeEnv {
1122    /// Construct the type environment from the AST.
1123    pub fn from_ast(defs: &[ast::Def]) -> Result<TypeEnv, Vec<Error>> {
1124        let mut tyenv = TypeEnv::default();
1125
1126        // Traverse defs, assigning type IDs to type names. We'll fill
1127        // in types on a second pass.
1128        for def in defs {
1129            match def {
1130                &ast::Def::Type(ref td) => {
1131                    let tid = TypeId(tyenv.type_map.len());
1132                    let name = tyenv.intern_mut(&td.name);
1133
1134                    if let Some(existing) = tyenv.type_map.get(&name).copied() {
1135                        tyenv.report_error(
1136                            td.pos,
1137                            format!("Type with name '{}' defined more than once", td.name.0),
1138                        );
1139                        let pos = unwrap_or_continue!(tyenv.types.get(existing.index())).pos();
1140                        match pos {
1141                            Some(pos) => tyenv.report_error(
1142                                pos,
1143                                format!("Type with name '{}' already defined here", td.name.0),
1144                            ),
1145                            None => tyenv.report_error(
1146                                td.pos,
1147                                format!("Type with name '{}' is a built-in type", td.name.0),
1148                            ),
1149                        }
1150                        continue;
1151                    }
1152
1153                    tyenv.type_map.insert(name, tid);
1154                }
1155                _ => {}
1156            }
1157        }
1158
1159        // Now lower AST nodes to type definitions, raising errors
1160        // where typenames of fields are undefined or field names are
1161        // duplicated.
1162        for def in defs {
1163            match def {
1164                &ast::Def::Type(ref td) => {
1165                    let tid = tyenv.types.len();
1166                    if let Some(ty) = tyenv.type_from_ast(TypeId(tid), td) {
1167                        tyenv.types.push(ty);
1168                    }
1169                }
1170                _ => {}
1171            }
1172        }
1173
1174        // Now collect types for extern constants.
1175        for def in defs {
1176            if let &ast::Def::Extern(ast::Extern::Const {
1177                ref name,
1178                ref ty,
1179                pos,
1180            }) = def
1181            {
1182                let ty = match tyenv.get_type_by_name(ty) {
1183                    Some(ty) => ty,
1184                    None => {
1185                        tyenv.report_error(pos, "Unknown type for constant");
1186                        continue;
1187                    }
1188                };
1189                let name = tyenv.intern_mut(name);
1190                tyenv.const_types.insert(name, ty);
1191            }
1192        }
1193
1194        tyenv.return_errors()?;
1195
1196        Ok(tyenv)
1197    }
1198
1199    fn return_errors(&mut self) -> Result<(), Vec<Error>> {
1200        if self.errors.is_empty() {
1201            Ok(())
1202        } else {
1203            Err(std::mem::take(&mut self.errors))
1204        }
1205    }
1206
1207    fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> Option<Type> {
1208        let name = self.intern(&ty.name).unwrap();
1209        match &ty.ty {
1210            &ast::TypeValue::Primitive(ref id, ..) => {
1211                if ty.is_nodebug {
1212                    self.report_error(ty.pos, "primitive types cannot be marked `nodebug`");
1213                    return None;
1214                }
1215                if ty.is_extern {
1216                    self.report_error(ty.pos, "primitive types cannot be marked `extern`");
1217                    return None;
1218                }
1219                Some(Type::Primitive(tid, self.intern_mut(id), ty.pos))
1220            }
1221            &ast::TypeValue::Enum(ref ty_variants, ..) => {
1222                if ty.is_extern && ty.is_nodebug {
1223                    self.report_error(ty.pos, "external types cannot be marked `nodebug`");
1224                    return None;
1225                }
1226
1227                let mut variants = vec![];
1228                for variant in ty_variants {
1229                    let combined_ident =
1230                        ast::Ident(format!("{}.{}", ty.name.0, variant.name.0), variant.name.1);
1231                    let fullname = self.intern_mut(&combined_ident);
1232                    let name = self.intern_mut(&variant.name);
1233                    let id = VariantId(variants.len());
1234                    if variants.iter().any(|v: &Variant| v.name == name) {
1235                        self.report_error(
1236                            variant.pos,
1237                            format!("Duplicate variant name in type: '{}'", variant.name.0),
1238                        );
1239                        return None;
1240                    }
1241                    let mut fields = vec![];
1242                    for field in &variant.fields {
1243                        let field_name = self.intern_mut(&field.name);
1244                        if fields.iter().any(|f: &Field| f.name == field_name) {
1245                            self.report_error(
1246                                field.pos,
1247                                format!(
1248                                    "Duplicate field name '{}' in variant '{}' of type",
1249                                    field.name.0, variant.name.0
1250                                ),
1251                            );
1252                            return None;
1253                        }
1254                        let field_tid = match self.get_type_by_name(&field.ty) {
1255                            Some(tid) => tid,
1256                            None => {
1257                                self.report_error(
1258                                    field.ty.1,
1259                                    format!(
1260                                        "Unknown type '{}' for field '{}' in variant '{}'",
1261                                        field.ty.0, field.name.0, variant.name.0
1262                                    ),
1263                                );
1264                                return None;
1265                            }
1266                        };
1267                        fields.push(Field {
1268                            name: field_name,
1269                            id: FieldId(fields.len()),
1270                            ty: field_tid,
1271                        });
1272                    }
1273                    variants.push(Variant {
1274                        name,
1275                        fullname,
1276                        id,
1277                        fields,
1278                    });
1279                }
1280                Some(Type::Enum {
1281                    name,
1282                    id: tid,
1283                    is_extern: ty.is_extern,
1284                    is_nodebug: ty.is_nodebug,
1285                    variants,
1286                    pos: ty.pos,
1287                })
1288            }
1289        }
1290    }
1291
1292    fn error(&self, pos: Pos, msg: impl Into<String>) -> Error {
1293        Error::TypeError {
1294            msg: msg.into(),
1295            span: Span::new_single(pos),
1296        }
1297    }
1298
1299    fn report_error(&mut self, pos: Pos, msg: impl Into<String>) {
1300        let err = self.error(pos, msg);
1301        self.errors.push(err);
1302    }
1303
1304    fn intern_mut(&mut self, ident: &ast::Ident) -> Sym {
1305        if let Some(s) = self.sym_map.get(&ident.0).copied() {
1306            s
1307        } else {
1308            let s = Sym(self.syms.len());
1309            self.syms.push(ident.0.clone());
1310            self.sym_map.insert(ident.0.clone(), s);
1311            s
1312        }
1313    }
1314
1315    fn intern(&self, ident: &ast::Ident) -> Option<Sym> {
1316        self.sym_map.get(&ident.0).copied()
1317    }
1318
1319    /// Lookup type by name.
1320    pub fn get_type_by_name(&self, sym: &ast::Ident) -> Option<TypeId> {
1321        self.intern(sym)
1322            .and_then(|sym| self.type_map.get(&sym))
1323            .copied()
1324    }
1325}
1326
1327#[derive(Clone, Debug, Default)]
1328struct Bindings {
1329    /// All bindings accumulated so far within the current rule, including let-
1330    /// bindings which have gone out of scope.
1331    seen: Vec<BoundVar>,
1332    /// Counter for unique scope IDs within this set of bindings.
1333    next_scope: usize,
1334    /// Stack of the scope IDs for bindings which are currently in scope.
1335    in_scope: Vec<usize>,
1336}
1337
1338impl Bindings {
1339    fn enter_scope(&mut self) {
1340        self.in_scope.push(self.next_scope);
1341        self.next_scope += 1;
1342    }
1343
1344    fn exit_scope(&mut self) {
1345        self.in_scope.pop();
1346    }
1347
1348    fn add_var(&mut self, name: Sym, ty: TypeId) -> VarId {
1349        let id = VarId(self.seen.len());
1350        let var = BoundVar {
1351            id,
1352            name,
1353            ty,
1354            scope: *self
1355                .in_scope
1356                .last()
1357                .expect("enter_scope should be called before add_var"),
1358        };
1359        log!("binding var {:?}", var);
1360        self.seen.push(var);
1361        id
1362    }
1363
1364    fn lookup(&self, name: Sym) -> Option<&BoundVar> {
1365        self.seen
1366            .iter()
1367            .rev()
1368            .find(|binding| binding.name == name && self.in_scope.contains(&binding.scope))
1369    }
1370}
1371
1372impl TermEnv {
1373    /// Construct the term environment from the AST and the type environment.
1374    pub fn from_ast(
1375        tyenv: &mut TypeEnv,
1376        defs: &[ast::Def],
1377        expand_internal_extractors: bool,
1378    ) -> Result<TermEnv, Vec<Error>> {
1379        let mut env = TermEnv {
1380            terms: vec![],
1381            term_map: StableMap::new(),
1382            rules: vec![],
1383            converters: StableMap::new(),
1384            expand_internal_extractors,
1385        };
1386
1387        env.collect_pragmas(defs);
1388        env.collect_term_sigs(tyenv, defs);
1389        env.collect_enum_variant_terms(tyenv);
1390        tyenv.return_errors()?;
1391        env.collect_constructors(tyenv, defs);
1392        env.collect_extractor_templates(tyenv, defs);
1393        tyenv.return_errors()?;
1394        env.collect_converters(tyenv, defs);
1395        tyenv.return_errors()?;
1396        env.collect_externs(tyenv, defs);
1397        tyenv.return_errors()?;
1398        env.collect_rules(tyenv, defs);
1399        env.check_for_undefined_decls(tyenv, defs);
1400        env.check_for_expr_terms_without_constructors(tyenv, defs);
1401        tyenv.return_errors()?;
1402
1403        Ok(env)
1404    }
1405
1406    fn collect_pragmas(&mut self, _: &[ast::Def]) {
1407        // currently, no pragmas are defined, but the infrastructure is useful to keep around
1408        return;
1409    }
1410
1411    fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1412        for def in defs {
1413            match def {
1414                &ast::Def::Decl(ref decl) => {
1415                    let name = tyenv.intern_mut(&decl.term);
1416                    if let Some(tid) = self.term_map.get(&name) {
1417                        tyenv.report_error(
1418                            decl.pos,
1419                            format!("Duplicate decl for '{}'", decl.term.0),
1420                        );
1421                        tyenv.report_error(
1422                            self.terms[tid.index()].decl_pos,
1423                            format!("Duplicate decl for '{}'", decl.term.0),
1424                        );
1425                    }
1426
1427                    if decl.multi && decl.partial {
1428                        tyenv.report_error(
1429                            decl.pos,
1430                            format!("Term '{}' can't be both multi and partial", decl.term.0),
1431                        );
1432                    }
1433
1434                    let arg_tys = decl
1435                        .arg_tys
1436                        .iter()
1437                        .map(|id| {
1438                            tyenv.get_type_by_name(id).ok_or_else(|| {
1439                                tyenv.report_error(id.1, format!("Unknown arg type: '{}'", id.0));
1440                            })
1441                        })
1442                        .collect::<Result<Vec<_>, _>>();
1443                    let arg_tys = match arg_tys {
1444                        Ok(a) => a,
1445                        Err(_) => {
1446                            continue;
1447                        }
1448                    };
1449                    let ret_ty = match tyenv.get_type_by_name(&decl.ret_ty) {
1450                        Some(t) => t,
1451                        None => {
1452                            tyenv.report_error(
1453                                decl.ret_ty.1,
1454                                format!("Unknown return type: '{}'", decl.ret_ty.0),
1455                            );
1456                            continue;
1457                        }
1458                    };
1459
1460                    let tid = TermId(self.terms.len());
1461                    self.term_map.insert(name, tid);
1462                    let flags = TermFlags {
1463                        pure: decl.pure,
1464                        multi: decl.multi,
1465                        partial: decl.partial,
1466                    };
1467                    self.terms.push(Term {
1468                        id: tid,
1469                        decl_pos: decl.pos,
1470                        name,
1471                        arg_tys,
1472                        ret_ty,
1473                        kind: TermKind::Decl {
1474                            flags,
1475                            constructor_kind: None,
1476                            extractor_kind: None,
1477                        },
1478                    });
1479                }
1480                _ => {}
1481            }
1482        }
1483    }
1484
1485    fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) {
1486        'types: for i in 0..tyenv.types.len() {
1487            let ty = &tyenv.types[i];
1488            match ty {
1489                &Type::Enum {
1490                    pos,
1491                    id,
1492                    ref variants,
1493                    ..
1494                } => {
1495                    for variant in variants {
1496                        if self.term_map.contains_key(&variant.fullname) {
1497                            let variant_name = tyenv.syms[variant.fullname.index()].clone();
1498                            tyenv.report_error(
1499                                pos,
1500                                format!("Duplicate enum variant constructor: '{variant_name}'",),
1501                            );
1502                            continue 'types;
1503                        }
1504                        let tid = TermId(self.terms.len());
1505                        let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::<Vec<_>>();
1506                        let ret_ty = id;
1507                        self.terms.push(Term {
1508                            id: tid,
1509                            decl_pos: pos,
1510                            name: variant.fullname,
1511                            arg_tys,
1512                            ret_ty,
1513                            kind: TermKind::EnumVariant {
1514                                variant: variant.id,
1515                            },
1516                        });
1517                        self.term_map.insert(variant.fullname, tid);
1518                    }
1519                }
1520                _ => {}
1521            }
1522        }
1523    }
1524
1525    fn collect_constructors(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1526        for def in defs {
1527            log!("collect_constructors from def: {:?}", def);
1528            match def {
1529                &ast::Def::Rule(ref rule) => {
1530                    let pos = rule.pos;
1531                    let term = match rule.pattern.root_term() {
1532                        Some(t) => t,
1533                        None => {
1534                            tyenv.report_error(
1535                                pos,
1536                                "Rule does not have a term at the LHS root".to_string(),
1537                            );
1538                            continue;
1539                        }
1540                    };
1541                    let term = match self.get_term_by_name(tyenv, &term) {
1542                        Some(tid) => tid,
1543                        None => {
1544                            tyenv
1545                                .report_error(pos, "Rule LHS root term is not defined".to_string());
1546                            continue;
1547                        }
1548                    };
1549                    let termdata = &mut self.terms[term.index()];
1550                    match &mut termdata.kind {
1551                        TermKind::Decl {
1552                            constructor_kind, ..
1553                        } => {
1554                            match constructor_kind {
1555                                None => {
1556                                    *constructor_kind = Some(ConstructorKind::InternalConstructor);
1557                                }
1558                                Some(ConstructorKind::InternalConstructor) => {
1559                                    // OK, no error; multiple rules can apply to
1560                                    // one internal constructor term.
1561                                }
1562                                Some(ConstructorKind::ExternalConstructor { .. }) => {
1563                                    tyenv.report_error(
1564                                        pos,
1565                                        "Rule LHS root term is incorrect kind; cannot \
1566                                         be external constructor"
1567                                            .to_string(),
1568                                    );
1569                                    continue;
1570                                }
1571                            }
1572                        }
1573                        TermKind::EnumVariant { .. } => {
1574                            tyenv.report_error(
1575                                pos,
1576                                "Rule LHS root term is incorrect kind; cannot be enum variant"
1577                                    .to_string(),
1578                            );
1579                            continue;
1580                        }
1581                    }
1582                }
1583                _ => {}
1584            }
1585        }
1586    }
1587
1588    fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1589        let mut extractor_call_graph = BTreeMap::new();
1590
1591        for def in defs {
1592            if let &ast::Def::Extractor(ref ext) = def {
1593                let term = match self.get_term_by_name(tyenv, &ext.term) {
1594                    Some(x) => x,
1595                    None => {
1596                        tyenv.report_error(
1597                            ext.pos,
1598                            "Extractor macro body definition on a non-existent term".to_string(),
1599                        );
1600                        return;
1601                    }
1602                };
1603
1604                let template = ext.template.make_macro_template(&ext.args[..]);
1605                log!("extractor def: {:?} becomes template {:?}", def, template);
1606
1607                let mut callees = BTreeSet::new();
1608                template.terms(&mut |pos, t| {
1609                    if let Some(term) = self.get_term_by_name(tyenv, t) {
1610                        callees.insert(term);
1611                    } else {
1612                        tyenv.report_error(
1613                            pos,
1614                            format!(
1615                                "`{}` extractor definition references unknown term `{}`",
1616                                ext.term.0, t.0
1617                            ),
1618                        );
1619                    }
1620                });
1621                extractor_call_graph.insert(term, callees);
1622
1623                let termdata = &mut self.terms[term.index()];
1624                match &mut termdata.kind {
1625                    TermKind::EnumVariant { .. } => {
1626                        tyenv.report_error(
1627                            ext.pos,
1628                            "Extractor macro body defined on term of incorrect kind; cannot be an \
1629                             enum variant",
1630                        );
1631                        continue;
1632                    }
1633                    TermKind::Decl {
1634                        flags,
1635                        extractor_kind,
1636                        ..
1637                    } => match extractor_kind {
1638                        None => {
1639                            if flags.multi {
1640                                tyenv.report_error(
1641                                    ext.pos,
1642                                    "A term declared with `multi` cannot have an internal extractor.".to_string());
1643                                continue;
1644                            }
1645                            *extractor_kind = Some(ExtractorKind::InternalExtractor { template });
1646                        }
1647                        Some(ext_kind) => {
1648                            tyenv.report_error(
1649                                ext.pos,
1650                                "Duplicate extractor definition".to_string(),
1651                            );
1652                            let pos = match ext_kind {
1653                                ExtractorKind::InternalExtractor { template } => template.pos(),
1654                                ExtractorKind::ExternalExtractor { pos, .. } => *pos,
1655                            };
1656                            tyenv.report_error(
1657                                pos,
1658                                "Extractor was already defined here".to_string(),
1659                            );
1660                            continue;
1661                        }
1662                    },
1663                }
1664            }
1665        }
1666
1667        // Check for cycles in the extractor call graph.
1668        let mut stack = vec![];
1669        'outer: for root in extractor_call_graph.keys().copied() {
1670            stack.clear();
1671            stack.push((root, vec![root], StableSet::new()));
1672
1673            while let Some((caller, path, mut seen)) = stack.pop() {
1674                let is_new = seen.insert(caller);
1675                if is_new {
1676                    if let Some(callees) = extractor_call_graph.get(&caller) {
1677                        stack.extend(callees.iter().map(|callee| {
1678                            let mut path = path.clone();
1679                            path.push(*callee);
1680                            (*callee, path, seen.clone())
1681                        }));
1682                    }
1683                } else {
1684                    let pos = match &self.terms[caller.index()].kind {
1685                        TermKind::Decl {
1686                            extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
1687                            ..
1688                        } => template.pos(),
1689                        _ => {
1690                            // There must have already been errors recorded.
1691                            assert!(!tyenv.errors.is_empty());
1692                            continue 'outer;
1693                        }
1694                    };
1695
1696                    let path: Vec<_> = path
1697                        .iter()
1698                        .map(|sym| tyenv.syms[sym.index()].as_str())
1699                        .collect();
1700                    let msg = format!(
1701                        "`{}` extractor definition is recursive: {}",
1702                        tyenv.syms[root.index()],
1703                        path.join(" -> ")
1704                    );
1705                    tyenv.report_error(pos, msg);
1706                    continue 'outer;
1707                }
1708            }
1709        }
1710    }
1711
1712    fn collect_converters(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1713        for def in defs {
1714            match def {
1715                &ast::Def::Converter(ast::Converter {
1716                    ref term,
1717                    ref inner_ty,
1718                    ref outer_ty,
1719                    pos,
1720                }) => {
1721                    let inner_ty_id = match tyenv.get_type_by_name(inner_ty) {
1722                        Some(ty) => ty,
1723                        None => {
1724                            tyenv.report_error(
1725                                inner_ty.1,
1726                                format!("Unknown inner type for converter: '{}'", inner_ty.0),
1727                            );
1728                            continue;
1729                        }
1730                    };
1731
1732                    let outer_ty_id = match tyenv.get_type_by_name(outer_ty) {
1733                        Some(ty) => ty,
1734                        None => {
1735                            tyenv.report_error(
1736                                outer_ty.1,
1737                                format!("Unknown outer type for converter: '{}'", outer_ty.0),
1738                            );
1739                            continue;
1740                        }
1741                    };
1742
1743                    let term_id = match self.get_term_by_name(tyenv, term) {
1744                        Some(term_id) => term_id,
1745                        None => {
1746                            tyenv.report_error(
1747                                term.1,
1748                                format!("Unknown term for converter: '{}'", term.0),
1749                            );
1750                            continue;
1751                        }
1752                    };
1753
1754                    match self.converters.entry((inner_ty_id, outer_ty_id)) {
1755                        Entry::Vacant(v) => {
1756                            v.insert(term_id);
1757                        }
1758                        Entry::Occupied(_) => {
1759                            tyenv.report_error(
1760                                pos,
1761                                format!(
1762                                    "Converter already exists for this type pair: '{}', '{}'",
1763                                    inner_ty.0, outer_ty.0
1764                                ),
1765                            );
1766                            continue;
1767                        }
1768                    }
1769                }
1770                _ => {}
1771            }
1772        }
1773    }
1774
1775    fn collect_externs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1776        for def in defs {
1777            match def {
1778                &ast::Def::Extern(ast::Extern::Constructor {
1779                    ref term,
1780                    ref func,
1781                    pos,
1782                }) => {
1783                    let func_sym = tyenv.intern_mut(func);
1784                    let term_id = match self.get_term_by_name(tyenv, term) {
1785                        Some(term) => term,
1786                        None => {
1787                            tyenv.report_error(
1788                                pos,
1789                                format!("Constructor declared on undefined term '{}'", term.0),
1790                            );
1791                            continue;
1792                        }
1793                    };
1794                    let termdata = &mut self.terms[term_id.index()];
1795                    match &mut termdata.kind {
1796                        TermKind::Decl {
1797                            constructor_kind, ..
1798                        } => match constructor_kind {
1799                            None => {
1800                                *constructor_kind =
1801                                    Some(ConstructorKind::ExternalConstructor { name: func_sym });
1802                            }
1803                            Some(ConstructorKind::InternalConstructor) => {
1804                                tyenv.report_error(
1805                                    pos,
1806                                    format!(
1807                                        "External constructor declared on term that already has rules: {}",
1808                                        term.0,
1809                                    ),
1810                                );
1811                            }
1812                            Some(ConstructorKind::ExternalConstructor { .. }) => {
1813                                tyenv.report_error(
1814                                    pos,
1815                                    "Duplicate external constructor definition".to_string(),
1816                                );
1817                            }
1818                        },
1819                        TermKind::EnumVariant { .. } => {
1820                            tyenv.report_error(
1821                                pos,
1822                                format!(
1823                                    "External constructor cannot be defined on enum variant: {}",
1824                                    term.0,
1825                                ),
1826                            );
1827                        }
1828                    }
1829                }
1830                &ast::Def::Extern(ast::Extern::Extractor {
1831                    ref term,
1832                    ref func,
1833                    pos,
1834                    infallible,
1835                }) => {
1836                    let func_sym = tyenv.intern_mut(func);
1837                    let term_id = match self.get_term_by_name(tyenv, term) {
1838                        Some(term) => term,
1839                        None => {
1840                            tyenv.report_error(
1841                                pos,
1842                                format!("Extractor declared on undefined term '{}'", term.0),
1843                            );
1844                            continue;
1845                        }
1846                    };
1847
1848                    let termdata = &mut self.terms[term_id.index()];
1849
1850                    match &mut termdata.kind {
1851                        TermKind::Decl { extractor_kind, .. } => match extractor_kind {
1852                            None => {
1853                                *extractor_kind = Some(ExtractorKind::ExternalExtractor {
1854                                    name: func_sym,
1855                                    infallible,
1856                                    pos,
1857                                });
1858                            }
1859                            Some(ExtractorKind::ExternalExtractor { pos: pos2, .. }) => {
1860                                tyenv.report_error(
1861                                    pos,
1862                                    "Duplicate external extractor definition".to_string(),
1863                                );
1864                                tyenv.report_error(
1865                                    *pos2,
1866                                    "External extractor already defined".to_string(),
1867                                );
1868                                continue;
1869                            }
1870                            Some(ExtractorKind::InternalExtractor { template }) => {
1871                                tyenv.report_error(
1872                                    pos,
1873                                    "Cannot define external extractor for term that already has an \
1874                                     internal extractor macro body defined"
1875                                        .to_string(),
1876                                );
1877                                tyenv.report_error(
1878                                    template.pos(),
1879                                    "Internal extractor macro body already defined".to_string(),
1880                                );
1881                                continue;
1882                            }
1883                        },
1884                        TermKind::EnumVariant { .. } => {
1885                            tyenv.report_error(
1886                                pos,
1887                                format!("Cannot define extractor for enum variant '{}'", term.0),
1888                            );
1889                            continue;
1890                        }
1891                    }
1892                }
1893                _ => {}
1894            }
1895        }
1896    }
1897
1898    fn collect_rules(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1899        for def in defs {
1900            match def {
1901                &ast::Def::Rule(ref rule) => {
1902                    let pos = rule.pos;
1903                    let mut bindings = Bindings::default();
1904                    bindings.enter_scope();
1905
1906                    let (sym, args) = if let ast::Pattern::Term { sym, args, .. } = &rule.pattern {
1907                        (sym, args)
1908                    } else {
1909                        tyenv.report_error(
1910                            pos,
1911                            "Rule does not have a term at the root of its left-hand side"
1912                                .to_string(),
1913                        );
1914                        continue;
1915                    };
1916
1917                    let root_term = if let Some(term) = self.get_term_by_name(tyenv, sym) {
1918                        term
1919                    } else {
1920                        tyenv.report_error(
1921                            pos,
1922                            "Cannot define a rule for an unknown term".to_string(),
1923                        );
1924                        continue;
1925                    };
1926
1927                    let termdata = &self.terms[root_term.index()];
1928
1929                    let flags = match &termdata.kind {
1930                        TermKind::Decl { flags, .. } => *flags,
1931                        _ => {
1932                            tyenv.report_error(
1933                                pos,
1934                                "Cannot define a rule on a left-hand-side that is an enum variant"
1935                                    .to_string(),
1936                            );
1937                            continue;
1938                        }
1939                    };
1940
1941                    termdata.check_args_count(args, tyenv, pos, sym);
1942                    let args = self.translate_args(args, termdata, tyenv, &mut bindings);
1943
1944                    let iflets = rule
1945                        .iflets
1946                        .iter()
1947                        .filter_map(|iflet| {
1948                            self.translate_iflet(tyenv, iflet, &mut bindings, flags)
1949                        })
1950                        .collect();
1951                    let rhs = unwrap_or_continue!(self.translate_expr(
1952                        tyenv,
1953                        &rule.expr,
1954                        Some(termdata.ret_ty),
1955                        &mut bindings,
1956                        flags,
1957                    ));
1958
1959                    bindings.exit_scope();
1960
1961                    let prio = if let Some(prio) = rule.prio {
1962                        if flags.multi {
1963                            tyenv.report_error(
1964                                pos,
1965                                "Cannot set rule priorities in multi-terms".to_string(),
1966                            );
1967                        }
1968                        prio
1969                    } else {
1970                        0
1971                    };
1972
1973                    let rid = RuleId(self.rules.len());
1974                    self.rules.push(Rule {
1975                        id: rid,
1976                        root_term,
1977                        args,
1978                        iflets,
1979                        rhs,
1980                        vars: bindings.seen,
1981                        prio,
1982                        pos,
1983                        name: rule.name.as_ref().map(|i| tyenv.intern_mut(i)),
1984                    });
1985                }
1986                _ => {}
1987            }
1988        }
1989    }
1990
1991    fn check_for_undefined_decls(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1992        for def in defs {
1993            if let ast::Def::Decl(decl) = def {
1994                let term = self.get_term_by_name(tyenv, &decl.term).unwrap();
1995                let term = &self.terms[term.index()];
1996                if !term.has_constructor() && !term.has_extractor() {
1997                    tyenv.report_error(
1998                        decl.pos,
1999                        format!(
2000                            "no rules, extractor, or external definition for declaration '{}'",
2001                            decl.term.0
2002                        ),
2003                    );
2004                }
2005            }
2006        }
2007    }
2008
2009    fn check_for_expr_terms_without_constructors(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
2010        for def in defs {
2011            if let ast::Def::Rule(rule) = def {
2012                rule.expr.terms(&mut |pos, ident| {
2013                    let term = match self.get_term_by_name(tyenv, ident) {
2014                        None => {
2015                            debug_assert!(!tyenv.errors.is_empty());
2016                            return;
2017                        }
2018                        Some(t) => t,
2019                    };
2020                    let term = &self.terms[term.index()];
2021                    if !term.has_constructor() {
2022                        tyenv.report_error(
2023                            pos,
2024                            format!(
2025                                "term `{}` cannot be used in an expression because \
2026                                 it does not have a constructor",
2027                                ident.0
2028                            ),
2029                        )
2030                    }
2031                });
2032            }
2033        }
2034    }
2035
2036    fn maybe_implicit_convert_pattern(
2037        &self,
2038        tyenv: &mut TypeEnv,
2039        pattern: &ast::Pattern,
2040        inner_ty: TypeId,
2041        outer_ty: TypeId,
2042    ) -> Option<ast::Pattern> {
2043        if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) {
2044            if self.terms[converter_term.index()].has_extractor() {
2045                // This is a little awkward: we have to
2046                // convert back to an Ident, to be
2047                // re-resolved. The pos doesn't matter
2048                // as it shouldn't result in a lookup
2049                // failure.
2050                let converter_term_ident = ast::Ident(
2051                    tyenv.syms[self.terms[converter_term.index()].name.index()].clone(),
2052                    pattern.pos(),
2053                );
2054                let expanded_pattern = ast::Pattern::Term {
2055                    sym: converter_term_ident,
2056                    pos: pattern.pos(),
2057                    args: vec![pattern.clone()],
2058                };
2059
2060                return Some(expanded_pattern);
2061            }
2062        }
2063        None
2064    }
2065
2066    fn translate_pattern(
2067        &self,
2068        tyenv: &mut TypeEnv,
2069        pat: &ast::Pattern,
2070        expected_ty: TypeId,
2071        bindings: &mut Bindings,
2072    ) -> Option<Pattern> {
2073        log!("translate_pattern: {:?}", pat);
2074        log!("translate_pattern: bindings = {:?}", bindings);
2075        match pat {
2076            // TODO: flag on primitive type decl indicating it's an integer type?
2077            &ast::Pattern::ConstInt { val, pos } => {
2078                let ty = &tyenv.types[expected_ty.index()];
2079                if !ty.is_int() && !ty.is_prim() {
2080                    tyenv.report_error(
2081                        pos,
2082                        format!(
2083                            "expected non-integer type {}, but found integer literal '{}'",
2084                            ty.name(tyenv),
2085                            val,
2086                        ),
2087                    );
2088                }
2089                Some(Pattern::ConstInt(expected_ty, val))
2090            }
2091            &ast::Pattern::ConstBool { val, pos } => {
2092                if expected_ty != TypeId::BOOL {
2093                    tyenv.report_error(
2094                        pos,
2095                        format!(
2096                            "Boolean literal '{val}' has type {} but we need {} in context",
2097                            BuiltinType::Bool.name(),
2098                            tyenv.types[expected_ty.index()].name(tyenv)
2099                        ),
2100                    )
2101                }
2102                Some(Pattern::ConstBool(TypeId::BOOL, val))
2103            }
2104            &ast::Pattern::ConstPrim { ref val, pos } => {
2105                let val = tyenv.intern_mut(val);
2106                let const_ty = match tyenv.const_types.get(&val) {
2107                    Some(ty) => *ty,
2108                    None => {
2109                        tyenv.report_error(pos, "Unknown constant");
2110                        return None;
2111                    }
2112                };
2113                if expected_ty != const_ty {
2114                    tyenv.report_error(pos, "Type mismatch for constant");
2115                }
2116                Some(Pattern::ConstPrim(const_ty, val))
2117            }
2118            &ast::Pattern::Wildcard { .. } => Some(Pattern::Wildcard(expected_ty)),
2119            &ast::Pattern::And { ref subpats, .. } => {
2120                // If any of the subpatterns fails to type-check, we'll report
2121                // an error at that point. Here, just skip it and keep looking
2122                // for more errors.
2123                let children = subpats
2124                    .iter()
2125                    .filter_map(|subpat| {
2126                        self.translate_pattern(tyenv, subpat, expected_ty, bindings)
2127                    })
2128                    .collect();
2129                Some(Pattern::And(expected_ty, children))
2130            }
2131            &ast::Pattern::BindPattern {
2132                ref var,
2133                ref subpat,
2134                pos,
2135            } => {
2136                let subpat = self.translate_pattern(tyenv, subpat, expected_ty, bindings)?;
2137
2138                // The sub-pattern's type should be `expected_ty`. If it isn't,
2139                // we've already reported a type error about it, but continue
2140                // using the type we actually found in hopes that we'll
2141                // generate fewer follow-on error messages.
2142                let ty = subpat.ty();
2143
2144                let name = tyenv.intern_mut(var);
2145                if bindings.lookup(name).is_some() {
2146                    tyenv.report_error(
2147                        pos,
2148                        format!("Re-bound variable name in LHS pattern: '{}'", var.0),
2149                    );
2150                    // Try to keep going.
2151                }
2152                let id = bindings.add_var(name, ty);
2153                Some(Pattern::BindPattern(ty, id, Box::new(subpat)))
2154            }
2155            &ast::Pattern::Var { ref var, pos } => {
2156                // Look up the variable; if it has already been bound,
2157                // then this becomes a `Var` node (which matches the
2158                // existing bound value), otherwise it becomes a
2159                // `BindPattern` with a wildcard subpattern to capture
2160                // at this location.
2161                let name = tyenv.intern_mut(var);
2162                match bindings.lookup(name) {
2163                    None => {
2164                        let id = bindings.add_var(name, expected_ty);
2165                        Some(Pattern::BindPattern(
2166                            expected_ty,
2167                            id,
2168                            Box::new(Pattern::Wildcard(expected_ty)),
2169                        ))
2170                    }
2171                    Some(bv) => {
2172                        if expected_ty != bv.ty {
2173                            tyenv.report_error(
2174                                pos,
2175                                format!(
2176                                    "Mismatched types: pattern expects type '{}' but already-bound var '{}' has type '{}'",
2177                                    tyenv.types[expected_ty.index()].name(tyenv),
2178                                    var.0,
2179                                    tyenv.types[bv.ty.index()].name(tyenv),
2180                                ),
2181                            );
2182                            // Try to keep going for more errors.
2183                        }
2184                        Some(Pattern::Var(bv.ty, bv.id))
2185                    }
2186                }
2187            }
2188            &ast::Pattern::Term {
2189                ref sym,
2190                ref args,
2191                pos,
2192            } => {
2193                // Look up the term.
2194                let tid = match self.get_term_by_name(tyenv, sym) {
2195                    Some(t) => t,
2196                    None => {
2197                        tyenv.report_error(pos, format!("Unknown term in pattern: '{}'", sym.0));
2198                        return None;
2199                    }
2200                };
2201
2202                let termdata = &self.terms[tid.index()];
2203
2204                // Get the return type and arg types. Verify the
2205                // expected type of this pattern, if any, against the
2206                // return type of the term. Insert an implicit
2207                // converter if needed.
2208                let ret_ty = termdata.ret_ty;
2209                if expected_ty != ret_ty {
2210                    // Can we do an implicit type conversion? Look
2211                    // up the converter term, if any. If one has
2212                    // been registered, and the term has an
2213                    // extractor, then build an expanded AST node
2214                    // right here and recurse on it.
2215                    if let Some(expanded_pattern) =
2216                        self.maybe_implicit_convert_pattern(tyenv, pat, ret_ty, expected_ty)
2217                    {
2218                        return self.translate_pattern(
2219                            tyenv,
2220                            &expanded_pattern,
2221                            expected_ty,
2222                            bindings,
2223                        );
2224                    }
2225
2226                    tyenv.report_error(
2227                        pos,
2228                        format!(
2229                            "Mismatched types: pattern expects type '{}' but term has return type '{}'",
2230                            tyenv.types[expected_ty.index()].name(tyenv),
2231                            tyenv.types[ret_ty.index()].name(tyenv),
2232                        ),
2233                    );
2234                    // Try to keep going for more errors.
2235                }
2236
2237                termdata.check_args_count(args, tyenv, pos, sym);
2238
2239                // TODO: check that multi-extractors are only used in terms declared `multi`
2240
2241                match &termdata.kind {
2242                    TermKind::EnumVariant { .. } => {}
2243                    TermKind::Decl {
2244                        extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
2245                        ..
2246                    } => {}
2247                    TermKind::Decl {
2248                        extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
2249                        ..
2250                    } => {
2251                        if self.expand_internal_extractors {
2252                            // Expand the extractor macro! We create a map
2253                            // from macro args to AST pattern trees and
2254                            // then evaluate the template with these
2255                            // substitutions.
2256                            log!("internal extractor macro args = {:?}", args);
2257                            let pat = template.subst_macro_args(&args)?;
2258                            return self.translate_pattern(tyenv, &pat, expected_ty, bindings);
2259                        }
2260                    }
2261                    TermKind::Decl {
2262                        extractor_kind: None,
2263                        ..
2264                    } => {
2265                        tyenv.report_error(
2266                            pos,
2267                            format!(
2268                                "Cannot use term '{}' that does not have a defined extractor in a \
2269                                 left-hand side pattern",
2270                                sym.0
2271                            ),
2272                        );
2273                    }
2274                }
2275
2276                let subpats = self.translate_args(args, termdata, tyenv, bindings);
2277                Some(Pattern::Term(ret_ty, tid, subpats))
2278            }
2279            &ast::Pattern::MacroArg { .. } => unreachable!(),
2280        }
2281    }
2282
2283    fn translate_args(
2284        &self,
2285        args: &Vec<ast::Pattern>,
2286        termdata: &Term,
2287        tyenv: &mut TypeEnv,
2288        bindings: &mut Bindings,
2289    ) -> Vec<Pattern> {
2290        args.iter()
2291            .zip(termdata.arg_tys.iter())
2292            .filter_map(|(arg, &arg_ty)| self.translate_pattern(tyenv, arg, arg_ty, bindings))
2293            .collect()
2294    }
2295
2296    fn maybe_implicit_convert_expr(
2297        &self,
2298        tyenv: &mut TypeEnv,
2299        expr: &ast::Expr,
2300        inner_ty: TypeId,
2301        outer_ty: TypeId,
2302    ) -> Option<ast::Expr> {
2303        // Is there a converter for this type mismatch?
2304        if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) {
2305            if self.terms[converter_term.index()].has_constructor() {
2306                let converter_ident = ast::Ident(
2307                    tyenv.syms[self.terms[converter_term.index()].name.index()].clone(),
2308                    expr.pos(),
2309                );
2310                return Some(ast::Expr::Term {
2311                    sym: converter_ident,
2312                    pos: expr.pos(),
2313                    args: vec![expr.clone()],
2314                });
2315            }
2316        }
2317        None
2318    }
2319
2320    fn translate_expr(
2321        &self,
2322        tyenv: &mut TypeEnv,
2323        expr: &ast::Expr,
2324        ty: Option<TypeId>,
2325        bindings: &mut Bindings,
2326        root_flags: TermFlags,
2327    ) -> Option<Expr> {
2328        log!("translate_expr: {:?}", expr);
2329        match expr {
2330            &ast::Expr::Term {
2331                ref sym,
2332                ref args,
2333                pos,
2334            } => {
2335                // Look up the term.
2336                let name = tyenv.intern_mut(&sym);
2337                let tid = match self.term_map.get(&name) {
2338                    Some(&t) => t,
2339                    None => {
2340                        // Maybe this was actually a variable binding and the user has placed
2341                        // parens around it by mistake? (See #4775.)
2342                        if bindings.lookup(name).is_some() {
2343                            tyenv.report_error(
2344                                pos,
2345                                format!(
2346                                    "Unknown term in expression: '{}'. Variable binding under this name exists; try removing the parens?", sym.0));
2347                        } else {
2348                            tyenv.report_error(
2349                                pos,
2350                                format!("Unknown term in expression: '{}'", sym.0),
2351                            );
2352                        }
2353                        return None;
2354                    }
2355                };
2356                let termdata = &self.terms[tid.index()];
2357
2358                // Get the return type and arg types. Verify the
2359                // expected type of this pattern, if any, against the
2360                // return type of the term, and determine whether we
2361                // are doing an implicit conversion. Report an error
2362                // if types don't match and no conversion is possible.
2363                let ret_ty = termdata.ret_ty;
2364                let ty = if ty.is_some() && ret_ty != ty.unwrap() {
2365                    // Is there a converter for this type mismatch?
2366                    if let Some(expanded_expr) =
2367                        self.maybe_implicit_convert_expr(tyenv, expr, ret_ty, ty.unwrap())
2368                    {
2369                        return self.translate_expr(
2370                            tyenv,
2371                            &expanded_expr,
2372                            ty,
2373                            bindings,
2374                            root_flags,
2375                        );
2376                    }
2377
2378                    tyenv.report_error(
2379                        pos,
2380                        format!("Mismatched types: expression expects type '{}' but term has return type '{}'",
2381                                tyenv.types[ty.unwrap().index()].name(tyenv),
2382                                tyenv.types[ret_ty.index()].name(tyenv)));
2383
2384                    // Keep going, to discover more errors.
2385                    ret_ty
2386                } else {
2387                    ret_ty
2388                };
2389
2390                if let TermKind::Decl { flags, .. } = &termdata.kind {
2391                    // On the left-hand side of a rule or in a pure term, only pure terms may be
2392                    // used.
2393                    let pure_required = root_flags.pure;
2394                    if pure_required && !flags.pure {
2395                        tyenv.report_error(
2396                            pos,
2397                            format!(
2398                                "Used non-pure constructor '{}' in pure expression context",
2399                                sym.0
2400                            ),
2401                        );
2402                    }
2403
2404                    // Multi-terms may only be used inside other multi-terms.
2405                    if !root_flags.multi && flags.multi {
2406                        tyenv.report_error(
2407                            pos,
2408                            format!(
2409                                "Used multi-constructor '{}' but this rule is not in a multi-term",
2410                                sym.0
2411                            ),
2412                        );
2413                    }
2414
2415                    // Partial terms may always be used on the left-hand side of a rule. On the
2416                    // right-hand side they may only be used inside other partial terms.
2417                    let partial_allowed = root_flags.partial;
2418                    if !partial_allowed && flags.partial {
2419                        tyenv.report_error(
2420                            pos,
2421                            format!(
2422                                "Rule can't use partial constructor '{}' on RHS; \
2423                                try moving it to if-let{}",
2424                                sym.0,
2425                                if root_flags.multi {
2426                                    ""
2427                                } else {
2428                                    " or make this rule's term partial too"
2429                                }
2430                            ),
2431                        );
2432                    }
2433                }
2434
2435                termdata.check_args_count(args, tyenv, pos, sym);
2436
2437                // Resolve subexpressions.
2438                let subexprs = args
2439                    .iter()
2440                    .zip(termdata.arg_tys.iter())
2441                    .filter_map(|(arg, &arg_ty)| {
2442                        self.translate_expr(tyenv, arg, Some(arg_ty), bindings, root_flags)
2443                    })
2444                    .collect();
2445
2446                Some(Expr::Term(ty, tid, subexprs))
2447            }
2448            &ast::Expr::Var { ref name, pos } => {
2449                let sym = tyenv.intern_mut(name);
2450                // Look through bindings, innermost (most recent) first.
2451                let bv = match bindings.lookup(sym) {
2452                    None => {
2453                        tyenv.report_error(pos, format!("Unknown variable '{}'", name.0));
2454                        return None;
2455                    }
2456                    Some(bv) => bv,
2457                };
2458
2459                // Verify type. Maybe do an implicit conversion.
2460                if ty.is_some() && bv.ty != ty.unwrap() {
2461                    // Is there a converter for this type mismatch?
2462                    if let Some(expanded_expr) =
2463                        self.maybe_implicit_convert_expr(tyenv, expr, bv.ty, ty.unwrap())
2464                    {
2465                        return self.translate_expr(
2466                            tyenv,
2467                            &expanded_expr,
2468                            ty,
2469                            bindings,
2470                            root_flags,
2471                        );
2472                    }
2473
2474                    tyenv.report_error(
2475                        pos,
2476                        format!(
2477                            "Variable '{}' has type {} but we need {} in context",
2478                            name.0,
2479                            tyenv.types[bv.ty.index()].name(tyenv),
2480                            tyenv.types[ty.unwrap().index()].name(tyenv)
2481                        ),
2482                    );
2483                }
2484
2485                Some(Expr::Var(bv.ty, bv.id))
2486            }
2487            &ast::Expr::ConstBool { val, pos } => {
2488                match ty {
2489                    Some(ty) if ty != TypeId::BOOL => tyenv.report_error(
2490                        pos,
2491                        format!(
2492                            "Boolean literal '{val}' has type {} but we need {} in context",
2493                            BuiltinType::Bool.name(),
2494                            tyenv.types[ty.index()].name(tyenv)
2495                        ),
2496                    ),
2497                    Some(..) | None => {}
2498                };
2499                Some(Expr::ConstBool(TypeId::BOOL, val))
2500            }
2501            &ast::Expr::ConstInt { val, pos } => {
2502                let Some(ty) = ty else {
2503                    tyenv.report_error(
2504                        pos,
2505                        "integer literal in a context that needs an explicit type".to_string(),
2506                    );
2507                    return None;
2508                };
2509
2510                let typ = &tyenv.types[ty.index()];
2511
2512                if !typ.is_int() && !typ.is_prim() {
2513                    tyenv.report_error(
2514                        pos,
2515                        format!(
2516                            "expected non-integer type {}, but found integer literal '{}'",
2517                            tyenv.types[ty.index()].name(tyenv),
2518                            val,
2519                        ),
2520                    );
2521                }
2522                Some(Expr::ConstInt(ty, val))
2523            }
2524            &ast::Expr::ConstPrim { ref val, pos } => {
2525                let val = tyenv.intern_mut(val);
2526                let const_ty = match tyenv.const_types.get(&val) {
2527                    Some(ty) => *ty,
2528                    None => {
2529                        tyenv.report_error(pos, "Unknown constant");
2530                        return None;
2531                    }
2532                };
2533                if ty.is_some() && const_ty != ty.unwrap() {
2534                    tyenv.report_error(
2535                        pos,
2536                        format!(
2537                            "Constant '{}' has wrong type: expected {}, but is actually {}",
2538                            tyenv.syms[val.index()],
2539                            tyenv.types[ty.unwrap().index()].name(tyenv),
2540                            tyenv.types[const_ty.index()].name(tyenv)
2541                        ),
2542                    );
2543                    return None;
2544                }
2545                Some(Expr::ConstPrim(const_ty, val))
2546            }
2547            &ast::Expr::Let {
2548                ref defs,
2549                ref body,
2550                pos,
2551            } => {
2552                bindings.enter_scope();
2553
2554                // For each new binding...
2555                let mut let_defs = vec![];
2556                for def in defs {
2557                    // Check that the given variable name does not already exist.
2558                    let name = tyenv.intern_mut(&def.var);
2559
2560                    // Look up the type.
2561                    let tid = match tyenv.get_type_by_name(&def.ty) {
2562                        Some(tid) => tid,
2563                        None => {
2564                            tyenv.report_error(
2565                                pos,
2566                                format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0),
2567                            );
2568                            continue;
2569                        }
2570                    };
2571
2572                    // Evaluate the variable's value.
2573                    let val = Box::new(unwrap_or_continue!(self.translate_expr(
2574                        tyenv,
2575                        &def.val,
2576                        Some(tid),
2577                        bindings,
2578                        root_flags,
2579                    )));
2580
2581                    // Bind the var with the given type.
2582                    let id = bindings.add_var(name, tid);
2583                    let_defs.push((id, tid, val));
2584                }
2585
2586                // Evaluate the body, expecting the type of the overall let-expr.
2587                let body = Box::new(self.translate_expr(tyenv, body, ty, bindings, root_flags)?);
2588                let body_ty = body.ty();
2589
2590                // Pop the bindings.
2591                bindings.exit_scope();
2592
2593                Some(Expr::Let {
2594                    ty: body_ty,
2595                    bindings: let_defs,
2596                    body,
2597                })
2598            }
2599        }
2600    }
2601
2602    fn translate_iflet(
2603        &self,
2604        tyenv: &mut TypeEnv,
2605        iflet: &ast::IfLet,
2606        bindings: &mut Bindings,
2607        root_flags: TermFlags,
2608    ) -> Option<IfLet> {
2609        // Translate the expr first. The `if-let` and `if` forms are part of the left-hand side of
2610        // the rule.
2611        let rhs = self.translate_expr(tyenv, &iflet.expr, None, bindings, root_flags.on_lhs())?;
2612        let lhs = self.translate_pattern(tyenv, &iflet.pattern, rhs.ty(), bindings)?;
2613
2614        Some(IfLet { lhs, rhs })
2615    }
2616
2617    /// Lookup term by name.
2618    pub fn get_term_by_name(&self, tyenv: &TypeEnv, sym: &ast::Ident) -> Option<TermId> {
2619        tyenv
2620            .intern(sym)
2621            .and_then(|sym| self.term_map.get(&sym))
2622            .copied()
2623    }
2624}
2625
2626#[cfg(test)]
2627mod test {
2628    use super::*;
2629    use crate::ast::Ident;
2630    use crate::lexer::Lexer;
2631    use crate::parser::parse;
2632
2633    #[test]
2634    fn build_type_env() {
2635        let text = r"
2636            (type UImm8 (primitive UImm8))
2637            (type A extern (enum (B (f1 u32) (f2 u32)) (C (f1 u32))))
2638        ";
2639        let ast = parse(Lexer::new(0, text).unwrap()).expect("should parse");
2640        let tyenv = TypeEnv::from_ast(&ast).expect("should not have type-definition errors");
2641
2642        let sym_a = tyenv
2643            .intern(&Ident("A".to_string(), Default::default()))
2644            .unwrap();
2645        let sym_b = tyenv
2646            .intern(&Ident("B".to_string(), Default::default()))
2647            .unwrap();
2648        let sym_c = tyenv
2649            .intern(&Ident("C".to_string(), Default::default()))
2650            .unwrap();
2651        let sym_a_b = tyenv
2652            .intern(&Ident("A.B".to_string(), Default::default()))
2653            .unwrap();
2654        let sym_a_c = tyenv
2655            .intern(&Ident("A.C".to_string(), Default::default()))
2656            .unwrap();
2657        let sym_uimm8 = tyenv
2658            .intern(&Ident("UImm8".to_string(), Default::default()))
2659            .unwrap();
2660        let sym_f1 = tyenv
2661            .intern(&Ident("f1".to_string(), Default::default()))
2662            .unwrap();
2663        let sym_f2 = tyenv
2664            .intern(&Ident("f2".to_string(), Default::default()))
2665            .unwrap();
2666
2667        assert_eq!(tyenv.type_map.get(&sym_uimm8).unwrap(), &TypeId(13));
2668        assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(14));
2669
2670        let expected_types = vec![
2671            Type::Primitive(
2672                TypeId(13),
2673                sym_uimm8,
2674                Pos {
2675                    file: 0,
2676                    offset: 19,
2677                },
2678            ),
2679            Type::Enum {
2680                name: sym_a,
2681                id: TypeId(14),
2682                is_extern: true,
2683                is_nodebug: false,
2684                variants: vec![
2685                    Variant {
2686                        name: sym_b,
2687                        fullname: sym_a_b,
2688                        id: VariantId(0),
2689                        fields: vec![
2690                            Field {
2691                                name: sym_f1,
2692                                id: FieldId(0),
2693                                ty: TypeId::U32,
2694                            },
2695                            Field {
2696                                name: sym_f2,
2697                                id: FieldId(1),
2698                                ty: TypeId::U32,
2699                            },
2700                        ],
2701                    },
2702                    Variant {
2703                        name: sym_c,
2704                        fullname: sym_a_c,
2705                        id: VariantId(1),
2706                        fields: vec![Field {
2707                            name: sym_f1,
2708                            id: FieldId(0),
2709                            ty: TypeId::U32,
2710                        }],
2711                    },
2712                ],
2713                pos: Pos {
2714                    file: 0,
2715                    offset: 62,
2716                },
2717            },
2718        ];
2719
2720        assert_eq!(
2721            tyenv.types.len(),
2722            expected_types.len() + BuiltinType::ALL.len()
2723        );
2724        for (i, (actual, expected)) in tyenv
2725            .types
2726            .iter()
2727            .skip(BuiltinType::ALL.len())
2728            .zip(&expected_types)
2729            .enumerate()
2730        {
2731            assert_eq!(expected, actual, "`{i}`th type is not equal!");
2732        }
2733    }
2734}