250 likes | 432 Views
Modern Compiler Design. T9 – More Type Checking. Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University gretay@post.tau.ac.il http://www.cs.tau.ac.il/~gretay. Today. MIPS code. exe. COOL code. txt. Today More type checking rules! SELF_TYPE….
E N D
Modern Compiler Design T9 – More Type Checking Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University gretay@post.tau.ac.il http://www.cs.tau.ac.il/~gretay
Today MIPS code exe COOL code txt • Today • More type checking rules! SELF_TYPE…. • PA4 with Eclipse on Windows • Next week • MIPS tutorial LexicalAnalysis Syntax Analysis Parsing AST SymbolTableetc. Inter.Rep. (IR) Code Gen.
Major Semantic Tasks • Inheritance graph construction and checking • Symbol table construction • construct symbol table for features using inheritance tree • assign enclosing scope for each AST node • Scope checking • check program using symbol tables • Check for Main class and main method • Type checking • uses inheritance graph and symbol tables • assign type for each AST node • Remaining Semantic Checks • checks that require type + symbol table information combined • Disclaimer: This is a naïve phase ordering. Phases could be mixed, combined, optimized, re-ordered etc.
Let Rule with Initialization O,M,K e0: T O(T/x) e1 : T1 O,M,K let x: Te0 in e1 : T1 O,M,K e0: T O(T0/x) e1 : T1 T T0 O,M,K let x: T0 e0 in e1 : T1 • Both rules are sound but more programs typecheck with the second one (uses subtyping) Weak rule class A { foo():C { … } }; class B inherits A { }; class C { bar():C { let x:A new B in x.foo() }; }
If-Then-Else O,M,K e0 :Bool O,M,K e1: T1 O,M,K e2 : T2 O,M,K if e0 then e1 else e2 fi : lub(T1, T2) Object IO D E C A B foo(a:A, b:B, c:C, e:E) : D { if (a < b) then e else c fi } lub(E,C) = Object Is Object D ? ERROR
Case Object IO D E IO C A B O,M,K e : T O[X/x],M,K e1: E O[Y/y],M,K e2: F O[Z/z],M,K e3: G O,M,K case e of x: X =>e1; y:Y =>e2 ; z:Z=>e3 esac : lub(E,F,G) X,Y,Z must be distinct types foo(d:D) : D { case d of x : IO => let a:A(new A) in x; y : E => (new B); z : C => z; esac }; lub(IO,B,C) = Object and Object D ERROR
Case Object IO D E A C A B O,M,K e : T O[X/x],M,K e1: E O[Y/y],M,K e2: F O[Z/z],M,K e3: G O,M,K case e of x: X =>e1; y:Y =>e2 ; z:Z=>e3 esac : lub(E,F,G) foo(d:D) : D { case d of x : IO => let a:A(new A) in a; y : E => (new B); z : C => z; esac }; lub(A,B,C) = C and C D OK
Case – why? • Static types can be too conservative • O,M,K e : P • programmer knows that for all vvalues(e), type(v)=C • C P and C ≠ P • Use dynamic check • runtime error if no branch can be selected class P { foo():P { new C }; }; class C inherits P { }; class D { x : C <- (new P).foo(); y : C <- case (new P).foo() of x : C => x; esac; }; ERROR OK
SELF_TYPE Example class A { foo() : A { self } ; }; class B inherits A { ... }; class Main { x : B (new B).foo(); }; class A { foo() : B { self } ; }; class B inherits A { ... }; class Main { x : B (new B).foo(); }; ERROR ERROR OK
SELF_TYPE Example • What can be a dynamic type of object returned by foo() ? • any subtype of A class A { foo() : A { self } ; }; class B inherits A { ... }; class Main { x : B (new B).foo(); }; class A { foo() : SELF_TYPE { self } ; }; class B inherits A { ... }; class Main { x : B (new B).foo(); }; ERROR OK
SELF_TYPE • Research idea • Helps type checker to accept more correct programs C,M,K (new A).foo() : A C,M,K (new B).foo() : B • SELF_TYPE is NOT a dynamictype • Meaning of SELF_TYPE depends on where it appears textually
Where can SELF_TYPE appear ? • Parser checks that SELF_TYPE appears only where a type is expected • How ? • But SELF_TYPE is not allowed everywhere a type can appear
Where can SELF_TYPE appear ? • class T1 inherits T2 { … } • T1, T2 cannot be SELF_TYPE • x : SELF_TYPE • attribute • let • case • new SELF_TYPE • creates an object of the same type as self • foo@T(e) • T cannot be SELF_TYPE • foo(x:T1):T2 {…} • only T2 can be SELF_TYPE
new Example class A { foo() : A { new SELF_TYPE }; }; class B inherits A { … } … (new A).foo(); (new B).foo(); creates A object creates B object
SELF_TYPE vs. SELF_TYPEC • SELF_TYPE is keyword • part of Cool syntax • refers to the type of self variable • NOT a dynamictype • meaning of SELF_TYPE depends on where it appears textually • may refer to class C in which it appears or its subclass • SELF_TYPEc is type • part of notations for type rules, not part of Cool syntax • referred to by SELF_TYPE keyword used in class C
Subtyping for SELF_TYPE • SELF_TYPEc SELF_TYPEc • SELF_TYPEc C • It is always safe to replace SELF_TYPEc with C • SELF_TYPEc T ? • if C T • T SELF_TYPEc ? • is always false in reference coolc • because SELF_TYPEc can denote any subtype of C
lub(T,T’) for SELF_TYPE • lub(SELF_TYPEc, SELF_TYPEc) = SELF_TYPEc • lub(T, SELF_TYPEc) = lub(T,C) • the best we can do
New Rules O, M, K self : SELF_TYPEk O, M, K new SELF_TYPE : SELF_TYPEk
Other rules • A use of SELF_TYPE refers to any subtype of the current class • Except in dispatch • because the method return type of SELF_TYPE might have nothing to do with the current class
Dispatch O, M, K c : C O, M, K a : A O, M, K b : B M(C, foo) = (A1, B1,SELF_TYPE) A A1 , B B1 O, M, K c.foo(a, b): C O, M, K c : C O, M, K a : A O, M, K b : B M(C, foo) = (A1, B1, D1) A A1 , B B1, D1 SELF_TYPE O, M, K c.foo(a, b) : D1 • which class is used to find the declaration of foo() ?
Static Dispatch O, M, K c : C O, M, K a : A O, M, K b : B M(C1, f) = (A1, B1, D1) A A1, B B1, C C1, D1 SELF_TYPE O, M, K c.f@C1(a, b): D1 • if we dispatch a method returning SELF_TYPE in class C1, do we get back C1 ? • No. SELF_TYPE is the type of self, which may be a subtype of the class in which the method appears O, M, K c : C O, M, K a : A O, M, K b : B M(C1, f) = (A1, B1,SELF_TYPE) A A1, B B1, C C1 O, M, K c@C1.f@(a, b): C
Error Handling • Error detection is easy • Error recovery: what type is assigned to an expression with no legitimate type ? • influences type of enclosing expressions • cascading errors let y : Int x + 2 in y + 3 • Better solution: special type No_Type • inheritance graph can be cyclic
Summary • Type is a set of values • Type rules are logical rules of inference • Soundness of (static) type systems • for every expression e, for every value v of e at runtime v values_of(static_type(e)) • static_type(e) may actually describe more values • can reject correct programs • Becomes more complicated with subtyping (inheritance)
PA4 with Eclipse on Windows • You do not have to use it • Warning 1: set up may take some time • requires rt.jar and matching java_cup • download PA4JE.tar.gz • create a new project in eclipse • put all sources in default package • set build path • Warning 2: Compile and test on nova !!