type checking compiler
TRANSCRIPT
-
7/30/2019 type checking compiler
1/215
Type-Checking II
-
7/30/2019 type checking compiler
2/215
Announcements
Written Assignment 2 Due Monday at 5:00PM.
Office hours today, Sunday, and Monday.
Ask questions on Piazzza!
Email the staff list with questions!
Midterm next Wednesday in class, 11:00 1:00.
Midterm review session next Monday in class.
We'll post practice midterms online.
Midterm covers all of scanning and parsing, but not semantic
analysis.
Open-book, open-notes, open-computer, closed-network.
OH switch next week: Monday office hours in Gates B24A,Friday office hours in Gates 160 at the scheduled times.
-
7/30/2019 type checking compiler
3/215
Where We Are
Lexical Analysis
Semantic Analysis
Syntax Analysis
IR Generation
IR Optimization
Code Generation
Optimization
SourceCode
Machine
Code
-
7/30/2019 type checking compiler
4/215
Review from Last Time
Static type checking in Decaf consists of twoseparate processes:
Inferring the type of each expression from the types
of its components. Confirming that the types of expressions in certain
contexts matches what is expected.
Logically two steps, but you will probably
combine into one pass.
-
7/30/2019 type checking compiler
5/215
Review from Last Time
while (numBitsSet(x + 5)
-
7/30/2019 type checking compiler
6/215
Review from Last Time
while (numBitsSet(x + 5)
-
7/30/2019 type checking compiler
7/215
Review from Last Time
while (numBitsSet(x + 5)
-
7/30/2019 type checking compiler
8/215
Review from Last Time
while (numBitsSet(x + 5)
-
7/30/2019 type checking compiler
9/215
Review from Last Time
while (numBitsSet(x + 5)
-
7/30/2019 type checking compiler
10/215
Review from Last Time
while (numBitsSet(x + 5)
-
7/30/2019 type checking compiler
11/215
Review from Last Time
We write
S e : T
ifin scope S, the expression e has type T.
-
7/30/2019 type checking compiler
12/215
Review from Last Time
S f(e1, ..., e
n) : U
fis an identifier.fis a non-member function in scope S.
fhas type (T1, , T
n) U
S ei: T
ifor 1 i n
Read rules
like this
-
7/30/2019 type checking compiler
13/215
Review from Last Time
S f(e1, ..., e
n) : U
fis an identifier.fis a non-member function in scope S.
fhas type (T1, , T
n) U
S ei: T
ifor 1 i n
-
7/30/2019 type checking compiler
14/215
Review from Last Time
We say that A B if A is convertible to B.
The least upper bound of A and B is the class C where
A C
B C
C C' for all other upper bounds.
The least upper bound is denoted A B when it exists.
A minimal upper bound of A and B is
an upper bound of A and B that is not larger than any other upper bound.
-
7/30/2019 type checking compiler
15/215
Review from Last Time
S f(e1, ..., e
n) : U
fis an identifier.fis a non-member function in scope S.
fhas type (T1, , T
n) U
S ei
: Ri
for 1 i n
Ri T
ifor 1 i n
-
7/30/2019 type checking compiler
16/215
Review from Last Time
S null : null type
-
7/30/2019 type checking compiler
17/215
Overview for Today
Type-checking statements.
Practical type-checking considerations.
Type-checking practical language constructs:
Function overloading.
Specializing overrides.
-
7/30/2019 type checking compiler
18/215
Using our Type Proofs
We can now prove the types of variousexpressions.
How do we check...
that ifstatements have well-formed conditionalexpressions?
that return statements actually return the right
type of value?
Use another proof system!
-
7/30/2019 type checking compiler
19/215
Proofs of Structural Soundness
Idea: extend our proof system to statements toconfirm that they are well-formed.
We say that
S WF( stmt)if the statement stmtis well-formed in scope S.
The type system is satisfied if for every functionfwith body B in scope S, we can showS WF(B).
-
7/30/2019 type checking compiler
20/215
A Simple Well-Formedness Rule
S WF( expr;)
S expr: T
-
7/30/2019 type checking compiler
21/215
A Simple Well-Formedness Rule
S WF( expr;)
S expr: T
If we canassign a valid
type to an
expression in
scope S
-
7/30/2019 type checking compiler
22/215
A Simple Well-Formedness Rule
S WF( expr;)
S expr: T
If we canassign a valid
type to an
expression in
scope SS expr: T
then it is a
valid statement
in scope S.
-
7/30/2019 type checking compiler
23/215
A More Complex Rule
-
7/30/2019 type checking compiler
24/215
A More Complex Rule
S WF( stmt1stmt
2)
S WF( stmt1)
S WF( stmt2)
-
7/30/2019 type checking compiler
25/215
Rules forbreak
-
7/30/2019 type checking compiler
26/215
Rules forbreak
S WF( break;)
S is in a for orwhile loop.
-
7/30/2019 type checking compiler
27/215
A Rule for Loops
-
7/30/2019 type checking compiler
28/215
A Rule for Loops
S WF( while (expr)stmt)
S expr:bool
S' is the scope inside the loop.
S' WF( stmt)
-
7/30/2019 type checking compiler
29/215
Rules for Block Statements
-
7/30/2019 type checking compiler
30/215
Rules for Block Statements
S WF( { declsstmt})
S' is the scope formed by adding decls to S
S' WF( stmt)
-
7/30/2019 type checking compiler
31/215
Rules forreturn
-
7/30/2019 type checking compiler
32/215
Rules forreturn
S WF( returnexpr;)
S is in a function returning TS expr: T'
T' T
S WF( return;)
S is in a function returning void
-
7/30/2019 type checking compiler
33/215
Checking Well-Formedness
Recursively walk the AST.
For each statement:
Typecheck any subexpressions it contains.
Report errors if no type can be assigned.
Report errors if the wrong type is assigned.
Typecheck child statements.
Check the overall correctness.
-
7/30/2019 type checking compiler
34/215
PracticalConcerns
-
7/30/2019 type checking compiler
35/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
-
7/30/2019 type checking compiler
36/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
-
7/30/2019 type checking compiler
37/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
-
7/30/2019 type checking compiler
38/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
-
7/30/2019 type checking compiler
39/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S hi i V W H
-
7/30/2019 type checking compiler
40/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x: T
xis an identifier.xis a variable in scope S with type T.
S thi i V W H
-
7/30/2019 type checking compiler
41/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x: T
xis an identifier.xis a variable in scope S with type T.
S x : int
S thi i V W H
-
7/30/2019 type checking compiler
42/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x: T
xis an identifier.xis a variable in scope S with type T.
S x : int
S thi i V W H
-
7/30/2019 type checking compiler
43/215
Something is Very Wrong Here
int x, y, z;if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x: T
xis an identifier.xis a variable in scope S with type T.
S x : int
S y : int
S z : int
S thi i V W H
-
7/30/2019 type checking compiler
44/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x: T
xis an identifier.xis a variable in scope S with type T.
S x : int
S y : int
S z : int
S thi i V W H
-
7/30/2019 type checking compiler
45/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S e1== e2 :bool
S e1
: T1
S e2
: T2
T1 T
2or T
2 T
1
Something is Very Wrong Here
-
7/30/2019 type checking compiler
46/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S e1== e2 :bool
S e1
: T1
S e2
: T2
T1 T
2or T
2 T
1
S x == y :bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
47/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S e1== e2 :bool
S e1
: T1
S e2
: T2
T1 T
2or T
2 T
1
S x == y :bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
48/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S i: int
iis an integer constant
Something is Very Wrong Here
-
7/30/2019 type checking compiler
49/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S
i: int
iis an integer constant
S 5 : int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
50/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S i
:int
iis an integer constant
S 5 : int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
51/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : intS e1 + e2 : int
S e1
: int
S e2
: int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
52/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : intS e1 + e2 : int
S e1
: int
S e2
: int
S x + y : int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
53/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : intS e1 + e2 : int
S e1
: int
S e2
: int
S x + y : int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
54/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : intS e1< e2 :bool
S e1
: int
S e2
: int
S x + y : int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
55/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : intS e1< e2 :bool
S e1
: int
S e2
: int
S x + y : int
S x + y < z :bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
56/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : intS e1< e2 :bool
S e1
: int
S e2
: int
S x + y : int
S x + y < z :bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
57/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S e1== e2 :bool
S e1
: T1
S e2
: T2
T1 T
2or T
2 T
1
Something is Very Wrong Here
-
7/30/2019 type checking compiler
58/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S e1== e2 :bool
S e1
: T1
S e2
: T2
T1 T
2or T
2 T
1
S x == z :bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
59/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1== e2 :bool
S e1
: T1
S e2
: T2
T1 T
2or T
2 T
1
Something is Very Wrong Here
-
7/30/2019 type checking compiler
60/215
Something is Very Wrong Here
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1>e
2:bool
S e1
: int
S e2
: int
Something is Very Wrong Here
-
7/30/2019 type checking compiler
61/215
So e g s e y o g e e
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1>e
2:bool
S e1
: int
S e2
: int
>
Something is Very Wrong Here
-
7/30/2019 type checking compiler
62/215
g y g
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1>e
2:bool
S e1
: int
S e2
: int
> Error: Cannot compare int and bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
63/215
g y g
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1>e
2:bool
S e1
: int
S e2
: int
> Error: Cannot compare int and bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
64/215
g y g
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {
/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1&& e
2:bool
S e1
:bool
S e2
:bool
> Error: Cannot compare int and bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
65/215
g y g
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1&& e
2:bool
S e1
:bool
S e2
:bool
> Error: Cannot compare int and bool
Error: Cannot compare ??? and bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
66/215
g y g
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1&& e
2:bool
S e1
:bool
S e2
:bool
> Error: Cannot compare int and bool
Error: Cannot compare ??? and bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
67/215
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1|| e
2:bool
S e1
:bool
S e2
:bool
> Error: Cannot compare int and bool
Error: Cannot compare ??? and bool
Something is Very Wrong Here
-
7/30/2019 type checking compiler
68/215
int x, y, z;
if (((x == y) > 5 && x + y < z) || x == z) {/* */
}
Facts
S x : int
S y : int
S z : int
S x == y :bool
S 5 : int
S x + y : int
S x + y < z :bool
S x == z :bool
S e1|| e
2:bool
S e1
:bool
S e2
:bool
> Error: Cannot compare int and bool
Error: Cannot compare ??? and bool
Error: Cannot compare ??? and bool
Cascading Errors
-
7/30/2019 type checking compiler
69/215
A type erroroccurs when we cannot prove thatan expression has a given type.
Type errors can easily cascade:
Can't prove a type for e1, so can't prove a type fore
1+e
2, so can't prove a type for (e
1+e
2)+e
3, etc.
How do we resolve this?
The Shape of Types
-
7/30/2019 type checking compiler
70/215
Vegetable
ArtichokeCarrot
The Shape of Types
-
7/30/2019 type checking compiler
71/215
Vegetable
ArtichokeCarrot bool string doubleintArrayTypes
The Shape of Types
-
7/30/2019 type checking compiler
72/215
Vegetable
ArtichokeCarrot bool string doubleintArrayTypes
null Type
The Shape of Types
-
7/30/2019 type checking compiler
73/215
Vegetable
ArtichokeCarrot bool string doubleintArrayTypes
null Type
Error Type
The Shape of Types
-
7/30/2019 type checking compiler
74/215
Vegetable
ArtichokeCarrot bool string doubleintArrayTypes
null Type
Error Type
The Error Type
-
7/30/2019 type checking compiler
75/215
Introduce a new type representing an error intothe type system.
The error type is less than all other types and isdenoted .
It is sometimes called the bottom type.
By definition, A for any type A.
On discovery of a type error, pretend that wecan prove the expression has type .
Update our inference rules to support .
Updated Rules for Addition
-
7/30/2019 type checking compiler
76/215
S e1
+ e2: double
S e1
: double1
S e2
: double2
T1
double
T2 double
Updated Rules for Addition
-
7/30/2019 type checking compiler
77/215
S e1
+ e2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
Updated Rules for Addition
-
7/30/2019 type checking compiler
78/215
S e1
+ e2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
Updated Rules for Addition
-
7/30/2019 type checking compiler
79/215
S e1
+ e2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
What does
this mean?
Updated Rules for Addition
-
7/30/2019 type checking compiler
80/215
S e1
+ e2: intS e
1+ e
2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
S e1
: T1
S e2
: T2
T1
int
T2 int
Updated Rules for Addition
-
7/30/2019 type checking compiler
81/215
S e1
+ e2: intS e
1+ e
2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
S e1
: T1
S e2
: T2
T1
int
T2 int
Prevents errorsfrom propagating.
Updated Rules for Addition
-
7/30/2019 type checking compiler
82/215
S e1
+ e2: intS e
1+ e
2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
S e1
: T1
S e2
: T2
T1
int
T2 int
Updated Rules for Addition
-
7/30/2019 type checking compiler
83/215
S e1
+ e2: intS e
1+ e
2: double
S e1
: T1
S e2
: T2
T1
double
T2 double
S e1
: T1
S e2
: T2
T1
int
T2 int
What happens ifboth operands have
error type?
Error-Recovery in Practice
-
7/30/2019 type checking compiler
84/215
In your semantic analyzer, you will need to dosome sort of error recovery.
We provide an error type Type::errorType.
But what about other cases? Calling a nonexistent function.
Declaring a variable of a bad type.
Treating a non-array as an array.
There are no right answers to these questions;just better and worse choices.
Implementing Convertibility
-
7/30/2019 type checking compiler
85/215
How do we implement the operator we'vedescribed so far?
Lots of cases:
Class Type
PrimitiveType
Array Type
Null Type
Error Type
Class Type PrimitiveType Array Type Null Type Error Type
If same orinherits from
No No No No
NoIf same
typeNo No No
No NoIf underlyingtypes match No No
Yes No No Yes No
Yes Yes Yes Yes Yes
FromTo
A Hierarchy for Types
-
7/30/2019 type checking compiler
86/215
Type
Class TypePrimitive
TypeArray Type Null Type Error Type
Methods You Might Want...
-
7/30/2019 type checking compiler
87/215
virtual bool Type::IsIdenticalTo(Type* other);
Returns whether two types represent the same actualtype.
virtual bool Type::IsConvertibleTo(Type* other);
Returns whether one type is convertible to someother type.
-
7/30/2019 type checking compiler
88/215
Type-Checking in
the Real World
-
7/30/2019 type checking compiler
89/215
Function Overloading
Function Overloading
-
7/30/2019 type checking compiler
90/215
Two functions are said to be overloads of oneanother if they have the same name but adifferent set of arguments.
At compile-time, determine which function is
meant by inspecting the types of thearguments.
Report an error if no one function is the best
function.
Overloading Example
-
7/30/2019 type checking compiler
91/215
void Function();void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
Function();
Function(137);
Function(42.0);
Function(new Base);
Function(new Derived);
Overloading Example
-
7/30/2019 type checking compiler
92/215
void Function();void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
Function();
Function(137);
Function(42.0);
Function(new Base);
Function(new Derived);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
93/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
94/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
Function(137);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
95/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
96/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
97/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
98/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Implementing Overloadingvoid Function();
-
7/30/2019 type checking compiler
99/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Implementing Overloadingvoid Function();
id i (i )
-
7/30/2019 type checking compiler
100/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Implementing Overloadingvoid Function();
id F ti (i t )
-
7/30/2019 type checking compiler
101/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
() (int x) (double x) (Base b) (Derived d)
Function(137);
Simple Overloading
-
7/30/2019 type checking compiler
102/215
We begin with a set of overloaded functions. After filtering out functions that cannot match,
we have a candidate set (C++ terminology) orset ofpotentially applicable methods (Java-
speak). If no functions are left, report an error.
If exactly one function left, choose it.
(We'll deal with two or more in a second)
-
7/30/2019 type checking compiler
103/215
Overloading with Inheritancevoid Function();
void Function(int x);
-
7/30/2019 type checking compiler
104/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
Function(new Derived);
Overloading with Inheritancevoid Function();
void Function(int x);
-
7/30/2019 type checking compiler
105/215
void Function(int x);
void Function(double x);
void Function(Base b);
void Function(Derived d);
Function(new Derived);
() (int x) (double x) (Base b) (Derived d)
Overloading with Inheritancevoid Function();
void Function(int x);
-
7/30/2019 type checking compiler
106/215
void Function(int x);
void Function(double x);void Function(Base b);
void Function(Derived d);
Function(new Derived);
() (int x) (double x) (Base b) (Derived d)
Overloading with Inheritancevoid Function();
void Function(int x);How do we
-
7/30/2019 type checking compiler
107/215
void Function(int x);
void Function(double x);void Function(Base b);
void Function(Derived d);
Function(new Derived);
() (int x) (double x) (Base b) (Derived d)
comparethese?
Finding the Best Match
Choose one function over another if it's strictly more
-
7/30/2019 type checking compiler
108/215
Choose one function over another if it s strictly more
specific.
Given two candidate functions A and B with argumenttypes A
1, A
2, , A
nand B
1, B
2, , B
n, we say that A
-
7/30/2019 type checking compiler
109/215
void Function(int x);
void Function(double x);void Function(Base b);
void Function(Derived d);
Function(new Derived);
() (int x) (double x) (Base b) (Derived d)
Overloading with Inheritancevoid Function();
void Function(int x);
-
7/30/2019 type checking compiler
110/215
o d u ct o ( t );
void Function(double x);void Function(Base b);
void Function(Derived d);
Function(new Derived);
() (int x) (double x) (Base b) (Derived d)
Overloading with Inheritancevoid Function();
void Function(int x);
-
7/30/2019 type checking compiler
111/215
( );
void Function(double x);void Function(Base b);
void Function(Derived d);
Function(new Derived);
() (int x) (double x) (Base b) (Derived d)
Ambiguous Calls
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
112/215
void Function(Derived d1, Base b2);void Function(Base b1, Derived d2);
Ambiguous Calls
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
113/215
void Function(Derived d1, Base b2);void Function(Base b1, Derived d2);
Function(new Derived, new Derived);
Ambiguous Calls
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
114/215
void Function(Derived d1, Base b2);void Function(Base b1, Derived d2);
Function(new Derived, new Derived);
Base, Base Base, Derived Derived, Base
Ambiguous Calls
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
115/215
void Function(Derived d1, Base b2);void Function(Base b1, Derived d2);
Function(new Derived, new Derived);
Base, Base Base, Derived Derived, Base
-
7/30/2019 type checking compiler
116/215
In the Real World
Often much more complex than this.
-
7/30/2019 type checking compiler
117/215
p
Example: variadic functions
Functions that can take multiple arguments.
Supported by C, C++, and Java.
Overloading with Variadic Functions
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
118/215
void Function(Derived d1, Base b2);void Function(Derived d1, ...);
Overloading with Variadic Functions
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
119/215
void Function(Derived d1, Base b2);void Function(Derived d1, ...);
Function(new Derived, new Derived);
Overloading with Variadic Functions
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
120/215
void Function(Derived d1, Base b2);void Function(Derived d1, ...);
Base, Base Derived, Base Derived,
Function(new Derived, new Derived);
Overloading with Variadic Functions
void Function(Base b1, Base b2);
-
7/30/2019 type checking compiler
121/215
void Function(Derived d1, Base b2);void Function(Derived d1, ...);
Base, Base Derived, Base Derived,
Function(new Derived, new Derived);
Overloading with Variadic Functions
Option one: Consider the call ambiguous.
-
7/30/2019 type checking compiler
122/215
There are indeed multiple valid function calls, andthat's that!
Option two: Prefer the non-variadic function.
A function specifically designed to handle a set ofarguments is probably a better match than onedesigned to handle arbitrarily many parameters.
Used in both C++ and (with minor modifications)
Java.
Hierarchical Function Overloads
Idea: Have a hierarchy of candidate functions.
-
7/30/2019 type checking compiler
123/215
Conceptually similar to a scope chain:
Start with the lowest hierarchy level and look for anoverload.
If a match is found, choose it. If multiple functions match, report an ambiguous call.
If no match is found, go to the next level in the chain.
Can you think of another example where we would
use a hierarchy like this?
Overloading with Variadic Functionsvoid Function(Base b1, Base b2);
void Function(Derived d1, Base b2);
i i i
-
7/30/2019 type checking compiler
124/215
Base, Base Derived, Base Derived,
Function(new Derived, new Derived);
void Function(Derived d1, ...);
Overloading with Variadic Functionsvoid Function(Base b1, Base b2);
void Function(Derived d1, Base b2);
id i ( i d d1 )
-
7/30/2019 type checking compiler
125/215
void Function(Derived d1, ...);
Base, Base Derived, Base
Derived,
Function(new Derived, new Derived);
Overloading with Variadic Functionsvoid Function(Base b1, Base b2);
void Function(Derived d1, Base b2);
id F ti (D i d d1 )
-
7/30/2019 type checking compiler
126/215
void Function(Derived d1, ...);
Base, Base Derived, Base
Derived,
Function(new Derived, new Derived);
Overloading with Variadic Functionsvoid Function(Base b1, Base b2);
void Function(Derived d1, Base b2);
id F ti (D i d d1 )
-
7/30/2019 type checking compiler
127/215
void Function(Derived d1, ...);
Base, Base Derived, Base
Derived,
Function(new Derived, new Derived);
Overloading with Variadic Functionsvoid Function(Base b1, Base b2);
void Function(Derived d1, Base b2);
id F ti (D i d d1 )
-
7/30/2019 type checking compiler
128/215
void Function(Derived d1, ...);
Base, Base Derived, Base
Derived,
Function(new Derived, new Derived);
Overloading with Variadic Functionsvoid Function(Base b1, Base b2);
void Function(Derived d1, Base b2);
void Function(Derived d1 );
-
7/30/2019 type checking compiler
129/215
void Function(Derived d1, ...);
Base, Base Derived, Base
Derived,
Function(new Derived, new Derived);
-
7/30/2019 type checking compiler
130/215
Covariance and
Contravariance
A Rule for Member Functions
f is an identifier
-
7/30/2019 type checking compiler
131/215
S e0.f(e
1, ..., e
n) : ?
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri T
ifor 1 i n
A Rule for Member Functions
f is an identifier
-
7/30/2019 type checking compiler
132/215
S e0.f(e
1, ..., e
n) : ?
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri T
ifor 1 i n
A Rule for Member Functions
f is an identifier
-
7/30/2019 type checking compiler
133/215
S e0.f(e
1, ..., e
n) : ?
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri T
ifor 1 i n
A Rule for Member Functions
f is an identifier
-
7/30/2019 type checking compiler
134/215
S e0.f(e
1, ..., e
n) : ?
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri T
ifor 1 i n
A Rule for Member Functions
f is an identifierS M
-
7/30/2019 type checking compiler
135/215
S e0.f(e
1, ..., e
n) : ?
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
A Rule for Member Functions
f is an identifier.S M
-
7/30/2019 type checking compiler
136/215
S e0.f(e
1, ..., e
n) : ?
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
A Rule for Member Functions
f is an identifier.S M
-
7/30/2019 type checking compiler
137/215
S e0.f(e
1, ..., e
n) : U
fis an identifier.S e
0: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Legal Code?class Id {
Id me() {
return this;}
-
7/30/2019 type checking compiler
138/215
}
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
Legal Code?class Id {
Id me() {
return this;}
-
7/30/2019 type checking compiler
139/215
}
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
Legal Code?class Id {
Id me() {
return this;}
-
7/30/2019 type checking compiler
140/215
}
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
Ego
Legal Code?class Id {
Id me() {
return this;
}
-
7/30/2019 type checking compiler
141/215
}
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
Ego
Legal Code?class Id {
Id me() {
return this;
} fis an identifier.S e : M
-
7/30/2019 type checking compiler
142/215
}
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
S e0.f(e
1, ..., e
n) : U
S e0
: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Ego
Legal Code?class Id {
Idme() {
return this;
} fis an identifier.S e : M
-
7/30/2019 type checking compiler
143/215
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
S e0.f(e
1, ..., e
n) : U
S e0
: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Ego
Legal Code?class Id {
Idme() {
return this;
} fis an identifier.S e : M
-
7/30/2019 type checking compiler
144/215
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
S e0.f(e
1, ..., e
n) : U
S e0
: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
IdEgo
Legal Code?class Id {
Idme() {
return this;
} fis an identifier.S e : M
-
7/30/2019 type checking compiler
145/215
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
S e0.f(e
1, ..., e
n) : U
S e0
: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
IdEgo
Legal Code?class Id {
Idme() {
return this;
} fis an identifier.S e0
: M
-
7/30/2019 type checking compiler
146/215
void beSelfish() {
/* */
}
}
class Ego extends Id {
void bePractical() {
/* */
}
}
int main() {
(new Ego).me().bePractical();
}
S e0.f(e
1, ..., e
n) : U
S e0
: M
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
bePracticalis not in
Id!Id
Ego
Limitations of Static Type Systems
Static type systems are often incomplete.
There are valid programs that are rejected.
-
7/30/2019 type checking compiler
147/215
p g j
Tension between the static and dynamic typesof objects.
Static type is the type declared in the programsource.
Dynamic type is the actual type of the object atruntime.
Soundness and Completeness
Static type systems sometimes reject valid
programs because they cannot prove theb f t
-
7/30/2019 type checking compiler
148/215
p g y pabsence of a type error.
A type system like this is called incomplete.
Instead, try to prove for every expression thatDynamicType(E) StaticType(E)
A type system like this is called sound.
Building a Good Static Checker
It is difficult to build a good static type checker.
Easy to have unsound rules.
-
7/30/2019 type checking compiler
149/215
Impossible to accept all valid programs.
Goal: make the language as expressive as
possible while still making the type-checkersound.
Relaxing our Restrictions
class Base {
Base clone() {
-
7/30/2019 type checking compiler
150/215
return new Base;
}
}
class Derived extends Base {
Base clone() {
return new Derived;
}}
Relaxing our Restrictions
class Base {
Base clone() {
-
7/30/2019 type checking compiler
151/215
return new Base;
}
}
class Derived extends Base {
Base clone() {
return new Derived;
}}
Relaxing our Restrictions
class Base {
Base clone() {
-
7/30/2019 type checking compiler
152/215
return new Base;
}
}
class Derived extends Base {
Derivedclone() {
return new Derived;
}}
Relaxing our Restrictions
class Base {
Base clone() {
-
7/30/2019 type checking compiler
153/215
return new Base;
}
}
class Derived extends Base {
Derivedclone() {
return new Derived;
}}
Is this safe?
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
154/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
155/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
156/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
157/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
158/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
159/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
160/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
161/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
162/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
The Intuition
Base b = new Base;
Derived d = new Derived;
-
7/30/2019 type checking compiler
163/215
Base b2 = b.clone();
Base b3 = d.clone();
Derived d2 = b.clone();
Derived d3 = d.clone();
Base reallyD = new Derived;
Base b4 = reallyD.clone();
Derived d4 = reallyD.clone();
Is this Safe?
fis an identifier.S e
0: M
f is a member function in class M
-
7/30/2019 type checking compiler
164/215
S e0.f(e
1, ..., e
n) : U
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Is this Safe?
fis an identifier.S e
0: M
f is a member function in class M
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
165/215
S e0.f(e
1, ..., e
n) : U
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Is this Safe?
fis an identifier.S e
0: M
f is a member function in class M
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
166/215
S e0.f(e
1, ..., e
n) : U
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
f has dynamic type
(T1, T
2, , T
n) V
and we know that
V U
Is this Safe?
fis an identifier.S e
0: M
f is a member function in class M.
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
167/215
S e0.f(e
1, ..., e
n) : U
fis a member function in class M.fhas type (T
1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
f has dynamic type
(T1, T
2, , T
n) V
and we know that
V U
So the rule is sound!
Covariant Return Types
Two functions A and B are covariant in their
return types if the return type of A is convertibleto the return type of B.
-
7/30/2019 type checking compiler
168/215
Many programming language support covariantreturn types.
C++ and Java, for example.
Not supported in Decaf.
But easy extra credit!
Relaxing our Restrictions (Again)
class Base {
bool equalTo(Base B) {/* */
-
7/30/2019 type checking compiler
169/215
}
}
class Derived extends Base {
bool equalTo(Base B) {
/* */
}}
Relaxing our Restrictions (Again)
class Base {
bool equalTo(Base B) {/* */
-
7/30/2019 type checking compiler
170/215
}
}
class Derived extends Base {
bool equalTo(Base B) {
/* */
}}
Relaxing our Restrictions (Again)
class Base {
bool equalTo(Base B) {/* */
-
7/30/2019 type checking compiler
171/215
}
}
class Derived extends Base {
bool equalTo(DerivedB) {
/* */
}}
Relaxing our Restrictions (Again)
class Base {
bool equalTo(Base B) {/* */
-
7/30/2019 type checking compiler
172/215
}
}
class Derived extends Base {
bool equalTo(Derived D) {
/* */
}}
Relaxing our Restrictions (Again)
class Base {
bool equalTo(Base B) {/* */
-
7/30/2019 type checking compiler
173/215
Is this safe?
}
}
class Derived extends Base {
bool equalTo(Derived D) {
/* */
}}
Is this Safe?
fis an identifier.S e
0: M
fis a member function in class M.
-
7/30/2019 type checking compiler
174/215
S e0.f(e
1, ..., e
n) : U
fhas type (T1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Is this Safe?
fis an identifier.S e
0: M
fis a member function in class M.f h t (T T ) U
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
175/215
S e0.f(e
1, ..., e
n) : U
fhas type (T1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Is this Safe?
fis an identifier.S e
0: M
fis a member function in class M.f h t (T T ) U
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
176/215
S e0.f(e
1, ..., e
n) : U
fhas type (T1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
f has dynamic type
(V1, V2, , Vn) U
and we know that
Vi T
ifor 1 i n
Is this Safe?
fis an identifier.S e
0: M
fis a member function in class M.f h t (T T ) U
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
177/215
S e0.f(e
1, ..., e
n) : U
fhas type (T1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
f has dynamic type
(V1, V2, , Vn) U
and we know that
Vi T
ifor 1 i nRi Ti for 1 i n
Vi Ti for 1 i n
Is this Safe?
fis an identifier.S e 0 : M
fis a member function in class M.f has type (T T ) U
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
178/215
S e0.f(e
1, ..., e
n) : U
fhas type (T1, , T
n) U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
f has dynamic type
(V1, V2, , Vn) U
and we know that
Vi T
ifor 1 i nRi Ti for 1 i n
Vi Ti for 1 i n
This doesn't mean thatR
i V
ifor 1 i n
A Concrete Example
-
7/30/2019 type checking compiler
179/215
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
-
7/30/2019 type checking compiler
180/215
class Borken extends Fine {
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(f);
}
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
-
7/30/2019 type checking compiler
181/215
class Borken extends Fine {
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(f);
}
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
-
7/30/2019 type checking compiler
182/215
class Borken extends Fine {
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(new Fine);
}
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
-
7/30/2019 type checking compiler
183/215
{
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(new Fine);
}
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
-
7/30/2019 type checking compiler
184/215
{
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(new Fine);
}
(That calls this
one)
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
-
7/30/2019 type checking compiler
185/215
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(new Fine);
}
(That calls this
one)
A Concrete Exampleclass Fine {
void nothingFancy(Fine f) {
/* do nothing */
}}
class Borken extends Fine {
Problem?
-
7/30/2019 type checking compiler
186/215
int missingFn() {
return 137;
}void nothingFancy(Borken b) {
Print(b.missingFn());
}
}
int main() {Fine f = new Borken;
f.nothingFancy(new Fine);
}
(That calls this
one)
Covariant Arguments are Unsafe
Allowing subclasses to restrict their parameter
types is fundamentally unsafe. Calls through base class can send objects of
the wrong type down to base classes
-
7/30/2019 type checking compiler
187/215
the wrong type down to base classes.
This is why Java's Object.equals takesanotherObject.
Some languages got this wrong.
Eiffel allows functions to be covariant in theirarguments; can cause runtime errors.
Contravariant Arguments
class Super {}
class Base extends Super {
bool equalTo(Base B) {/* */
}
-
7/30/2019 type checking compiler
188/215
}
}
class Derived extends Base {
bool equalTo(Base B) {
/* */
}}
Contravariant Argumentsclass Super {}
class Base extends Super {
bool equalTo(Base B) {/* */
}
-
7/30/2019 type checking compiler
189/215
}
}
class Derived extends Base {
bool equalTo(Base B) {
/* */
}}
Contravariant Argumentsclass Super {}
class Base extends Super {
bool equalTo(Base B) {/* */
}
-
7/30/2019 type checking compiler
190/215
}
}
class Derived extends Base {
bool equalTo(Super B) {
/* */
}}
Contravariant Argumentsclass Super {}
class Base extends Super {
bool equalTo(Base B) {/* */
}
-
7/30/2019 type checking compiler
191/215
}
}
class Derived extends Base {
bool equalTo(Super B) {
/* */
}}
Contravariant Argumentsclass Super {}
class Base extends Super {
bool equalTo(Base B) {/* */
}
-
7/30/2019 type checking compiler
192/215
}
}
class Derived extends Base {
bool equalTo(Super B) {
/* */
}} Is this safe?
Is this Safe?
fis an identifier.
S e 0 : Mfis a member function in class M.
fhas type (T1, , T
n) U
-
7/30/2019 type checking compiler
193/215
S e0.f(e
1, ..., e
n) : U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Is this Safe?
fis an identifier.
S e 0 : Mfis a member function in class M.
fhas type (T1, , T
n) U
This refers to the
static type of the
function.
-
7/30/2019 type checking compiler
194/215
S e0.f(e
1, ..., e
n) : U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
Is this Safe?
fis an identifier.
S e 0 : Mfis a member function in class M.
fhas type (T1, , T
n) U
This refers to the
static type of the
function.
f has dynamic type
-
7/30/2019 type checking compiler
195/215
S e0.f(e
1, ..., e
n) : U
S ei: R
ifor 1 i n
Ri Ti for 1 i n
f has dynamic type
(V1, V2, , Vn) U
and we know that
Ti V
ifor 1 i n
Is this Safe?
fis an identifier.
S e 0 : Mfis a member function in class M.
fhas type (T1, , T
n) U
S R f 1 i
This refers to the
static type of the
function.
f has dynamic type
-
7/30/2019 type checking compiler
196/215
S e0.f(e
1, ..., e
n) : U
S ei: R
ifor 1 i n
Ri T
ifor 1 i n
f has dynamic type
(V1, V2, , Vn) U
and we know that
Ti V
ifor 1 i nRi Ti for 1 i n
Ti Vi for 1 i n
Is this Safe?
fis an identifier.
S e 0 : Mfis a member function in class M.
fhas type (T1, , T
n) U
S R f 1 i
This refers to the
static type of the
function.
f has dynamic type
-
7/30/2019 type checking compiler
197/215
S e0.f(e
1, ..., e
n) : U
S ei: R
ifor 1 i n
Ri T
ifor 1 i n
f has dynamic type
(V1, V2, , Vn) U
and we know that
Ti V
ifor 1 i nRi Ti for 1 i n
Ti Vi for 1 i nso
Ri V
ifor 1 i n
Contravariant Arguments are Safe
Intuition: When called through base class, will
accept anything the base class already would. Most languages do not support contravariant
arguments.
-
7/30/2019 type checking compiler
198/215
Why?
Increases the complexity of the compiler and thelanguage specification.
Increases the complexity of checking methodoverrides.
Contravariant Overridesclass Super {}
class Duper extends Super {}
class Base extends Super {
bool equalTo(Base B) {
/* */
}
}
-
7/30/2019 type checking compiler
199/215
}
class Derived extends Base {bool equalTo(Super B) {
/* */
}
bool equalTo(Duper B) {
/* */}
}
Contravariant Overridesclass Super {}
class Duper extends Super {}
class Base extends Super {
bool equalTo(Base B) {/* */
}
}
-
7/30/2019 type checking compiler
200/215
}
class Derived extends Base {bool equalTo(Super B) {
/* */
}
bool equalTo(Duper B) {
/* */}
}
Two overrides?Or an overload
and an override?
So What?
Need to be very careful when introducing
language features into a statically-typedlanguage.
Easy to design language features; hard to
-
7/30/2019 type checking compiler
201/215
design language features that are type-safe.
Type proof system can sometimes help detectthese errors in the abstract.
Array Polymorphism
In some languages like C++ and Java, it is
possible to treat arrays of objectspolymorphically.
class A { };
l B bli A { }
class A { };
l B t d A { }
-
7/30/2019 type checking compiler
202/215
Is this safe?
class B: public A { };
B* bArray = new B[137];A* aArray = bArray;
class B extends A { };
B[] bArray = new B[137];A[] aArray = bArray;
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {public A getElement(int index);
}
-
7/30/2019 type checking compiler
203/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
}
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {publicA getElement(int index);
}
-
7/30/2019 type checking compiler
204/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
}
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {publicA getElement(int index);
}
-
7/30/2019 type checking compiler
205/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
}
Is this safe?
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {publicA getElement(int index);
}
-
7/30/2019 type checking compiler
206/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
}
Is this safe?
Yes!
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {public A getElement(int index);
public void setElement(int index, A value);
}
-
7/30/2019 type checking compiler
207/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
public void setElement(int index, B value);
}
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {public A getElement(int index);
public void setElement(int index, A value);
}
-
7/30/2019 type checking compiler
208/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
public void setElement(int index, B value);
}
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {public A getElement(int index);
public void setElement(int index, A value);
}
-
7/30/2019 type checking compiler
209/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
public void setElement(int index, B value);
}
Is this safe?
A Different Approach to Arrays
Think of arrays as classes:
class ArrayOfA {public A getElement(int index);
public void setElement(int index, A value);
}
-
7/30/2019 type checking compiler
210/215
class ArrayOfB extends ArrayOfA {
public B getElement(int index);
public void setElement(int index, B value);
}
Is this safe?
No!
Problematic Java Code
class A {
}
class B extends A {
public static void main(String[] args) {
A[] arr new B[137];
-
7/30/2019 type checking compiler
211/215
A[] arr = new B[137];
arr[0] = new A();}
}
Problematic Java Code
class A {
}
class B extends A {
public static void main(String[] args) {
A[] arr = new B[137];
-
7/30/2019 type checking compiler
212/215
A[] arr = new B[137];
arr[0] = new A();}
}
Java's Solution
All array writes checked at runtime.
ThrowsArrayStoreException if the elementstored in an array has the wrong type.
Pay at runtime for something that could be
-
7/30/2019 type checking compiler
213/215
detected at compile-time.
Almost no benefits in practice; arraypolymorphism is rarely used.
Java's Solution
All array writes checked at runtime.
ThrowsArrayStoreException if the elementstored in an array has the wrong type.
Pay at runtime for something that could be
-
7/30/2019 type checking compiler
214/215
detected at compile-time.
Almost no benefits in practice; arraypolymorphism is rarely used.
Please don't add this as an extension to Decaf.
Summary
We can extend our type proofs to handle well-formedness proofs.
The error type is convertible to all other types and helpsprevent cascading errors.
Overloading is resolved at compile-time and determineshi h f f ti t ll
-
7/30/2019 type checking compiler
215/215
which of many functions to call.
Overloading ranks functions against one another todetermine the best match.
Functions can safely be covariant in their return typesand contravariant in their argument types.
Don't treat arrays polymorphically!