Semantic model of Move code. Builds and represents the type-checked AST with full type information.
This crate transforms Move source code into a semantic model (GlobalEnv) containing modules, functions, structs, enums, and specifications with resolved types and locations.
Pipeline: Move Source → Compiler (parse/type-check) → ModelBuilder → GlobalEnv
src/
├── lib.rs # Entry points: run_model_builder(), run_spec_checker()
├── model.rs # Core types: GlobalEnv, ModuleEnv, FunctionEnv, etc. (~6500 lines)
├── ty.rs # Type system: Type enum, PrimitiveType, Substitution (~1300 lines)
├── symbol.rs # Symbol pool for interned strings
├── ast.rs # AST for spec language: Attribute, Value, ModuleName
├── pragmas.rs # Pragma handling
├── code_writer.rs # Code generation utilities
├── well_known.rs # Well-known module/function names
└── builder/
├── model_builder.rs # ModelBuilder: orchestrates model construction
├── module_builder.rs # ModuleBuilder: translates individual modules
└── exp_translator.rs # ExpTranslator: translates expressions
GlobalEnv (root container)
├── SymbolPool # Interned strings
├── source_files # Source file registry
├── module_data[] # All loaded modules
│ └── ModuleData
│ ├── struct_data # BTreeMap<DatatypeId, StructData>
│ ├── enum_data # BTreeMap<DatatypeId, EnumData>
│ ├── function_data # BTreeMap<FunId, FunctionData>
│ └── named_constants
└── exp_info # NodeId → (Loc, Type) mapping
Root environment containing all data:
// Access patterns
let module_env = global_env.get_module(module_id);
let func_env = module_env.get_function(func_id);
let struct_env = module_env.get_struct(struct_id);
// Node tracking
let node_id = global_env.new_node_id();
let loc = global_env.get_node_loc(node_id);
let ty = global_env.get_node_type(node_id);
// Target modules (non-dependency)
for module in global_env.get_target_modules() { ... }Lightweight reference wrappers providing read access:
let module_env: ModuleEnv<'_> = global_env.get_module(id);
let func_env: FunctionEnv<'_> = module_env.get_function(func_id);
let struct_env: StructEnv<'_> = module_env.get_struct(struct_id);
// Key methods
func_env.get_bytecode() // Move bytecode instructions
func_env.get_parameters() // Parameter list
struct_env.get_fields() // Field iterator
struct_env.get_abilities() // Copy, Drop, Store, Keypub enum Type {
Primitive(PrimitiveType), // Bool, U8, U64, Address, etc.
Vector(Box<Type>),
Datatype(ModuleId, DatatypeId, Vec<Type>), // Struct/Enum
Reference(bool, Box<Type>), // bool = is_mutable
TypeParameter(u16),
Tuple(Vec<Type>),
Fun(Vec<Type>, Box<Type>), // Spec-only function type
Error, Var(u16), // Temporary during type inference
}ModuleId(RawIndex)- Index-based for fast Vec accessDatatypeId(Symbol)- Symbol-based for struct/enumFunId(Symbol)- Function identifierFieldId(Symbol)- Field identifierNodeId(usize)- AST node identifierQualifiedId<Id>- Id qualified by module
-
Compiler Pipeline (lib.rs)
- Parser → Expansion → Typing → Compilation
- Collects diagnostics
-
Spec Checking (lib.rs)
- Creates ModelBuilder with mutable GlobalEnv
- Iterates modules in dependency order
-
Module Translation (module_builder.rs)
- Declaration analysis: register structs, enums, functions
- Definition analysis: type-check bodies
- Population: add to GlobalEnv
// Build model from source files
let env = run_model_builder(targets, deps, named_address_map, options)?;
// Build model from compiled modules
let env = run_bytecode_model_builder(modules)?;
// Access modules
for module in env.get_modules() {
for func in module.get_functions() {
println!("{}", func.get_name());
}
}All strings are interned for fast comparison:
let symbol = env.symbol_pool().make("my_name");
let name = env.symbol_pool().string(symbol);The crate defines well-known identifiers for:
- Prover modules: "prover", "ghost", "vector_iter"
- Spec functions: requires, ensures, asserts, invariant, global
- Sui framework: object, dynamic_field, event, transfer
- Standard library: vector, option, table
- Reference-based access:
ModuleEnv,FunctionEnvare references, not owned data - LazyLock caching: Call graphs computed on first access via
RefCell<Option<_>> - Source mapping:
FileId→ codespan Files database for error reporting - Extensions:
BTreeMap<TypeId, Box<dyn Any>>for tool-specific data
// Get qualified function ID
let qid = func_env.get_qualified_id();
// Check if function is native
if func_env.is_native() { ... }
// Get struct fields by name
if let Some(field) = struct_env.find_field(symbol) { ... }
// Check abilities
if struct_env.has_memory() { ... } // Key ability
// Iterate dependencies
for dep_id in module_env.get_dependencies() { ... }