Download presentation
Presentation is loading. Please wait.
Published byTyson Pille Modified over 10 years ago
1
1 Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University gretay@post.tau.ac.il http://www.cs.tau.ac.il/~gretay Modern Compiler Design T8 – Semantic Analysis: Type Checking
2
2 Example “drive” + “drink” 12 + “Rumster” String string Int String ERROR (in Java ) in Cool ?
3
3 Today COOL code txt Executable code exe Lexical Analysis Syntax Analysis Parsing ASTSymbol Table etc. Inter. Rep. (IR) Code Gen. Goals Implementing Type Checking for Cool Cool Type Rules Coming up: MIPS tutorial
4
4 Inheritance Graph What do we put in it? all predefined classes: Int, String, Bool, Object, IO all user-defined classes Why do we put it there ? to be able to check that something is a type to be able to compare types (for type checking) Implementation mapping class names to nodes in the graph node points to its superclass node
5
5 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
6
6 Semantic Checks Scope rules identifiers are defined no multiple definition of same identifier local variables are defined before used … Type rules which types can be combined with certain operator assignment of expression to variable formal and actual parameters of a method call …
7
7 Notation for Inference Rules By tradition inference rules are written Hypothesis 1 Hypothesis 2... Hypothesis n Conclusion means “it is provable that...” Cool type rules have hypothesis and conclusion O,M,C e: T [ NAME] conditions type environment
8
8 Type Checking - Implementation Single traversal over AST Types passed up the tree Type environment passed down the tree
9
9 Example (45 + x) < (~32) plus neg lt … int_const val=45 object name=x int_const val=32 : Int O,M,C int_const : Int O,M,C x : Int O(x) = Int classFoo kindSymbol globals Foo Intc Symbol test Intx Int->Inttest kindSymbol lookup(x)
10
10 Example (45 + x) < (~32) plus neg lt … int_const val=45 object name=x int_const val=32 : Int : Bool O,M,C int_const : Int O,M,C E1 : Int O,M,C E2 : Int O,M,C E1 < E2 : Bool O,M,C E1 : Int O,M,C E2 : Int O,M,C E1 + E2 : Int O,M,C E1 : Int O,M,C ~E1 : Int O,M,C x : Int O(x) = Int
11
11 Cool Types How types are represented ? AbstractSymbol compare types by comparing AbstractSymbols When are types are created? during lexer/parsing predefined types
12
12 Cool Types The types are Class Names SELF_TYPE The user declares types for identifiers The semantic analysis infers types for expressions Every expression has a unique type A language’s type system specifies which operations are valid for which types The goal of type checking is to ensure that operations are used with the correct types Enforces intended interpretation of values Cool is statically typed: type checking during compilation
13
13 Cool Types Environment O, M, K e: T gives types to free identifiers in the current scope information about the formal parameters and return type of methods the class in which an expression e appears Why separate object/methods? In Cool, the method and object identifiers live in different name spaces type environment
14
14 Cool Types Environment O, M, K e: T O --- mapping Object Id’s to types symbol table - current scope O(x) = T M --- mapping methods to method signatures M(C, f) = (A, B, D) means there is a method f(a:A, b:B): D defined in class C (or its ancestor) K --- the class in which expression e appears when SELF_TYPE is involved type environment
15
15 Type rules O, M, K e1 : Int O, M, K e2 : Int O, M, K e1 + e2 : Int Rules give templates describing how to type expressions By filling the templates, we can produce complete typings for expressions O,M,C int_const : Int O,M,C x : T O(x) = T
16
16 Example 1 +2 Templates: Inference: 2 is an integer O,M,C 2: Int [Int] O,M,C 1+2: Int [Add] 1 is an integer O,M,C 1 : Int [Int] O,M,C int_const : Int O,M,C E1 : Int O,M,C E2 : Int O,M,C E1 + E2 : Int
17
17 Subtyping Define a relation on classes X X X Y if X inherits from Y X Z if X Y and Y Z A C B Object E D and D E AB C D Object E IO
18
18 Least Upper Bounds Z is the least upper bound of X and Y lub(X, Y)=Z X Z and Y Z Z is upper bound X Z’ and Y Z’ Z Z’ Z is the least upper bound
19
19 Least Upper Bounds lub(A,B) = C lub(C,D) = D lub(C,E) = Object In Cool, the least upper bound of two types is their least common ancestor in the inheritance tree AB C D Object E IO
20
20 Dynamic and Static Types in Cool A variable of static type A can hold the value of static type B if B A class A {... } class B inherits A {... } class Main ( x: A new A ;... x new B ; } dynamic type of x is A dynamic type of x is B static type of x is A
21
21 Dynamic and Static Types The dynamic type of an object is the class that is used in the new expression a runtime notion even languages that are statically typed have dynamic types The static type of an expression captures all the dynamic types that the expression could have a compile-time notion
22
22 Static vs. Dynamic Typing Static typing proponents say: Static checking catches many programming errors Prove properties of your code Avoids the overhead of runtime type checks x C, Java, Cool, ML Dynamic typing proponents say: Static type systems are restrictive Rapid prototyping difficult with type systems Complicates the programming language and the compiler Compiler optimizations can hide costs x machine code In practice, most code is written in statically typed languages with escape mechanisms Unsafe casts in C, Java union in C
23
23 Soundness A type system is sound if e. dynamic_type(e) static_type(e) whenever the inferred type of e is T ( denoted by O,M,C e : T ) Then e evaluates to a value of type T in all executions of the program We only want sound rules But some sound rules are better than others
24
24 Assign O (x) = T 0 O,M,K e 1 : T 1 T 1 T 0 O,M,K x e 1 : T 1 [Assign] class A { foo() : A { … } }; class B inherits A { };... let x:B in x (new B).foo(); let x:A in x (new B).foo(); let x:Object in x (new B).foo(); ERROR OK A
25
25 Let Rule with Initialization Both rules are sound but more programs typecheck with the second one uses subtyping O,M,K e 0 : T O(T/x) e 1 : T 1 O,M,K let x: T e 0 in e 1 : T 1 Weak rule O,M,K e 0 : T O(T 0 /x) e 1 : T 1 T T 0 O,M,K let x: T 0 e 0 in e 1 : T 1 class A { foo():C { … } }; class B inherits A { };... let x:A new B in x.foo();
26
26 If-Then-Else O,M,K e 0 :Bool O,M,K e 1 : T 1 O,M,K e 2 : T 2 O,M,K if e 0 then e 1 else e 2 fi : lub(T 1, T 2 ) AB C D Object E IO 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
27
27 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 Case O,M,K e : T O[X/x],M,K e 1 : E O[Y/y],M,K e 2 : F O[Z/z],M,K e 3 : G O,M,K case e of x: X =>e 1 ; y:Y =>e 2 ; z:Z=>e 3 esac : lub(E,F,G) AB C D Object E IO ERROR IO
28
28 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 Case O,M,K e : T O[X/x],M,K e 1 : E O[Y/y],M,K e 2 : F O[Z/z],M,K e 3 : G O,M,K case e of x: X =>e 1 ; y:Y =>e 2 ; z:Z=>e 3 esac : lub(E,F,G) AB C D Object E IO OK A
29
29 Dispatch O, M c : C O, M a : A O, M b : B M(C, f) = (A1, B1, D1) A A1, B B1 O, M, K c.f(a, b): D1 [Dispatch] class C1 { foo(a:A1, b:B1) : D1 {new D1 ; }; }; … (new C).foo( (new A), (new B) );
30
30 Static Dispatch [StaticDispatch] O, M, K c : C O, M, K a : A O, M, K b : B M(C, f) = (A1, B1, D1) A A1, B B1, C C1 O, M, K c@C1.f(a, b): D1 class C1 { foo(a:A1, b:B1) : D1 {new D1 ; }; }; … (new C)@C1.foo( (new A), (new B) );
31
31 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 { B x (new B).foo(); }; class A { foo() : SELF_TYPE { self } ; }; class B inherits A {... }; class Main { B x (new B).foo(); }; ERROROK
32
32 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 dynamic type Meaning of SELF_TYPE depends on where it appears textually
33
33 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
34
34 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
35
35 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
36
36 Subtyping for SELF_TYPE SELF_TYPE c SELF_TYPE c SELF_TYPE c C It is always safe to replace SELF_TYPE c with C SELF_TYPE c T if C T T SELF_TYPE c is always false because SELF_TYPE c can denote any subtype of C
37
37 lub(T,T’) for SELF_TYPE lub(SELF_TYPE c, SELF_TYPE c ) = SELF_TYPE c lub(T, SELF_TYPE c ) = lub(T,C) the best we can do
38
38 New Rules O, M, K self : SELF_TYPE k O, M, K new SELF_TYPE : SELF_TYPE k
39
39 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
40
40 Dispatch O, M c : C O, M a : A O, M b : B M(C, foo) = (A1, B1, D1) A A1, B B1, D1 SELF_TYPE O, M, K c.foo(a, b) : D1 O, M c : C O, M a : A O, M b : B M(C, foo) = (A1, B1, SELF_TYPE) A A1, B B1 O, M, K c.foo(a, b): C which class is used to find the declaration of foo() ?
41
41 Example class A { foo() : A { self }; }; class B inherits A { … } … (new A).foo(); (new B).foo(); returns A object returns B object
42
42 Static Dispatch O, M, K c : C O, M, K a : A O, M, K b : B M(C, f) = (A1, B1, D1) A A1, B B1, C C1, D1 SELF_TYPE O, M, K c.f@C1(a, b): D1 O, M, K c : C O, M, K a : A O, M, K b : B M(C, f) = (A1, B1, SELF_TYPE) A A1, B B1, C C1 O, M, K c@C1.f@(a, b): C 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
43
43 SELF_TYPE Example class A { deligate : B; callMe() : ??? { deligate.callMe(); } ; }; class B { callMe() : SELF_TYPE { self }; }; class Main { A a (new A).callMe(); }; ERROR SELF_TYPE
44
44 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
45
45 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)
46
46 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.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.