package asli

  1. Overview
  2. Docs

Type inference and checker for ASL language

module PE = PPrintEngine
module PC = PPrintCombinators
module PP = Asl_parser_pp
module AST = Asl_ast
module Visitor = Asl_visitor
val verbose : bool

Exceptions thrown by typechecker

exception UnknownObject of AST.l * string * string
exception DoesNotMatch of AST.l * string * string * string
exception IsNotA of AST.l * string * string
exception Ambiguous of AST.l * string * string
exception TypeError of AST.l * string
exception InternalError of string

AST construction utilities

val type_unit : AST.ty
val type_integer : AST.ty
val type_bool : AST.ty
val type_real : AST.ty
val type_string : AST.ty
val type_bits : AST.expr -> AST.ty
val type_exn : AST.ty

Construct expression "eq_int(x, y)"

Construct expression "add_int(x, y)"

Construct expression "sub_int(x, y)"

Construct expression "(0 + x1) + ... + xn"

Prettyprinting support

Table of binary operators used for resugaring expressions when printing error messages.

val add_binop : AST.binop -> AST.ident -> unit
val ppp_expr : AST.expr -> string

Very pretty print expression (resugaring expressions)

val ppp_type : LibASL.Asl_utils.AST.ty -> string

Very pretty print type (resugaring expressions)

Environment representing global and local objects

type typedef =
  1. | Type_Builtin of AST.ident
  2. | Type_Forward
  3. | Type_Record of (AST.ty * AST.ident) list
  4. | Type_Enumeration of AST.ident list
  5. | Type_Abbreviation of AST.ty
val pp_typedef : typedef -> string
val pp_funtype : funtype -> PE.document
val fv_funtype : funtype -> Asl_utils.IdentSet.t
val pp_sfuntype : sfuntype -> PE.document
val sformal_type : AST.sformal -> LibASL.Asl_utils.AST.ty
val funtype_of_sfuntype : sfuntype -> funtype
module Operator1 : sig ... end
module Operators1 : sig ... end
module Operator2 : sig ... end
module Operators2 : sig ... end

Global Environment (aka the Global Symbol Table)

module GlobalEnv : sig ... end
val isConstant : GlobalEnv.t -> LibASL.Asl_utils.AST.ident -> bool

dereference typedef

compare index types

structural match on two types - ignoring the dependent type part

Field typechecking support

type fieldtypes =
  1. | FT_Record of (AST.ty * AST.ident) list
  2. | FT_Register of (LibASL.Asl_utils.AST.slice list * AST.ident) list

Field accesses can be either record fields or fields of registers

This type captures the information needed to typecheck either of these

  • a list of fieldname/type pairs for records
  • a list of fieldname/slice pairs for registers

Get fieldtype information for a record/register type

Get fieldtype information for a named field of a record

Get fieldtype information for a named field of a slice

Get named field of a register and calculate type

Get named fields of a register and calculate type of concatenating them

Environment (aka the Local+Global Symbol Table)

module Env : sig ... end

Unification

Expression simplification

Perform simple constant folding of expression

It's primary role is to enable the 'DIV' hacks in z3_of_expr which rely on shallow syntactic transforms. It has a secondary benefit of sometimes causing constraints to become so trivial that we don't even need to invoke Z3 which gives a performance benefit.

Perform simple constant folding of expressions within a type

Z3 support code

Convert ASL expression to Z3 expression. This only copes with a limited set of operations: ==, +, -, * and DIV. (It is possible that we will need to extend this list in the future but it is sufficient for the current ASL specifications.)

The support for DIV is not sound - it is a hack needed to cope with the way ASL code is written and generally needs a side condition that the division is exact (no remainder).

ufs is a mutable list of conversions used to handle subexpressions that cannot be translated. We treat such subexpressions as uninterpreted functions and add them to the 'ufs' list so that we can reason that "F(x) == F(x)" without knowing "F".

val check_constraints : AST.expr list -> AST.expr list -> bool

check that bs => cs

Unification support code

class unifier : LibASL.Asl_utils.AST.l -> AST.expr list -> object ... end

Unifier

