diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
index 8f97c7f25cb505f0ee899d62c6e16c678cd0b02d..9c86167a368688998470eb4bef809eaeb231483e 100644
--- a/src/main/java/chocopy/pa2/TypeChecker.java
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -42,9 +42,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     public SymbolType analyze(VarDef varDef) {
         SymbolType lType = varDef.value.dispatch(this);
         SymbolType vType = varDef.var.dispatch(this);
-        if(!vType.equals(lType))
+        if(!(vType.equals(lType) || lType.equals(NONE_TYPE)))
             err(varDef, "incorrect initialization type");
-        return lType;
+        return vType;
     }
 
     @Override
@@ -177,31 +177,25 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     @Override
     public SymbolType analyze(AssignStmt node) {
         SymbolType right_type = node.value.dispatch(this);
+        SymbolType left_type = null;
         if(right_type == null)
             right_type = NONE_TYPE;
-        if(node.targets.size() == 1) {
-            String target = node.targets.get(0).toString();
-            System.out.println("debug: assign to target " + target);
-            SymbolType left_type = sym.get(target);
+        for(Expr target : node.targets) {
+            Identifier id = (Identifier) target;
+            if(id == null) {
+                err(node, "assign to non-identifier expr.");
+                return NONE_TYPE;
+            }
+            left_type = id.dispatch(this);
             if(left_type == null) {
-                err(node, "Syntax error: assign to non-declared variable.");
-                return OBJECT_TYPE;
+                err(node, "Syntax error: assign to non-declared variable: " + id.name);
+                return NONE_TYPE;
             }
-            if(!left_type.equals(right_type)) {
-                err(node, "Syntax error: implicit type convertion not allowed.");
+            if(!typeConvertible(right_type,  left_type)) {
+                err(node, "Syntax error: implicit type convertion failed.");
             }
-            return right_type;
-        }
-        else {
-            if(!right_type.isListType()) {
-                err(node, "Syntax error: assign non-list type to list targets");
-                return OBJECT_TYPE;
-            }
-            ListValueType right_ls_type = (ListValueType) right_type;
-            // TODO: assign list to list
-            err(node, "Not implemented error: assign list to list");
-            return OBJECT_TYPE;
         }
+        return left_type;
     }
 
     @Override
@@ -363,11 +357,15 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             SymbolType this_type = expr.dispatch(this);
             if(elementType == null)
                 elementType = this_type;
-            if(!this_type.equals(elementType))
-                err(node, "list elements must have the same type.");
+            if(!typeConvertible(this_type, elementType))  {
+                //err(node, "list elements must have the same type.");
+                elementType = calcCommonType(this_type, elementType);
+            }
         }
-        ListValueType resultType = new ListValueType(elementType);
-        return node.setInferredType(resultType);
+        if(elementType == null)
+            return node.setInferredType(EMPTY_TYPE);
+        else
+            return node.setInferredType(new ListValueType(elementType));
     }
 
     @Override
@@ -415,4 +413,35 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         err(id, "Not a variable: %s", varName);
         return id.setInferredType(ValueType.OBJECT_TYPE);
     }
+
+    private boolean typeConvertible(SymbolType from, SymbolType to) {
+        if(from == null || to == null)
+            throw new RuntimeException("debug: SymbolType can not be null");
+        if(from.equals(NONE_TYPE) || to.equals(OBJECT_TYPE))
+            return true;
+        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())  {
+            return from.equals(to);
+        }
+
+        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 SymbolType calcCommonType(SymbolType another, SymbolType preferred) {
+        SymbolType l = another, r = preferred;
+        if(l == null || r == null)
+            throw new RuntimeException("debug: SymbolType can not be null");
+        if(l.equals(NONE_TYPE))
+            return r;
+        if(r.equals(NONE_TYPE))
+            return l;
+        if(typeConvertible(l, r))
+            return r;
+        if(typeConvertible(r, l))
+            return l;
+        return OBJECT_TYPE;
+    }
 }