diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
index aa8724ad6eabf9c0c52c471a9e424ee04fd8f3d7..12c534b6f08a582ae715628c2e1ac88fd3da3d15 100644
--- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
+++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
@@ -45,6 +45,7 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<SymbolType> {
                 continue;
             }
 
+            // TODO: DO NOT throw on duplicate id. generate a compiler error.
             sym.put(name, type);
         }
 
diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
index 1bf1afa15c6f20ea29ce007f6d557d9e36676706..5b4e4903047ba8215de5f357fc04b760217532f0 100644
--- a/src/main/java/chocopy/pa2/TypeChecker.java
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -7,12 +7,10 @@ import chocopy.common.analysis.types.ListValueType;
 import chocopy.common.analysis.types.SymbolType;
 import chocopy.common.analysis.types.ValueType;
 import chocopy.common.astnodes.*;
-import org.jetbrains.annotations.NotNull;
 
 import java.util.*;
 
-import static chocopy.common.analysis.types.SymbolType.INT_TYPE;
-import static chocopy.common.analysis.types.SymbolType.OBJECT_TYPE;
+import static chocopy.common.analysis.types.SymbolType.*;
 
 /** Analyzer that performs ChocoPy type checks on all nodes.  Applied after
  *  collecting declarations. */
@@ -66,7 +64,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     }
     @Override
     public SymbolType analyze(NoneLiteral node) {
-        return node.setInferredType(SymbolType.NONE_TYPE);
+        return node.setInferredType(NONE_TYPE);
     }
     @Override
     public SymbolType analyze(BooleanLiteral node) {
@@ -77,7 +75,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     public SymbolType analyze(AssignStmt node) {
         SymbolType right_type = node.value.dispatch(this);
         if(right_type == null)
-            right_type = ValueType.NONE_TYPE;
+            right_type = NONE_TYPE;
         if(node.targets.size() == 1) {
             String target = node.targets.get(0).toString();
             System.out.println("debug: assign to target " + target);
@@ -108,6 +106,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         String op = node.operator;
         SymbolType left_type = node.left.dispatch(this);
         SymbolType right_type = node.right.dispatch(this);
+        if(left_type == null)
+            left_type = NONE_TYPE;
+        if(right_type == null)
+            right_type = NONE_TYPE;
 
         switch(op) {
             case "-":
@@ -146,7 +148,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         }
 
         // Now set target type.
-        SymbolType result_type = ValueType.NONE_TYPE;
+        SymbolType result_type = NONE_TYPE;
         switch(op) {
             case "-":
             case "*":
@@ -195,6 +197,56 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         return node.setInferredType(fType.returnType);
     }
 
+    @Override
+    public SymbolType analyze(UnaryExpr node) {
+        String op = node.operator;
+        switch(op) {
+            case "not":
+                if(!node.operand.dispatch(this).equals(ValueType.BOOL_TYPE)) {
+                    err(node, "operand of not should be bool.");
+                }
+                return node.setInferredType(ValueType.BOOL_TYPE);
+            case "-":
+                if(!node.operand.dispatch(this).equals(INT_TYPE)) {
+                    err(node, "operand of - should be int");
+                }
+                return node.setInferredType(INT_TYPE);
+            default:
+                err(node, "operator " + op + " unknown.");
+                return node.setInferredType(NONE_TYPE);
+        }
+    }
+
+    @Override
+    public SymbolType analyze(IfExpr node) {
+        SymbolType then_type = node.thenExpr.dispatch(this);
+        SymbolType else_type = node.elseExpr.dispatch(this);
+        if(!then_type.equals(else_type)) {
+            err(node, "then_type not equals to else_type. ");
+        }
+        return node.setInferredType(then_type);
+    }
+
+    @Override
+    public SymbolType analyze(IndexExpr node) {
+        SymbolType list_type = node.list.dispatch(this);
+        SymbolType index_type = node.index.dispatch(this);
+        if(index_type != INT_TYPE) {
+            err(node, "index_type should be int.");
+        }
+        if(list_type == STR_TYPE) {
+            return node.setInferredType(STR_TYPE);
+        }
+        else if(list_type.isListType()) {
+            ListValueType t = (ListValueType) list_type;
+            return node.setInferredType(t.elementType);
+        }
+        else {
+            err(node, "type " + list_type.toString() + " is not index-able.");
+            return node.setInferredType(NONE_TYPE);
+        }
+    }
+
     @Override
     public SymbolType analyze(Identifier id) {
         String varName = id.name;