# Changes: ## 0. Introduce a new type of cast: Upcast or Enum Cast. The naming of the cast is not determined. ## 1. Updates on CastExpr::CastKind ``` enum CastKind { Default, // C Coerce, // reinterpret cast Return, // overload selection Up // <------ NEW; Cast to a super type }; ``` Scope: All enumerations, including C enumeration, and CFA enumeration (typed and opague). Example Usage: ``` enum A { a }; enum B { b }; enum AB { inline A, inline B, ab }; // Explicit (user called) up cast (AB) A.a; // Implicit (generated) up cast void foo(AB); foo(A.a); ``` Aside: Expressions "(AB) a" or "foo(a)" don't introduce a upcast. Because enum AB is an enum type with elements AB.a, AB.b, and AB.ab. The expression "(AB) a" results in AB.a since it has a lower cost than "(AB) A.a". (no conversion/cast cost) ## 2. Why needs a new cast type The up cast is a special kind of a cast that requires "offset operations". ``` (AB) b.b; // is equivalent to (AB) ((unsigned int)b.b + OFFSET) // (AB)(0 + 1) ``` OFFSET is an constanct value: The OFFSET from B to AB is 1. It is the number of enumerators declared before the declaration "inline B". The statement "inline B" is after "inline A", where "inline A" introduces one enumerator. Similarilty: ``` enum E { e; }; enum ABCDE { inline AB, C, D, inline E }; ``` The OFFSET from type E to type ABCDE is "# of element from AB" + 1 (C) + 1 (D), 4. But we don't want to introduce the OFFSET_OPERATION + 4 on every cast from type E to type ABCDE. Sometime, the compiler introduce a generated cast (AB) E.e to maniputate expression type. It actually happens when after we have an upcast, we need to cast the expression (E.e + 4) to type ABCED, without "upcast it agains". It is a widening cast with no upcast effect. ## 3. Implication A new pass "Upcast Pass" where happens before the resolver to identify Upcast. A cast (T) y for variable y with type Y is an upcast only if there is a "Upcast Path" from type T to type Y. For example, ``` enum T { ..., inline A, ... }; enum A { ..., inline B, ... }; enum B { ..., inline Y, ... }; enum Y { ... }; ``` There is a upcast Path from Y to T: Y -(upcast)-> B -(upcast)-> A -(upcast)-> T. The pass runs an algorithm to determine if there is such path exist from Y to T. Aisde: The cast is "bottom-up": (T)((A)((B) y)), casting from the smaller type to the bigger type. But the algorithm is search "top-down", from T to Y. Because inline information is stored in the super type. T knows it inlines A, A knows it inline B, but not vise versa. The CastKind will replaced by "CastKind::Up" The unifier in the resolver identify a function calls "foo(A.a)" performs an upcast, by running the algorithmn from AB to A, and introduce the implicit upcast in the Application Expression "foo((AB) A.B)". For all Upcast, the resolver replace them with 1. a offset operation (a functiion call ?+?(expr, OFFSET)), 2 and a Coerce cast from the lower type to the supper type. (There are some cast between enum type to integral type in between to satisfy the function ?+?(). We can ignore them for now.) Upcast should only exisit in the AST between the "Upcast Pass" and the "Resolver". They are essentially labels saying: this node needs an offset operation. "Upcast Pass" is a subpass of resolver. It does not need to be a standalone pass. It can be a special step when the compiler visits a CastExpr nocde.