From 2cf776372deb942d787c4e485f055f04a568c5c0 Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Mon, 8 Apr 2019 01:25:38 -0700
Subject: [PATCH] fix class inherit problems, fix type conversion, fix class
 member, fix some expr infer, etc

---
 .../common/analysis/types/ClassValueType.java |  8 +++
 src/main/java/chocopy/pa2/TypeChecker.java    | 69 +++++++++++++++++--
 2 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/src/main/java/chocopy/common/analysis/types/ClassValueType.java b/src/main/java/chocopy/common/analysis/types/ClassValueType.java
index c845503..0f01243 100644
--- a/src/main/java/chocopy/common/analysis/types/ClassValueType.java
+++ b/src/main/java/chocopy/common/analysis/types/ClassValueType.java
@@ -18,12 +18,20 @@ public class ClassValueType extends ValueType {
     @JsonIgnore
     public Map<String, SymbolType> memberMap = null;
 
+    @JsonIgnore
+    public ClassValueType parent = OBJECT_TYPE;
+
     /** A class type for the class named CLASSNAME. */
     @JsonCreator
     public ClassValueType(@JsonProperty String className) {
         this.className = className;
     }
 
+    public ClassValueType(String className, ClassValueType parentType) {
+        this.className = className;
+        parent = parentType;
+    }
+
     /** A class type for the class referenced by CLASSTYPEANNOTATION. */
     public ClassValueType(ClassType classTypeAnnotation) {
         this.className = classTypeAnnotation.className;
diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
index 2b4ea8f..19a64f5 100644
--- a/src/main/java/chocopy/pa2/TypeChecker.java
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -102,6 +102,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         // My-name already pushed to symbolMap
         // TA doesn't like this: // classDef.name.dispatch(this);
         // TA doesn't like this: // classDef.superClass.dispatch(this);
+        ClassValueType superType = (ClassValueType) classDef.superClass.dispatch(this);
+        classDef.superClass.setInferredType(null); // make TA happy
 
         // Append parent to child if not exist.
         if(!classDef.superClass.name.equals("object")) {
@@ -115,7 +117,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             }
         }
 
-        ClassValueType result_type = new ClassValueType(classDef.name.name);
+        ClassValueType result_type = new ClassValueType(classDef.name.name, superType);
         result_type.memberMap = classDef.memberMap;
         SymbolTable<SymbolType> symLayer = new SymbolTable<>(sym);
         // TODO: Maybe this is not necessary. I'm a cxx programmer.
@@ -245,6 +247,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
                 Identifier id = (Identifier) target;
                 left_type = id.dispatch(this);
             }
+            else if(target instanceof MemberExpr) {
+                MemberExpr memberExpr = (MemberExpr) target;
+                left_type = memberExpr.dispatch(this);
+            }
             else {
                 err(node, "Not implemented assignStmt, target=" + target.getClass().getName());
             }
@@ -512,7 +518,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             err(node, "undefined identifier " + node.member.name + " as object member.");
             return NONE_TYPE;
         }
-        return resultType;
+        return node.setInferredType(resultType);
     }
 
     @Override
@@ -525,13 +531,31 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
 
         FuncType funcType = (FuncType) methodType;
         List<SymbolType> args_type = new ArrayList<>();
+        if(node.method instanceof MemberExpr) {
+            args_type.add(((MemberExpr)node.method).object.getInferredType());
+        }
         for(Expr expr : node.args) {
             args_type.add(expr.dispatch(this));
         }
-        if(!args_type.equals(funcType.parameters)) {
-            err(node, "function/method parameter list mismatch");
+
+        if(!matchArgList(args_type, funcType.parameters)) {
+            err(node, "function/method parameter list mismatch. Got " + args_type.toString() + ",expecting " + funcType.parameters);
+        }
+        return node.setInferredType(funcType.returnType);
+    }
+    private boolean matchArgList(List<SymbolType> got, List<ValueType> expect) {
+        System.out.println("debug> match arg> " + got + " -> " + expect + ", size " + got.size() + expect.size());
+        if(got.size() != expect.size())
+            return false;
+        for(int cter = 0; cter < got.size(); ++cter) {
+            System.out.println("debug> match arg> " + got.get(cter).toString() + " -> " + expect.get(cter).toString());
+            if(typeConvertible(got.get(cter), expect.get(cter)))
+                continue; // ok
+            else
+                return false;
         }
-        return funcType.returnType;
+        System.out.println("debug> SUCC match arg> " + got + " -> " + expect + ", size " + got.size() + expect.size());
+        return true;
     }
 
     ///////////////////////////// Others //////////////////////////////////////
@@ -587,14 +611,44 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         if(from.equals(EMPTY_TYPE)) from = new ListValueType(NONE_TYPE);
         if(to.equals(EMPTY_TYPE)) to = new ListValueType(NONE_TYPE);
         if(!from.isListType() || !to.isListType())  {
+            // Cast class to parent
+            if(from instanceof ClassValueType && to instanceof ClassValueType) {
+                if(_typeConvertible_calcClassInheritChainCommonNode((ClassValueType) from, (ClassValueType) to).equals(to))
+                    return true; // Can cast from->to
+            }
             return from.equals(to);
         }
 
+        // Convert list to list:
         ListValueType lsFrom = (ListValueType) from, lsTo =  (ListValueType) to;
         if(lsFrom.elementType == null || lsFrom.elementType.equals(NONE_TYPE))
             return true;
         return typeConvertible(lsFrom.elementType, lsTo.elementType);
     }
+    private ClassValueType _typeConvertible_calcClassInheritChainCommonNode(ClassValueType l, ClassValueType r) {
+        int l_depth = 1, r_depth = 1;
+        ClassValueType l_curr = l, r_curr = r;
+        while(!l_curr.equals(OBJECT_TYPE)) {
+            ++l_depth;
+            l_curr = l_curr.parent;
+        }
+        while(!r_curr.equals(OBJECT_TYPE)) {
+            ++r_depth;
+            r_curr = r_curr.parent;
+        }
+        l_curr = l;
+        r_curr = r;
+        for(;l_depth > r_depth; --l_depth)
+            l_curr = l_curr.parent;
+        for(;r_depth > l_depth; --r_depth)
+            r_curr = r_curr.parent;
+        while(!l_curr.equals(r_curr)) { // NOTE: Use reference compare
+            l_curr = l_curr.parent;
+            r_curr = r_curr.parent;
+        }
+        if(l_curr == null) return OBJECT_TYPE;
+        else return l_curr;
+    }
     private SymbolType calcCommonType(SymbolType another, SymbolType preferred) {
         SymbolType l = another, r = preferred;
         if(l == null || r == null)
@@ -607,6 +661,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             return r;
         if(typeConvertible(r, l))
             return l;
+        if(another instanceof ClassValueType && preferred instanceof ClassValueType) {
+            return _typeConvertible_calcClassInheritChainCommonNode((ClassValueType) another, (ClassValueType) preferred);
+        }
         return OBJECT_TYPE;
     }
     private boolean typeIsUserDefinedClass(SymbolType type) {
@@ -622,13 +679,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     }
     private ValueType fixClassTypeProblem(ValueType valType) {
         if(typeIsUserDefinedClass(valType)) {
-            System.out.println("debug: annotation class name resolved." + valType.className());
             ClassValueType realType = (ClassValueType)sym.get(valType.className());
             if(realType == null) {
                 System.out.println("FIXME: annotation uses an unknown class type. Unable to assign member map.");
                 return valType;
             }
-            System.out.println("debug: -m- " + realType.memberMap);
             return realType;
         }
         else
-- 
GitLab