val with_unify : Env.t -> LibASL.Asl_utils.AST.l -> (unifier -> 'a) -> AST.expr Asl_utils.Bindings.t * 'a0

Create a fresh unifier, invoke a function that uses the unifier and check that the constraints are satisfied. Returns the synthesized bindings and result of function

Type Unification

Notes on how type inference works:

  • we use structural matching (ignoring the dependent type) to disambiguate each binop/unop/function/procedure call/getter/setter
  • as we construct each TApply node,
  • we insert fresh type variables $0, $1, ... for each of the type arguments (these are things we are going to solve for)
  • unification generates two kinds of constraints: 1. bindings for type variables whenever unification requires "$i == e" or "e == $i" for some type variable $i 2. constraints where there are multiple bindings for a single variable 3. constraints on type variables whenever unification requires "e1 == e2" where e1 is not a variable
  • after scanning an entire assignment/expression, we check: 1. do we have at least one binding for each variable? 2. are the bindings consistent with the constraints? Note that we could potentially give better (more localized) type errors if we check for consistency as we go along and if we check that a variable is bound as soon as the result type could not possibly involve the variable. (e.g., when checking "(e1 == e2 && Q) || R", any type variables associated with the equality check do not impact the && or || because "boolean" does not have any type parameters.)

Note that there is a choice of what type arguments to add to a function

bits(N) ZeroExtend(bits(M) x, integer N)

We can either:

  • add only the missing information "M" In effect, we are saying that missing type parameters are implicit parameters that are added by the type inference process and that the "type parameters" are basically just value expressions that are added by type inference.
  • add type arguments for both "M" and "N". In effect we are saying that type parameters are distinct from value parameters and we are in the strange situation that a function could have both a value parameter M and a type parameter N and they might be bound to different (but equivalent) arguments. This is what archex does.

Unify two index types

Unify two types

This performs a structural match on two types - ignoring the dependent type part

Apply substitutions to an expression

Apply substitutions to an L-expression

Apply substitutions to a type

val mkfresh_funtype : unifier -> funtype -> funtype

Replace all type variables in function type with fresh variables

val mkfresh_sfuntype : unifier -> sfuntype -> sfuntype

Replace all type variables in setter function type with fresh variables

Check that ty2 is a subtype of ty1: ty1 >= ty2

Check that ty1 is identical to ty2

Disambiguation of functions and operators

val reportChoices : LibASL.Asl_utils.AST.l -> string -> string -> LibASL.Asl_utils.AST.ty list -> funtype list -> unit

Generate error message when function disambiguation fails

val isCompatibleFunction : GlobalEnv.t -> bool -> LibASL.Asl_utils.AST.ty list -> funtype -> bool

Check whether a list of function argument types is compatible with the type of a function.

One function type is compatible with another if they have the same number of arguments and each argument has the same base type

val chooseFunction : GlobalEnv.t -> LibASL.Asl_utils.AST.l -> string -> string -> bool -> LibASL.Asl_utils.AST.ty list -> funtype list -> funtype option

Disambiguate a function name based on the number and type of arguments

val isCompatibleSetterFunction : GlobalEnv.t -> LibASL.Asl_utils.AST.ty list -> sfuntype -> bool

Check whether a list of function argument types is compatible with the type of a setter function.

One function type is compatible with another if they have the same number of arguments and each argument has the same base type

val chooseSetterFunction : GlobalEnv.t -> LibASL.Asl_utils.AST.l -> string -> AST.ident -> LibASL.Asl_utils.AST.ty list -> sfuntype list -> sfuntype option

Disambiguate a setter function name based on the number and type of arguments

Instantiate type of function using unifier 'u'

Instantiate type of setter function using unifier 'u'

Disambiguate and typecheck application of a function to a list of arguments

Disambiguate and typecheck application of a unary operator to argument

Typecheck expressions

Typecheck list of expressions

Typecheck expression and check that it is a subtype of ty

Typecheck bitslice syntax This primarily consists of disambiguating between array indexing and bitslicing Note that this function is almost identical to tc_slice_lexpr

Typecheck list of types

Typecheck type

Typecheck L-expressions

Typecheck bitslice syntax

This primarily consists of disambiguating between array indexing and bitslicing Note that this function is almost identical to tc_slice_expr

Typecheck left hand side of expression in context where type of right hand side is not yet known

Typecheck statements

Typecheck left hand side of expression and check that rhs type 'ty' is compatible. Return set of variables assigned to in this expression

Typecheck list of statements

Typecheck 'if expr then stmt'

Typecheck exception catcher 'when expr stmt'

Typecheck statement

Typecheck function definition

Typecheck function body (list of statements)

Typecheck list of function arguments

Typecheck setter procedure argument

val tc_sformals : Env.t -> LibASL.Asl_utils.AST.l -> AST.sformal list -> AST.sformal list

Typecheck list of setter procedure arguments

Typecheck instruction

Typecheck instruction encoding

Typecheck bitslice of instruction opcode

val check_width : LibASL.Asl_utils.AST.l -> int -> int -> unit
val tc_decode_pattern : LibASL.Asl_utils.AST.l -> int -> AST.decode_pattern -> AST.decode_pattern

Typecheck instruction decode pattern match

val tc_decode_body : GlobalEnv.t -> AST.decode_body -> AST.decode_body

Typecheck instruction decode body

val tc_decode_alt : GlobalEnv.t -> LibASL.Asl_utils.AST.l -> int list -> AST.decode_alt -> AST.decode_alt

Typecheck instruction decode case alternative

val tc_decode_case : GlobalEnv.t -> AST.l -> AST.instr_field list -> AST.decode_case -> AST.decode_case

Typecheck instruction decode case

Typecheck global declaration

Typecheck global declaration, extending environment as needed

Generate function prototype declarations.

This allows function declarations within a translation unit to be placed in any order.

val env0 : GlobalEnv.t

Overall typechecking environment shared by all invocations of typechecker

val tc_declarations : bool -> LibASL.Asl_utils.AST.declaration list -> LibASL.Asl_utils.AST.declaration list

Typecheck a list of declarations - main entrypoint into typechecker