Lecture 19 - Type systems
Types and Type Systems
Type: A set of values and meaningful operations on them
Types provide semantic βsanity checksβ and determine efficient implementations for data objects
Types help identify
- Errors
- Dereferencing a non-pointer
- Adding a function to something
- Incorrect number of parameters to a procedure
- Which operation to use for overloaded names and operators, or what type of type coercion to use (e.g.: 3.0 + 1)
- Identification of polymorphic functions
Type System
Type system: Each language construct (operator, expression, statement, β¦) is associated with a type expression. The type system is a collection of rules for assigning type expressions to these constructs
Type expressions for:
- Basic types:
integer,char,real,boolean,typeError - Constructed types, e.g., one-dimensional arrays:
array(lb, ub, elem_type), where elem_type is a type expression
A type checker implements a type system. It computes or βconstructsβ type expressions for each language construct.
Inference rules
Example type inference rule:
E β’ e1 : integer, E β’ e2 : integer => E β’ e1 + e2 : integer
Where E is a type environment that maps constants and variables to their type expressions
Example
Letβs say we have the expression 1 + 5.
We can describe our E as E = {1 : integer, 5 : integer}
We also have the following inference rules (that are fairly trivial)
- E = {1 : integer, 5 : integer} β’ 1 : integer
- E = {1 : integer, 5 : integer} β’ 5 : integer
This means that we also have the following inference rule
E β’ 1 : integer, E β’ 5 : integer => E β’ 1 + 5 : integer
Polymorphic example
What would the type of dereferencing a pointer?
- E β’ e1 : pointer (π) => E β’ * e1 : π
- π is any type expression
What would be the type of referencing a value?
- E β’ e1 : π => E β’ & e1 : pointer (π)
- π is any type expression
More complicated example
Letβs say we have the following expression *(&a)+3, and E starts off as E = {3 : integer}
- We donβt know what type
ais, so letβs just call it π- E = {3 : integer, a : π }
- Using the inference rule E β’ e1 : π => E β’ &e1 : pointer(π), we know that E β’ (&a) : pointer(π)
- Using the inference rule E β’ e1 : pointer (π) => E β’ * e1 : π, we know that E β’ *(&a) : π
- Since our addition rule only works with integers, using the inference rule E β’ *(&a) : π, E β’ 3 : integer => E β’ *(&a)+3 : integer
- E = {3 : integer, a : π, π : integer}
- Which also means that E β’ a : integer since E β’ π : integer
Type Equivalence
Structural type equivalence: type names are expanded Name type equivalence: type names are not expanded
Example:
type A is array(1..10) of integer;
type B is array(1..10) of integer;
a: A;
b: B;
c, d: array(1..10) of integer;
e: array(1..10) of integer;Are a,b,c,d,e the same type?
- For structural type equivalence they are equivalent
- For name equivalence, a and b are different, while c,d,e are equivalent
Project 2 hint:
The definition of type expression as C types (structs) should be done in attr.h. attr.c may contain helper functions The assignment of type expression C types to terminals and nonterminals of the grammar is done in parse.y
Lexically-scoped Symbol Tables
The problem
- The compiler needs a distinct record for each declaration
- Nested lexical scopes admit duplicate declarations
The interface
insert(name, level)creates a record fornameatlevellookup(name, level)returns pointer or indexdelete(level)removes all names declared atlevel
Many implementation schemes have been proposed
- Weβll stay at the conceptual level
- Hash table implementation is tricky, detailed, & fun