Upload
kourtney-warren
View
19
Download
0
Embed Size (px)
DESCRIPTION
Type Checking. Legality checks Operator determination Overload resolution. Type as a synthesized attribute. Expr ::= Expr + Term if Etype (Expr 2 ) = Etype (Term) then Etype (Expr 1 ) := Etype (Expr 2 ); else Etype (Expr1) = Any_Type; - PowerPoint PPT Presentation
Citation preview
Type Checking
Legality checksOperator determinationOverload resolution
Type as a synthesized attribute
Expr ::= Expr + Term
if Etype (Expr2) = Etype (Term) then
Etype (Expr1) := Etype (Expr2);
else
Etype (Expr1) = Any_Type;
Error (“incompatible types for +”, Expr1);
end if; Sufficient for Pascal and C
Rules for operations on composite types
Indexed_Component ::= Prefix ( Expr )
A_Typ := Etype (Prefix);
Etype (Indexed_Component) := Any_Type; - - by default
if not Is_Array_Type (A_Typ) then
Error (“expect array type in indexed component”, Prefix);
elsif Etype (Expr) /= Index_Type (A_Typ) then
Error (“wrong index type”, Expr);
else
Etype (Indexed_Component) := Component_Type (A_Typ);
end if;
Type expressions
Built from: Primitive types: boolean, float, integer Type constructors: array, record, access, function
Type_Expr ::= Prim_Type Type_Expr ::= Type_Name Type_Expr ::= array (Type_Expr) Type_Expr
Pascal, Ada : index type is part of type expression Early Pascal : index bounds are part of type expression (bad idea)
Type_Expr ::= record (…) Type_Expr ::= access Type_Expr Type checking is a set of rules to compute the type expressions of
all expressions in the program
Product types and functions
Type_Expr := Type_Expr * Type_Expr Intuitively, a pair of types
Type_Expr := Type_Expr1 -> Type_Expr2
A function that takes an argument of type Type_Expr1 and returns a value of type Type_Expr2
function Distance (C1, C2 : Character) return Integer; Distance: character * character -> integer real merge (int[] a, int[]b); merge: array ( int ) * array ( int ) -> real
Type checking and type equivalence
Type correctness can be stated in terms of equivalence of type expressions:
int [ ] arr1; // arr2 : array ( int )
int [ ] arr2; // arr2 : array ( int )
…
Arr1 = arr2;
// ok in Java: type expressions are equivalent
Usually the rule in languages where a declaration can contain an arbitrary type expression
Type checking and name equivalence
Arr1 : array (1..10) of integer;
Arr2 : array (1..10) of integer;
…
Arr1 := Arr2; // illegal in Ada: different anonymous types.
-- same as:
type anon1 is array (1..10) of integer;
Arr1 : anon1; -- Arr1 : anon1
type anon2 is array (1..10) of integer;
Arr2 : anon2: -- Arr2 : anon2
-- Arr1 and Arr2 are not equivalent.
Language does not allow arbitrary (anonymous) type expressions in a declaration
Type expressions with cycles
type t1 = record c: integer; p: pointer (t1); end record;type t2 = record c: integer; p: pointer (t2); end record;
t1 and t2 are equivalent in Algol68
C approach: name of type is part of type expression, types are not equivalent:
struct cell { int c; struct cell *next;
/* struct cell is in type expression */};
Type checking and coercions
If language allows coercions, type depends on context, cannot be purely synthesized.
For C++ boolean operators (Stroustrup C.6.3) If either operand is of type long double, the other is
converted to long double Otherwise, if either operand is double, the other is
converted to double Otherwise, if either is float, the other is converted to float Otherwise, integral promotions are performed on both:
char, (un) signed_char, (unsigned) short int -> int bit-field -> int bool -> int
Further complication: user-defined conversions.
Overload resolution If expression is overloaded, collect set of possible
meanings sm. If context is overloaded, collect set of possible context
types sc. Expression is legal in context if intersection of sc and sm
is a singleton: | sc ∩ sm | = 1
C++: if multiple interpretations, select the one with smallest number of coercions
Ada: if multiple interpretations, select predefined numeric operator over user-defined one
Overloaded context: procedure call
procedure P (x : integer; y : float);
procedure P (x : float; y : float);
procedure P (x : boolean; z : integer);
function F (x : integer) return integer;
function F (x : float) return integer;
function F (x : integer) return float;
function F (x : float) return boolean;
…
P (f (3.14), f (1)); -- P1 (f2 (3.14), f3 (1));
Two-pass type resolution
Bottom-up (analyze) : synthesize candidate types Top-down (resolve): propagate unique context type
procedure analyze_indexed_component (N : Node_Id) isbegin
analyze prefix, collect set of interpretations Pre analyze index, collect set of interpretations Ind forall t in Pre loop if there is a compatible ix in Ind then
add component_Type (t) to interpretations of N else remove t from Pre; end if;
end loop; end;
Two-pass type resolution (2)
procedure resolve_indexed_component (N : Node_Id; Typ : Entity_Id)
is
begin
find unique interpretation of prefix whose component type is Typ
resolve index using this interpretation
end;
General scheme:
bottom-up: analyze descendants, synthesize local attribute
top-down : disambiguate construct, propagate to descendants
Type variables and polymorphism
In a language with list primitives (LISP, ML) what is the type expression that describes CAR or hd?
Informally, given a list of components of any kind, CAR yields a value of that kind:
Car : list_of_whatever -> whatever
A type variable is universally quantified: the expression is valid for any instantiation of the variable. In ML notation: Head (hd) α list -> α Tail (tl) α list -> α list Constructor (::) : α * α list -> α list
Polymorphic functions
fun len lis = if lis = null then 0 else 1 + len (tl lis) Len : α list -> int
fun map (f lis) =
if L = null then null else f (hd lis) :: map (f (tl lis))
Map: (α ->β) * α list -> β list
Map applies a function to each element of a list. The result type of the function is not necessarily equal to the element type of the list.
The limits of type inference
Overloading must be handled specially Self-application is not typable:
1 + g (g)
g is a function: g: α -> β
g applied to itself yields an integer: β = int α = α -> β : circular definition (not unifiable)