commit b758a071dc0208960495f7a5ce305d3241ddf3af
Author: github-classroom[bot] <66690702+github-classroom[bot]@users.noreply.github.com>
Date:   Wed Mar 3 14:08:57 2021 +0000
    Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..21cc758
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,149 @@
+.DS_Store
+__pycache__
+target
+
+# Created by https://www.gitignore.io/api/java,eclipse,intellij,emacs,vim
+
+### Java ###
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+
+### Eclipse ###
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# TeXlipse plugin
+.texlipse
+
+
+### Intellij ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
+
+*.iml
+
+## Directory-based project format:
+.idea/
+# if you remove the above rule, at least ignore the following:
+
+# User-specific stuff:
+# .idea/workspace.xml
+# .idea/tasks.xml
+# .idea/dictionaries
+
+# Sensitive or high-churn files:
+# .idea/dataSources.ids
+# .idea/dataSources.xml
+# .idea/sqlDataSources.xml
+# .idea/dynamic.xml
+# .idea/uiDesigner.xml
+
+# Gradle:
+# .idea/gradle.xml
+# .idea/libraries
+
+# Mongo Explorer plugin:
+# .idea/mongoSettings.xml
+
+## File-based project format:
+*.ipr
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+
+
+### Emacs ###
+# -*- mode: gitignore; -*-
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+# flymake-mode
+*_flymake.*
+
+# eshell files
+/eshell/history
+/eshell/lastdir
+
+# elpa packages
+/elpa/
+
+# reftex files
+*.rel
+
+# AUCTeX auto folder
+/auto/
+
+# cask packages
+.cask/
+
+
+### Vim ###
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+*.un~
+Session.vim
+.netrwhist
+*~
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0808d4b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2017-2018 The Regents of the University of California
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6716c27
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# NYU Compiler Construction CSCI-GA.2130/Spring 2021: Programming Assignment 2
+
+This assignment is adapted from https://github.com/cs164berkeley/pa2-chocopy-semantic-analysis with the authors' permission.
+
+See the PA2 document on Piazza for a detailed specification.
+
+## Quickstart
+
+Run the following commands to compile your analyzer and run the tests:
+```
+mvn clean package
+java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
+  --pass=.s --test --dir src/test/data/pa2/sample/
+```
+
+The dot in `--pass` makes the compiler skip parsing and go straight to semantic analysis.
+`--pass=.s` uses your (`s` for `student`) analyzer to perform semantic analysis on a preparsed input (in this case, the `.ast` files under `src/test/data/pa2/sample/`).
+With the starter code, only two tests should pass.
+Your main objective is to build an analyzer that passes all the provided tests.
+
+`--pass=.r` uses the reference (`r` for `reference`) analyzer, which should pass all tests.
+
+In addition to running in test mode with `--test`, you can also observe the actual output of your (or reference) analyzer with:
+```
+java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
+  --pass=.s src/test/data/pa2/sample/expr_unary.py.ast
+```
+
+You can also run both passes on the original `.py` file:
+```
+java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
+  --pass=rr src/test/data/pa2/sample/expr_unary.py
+```
+
+Once you merge your parser code from assignment 1, you should be able to use `--pass=ss`.
diff --git a/chocopy-ref.jar b/chocopy-ref.jar
new file mode 100644
index 0000000..a497f25
Binary files /dev/null and b/chocopy-ref.jar differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..1766e51
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,330 @@
+
+    4.0.0 
+    chocopy 
+    chocopy 
+    jar 
+    2.2-SNAPSHOT 
+    chocopy 
+    http://maven.apache.org 
+
+    
+    
+        false 
+     
+
+    
+        
+        
+            
+                
+                    de.jflex 
+                    jflex-maven-plugin 
+                    1.6.1 
+                 
+                
+                    com.github.vbmacher 
+                    cup-maven-plugin 
+                    11b-20160615 
+                 
+                
+                    maven-assembly-plugin 
+                    3.1.0 
+                 
+                
+                    maven-jar-plugin 
+                    3.1.0 
+                 
+                
+                    maven-site-plugin 
+                    3.7.1 
+                 
+             
+         
+
+        
+            
+                maven-assembly-plugin 
+                
+                    
+                        jar-with-dependencies 
+                     
+                    assignment 
+                    false 
+                 
+                
+                    
+                        make-assembly 
+                        package  
+                        
+                            single 
+                         
+                     
+                 
+             
+            
+                org.apache.maven.plugins 
+                maven-compiler-plugin 
+                3.8.0 
+                
+                    UTF-8 
+                    1.8 
+                    1.8 
+                    true 
+                    true 
+                 
+             
+         
+
+        
+          
+            src/main/asm 
+            
+              **/*.s 
+              **/*.os 
+             
+            
+              **/reference/*.s 
+             
+           
+         
+     
+
+    
+        
+            reference 
+            
+                
+                
+                    src/main/java/chocopy/reference/ 
+                 
+             
+            
+                
+                    
+                    
+                        maven-jar-plugin 
+                        
+                            
+                                **/pa1/* 
+                                **/pa2/* 
+                                **/pa3/* 
+                             
+                         
+                     
+                    
+                    
+                        maven-assembly-plugin 
+                        
+                            
+                                jar-with-dependencies 
+                             
+                            chocopy-ref 
+                            false 
+                         
+                     
+                    
+                    
+                        de.jflex 
+                        jflex-maven-plugin 
+                        
+                            
+                                jflex-reference 
+                                
+                                    generate 
+                                 
+                                
+                                    
+                                        src/main/jflex/chocopy/reference/ChocoPy.jflex 
+                                     
+                                    ${chocopy.debug} 
+                                    true 
+                                 
+                             
+                         
+                     
+                    
+                    
+                        com.github.vbmacher 
+                        cup-maven-plugin 
+                        
+                            
+                                cup-reference 
+                                
+                                    generate 
+                                 
+                                
+                                    src/main/cup/chocopy/reference/ChocoPy.cup 
+                                    chocopy.reference 
+                                    ChocoPyParser 
+                                    ChocoPyTokens 
+                                    ${chocopy.debug} 
+                                    ${chocopy.debug} 
+                                    ${chocopy.debug} 
+                                    true 
+                                 
+                             
+                         
+                     
+                    
+                    
+                        maven-compiler-plugin 
+                        
+                            true 
+                            none 
+                         
+                     
+                    
+                    
+                        org.apache.maven.plugins 
+                        maven-dependency-plugin 
+                        3.1.1 
+                        
+                            
+                                copy-dependencies 
+                                package 
+                                
+                                    copy-dependencies 
+                                 
+                             
+                         
+                     
+                 
+             
+         
+
+        
+            pa1 
+            
+                
+                
+                    src/main/java/chocopy/pa1 
+                 
+             
+            
+                
+                    
+                    
+                        de.jflex 
+                        jflex-maven-plugin 
+                        
+                            
+                                jflex-pa1 
+                                
+                                    generate 
+                                 
+                                
+                                    
+                                        src/main/jflex/chocopy/pa1/ChocoPy.jflex 
+                                     
+                                    ${chocopy.debug} 
+                                    true 
+                                 
+                             
+                         
+                     
+                    
+                    
+                        com.github.vbmacher 
+                        cup-maven-plugin 
+                        
+                            
+                                cup-pa1 
+                                
+                                    generate 
+                                 
+                                
+                                    src/main/cup/chocopy/pa1/ChocoPy.cup 
+                                    chocopy.pa1 
+                                    ChocoPyParser 
+                                    ChocoPyTokens 
+                                    ${chocopy.debug} 
+                                    ${chocopy.debug} 
+                                    ${chocopy.debug} 
+                                    true 
+                                 
+                             
+                         
+                     
+                 
+             
+         
+        
+            pa2 
+            
+                
+                
+                    src/main/java/chocopy/pa2 
+                 
+             
+         
+        
+            pa3 
+            
+                
+                
+                    src/main/java/chocopy/pa3 
+                 
+             
+         
+     
+
+
+    
+      
+        venus164-repo 
+        Repository for Venus164 
+        https://raw.githubusercontent.com/chocopy/venus/maven-repository/ 
+       
+     
+
+    
+        
+            net.sourceforge.argparse4j 
+            argparse4j 
+            0.8.1 
+         
+        
+            com.fasterxml.jackson.core 
+            jackson-databind 
+            [2.9.10.1,) 
+         
+        
+            com.fasterxml.jackson.module 
+            jackson-module-parameter-names 
+            2.9.10 
+         
+        
+            com.github.vbmacher 
+            java-cup-runtime 
+            11b-20160615 
+         
+        
+        
+            de.jflex 
+            jflex 
+            1.6.1 
+         
+        
+            org.jetbrains.kotlin 
+            kotlin-stdlib 
+            1.2.71 
+         
+        
+            edu.berkeley.eecs.venus164 
+            venus164 
+            0.2.4 
+         
+        
+            junit 
+            junit 
+            4.12 
+            test 
+         
+        
+            net.sf.proguard 
+            proguard-base 
+            6.0.3 
+         
+     
+ 
diff --git a/src/main/java/chocopy/common/Utils.java b/src/main/java/chocopy/common/Utils.java
new file mode 100644
index 0000000..aefd409
--- /dev/null
+++ b/src/main/java/chocopy/common/Utils.java
@@ -0,0 +1,54 @@
+package chocopy.common;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.stream.Collectors;
+
+/** Utility functions for general use. */
+public class Utils {
+
+    /**
+     * Return resource file FILENAME's contents as a string. FILENAME can refer to a file within the
+     * class hierarchy, so that a text resource in file resource.txt in the chocopy.common.codegen
+     * package, for example, could be referred to with FILENAME chocopy/common/codegen/resource.txt.
+     *
+     * 
Credit: Lucio Paiva.
+     */
+    public static String getResourceFileAsString(String fileName) {
+        InputStream is = Utils.class.getClassLoader().getResourceAsStream(fileName);
+        if (is != null) {
+            BufferedReader reader =
+                    new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+            return reader.lines().collect(Collectors.joining(System.lineSeparator()));
+        }
+        return null;
+    }
+
+    /**
+     * Return an exception signalling a fatal error having a message formed from MSGFORMAT and ARGS,
+     * as for String.format.
+     */
+    public static Error fatal(String msgFormat, Object... args) {
+        return new Error(String.format(msgFormat, args));
+    }
+
+    /**
+     * Return the string S padded with FILL to TOLEN characters. Padding is on the left if
+     * PADONLEFT, and otherwise on the right. If S is already at least TOLEN characters, returns S.
+     */
+    public static String pad(String s, Character fill, int toLen, boolean padOnLeft) {
+        StringBuilder result = new StringBuilder(toLen);
+        if (!padOnLeft) {
+            result.append(s);
+        }
+        for (int n = s.length(); n < toLen; n += 1) {
+            result.append(fill);
+        }
+        if (padOnLeft) {
+            result.append(s);
+        }
+        return result.toString();
+    }
+}
diff --git a/src/main/java/chocopy/common/analysis/AbstractNodeAnalyzer.java b/src/main/java/chocopy/common/analysis/AbstractNodeAnalyzer.java
new file mode 100644
index 0000000..7225c2b
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/AbstractNodeAnalyzer.java
@@ -0,0 +1,174 @@
+package chocopy.common.analysis;
+
+import chocopy.common.astnodes.*;
+
+/**
+ * An empty implementation of the {@link NodeAnalyzer} that simply returns does nothing and returns
+ * null for every AST node type.
+ *
+ * 
T is the type of analysis result.
+ */
+public class AbstractNodeAnalyzer implements NodeAnalyzer {
+    @Override
+    public T analyze(AssignStmt node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(BinaryExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(BooleanLiteral node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(CallExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ClassDef node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ClassType node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(CompilerError node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(Errors node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ExprStmt node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ForStmt node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(FuncDef node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(GlobalDecl node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(Identifier node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(IfExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(IfStmt node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(IndexExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(IntegerLiteral node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ListExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ListType node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(MemberExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(MethodCallExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(NoneLiteral node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(NonLocalDecl node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(Program node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(ReturnStmt node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(StringLiteral node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(TypedVar node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(UnaryExpr node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(VarDef node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public T analyze(WhileStmt node) {
+        return defaultAction(node);
+    }
+
+    @Override
+    public void setDefault(T value) {
+        defaultValue = value;
+    }
+
+    @Override
+    public T defaultAction(Node node) {
+        return defaultValue;
+    }
+
+    /** Default value for non-overridden methods. */
+    private T defaultValue = null;
+}
diff --git a/src/main/java/chocopy/common/analysis/NodeAnalyzer.java b/src/main/java/chocopy/common/analysis/NodeAnalyzer.java
new file mode 100644
index 0000000..2326fbc
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/NodeAnalyzer.java
@@ -0,0 +1,93 @@
+package chocopy.common.analysis;
+
+import chocopy.common.astnodes.*;
+
+/**
+ * This interface can be used to separate logic for various concrete classes in the AST class
+ * hierarchy.
+ *
+ * The idea is that a phase of the analysis is encapsulated in a class that implements this
+ * interface, and contains an overriding of the analyze method for each concrete Node class that
+ * needs something other than default processing. Each concrete node class, C, implements a generic
+ * dispatch method that takes a NodeAnalyzer argument and calls the overloading of analyze that
+ * takes an argument of type C. The effect is that anode.dispatch(anAnalyzer) executes the method
+ * anAnalyzer.analyze that is appropriate to aNode's dynamic type. As a result each NodeAnalyzer
+ * subtype encapsulates all implementations of a particular action on Nodes. Thus, it inverts the
+ * usual OO pattern in which the implementations of analysis A for each different class are
+ * scattered among the class bodies themselves as overridings of a method A on the Node class.
+ *
+ * The class AbstractNodeAnalyzer provides empty default implementations for these methods.
+ *
+ * 
The type T is the type of result returned by the encapsulated analysis.
+ */
+public interface NodeAnalyzer {
+
+    T analyze(AssignStmt node);
+
+    T analyze(BinaryExpr node);
+
+    T analyze(BooleanLiteral node);
+
+    T analyze(CallExpr node);
+
+    T analyze(ClassDef node);
+
+    T analyze(ClassType node);
+
+    T analyze(CompilerError node);
+
+    T analyze(Errors node);
+
+    T analyze(ExprStmt node);
+
+    T analyze(ForStmt node);
+
+    T analyze(FuncDef node);
+
+    T analyze(GlobalDecl node);
+
+    T analyze(Identifier node);
+
+    T analyze(IfExpr node);
+
+    T analyze(IfStmt node);
+
+    T analyze(IndexExpr node);
+
+    T analyze(IntegerLiteral node);
+
+    T analyze(ListExpr node);
+
+    T analyze(ListType node);
+
+    T analyze(MemberExpr node);
+
+    T analyze(MethodCallExpr node);
+
+    T analyze(NoneLiteral node);
+
+    T analyze(NonLocalDecl node);
+
+    T analyze(Program node);
+
+    T analyze(ReturnStmt node);
+
+    T analyze(StringLiteral node);
+
+    T analyze(TypedVar node);
+
+    T analyze(UnaryExpr node);
+
+    T analyze(VarDef node);
+
+    T analyze(WhileStmt node);
+
+    /**
+     * Set the default value returned by calls to analyze that are not overridden to VALUE. By
+     * default, this is null.
+     */
+    void setDefault(T value);
+
+    /** Default value for non-overridden methods. */
+    T defaultAction(Node node);
+}
diff --git a/src/main/java/chocopy/common/analysis/SymbolTable.java b/src/main/java/chocopy/common/analysis/SymbolTable.java
new file mode 100644
index 0000000..bc22ac4
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/SymbolTable.java
@@ -0,0 +1,62 @@
+package chocopy.common.analysis;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A block-structured symbol table a mapping identifiers to information about them of type T in a
+ * given declarative region.
+ */
+public class SymbolTable {
+
+    /** Contents of the current (innermost) region. */
+    private final Map tab = new HashMap<>();
+    /** Enclosing block. */
+    private final SymbolTable parent;
+
+    /** A table representing a region nested in that represented by PARENT0. */
+    public SymbolTable(SymbolTable parent0) {
+        parent = parent0;
+    }
+
+    /** A top-level symbol table. */
+    public SymbolTable() {
+        this.parent = null;
+    }
+
+    /** Returns the mapping of NAME in the innermost nested region containing this one. */
+    public T get(String name) {
+        if (tab.containsKey(name)) {
+            return tab.get(name);
+        } else if (parent != null) {
+            return parent.get(name);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Adds a new mapping of NAME -> VALUE to the current region, possibly shadowing mappings in the
+     * enclosing parent. Returns modified table.
+     */
+    public SymbolTable put(String name, T value) {
+        tab.put(name, value);
+        return this;
+    }
+
+    /** Returns whether NAME has a mapping in this region (ignoring enclosing regions. */
+    public boolean declares(String name) {
+        return tab.containsKey(name);
+    }
+
+    /** Returns all the names declared this region (ignoring enclosing regions). */
+    public Set getDeclaredSymbols() {
+        return tab.keySet();
+    }
+
+    /** Returns the parent, or null if this is the top level. */
+    public SymbolTable getParent() {
+        return this.parent;
+    }
+}
diff --git a/src/main/java/chocopy/common/analysis/types/ClassValueType.java b/src/main/java/chocopy/common/analysis/types/ClassValueType.java
new file mode 100644
index 0000000..05c2e93
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ClassValueType.java
@@ -0,0 +1,53 @@
+package chocopy.common.analysis.types;
+
+import chocopy.common.astnodes.ClassType;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Objects;
+
+/** Represents the semantic value of a simple class reference. */
+public class ClassValueType extends ValueType {
+
+    /** The name of the class. */
+    private final String className;
+
+    /** A class type for the class named CLASSNAME. */
+    @JsonCreator
+    public ClassValueType(@JsonProperty String className) {
+        this.className = className;
+    }
+
+    /** A class type for the class referenced by CLASSTYPEANNOTATION. */
+    public ClassValueType(ClassType classTypeAnnotation) {
+        this.className = classTypeAnnotation.className;
+    }
+
+    @Override
+    @JsonProperty
+    public String className() {
+        return className;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ClassValueType classType = (ClassValueType) o;
+        return Objects.equals(className, classType.className);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(className);
+    }
+
+    @Override
+    public String toString() {
+        return className;
+    }
+}
diff --git a/src/main/java/chocopy/common/analysis/types/FuncType.java b/src/main/java/chocopy/common/analysis/types/FuncType.java
new file mode 100644
index 0000000..69fdefc
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/FuncType.java
@@ -0,0 +1,45 @@
+package chocopy.common.analysis.types;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Semantic information for a function or method. */
+public class FuncType extends Type {
+
+    /** Types of parameters. */
+    public final List parameters;
+    /** Function's return type. */
+    public final ValueType returnType;
+
+    /** Create a FuncType returning RETURNTYPE0, initially parameterless. */
+    public FuncType(ValueType returnType0) {
+        this(new ArrayList<>(), returnType0);
+    }
+
+    /**
+     * Create a FuncType for NAME0 with formal parameter types PARAMETERS0, returning type
+     * RETURNTYPE0.
+     */
+    @JsonCreator
+    public FuncType(List parameters0, ValueType returnType0) {
+        this.parameters = parameters0;
+        this.returnType = returnType0;
+    }
+
+    @Override
+    public boolean isFuncType() {
+        return true;
+    }
+
+    /** Return the type of the K-th parameter. */
+    public ValueType getParamType(int k) {
+        return parameters.get(k);
+    }
+
+    @Override
+    public String toString() {
+        return "";
+    }
+}
diff --git a/src/main/java/chocopy/common/analysis/types/ListValueType.java b/src/main/java/chocopy/common/analysis/types/ListValueType.java
new file mode 100644
index 0000000..fae59c7
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ListValueType.java
@@ -0,0 +1,57 @@
+package chocopy.common.analysis.types;
+
+import chocopy.common.astnodes.ListType;
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.Objects;
+
+/** Represents a semantic value of a list type denotation. */
+public class ListValueType extends ValueType {
+
+    /** This ListValueType represents [ELEMENTTYPE]. */
+    public final ValueType elementType;
+
+    /** Represents [ELEMENTTYPE]. */
+    @JsonCreator
+    public ListValueType(Type elementType) {
+        this.elementType = (ValueType) elementType;
+    }
+
+    /** Represents [], where  is that denoted in TYPEANNOTATION. */
+    public ListValueType(ListType typeAnnotation) {
+        elementType = ValueType.annotationToValueType(typeAnnotation.elementType);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ListValueType listType = (ListValueType) o;
+        return Objects.equals(elementType, listType.elementType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(elementType);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + elementType.toString() + "]";
+    }
+
+    /** Returns true iff I represent [T]. */
+    @Override
+    public boolean isListType() {
+        return true;
+    }
+
+    @Override
+    public ValueType elementType() {
+        return elementType;
+    }
+}
diff --git a/src/main/java/chocopy/common/analysis/types/Type.java b/src/main/java/chocopy/common/analysis/types/Type.java
new file mode 100644
index 0000000..2eddc37
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/Type.java
@@ -0,0 +1,68 @@
+package chocopy.common.analysis.types;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+/**
+ * Representation for the static type of symbols and expressions during type-checking.
+ *
+ * Symbols such as variables and attributes will typically map to a {@link ValueType}.
+ *
+ * 
Symbols such as classes will typically map to a more complex Type.
+ */
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "kind")
+@JsonSubTypes({
+    @JsonSubTypes.Type(FuncType.class),
+    @JsonSubTypes.Type(ClassValueType.class),
+    @JsonSubTypes.Type(ListValueType.class)
+})
+public abstract class Type {
+
+    /** The type object. */
+    public static final ClassValueType OBJECT_TYPE = new ClassValueType("object");
+    /** The type int. */
+    public static final ClassValueType INT_TYPE = new ClassValueType("int");
+    /** The type str. */
+    public static final ClassValueType STR_TYPE = new ClassValueType("str");
+    /** The type bool. */
+    public static final ClassValueType BOOL_TYPE = new ClassValueType("bool");
+
+    /** The type of None. */
+    public static final ClassValueType NONE_TYPE = new ClassValueType("");
+    /** The type of []. */
+    public static final ClassValueType EMPTY_TYPE = new ClassValueType("");
+
+    /** Returns the name of the class, if this is a class type, Otherwise null. */
+    public String className() {
+        return null;
+    }
+
+    /** Return true iff this is a type that does not include the value None. */
+    @JsonIgnore
+    public boolean isSpecialType() {
+        return equals(INT_TYPE) || equals(BOOL_TYPE) || equals(STR_TYPE);
+    }
+
+    @JsonIgnore
+    public boolean isListType() {
+        return false;
+    }
+
+    @JsonIgnore
+    public boolean isFuncType() {
+        return false;
+    }
+
+    /** Return true iff this type represents a kind of assignable value. */
+    @JsonIgnore
+    public boolean isValueType() {
+        return false;
+    }
+
+    /** For list types, return the type of the elements; otherwise null. */
+    @JsonIgnore
+    public ValueType elementType() {
+        return null;
+    }
+}
diff --git a/src/main/java/chocopy/common/analysis/types/ValueType.java b/src/main/java/chocopy/common/analysis/types/ValueType.java
new file mode 100644
index 0000000..bb5d908
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ValueType.java
@@ -0,0 +1,29 @@
+package chocopy.common.analysis.types;
+
+import chocopy.common.astnodes.ClassType;
+import chocopy.common.astnodes.ListType;
+import chocopy.common.astnodes.TypeAnnotation;
+
+/**
+ * A ValueType references types that are assigned to variables and expressions.
+ *
+ * In particular, ValueType can be a {@link ClassValueType} (e.g. "int") or a {@link
+ * ListValueType} (e.g. "[int]").
+ */
+public abstract class ValueType extends Type {
+
+    /** Returns the type corresponding to ANNOTATION. */
+    public static ValueType annotationToValueType(TypeAnnotation annotation) {
+        if (annotation instanceof ClassType) {
+            return new ClassValueType((ClassType) annotation);
+        } else {
+            assert annotation instanceof ListType;
+            return new ListValueType((ListType) annotation);
+        }
+    }
+
+    @Override
+    public boolean isValueType() {
+        return true;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/AssignStmt.java b/src/main/java/chocopy/common/astnodes/AssignStmt.java
new file mode 100644
index 0000000..1452463
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/AssignStmt.java
@@ -0,0 +1,25 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** Single and multiple assignments. */
+public class AssignStmt extends Stmt {
+    /** List of left-hand sides. */
+    public final List targets;
+    /** Right-hand-side value to be assigned. */
+    public final Expr value;
+
+    /** AST for TARGETS[0] = TARGETS[1] = ... = VALUE spanning source locations [LEFT..RIGHT]. */
+    public AssignStmt(Location left, Location right, List targets, Expr value) {
+        super(left, right);
+        this.targets = targets;
+        this.value = value;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/BinaryExpr.java b/src/main/java/chocopy/common/astnodes/BinaryExpr.java
new file mode 100644
index 0000000..f4ce05b
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/BinaryExpr.java
@@ -0,0 +1,31 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/**   . */
+public class BinaryExpr extends Expr {
+
+    /** Left operand. */
+    public final Expr left;
+    /** Operator name. */
+    public final String operator;
+    /** Right operand. */
+    public final Expr right;
+
+    /**
+     * An AST for expressions of the form LEFTEXPR OP RIGHTEXPR from text in range
+     * [LEFTLOC..RIGHTLOC].
+     */
+    public BinaryExpr(
+            Location leftLoc, Location rightLoc, Expr leftExpr, String op, Expr rightExpr) {
+        super(leftLoc, rightLoc);
+        left = leftExpr;
+        operator = op;
+        right = rightExpr;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/BooleanLiteral.java b/src/main/java/chocopy/common/astnodes/BooleanLiteral.java
new file mode 100644
index 0000000..ffce126
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/BooleanLiteral.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Literals True or False. */
+public final class BooleanLiteral extends Literal {
+
+    /** True iff I represent True. */
+    public final boolean value;
+
+    /** An AST for the token True or False at [LEFT..RIGHT], depending on VALUE. */
+    public BooleanLiteral(Location left, Location right, boolean value) {
+        super(left, right);
+        this.value = value;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/CallExpr.java b/src/main/java/chocopy/common/astnodes/CallExpr.java
new file mode 100644
index 0000000..84f13ae
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/CallExpr.java
@@ -0,0 +1,26 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** A function call. */
+public class CallExpr extends Expr {
+
+    /** The called function. */
+    public final Identifier function;
+    /** The actual parameter expressions. */
+    public final List args;
+
+    /** AST for FUNCTION(ARGS) at [LEFT..RIGHT]. */
+    public CallExpr(Location left, Location right, Identifier function, List args) {
+        super(left, right);
+        this.function = function;
+        this.args = args;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ClassDef.java b/src/main/java/chocopy/common/astnodes/ClassDef.java
new file mode 100644
index 0000000..63531c8
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ClassDef.java
@@ -0,0 +1,39 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** A class definition. */
+public class ClassDef extends Declaration {
+
+    /** Name of the declared class. */
+    public final Identifier name;
+    /** Name of the parent class. */
+    public final Identifier superClass;
+    /** Body of the class. */
+    public final List declarations;
+
+    /** An AST for class NAME(SUPERCLASS): DECLARATIONS. spanning source locations [LEFT..RIGHT]. */
+    public ClassDef(
+            Location left,
+            Location right,
+            Identifier name,
+            Identifier superClass,
+            List declarations) {
+        super(left, right);
+        this.name = name;
+        this.superClass = superClass;
+        this.declarations = declarations;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    @Override
+    public Identifier getIdentifier() {
+        return this.name;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ClassType.java b/src/main/java/chocopy/common/astnodes/ClassType.java
new file mode 100644
index 0000000..fd4cd4d
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ClassType.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** A simple class type name. */
+public final class ClassType extends TypeAnnotation {
+
+    /** The denotation of the class in source. */
+    public final String className;
+
+    /** An AST denoting a type named CLASSNAME0 at [LEFT..RIGHT]. */
+    public ClassType(Location left, Location right, String className0) {
+        super(left, right);
+        className = className0;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/CompilerError.java b/src/main/java/chocopy/common/astnodes/CompilerError.java
new file mode 100644
index 0000000..81cc5bb
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/CompilerError.java
@@ -0,0 +1,56 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/** Represents a single error. Does not correspond to any Python source construct. */
+public class CompilerError extends Node {
+
+    /**
+     * Represents an error with message MESSAGE. Iff SYNTAX, it is a syntactic error. The error
+     * applies to source text at [LEFT..RIGHT].
+     */
+    public CompilerError(Location left, Location right, String message, boolean syntax) {
+        super(left, right);
+        this.message = message;
+        this.syntax = syntax;
+    }
+
+    @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+    public boolean isSyntax() {
+        return syntax;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        CompilerError that = (CompilerError) o;
+        return Objects.equals(message, that.message)
+                && Arrays.equals(getLocation(), that.getLocation());
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(message);
+        result = 31 * result + Arrays.hashCode(getLocation());
+        return result;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    /** The error message. */
+    public final String message;
+    /** True if this is a syntax error. */
+    private final boolean syntax;
+}
diff --git a/src/main/java/chocopy/common/astnodes/Declaration.java b/src/main/java/chocopy/common/astnodes/Declaration.java
new file mode 100644
index 0000000..0faa921
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Declaration.java
@@ -0,0 +1,17 @@
+package chocopy.common.astnodes;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Base of all AST nodes representing definitions or declarations. */
+public abstract class Declaration extends Node {
+
+    /** A definition or declaration spanning source locations [LEFT..RIGHT]. */
+    public Declaration(Location left, Location right) {
+        super(left, right);
+    }
+
+    /** Return the identifier defined by this Declaration. */
+    @JsonIgnore
+    public abstract Identifier getIdentifier();
+}
diff --git a/src/main/java/chocopy/common/astnodes/Errors.java b/src/main/java/chocopy/common/astnodes/Errors.java
new file mode 100644
index 0000000..86240dd
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Errors.java
@@ -0,0 +1,71 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** Collects the error messages in a Program. There is exactly one per Program node. */
+public class Errors extends Node {
+
+    /** The accumulated error messages in the order added. */
+    public final List errors;
+
+    /** True iff multiple semantic errors allowed on a node. */
+    @JsonIgnore private boolean allowMultipleErrors;
+
+    /**
+     * An Errors whose list of CompilerErrors is ERRORS. The list should be modified using this.add.
+     */
+    @JsonCreator
+    public Errors(List errors) {
+        super(null, null);
+        this.errors = errors;
+        allowMultipleErrors = true;
+    }
+
+    /** Return true iff there are any errors. */
+    public boolean hasErrors() {
+        return !this.errors.isEmpty();
+    }
+
+    /** Prevent multiple semantic errors on the same node. */
+    public void suppressMultipleErrors() {
+        allowMultipleErrors = false;
+    }
+
+    /**
+     * Add a new semantic error message attributed to NODE, with message String.format(MESSAGEFORM,
+     * ARGS).
+     */
+    public void semError(Node node, String messageForm, Object... args) {
+        if (allowMultipleErrors || !node.hasError()) {
+            String msg = String.format(messageForm, args);
+            CompilerError err = new CompilerError(null, null, msg, false);
+            err.setLocation(node.getLocation());
+            add(err);
+            if (!node.hasError()) {
+                node.setErrorMsg(msg);
+            }
+        }
+    }
+
+    /**
+     * Add a new syntax error message attributed to the source text between LEFT and RIGHT, and with
+     * message String.format(MESSAGEFORM, ARGS).
+     */
+    public void syntaxError(Location left, Location right, String messageForm, Object... args) {
+        add(new CompilerError(left, right, String.format(messageForm, args), true));
+    }
+
+    /** Add ERR to the list of errors. */
+    public void add(CompilerError err) {
+        errors.add(err);
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/Expr.java b/src/main/java/chocopy/common/astnodes/Expr.java
new file mode 100644
index 0000000..7372d58
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Expr.java
@@ -0,0 +1,43 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.types.Type;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/**
+ * Base of all AST nodes representing expressions.
+ *
+ * There is nothing in this class, but there will be many AST node types that have fields that
+ * are *any expression*. For those cases, having a field of this type will encompass all types of
+ * expressions such as binary expressions and literals that subclass this class.
+ */
+public abstract class Expr extends Node {
+
+    /** A Python expression spanning source locations [LEFT..RIGHT]. */
+    public Expr(Location left, Location right) {
+        super(left, right);
+    }
+
+    /**
+     * The type of the value that this expression evaluates to.
+     *
+     * 
This field is always null  after the parsing stage, but is populated by the
+     * typechecker in the semantic analysis stage.
+     *
+     * 
After typechecking this field may be null  only for expressions that cannot be
+     * assigned a type. In particular, {@link NoneLiteral} expressions will not have a typed
+     * assigned to them.
+     */
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Type inferredType;
+
+    /** Set getInferredType() to TYPE, returning TYPE. */
+    public Type setInferredType(Type type) {
+        inferredType = type;
+        return type;
+    }
+
+    public Type getInferredType() {
+        return inferredType;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ExprStmt.java b/src/main/java/chocopy/common/astnodes/ExprStmt.java
new file mode 100644
index 0000000..5b921a0
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ExprStmt.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Statements consisting of expressions. */
+public final class ExprStmt extends Stmt {
+
+    /** The expression I evaluate. */
+    public final Expr expr;
+
+    /** The AST for EXPR spanning source locations [LEFT..RIGHT] in a statement context. */
+    public ExprStmt(Location left, Location right, Expr expr) {
+        super(left, right);
+        this.expr = expr;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ForStmt.java b/src/main/java/chocopy/common/astnodes/ForStmt.java
new file mode 100644
index 0000000..019b2d8
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ForStmt.java
@@ -0,0 +1,29 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** For statements. */
+public class ForStmt extends Stmt {
+    /** Control variable. */
+    public final Identifier identifier;
+    /** Source of values of control statement. */
+    public final Expr iterable;
+    /** Repeated statements. */
+    public final List body;
+
+    /** The AST for for IDENTIFIER in ITERABLE: BODY spanning source locations [LEFT..RIGHT]. */
+    public ForStmt(
+            Location left, Location right, Identifier identifier, Expr iterable, List body) {
+        super(left, right);
+        this.identifier = identifier;
+        this.iterable = iterable;
+        this.body = body;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/FuncDef.java b/src/main/java/chocopy/common/astnodes/FuncDef.java
new file mode 100644
index 0000000..b3ca0f2
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/FuncDef.java
@@ -0,0 +1,50 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** Def statements. */
+public class FuncDef extends Declaration {
+
+    /** Defined name. */
+    public final Identifier name;
+    /** Formal parameters. */
+    public final List params;
+    /** Return type annotation. */
+    public final TypeAnnotation returnType;
+    /** Local-variable,inner-function, global, and nonlocal declarations. */
+    public final List declarations;
+    /** Other statements. */
+    public final List statements;
+
+    /**
+     * The AST for def NAME(PARAMS) -> RETURNTYPE: DECLARATIONS STATEMENTS spanning source locations
+     * [LEFT..RIGHT].
+     */
+    public FuncDef(
+            Location left,
+            Location right,
+            Identifier name,
+            List params,
+            TypeAnnotation returnType,
+            List declarations,
+            List statements) {
+        super(left, right);
+        this.name = name;
+        this.params = params;
+        this.returnType = returnType;
+        this.declarations = declarations;
+        this.statements = statements;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    @Override
+    public Identifier getIdentifier() {
+        return this.name;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/GlobalDecl.java b/src/main/java/chocopy/common/astnodes/GlobalDecl.java
new file mode 100644
index 0000000..b347d4d
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/GlobalDecl.java
@@ -0,0 +1,26 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Declaration of global variable. */
+public class GlobalDecl extends Declaration {
+
+    /** The declared variable. */
+    public final Identifier variable;
+
+    /** The AST for the declaration global VARIABLE spanning source locations [LEFT..RIGHT]. */
+    public GlobalDecl(Location left, Location right, Identifier variable) {
+        super(left, right);
+        this.variable = variable;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    @Override
+    public Identifier getIdentifier() {
+        return this.variable;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/Identifier.java b/src/main/java/chocopy/common/astnodes/Identifier.java
new file mode 100644
index 0000000..7593126
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Identifier.java
@@ -0,0 +1,24 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** A simple identifier. */
+public class Identifier extends Expr {
+
+    /** Text of the identifier. */
+    public final String name;
+
+    /**
+     * An AST for the variable, method, or parameter named NAME, spanning source locations
+     * [LEFT..RIGHT].
+     */
+    public Identifier(Location left, Location right, String name) {
+        super(left, right);
+        this.name = name;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/IfExpr.java b/src/main/java/chocopy/common/astnodes/IfExpr.java
new file mode 100644
index 0000000..3d3d809
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IfExpr.java
@@ -0,0 +1,26 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Conditional expressions. */
+public class IfExpr extends Expr {
+    /** Boolean condition. */
+    public final Expr condition;
+    /** True branch. */
+    public final Expr thenExpr;
+    /** False branch. */
+    public final Expr elseExpr;
+
+    /** The AST for THENEXPR if CONDITION else ELSEEXPR spanning source locations [LEFT..RIGHT]. */
+    public IfExpr(Location left, Location right, Expr condition, Expr thenExpr, Expr elseExpr) {
+        super(left, right);
+        this.condition = condition;
+        this.thenExpr = thenExpr;
+        this.elseExpr = elseExpr;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/IfStmt.java b/src/main/java/chocopy/common/astnodes/IfStmt.java
new file mode 100644
index 0000000..185b8a1
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IfStmt.java
@@ -0,0 +1,35 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** Conditional statement. */
+public class IfStmt extends Stmt {
+    /** Test condition. */
+    public final Expr condition;
+    /** "True" branch. */
+    public final List thenBody;
+    /** "False" branch. */
+    public final List elseBody;
+
+    /**
+     * The AST for if CONDITION: THENBODY else: ELSEBODY spanning source locations [LEFT..RIGHT].
+     */
+    public IfStmt(
+            Location left,
+            Location right,
+            Expr condition,
+            List thenBody,
+            List elseBody) {
+        super(left, right);
+        this.condition = condition;
+        this.thenBody = thenBody;
+        this.elseBody = elseBody;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/IndexExpr.java b/src/main/java/chocopy/common/astnodes/IndexExpr.java
new file mode 100644
index 0000000..ce788fa
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IndexExpr.java
@@ -0,0 +1,24 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** List-indexing expression. */
+public class IndexExpr extends Expr {
+
+    /** Indexed list. */
+    public final Expr list;
+    /** Expression for index value. */
+    public final Expr index;
+
+    /** The AST for LIST[INDEX]. spanning source locations [LEFT..RIGHT]. */
+    public IndexExpr(Location left, Location right, Expr list, Expr index) {
+        super(left, right);
+        this.list = list;
+        this.index = index;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/IntegerLiteral.java b/src/main/java/chocopy/common/astnodes/IntegerLiteral.java
new file mode 100644
index 0000000..f2d165b
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IntegerLiteral.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Integer numerals. */
+public final class IntegerLiteral extends Literal {
+
+    /** Value denoted. */
+    public final int value;
+
+    /** The AST for the literal VALUE, spanning source locations [LEFT..RIGHT]. */
+    public IntegerLiteral(Location left, Location right, int value) {
+        super(left, right);
+        this.value = value;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ListExpr.java b/src/main/java/chocopy/common/astnodes/ListExpr.java
new file mode 100644
index 0000000..eab6045
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ListExpr.java
@@ -0,0 +1,23 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** List displays. */
+public final class ListExpr extends Expr {
+
+    /** List of element expressions. */
+    public final List elements;
+
+    /** The AST for [ ELEMENTS ]. spanning source locations [LEFT..RIGHT]. */
+    public ListExpr(Location left, Location right, List elements) {
+        super(left, right);
+        this.elements = elements;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ListType.java b/src/main/java/chocopy/common/astnodes/ListType.java
new file mode 100644
index 0000000..32782ad
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ListType.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Type denotation for a list type. */
+public final class ListType extends TypeAnnotation {
+
+    /** The element of list element. */
+    public final TypeAnnotation elementType;
+
+    /** The AST for the type annotation [ ELEMENTTYPE ]. spanning source locations [LEFT..RIGHT]. */
+    public ListType(Location left, Location right, TypeAnnotation elementType) {
+        super(left, right);
+        this.elementType = elementType;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/Literal.java b/src/main/java/chocopy/common/astnodes/Literal.java
new file mode 100644
index 0000000..2afd1be
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Literal.java
@@ -0,0 +1,16 @@
+package chocopy.common.astnodes;
+
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/**
+ * Base of all the literal nodes.
+ *
+ * There is nothing in this class, but it is useful to isolate expressions that are constant
+ * literals.
+ */
+public abstract class Literal extends Expr {
+    /** A literal spanning source locations [LEFT..RIGHT]. */
+    public Literal(Location left, Location right) {
+        super(left, right);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/MemberExpr.java b/src/main/java/chocopy/common/astnodes/MemberExpr.java
new file mode 100644
index 0000000..a9e0a4f
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/MemberExpr.java
@@ -0,0 +1,24 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Attribute accessor. */
+public class MemberExpr extends Expr {
+
+    /** Object selected from. */
+    public final Expr object;
+    /** Name of attribute (instance variable or method). */
+    public final Identifier member;
+
+    /** The AST for OBJECT.MEMBER. spanning source locations [LEFT..RIGHT]. */
+    public MemberExpr(Location left, Location right, Expr object, Identifier member) {
+        super(left, right);
+        this.object = object;
+        this.member = member;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/MethodCallExpr.java b/src/main/java/chocopy/common/astnodes/MethodCallExpr.java
new file mode 100644
index 0000000..ab3f424
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/MethodCallExpr.java
@@ -0,0 +1,26 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** Method calls. */
+public class MethodCallExpr extends Expr {
+
+    /** Expression for the bound method to be called. */
+    public final MemberExpr method;
+    /** Actual parameters. */
+    public final List args;
+
+    /** The AST for METHOD(ARGS). spanning source locations [LEFT..RIGHT]. */
+    public MethodCallExpr(Location left, Location right, MemberExpr method, List args) {
+        super(left, right);
+        this.method = method;
+        this.args = args;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/Node.java b/src/main/java/chocopy/common/astnodes/Node.java
new file mode 100644
index 0000000..c95f3d6
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Node.java
@@ -0,0 +1,176 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.io.IOException;
+
+/**
+ * Root of the AST class hierarchy. Every node has a left and right location, indicating the start
+ * and end of the represented construct in the source text.
+ *
+ * Every node can be marked with an error message, which serves two purposes: 1. It indicates
+ * that an error message has been issued for this Node, allowing tne program to reduce cascades of
+ * error messages. 2. It aids in debugging by making it convenient to see which Nodes have caused an
+ * error.
+ */
+@JsonTypeInfo(
+        use = JsonTypeInfo.Id.NAME,
+        include = JsonTypeInfo.As.EXISTING_PROPERTY,
+        property = "kind")
+/* List of all concrete subclasses of Node. */
+@JsonSubTypes({
+    @JsonSubTypes.Type(AssignStmt.class),
+    @JsonSubTypes.Type(BinaryExpr.class),
+    @JsonSubTypes.Type(BooleanLiteral.class),
+    @JsonSubTypes.Type(CallExpr.class),
+    @JsonSubTypes.Type(ClassDef.class),
+    @JsonSubTypes.Type(ClassType.class),
+    @JsonSubTypes.Type(CompilerError.class),
+    @JsonSubTypes.Type(Errors.class),
+    @JsonSubTypes.Type(ExprStmt.class),
+    @JsonSubTypes.Type(ForStmt.class),
+    @JsonSubTypes.Type(FuncDef.class),
+    @JsonSubTypes.Type(GlobalDecl.class),
+    @JsonSubTypes.Type(Identifier.class),
+    @JsonSubTypes.Type(IfExpr.class),
+    @JsonSubTypes.Type(IfStmt.class),
+    @JsonSubTypes.Type(IndexExpr.class),
+    @JsonSubTypes.Type(IntegerLiteral.class),
+    @JsonSubTypes.Type(ListExpr.class),
+    @JsonSubTypes.Type(ListType.class),
+    @JsonSubTypes.Type(MemberExpr.class),
+    @JsonSubTypes.Type(MethodCallExpr.class),
+    @JsonSubTypes.Type(NoneLiteral.class),
+    @JsonSubTypes.Type(NonLocalDecl.class),
+    @JsonSubTypes.Type(Program.class),
+    @JsonSubTypes.Type(ReturnStmt.class),
+    @JsonSubTypes.Type(StringLiteral.class),
+    @JsonSubTypes.Type(TypedVar.class),
+    @JsonSubTypes.Type(UnaryExpr.class),
+    @JsonSubTypes.Type(VarDef.class),
+    @JsonSubTypes.Type(WhileStmt.class),
+})
+public abstract class Node {
+
+    /** Node-type indicator for JSON form. */
+    public final String kind;
+
+    /**
+     * Source position information: 0: line number of start, 1: column number of start, 2: line
+     * number of end, 3: column number of end.
+     */
+    private final int[] location = new int[4];
+
+    /**
+     * First error message "blamed" on this Node. When non-null, indicates that an error has been
+     * found in this Node.
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private String errorMsg;
+
+    /** A Node corresponding to source text between LEFT and RIGHT. */
+    public Node(Location left, Location right) {
+        if (left != null) {
+            location[0] = left.getLine();
+            location[1] = left.getColumn();
+        }
+        if (right != null) {
+            location[2] = right.getLine();
+            location[3] = right.getColumn();
+        }
+        this.kind = getClass().getSimpleName();
+        this.errorMsg = null;
+    }
+
+    /**
+     * Return my source location as { , , ,  }.
+     * Result should not be modified, and contents will change after setLocation().
+     */
+    public int[] getLocation() {
+        return location;
+    }
+
+    /** Copy LOCATION as getLocation(). */
+    public void setLocation(final int[] location) {
+        System.arraycopy(location, 0, this.location, 0, 4);
+    }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String msg) {
+        this.errorMsg = msg;
+    }
+
+    /** Return true iff I have been marked with an error message. */
+    @JsonIgnore
+    public boolean hasError() {
+        return this.errorMsg != null;
+    }
+
+    /**
+     * Invoke ANALYZER on me as a node of static type T. See the comment on NodeAnalyzer. Returns
+     * modified Node.
+     */
+    public abstract  T dispatch(NodeAnalyzer analyzer);
+
+    /** Print out the AST in JSON format. */
+    @Override
+    public String toString() {
+        try {
+            return toJSON();
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Return a serialization of this node in JSON format. */
+    public String toJSON() throws JsonProcessingException {
+        return mapper.writeValueAsString(this);
+    }
+
+    /** Mapper to-and-from serialized JSON. */
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    static {
+        mapper.enable(SerializationFeature.INDENT_OUTPUT);
+        mapper.registerModule(new ParameterNamesModule());
+    }
+
+    /** Returns a T from JSON, a JSON-serialized T value with class CLAS. */
+    public static  T fromJSON(String json, Class clas) throws IOException {
+        return mapper.readValue(json, clas);
+    }
+
+    /**
+     * Returns the result of converting JSON, a JSon-serialization of a Node value, into the value
+     * it serializes.
+     */
+    public static Node fromJSON(String json) throws IOException {
+        return fromJSON(json, Node.class);
+    }
+
+    /**
+     * Returns the result of converting TREE to the value of type T that it represents, where CLAS
+     * reflects T.
+     */
+    public static  T fromJSON(JsonNode tree, Class clas) throws IOException {
+        return mapper.treeToValue(tree, clas);
+    }
+
+    /** Returns the translation of serialized value SRC into the corresponding JSON tree. */
+    public static JsonNode readTree(String src) throws IOException {
+        return mapper.readTree(src);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/NonLocalDecl.java b/src/main/java/chocopy/common/astnodes/NonLocalDecl.java
new file mode 100644
index 0000000..ebaf78d
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/NonLocalDecl.java
@@ -0,0 +1,26 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Nonlocal declaration. */
+public class NonLocalDecl extends Declaration {
+
+    /** Name of identifier being declared. */
+    public final Identifier variable;
+
+    /** The AST for nonlocal VARIABLE spanning source locations [LEFT..RIGHT]. */
+    public NonLocalDecl(Location left, Location right, Identifier variable) {
+        super(left, right);
+        this.variable = variable;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    @Override
+    public Identifier getIdentifier() {
+        return this.variable;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/NoneLiteral.java b/src/main/java/chocopy/common/astnodes/NoneLiteral.java
new file mode 100644
index 0000000..b51a581
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/NoneLiteral.java
@@ -0,0 +1,17 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** The expression 'None'. */
+public final class NoneLiteral extends Literal {
+
+    /** The AST for None, spanning source locations [LEFT..RIGHT]. */
+    public NoneLiteral(Location left, Location right) {
+        super(left, right);
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/Program.java b/src/main/java/chocopy/common/astnodes/Program.java
new file mode 100644
index 0000000..e95b2e7
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Program.java
@@ -0,0 +1,56 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** An entire Chocopy program. */
+public class Program extends Node {
+
+    /** Initial variable, class, and function declarations. */
+    public final List declarations;
+    /** Trailing statements. */
+    public final List statements;
+    /** Accumulated errors. */
+    public final Errors errors;
+
+    /**
+     * The AST for the program DECLARATIONS STATEMENTS spanning source locations [LEFT..RIGHT].
+     *
+     * ERRORS is the container for all error messages applying to the program.
+     */
+    public Program(
+            Location left,
+            Location right,
+            List declarations,
+            List statements,
+            Errors errors) {
+        super(left, right);
+        this.declarations = declarations;
+        this.statements = statements;
+        if (errors == null) {
+            this.errors = new Errors(new ArrayList<>());
+        } else {
+            this.errors = errors;
+        }
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    /** Returns true iff there is at least one error in the program. */
+    @JsonIgnore
+    public boolean hasErrors() {
+        return errors.hasErrors();
+    }
+
+    /** A convenience method returning the list of all CompilerErrors for this program. */
+    @JsonIgnore
+    public List getErrorList() {
+        return errors.errors;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/ReturnStmt.java b/src/main/java/chocopy/common/astnodes/ReturnStmt.java
new file mode 100644
index 0000000..e665042
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ReturnStmt.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Return from function. */
+public class ReturnStmt extends Stmt {
+
+    /** Returned value. */
+    public final Expr value;
+
+    /** The AST for return VALUE spanning source locations [LEFT..RIGHT]. */
+    public ReturnStmt(Location left, Location right, Expr value) {
+        super(left, right);
+        this.value = value;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/Stmt.java b/src/main/java/chocopy/common/astnodes/Stmt.java
new file mode 100644
index 0000000..b87780e
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Stmt.java
@@ -0,0 +1,18 @@
+package chocopy.common.astnodes;
+
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/**
+ * Base of all AST nodes representing statements.
+ *
+ * There is nothing in this class, but there will be some AST node types that have fields that
+ * are *any statement* or a list of statements. For those cases, having a field of this type will
+ * encompass all types of statements such as expression statements, if statements, while statements,
+ * etc.
+ */
+public abstract class Stmt extends Node {
+    /** A statement spanning source locations [LEFT..RIGHT]. */
+    public Stmt(Location left, Location right) {
+        super(left, right);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/StringLiteral.java b/src/main/java/chocopy/common/astnodes/StringLiteral.java
new file mode 100644
index 0000000..0eaf928
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/StringLiteral.java
@@ -0,0 +1,21 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** String constants. */
+public final class StringLiteral extends Literal {
+
+    /** Contents of the literal, not including quotation marks. */
+    public final String value;
+
+    /** The AST for a string literal containing VALUE, spanning source locations [LEFT..RIGHT]. */
+    public StringLiteral(Location left, Location right, String value) {
+        super(left, right);
+        this.value = value;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/TypeAnnotation.java b/src/main/java/chocopy/common/astnodes/TypeAnnotation.java
new file mode 100644
index 0000000..d90b59e
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/TypeAnnotation.java
@@ -0,0 +1,11 @@
+package chocopy.common.astnodes;
+
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Base of all AST nodes representing type annotations (list or class types. */
+public abstract class TypeAnnotation extends Node {
+    /** An annotation spanning source locations [LEFT..RIGHT]. */
+    public TypeAnnotation(Location left, Location right) {
+        super(left, right);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/TypedVar.java b/src/main/java/chocopy/common/astnodes/TypedVar.java
new file mode 100644
index 0000000..98aae43
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/TypedVar.java
@@ -0,0 +1,24 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** An identifier with attached type annotation. */
+public class TypedVar extends Node {
+
+    /** The typed identifier. */
+    public final Identifier identifier;
+    /** The declared type. */
+    public final TypeAnnotation type;
+
+    /** The AST for IDENTIFIER : TYPE. spanning source locations [LEFT..RIGHT]. */
+    public TypedVar(Location left, Location right, Identifier identifier, TypeAnnotation type) {
+        super(left, right);
+        this.identifier = identifier;
+        this.type = type;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/UnaryExpr.java b/src/main/java/chocopy/common/astnodes/UnaryExpr.java
new file mode 100644
index 0000000..199e701
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/UnaryExpr.java
@@ -0,0 +1,24 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** An expression applying a unary operator. */
+public class UnaryExpr extends Expr {
+
+    /** The text representation of the operator. */
+    public final String operator;
+    /** The operand to which it is applied. */
+    public final Expr operand;
+
+    /** The AST for OPERATOR OPERAND spanning source locations [LEFT..RIGHT]. */
+    public UnaryExpr(Location left, Location right, String operator, Expr operand) {
+        super(left, right);
+        this.operator = operator;
+        this.operand = operand;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/VarDef.java b/src/main/java/chocopy/common/astnodes/VarDef.java
new file mode 100644
index 0000000..61d261a
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/VarDef.java
@@ -0,0 +1,32 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** A declaration of a variable (i.e., with type annotation). */
+public class VarDef extends Declaration {
+    /** The variable and its assigned type. */
+    public final TypedVar var;
+    /** The initial value assigned. */
+    public final Literal value;
+
+    /**
+     * The AST for VAR = VALUE where VAR has a type annotation, and spanning source locations
+     * [LEFT..RIGHT].
+     */
+    public VarDef(Location left, Location right, TypedVar var, Literal value) {
+        super(left, right);
+        this.var = var;
+        this.value = value;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+
+    /** The identifier defined by this declaration. */
+    @Override
+    public Identifier getIdentifier() {
+        return this.var.identifier;
+    }
+}
diff --git a/src/main/java/chocopy/common/astnodes/WhileStmt.java b/src/main/java/chocopy/common/astnodes/WhileStmt.java
new file mode 100644
index 0000000..9a521e1
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/WhileStmt.java
@@ -0,0 +1,25 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+import java.util.List;
+
+/** Indefinite repetition construct. */
+public class WhileStmt extends Stmt {
+    /** Test for whether to continue. */
+    public final Expr condition;
+    /** Loop body. */
+    public final List body;
+
+    /** The AST for while CONDITION: BODY spanning source locations [LEFT..RIGHT]. */
+    public WhileStmt(Location left, Location right, Expr condition, List body) {
+        super(left, right);
+        this.condition = condition;
+        this.body = body;
+    }
+
+    public  T dispatch(NodeAnalyzer analyzer) {
+        return analyzer.analyze(this);
+    }
+}
diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
new file mode 100644
index 0000000..29aaf5a
--- /dev/null
+++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
@@ -0,0 +1,55 @@
+package chocopy.pa2;
+
+import chocopy.common.analysis.AbstractNodeAnalyzer;
+import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.types.Type;
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.*;
+
+/** Analyzes declarations to create a top-level symbol table. */
+public class DeclarationAnalyzer extends AbstractNodeAnalyzer {
+
+    /** Current symbol table. Changes with new declarative region. */
+    private final SymbolTable sym = new SymbolTable<>();
+    /** Global symbol table. */
+    private final SymbolTable globals = sym;
+    /** Receiver for semantic error messages. */
+    private final Errors errors;
+
+    /** A new declaration analyzer sending errors to ERRORS0. */
+    public DeclarationAnalyzer(Errors errors0) {
+        errors = errors0;
+    }
+
+    public SymbolTable getGlobals() {
+        return globals;
+    }
+
+    @Override
+    public Type analyze(Program program) {
+        for (Declaration decl : program.declarations) {
+            Identifier id = decl.getIdentifier();
+            String name = id.name;
+
+            Type type = decl.dispatch(this);
+
+            if (type == null) {
+                continue;
+            }
+
+            if (sym.declares(name)) {
+                errors.semError(
+                        id, "Duplicate declaration of identifier in same " + "scope: %s", name);
+            } else {
+                sym.put(name, type);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public Type analyze(VarDef varDef) {
+        return ValueType.annotationToValueType(varDef.var.type);
+    }
+}
diff --git a/src/main/java/chocopy/pa2/StudentAnalysis.java b/src/main/java/chocopy/pa2/StudentAnalysis.java
new file mode 100644
index 0000000..b008a2b
--- /dev/null
+++ b/src/main/java/chocopy/pa2/StudentAnalysis.java
@@ -0,0 +1,30 @@
+package chocopy.pa2;
+
+import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.types.Type;
+import chocopy.common.astnodes.Program;
+
+/** Top-level class for performing semantic analysis. */
+public class StudentAnalysis {
+
+    /**
+     * Perform semantic analysis on PROGRAM, adding error messages and type annotations. Provide
+     * debugging output iff DEBUG. Returns modified tree.
+     */
+    public static Program process(Program program, boolean debug) {
+        if (program.hasErrors()) {
+            return program;
+        }
+
+        DeclarationAnalyzer declarationAnalyzer = new DeclarationAnalyzer(program.errors);
+        program.dispatch(declarationAnalyzer);
+        SymbolTable globalSym = declarationAnalyzer.getGlobals();
+
+        if (!program.hasErrors()) {
+            TypeChecker typeChecker = new TypeChecker(globalSym, program.errors);
+            program.dispatch(typeChecker);
+        }
+
+        return program;
+    }
+}
diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
new file mode 100644
index 0000000..ab8acc1
--- /dev/null
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -0,0 +1,94 @@
+package chocopy.pa2;
+
+import chocopy.common.analysis.AbstractNodeAnalyzer;
+import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.types.Type;
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.*;
+
+import static chocopy.common.analysis.types.Type.INT_TYPE;
+import static chocopy.common.analysis.types.Type.OBJECT_TYPE;
+
+/**
+ * Analyzer that performs ChocoPy type checks on all nodes. Applied after collecting declarations.
+ */
+public class TypeChecker extends AbstractNodeAnalyzer {
+
+    /** The current symbol table (changes depending on the function being analyzed). */
+    private final SymbolTable sym;
+    /** Collector for errors. */
+    private final Errors errors;
+
+    /**
+     * Creates a type checker using GLOBALSYMBOLS for the initial global symbol table and ERRORS0 to
+     * receive semantic errors.
+     */
+    public TypeChecker(SymbolTable globalSymbols, Errors errors0) {
+        sym = globalSymbols;
+        errors = errors0;
+    }
+
+    /**
+     * Inserts an error message in NODE if there isn't one already. The message is constructed with
+     * MESSAGE and ARGS as for String.format.
+     */
+    private void err(Node node, String message, Object... args) {
+        errors.semError(node, message, args);
+    }
+
+    @Override
+    public Type analyze(Program program) {
+        for (Declaration decl : program.declarations) {
+            decl.dispatch(this);
+        }
+        for (Stmt stmt : program.statements) {
+            stmt.dispatch(this);
+        }
+        return null;
+    }
+
+    @Override
+    public Type analyze(ExprStmt s) {
+        s.expr.dispatch(this);
+        return null;
+    }
+
+    @Override
+    public Type analyze(IntegerLiteral i) {
+        return i.setInferredType(Type.INT_TYPE);
+    }
+
+    @Override
+    public Type analyze(BinaryExpr e) {
+        Type t1 = e.left.dispatch(this);
+        Type t2 = e.right.dispatch(this);
+
+        switch (e.operator) {
+            case "-":
+            case "*":
+            case "//":
+            case "%":
+                if (INT_TYPE.equals(t1) && INT_TYPE.equals(t2)) {
+                    return e.setInferredType(INT_TYPE);
+                } else {
+                    err(e, "Cannot apply operator `%s` on types `%s` and `%s`", e.operator, t1, t2);
+                    return e.setInferredType(INT_TYPE);
+                }
+            default:
+                return e.setInferredType(OBJECT_TYPE);
+        }
+    }
+
+    @Override
+    public Type analyze(Identifier id) {
+        String varName = id.name;
+        Type varType = sym.get(varName);
+
+        if (varType != null && varType.isValueType()) {
+            return id.setInferredType(varType);
+        }
+
+        err(id, "Not a variable: %s", varName);
+        return id.setInferredType(ValueType.OBJECT_TYPE);
+    }
+}
diff --git a/src/test/data/pa2/sample/ast_coverage.py b/src/test/data/pa2/sample/ast_coverage.py
new file mode 100644
index 0000000..a27e796
--- /dev/null
+++ b/src/test/data/pa2/sample/ast_coverage.py
@@ -0,0 +1,38 @@
+count:int = 0
+
+def foo(s: str) -> int:
+    return len(s)
+
+class bar(object):
+    p: bool = True
+
+    def baz(self:"bar", xx: [int]) -> str:
+        global count
+        x:int = 0
+        y:int = 1
+
+        def qux(y: int) -> object:
+            nonlocal x
+            if x > y:
+                x = -1
+
+        for x in xx:
+            self.p = x == 2
+
+        qux(0) # Yay! ChocoPy
+
+        count = count + 1
+
+        while x <= 0:
+            if self.p:
+                xx[0] = xx[1]
+                self.p = not self.p
+                x = x + 1
+            elif foo("Long"[0]) == 1:
+                self.p = self is None
+
+        return "Nope"
+
+print(bar().baz([1,2]))
+
+
diff --git a/src/test/data/pa2/sample/ast_coverage.py.ast b/src/test/data/pa2/sample/ast_coverage.py.ast
new file mode 100644
index 0000000..18d47cd
--- /dev/null
+++ b/src/test/data/pa2/sample/ast_coverage.py.ast
@@ -0,0 +1,627 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 36, 24 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 9 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "name" : "count"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 7, 1, 9 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 13, 1, 13 ],
+      "value" : 0
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 4, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 3, 9, 3, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 9, 3, 9 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 12, 3, 14 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 20, 3, 22 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 4, 5, 4, 17 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 4, 12, 4, 17 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 12, 4, 14 ],
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 16, 4, 16 ],
+          "name" : "s"
+        } ]
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 6, 1, 36, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 7, 6, 9 ],
+      "name" : "bar"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 11, 6, 16 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 18 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "name" : "p"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 8, 7, 11 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 15, 7, 18 ],
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 34, 22 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 9, 13, 9, 22 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 13, 9, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 18, 9, 22 ],
+          "className" : "bar"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 9, 25, 9, 33 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 25, 9, 26 ],
+          "name" : "xx"
+        },
+        "type" : {
+          "kind" : "ListType",
+          "location" : [ 9, 29, 9, 33 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 9, 30, 9, 32 ],
+            "className" : "int"
+          }
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 39, 9, 41 ],
+        "className" : "str"
+      },
+      "declarations" : [ {
+        "kind" : "GlobalDecl",
+        "location" : [ 10, 9, 10, 20 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 16, 10, 20 ],
+          "name" : "count"
+        }
+      }, {
+        "kind" : "VarDef",
+        "location" : [ 11, 9, 11, 17 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 11, 9, 11, 13 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 9 ],
+            "name" : "x"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 11, 11, 11, 13 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 17, 11, 17 ],
+          "value" : 0
+        }
+      }, {
+        "kind" : "VarDef",
+        "location" : [ 12, 9, 12, 17 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 12, 9, 12, 13 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 12, 9, 12, 9 ],
+            "name" : "y"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 12, 11, 12, 13 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 12, 17, 12, 17 ],
+          "value" : 1
+        }
+      }, {
+        "kind" : "FuncDef",
+        "location" : [ 14, 9, 19, 8 ],
+        "name" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 13, 14, 15 ],
+          "name" : "qux"
+        },
+        "params" : [ {
+          "kind" : "TypedVar",
+          "location" : [ 14, 17, 14, 22 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 14, 17, 14, 17 ],
+            "name" : "y"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 14, 20, 14, 22 ],
+            "className" : "int"
+          }
+        } ],
+        "returnType" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 28, 14, 33 ],
+          "className" : "object"
+        },
+        "declarations" : [ {
+          "kind" : "NonLocalDecl",
+          "location" : [ 15, 13, 15, 22 ],
+          "variable" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 22, 15, 22 ],
+            "name" : "x"
+          }
+        } ],
+        "statements" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 16, 13, 19, 8 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 16, 16, 16, 20 ],
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 16, 16, 16 ],
+              "name" : "x"
+            },
+            "operator" : ">",
+            "right" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 20, 16, 20 ],
+              "name" : "y"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 17, 17, 17, 22 ],
+            "targets" : [ {
+              "kind" : "Identifier",
+              "location" : [ 17, 17, 17, 17 ],
+              "name" : "x"
+            } ],
+            "value" : {
+              "kind" : "UnaryExpr",
+              "location" : [ 17, 21, 17, 22 ],
+              "operator" : "-",
+              "operand" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 17, 22, 17, 22 ],
+                "value" : 1
+              }
+            }
+          } ],
+          "elseBody" : [ ]
+        } ]
+      } ],
+      "statements" : [ {
+        "kind" : "ForStmt",
+        "location" : [ 19, 9, 22, 8 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 13, 19, 13 ],
+          "name" : "x"
+        },
+        "iterable" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 18, 19, 19 ],
+          "name" : "xx"
+        },
+        "body" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 20, 13, 20, 27 ],
+          "targets" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 20, 13, 20, 18 ],
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 13, 20, 16 ],
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 18, 20, 18 ],
+              "name" : "p"
+            }
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 20, 22, 20, 27 ],
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 22, 20, 22 ],
+              "name" : "x"
+            },
+            "operator" : "==",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 20, 27, 20, 27 ],
+              "value" : 2
+            }
+          }
+        } ]
+      }, {
+        "kind" : "ExprStmt",
+        "location" : [ 22, 9, 22, 14 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 22, 9, 22, 14 ],
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 22, 9, 22, 11 ],
+            "name" : "qux"
+          },
+          "args" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 22, 13, 22, 13 ],
+            "value" : 0
+          } ]
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 24, 9, 24, 25 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 24, 9, 24, 13 ],
+          "name" : "count"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 24, 17, 24, 25 ],
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 24, 17, 24, 21 ],
+            "name" : "count"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 24, 25, 24, 25 ],
+            "value" : 1
+          }
+        }
+      }, {
+        "kind" : "WhileStmt",
+        "location" : [ 26, 9, 34, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 26, 15, 26, 20 ],
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 26, 15, 26, 15 ],
+            "name" : "x"
+          },
+          "operator" : "<=",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 26, 20, 26, 20 ],
+            "value" : 0
+          }
+        },
+        "body" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 27, 13, 34, 8 ],
+          "condition" : {
+            "kind" : "MemberExpr",
+            "location" : [ 27, 16, 27, 21 ],
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 27, 16, 27, 19 ],
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 27, 21, 27, 21 ],
+              "name" : "p"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 28, 17, 28, 29 ],
+            "targets" : [ {
+              "kind" : "IndexExpr",
+              "location" : [ 28, 17, 28, 21 ],
+              "list" : {
+                "kind" : "Identifier",
+                "location" : [ 28, 17, 28, 18 ],
+                "name" : "xx"
+              },
+              "index" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 28, 20, 28, 20 ],
+                "value" : 0
+              }
+            } ],
+            "value" : {
+              "kind" : "IndexExpr",
+              "location" : [ 28, 25, 28, 29 ],
+              "list" : {
+                "kind" : "Identifier",
+                "location" : [ 28, 25, 28, 26 ],
+                "name" : "xx"
+              },
+              "index" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 28, 28, 28, 28 ],
+                "value" : 1
+              }
+            }
+          }, {
+            "kind" : "AssignStmt",
+            "location" : [ 29, 17, 29, 35 ],
+            "targets" : [ {
+              "kind" : "MemberExpr",
+              "location" : [ 29, 17, 29, 22 ],
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 29, 17, 29, 20 ],
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 29, 22, 29, 22 ],
+                "name" : "p"
+              }
+            } ],
+            "value" : {
+              "kind" : "UnaryExpr",
+              "location" : [ 29, 26, 29, 35 ],
+              "operator" : "not",
+              "operand" : {
+                "kind" : "MemberExpr",
+                "location" : [ 29, 30, 29, 35 ],
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 29, 30, 29, 33 ],
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 29, 35, 29, 35 ],
+                  "name" : "p"
+                }
+              }
+            }
+          }, {
+            "kind" : "AssignStmt",
+            "location" : [ 30, 17, 30, 25 ],
+            "targets" : [ {
+              "kind" : "Identifier",
+              "location" : [ 30, 17, 30, 17 ],
+              "name" : "x"
+            } ],
+            "value" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 30, 21, 30, 25 ],
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 30, 21, 30, 21 ],
+                "name" : "x"
+              },
+              "operator" : "+",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 30, 25, 30, 25 ],
+                "value" : 1
+              }
+            }
+          } ],
+          "elseBody" : [ {
+            "kind" : "IfStmt",
+            "location" : [ 31, 13, 34, 8 ],
+            "condition" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 31, 18, 31, 36 ],
+              "left" : {
+                "kind" : "CallExpr",
+                "location" : [ 31, 18, 31, 31 ],
+                "function" : {
+                  "kind" : "Identifier",
+                  "location" : [ 31, 18, 31, 20 ],
+                  "name" : "foo"
+                },
+                "args" : [ {
+                  "kind" : "IndexExpr",
+                  "location" : [ 31, 22, 31, 30 ],
+                  "list" : {
+                    "kind" : "StringLiteral",
+                    "location" : [ 31, 22, 31, 27 ],
+                    "value" : "Long"
+                  },
+                  "index" : {
+                    "kind" : "IntegerLiteral",
+                    "location" : [ 31, 29, 31, 29 ],
+                    "value" : 0
+                  }
+                } ]
+              },
+              "operator" : "==",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 31, 36, 31, 36 ],
+                "value" : 1
+              }
+            },
+            "thenBody" : [ {
+              "kind" : "AssignStmt",
+              "location" : [ 32, 17, 32, 37 ],
+              "targets" : [ {
+                "kind" : "MemberExpr",
+                "location" : [ 32, 17, 32, 22 ],
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 17, 32, 20 ],
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 22, 32, 22 ],
+                  "name" : "p"
+                }
+              } ],
+              "value" : {
+                "kind" : "BinaryExpr",
+                "location" : [ 32, 26, 32, 37 ],
+                "left" : {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 26, 32, 29 ],
+                  "name" : "self"
+                },
+                "operator" : "is",
+                "right" : {
+                  "kind" : "NoneLiteral",
+                  "location" : [ 32, 34, 32, 37 ]
+                }
+              }
+            } ],
+            "elseBody" : [ ]
+          } ]
+        } ]
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 34, 9, 34, 21 ],
+        "value" : {
+          "kind" : "StringLiteral",
+          "location" : [ 34, 16, 34, 21 ],
+          "value" : "Nope"
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 36, 1, 36, 23 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 36, 1, 36, 23 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 36, 1, 36, 5 ],
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 36, 7, 36, 22 ],
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 36, 7, 36, 15 ],
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 36, 7, 36, 11 ],
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 36, 7, 36, 9 ],
+              "name" : "bar"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 36, 13, 36, 15 ],
+            "name" : "baz"
+          }
+        },
+        "args" : [ {
+          "kind" : "ListExpr",
+          "location" : [ 36, 17, 36, 21 ],
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 36, 18, 36, 18 ],
+            "value" : 1
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 36, 20, 36, 20 ],
+            "value" : 2
+          } ]
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/ast_coverage.py.ast.typed b/src/test/data/pa2/sample/ast_coverage.py.ast.typed
new file mode 100644
index 0000000..709f895
--- /dev/null
+++ b/src/test/data/pa2/sample/ast_coverage.py.ast.typed
@@ -0,0 +1,952 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 36, 24 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 9 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "name" : "count"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 7, 1, 9 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 13, 1, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 4, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 3, 9, 3, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 9, 3, 9 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 12, 3, 14 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 20, 3, 22 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 4, 5, 4, 17 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 4, 12, 4, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 12, 4, 14 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 16, 4, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        } ]
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 6, 1, 36, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 7, 6, 9 ],
+      "name" : "bar"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 11, 6, 16 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 18 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "name" : "p"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 8, 7, 11 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 15, 7, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 34, 22 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 9, 13, 9, 22 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 13, 9, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 18, 9, 22 ],
+          "className" : "bar"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 9, 25, 9, 33 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 25, 9, 26 ],
+          "name" : "xx"
+        },
+        "type" : {
+          "kind" : "ListType",
+          "location" : [ 9, 29, 9, 33 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 9, 30, 9, 32 ],
+            "className" : "int"
+          }
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 39, 9, 41 ],
+        "className" : "str"
+      },
+      "declarations" : [ {
+        "kind" : "GlobalDecl",
+        "location" : [ 10, 9, 10, 20 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 16, 10, 20 ],
+          "name" : "count"
+        }
+      }, {
+        "kind" : "VarDef",
+        "location" : [ 11, 9, 11, 17 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 11, 9, 11, 13 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 9 ],
+            "name" : "x"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 11, 11, 11, 13 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 17, 11, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      }, {
+        "kind" : "VarDef",
+        "location" : [ 12, 9, 12, 17 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 12, 9, 12, 13 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 12, 9, 12, 9 ],
+            "name" : "y"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 12, 11, 12, 13 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 12, 17, 12, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }, {
+        "kind" : "FuncDef",
+        "location" : [ 14, 9, 19, 8 ],
+        "name" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 13, 14, 15 ],
+          "name" : "qux"
+        },
+        "params" : [ {
+          "kind" : "TypedVar",
+          "location" : [ 14, 17, 14, 22 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 14, 17, 14, 17 ],
+            "name" : "y"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 14, 20, 14, 22 ],
+            "className" : "int"
+          }
+        } ],
+        "returnType" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 28, 14, 33 ],
+          "className" : "object"
+        },
+        "declarations" : [ {
+          "kind" : "NonLocalDecl",
+          "location" : [ 15, 13, 15, 22 ],
+          "variable" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 22, 15, 22 ],
+            "name" : "x"
+          }
+        } ],
+        "statements" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 16, 13, 19, 8 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 16, 16, 16, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 16, 16, 16 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : ">",
+            "right" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 20, 16, 20 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "y"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 17, 17, 17, 22 ],
+            "targets" : [ {
+              "kind" : "Identifier",
+              "location" : [ 17, 17, 17, 17 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            } ],
+            "value" : {
+              "kind" : "UnaryExpr",
+              "location" : [ 17, 21, 17, 22 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "operator" : "-",
+              "operand" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 17, 22, 17, 22 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            }
+          } ],
+          "elseBody" : [ ]
+        } ]
+      } ],
+      "statements" : [ {
+        "kind" : "ForStmt",
+        "location" : [ 19, 9, 22, 8 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 13, 19, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "iterable" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 18, 19, 19 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "xx"
+        },
+        "body" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 20, 13, 20, 27 ],
+          "targets" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 20, 13, 20, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 13, 20, 16 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bar"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 18, 20, 18 ],
+              "name" : "p"
+            }
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 20, 22, 20, 27 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 22, 20, 22 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : "==",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 20, 27, 20, 27 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 2
+            }
+          }
+        } ]
+      }, {
+        "kind" : "ExprStmt",
+        "location" : [ 22, 9, 22, 14 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 22, 9, 22, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 22, 9, 22, 11 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              }
+            },
+            "name" : "qux"
+          },
+          "args" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 22, 13, 22, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 0
+          } ]
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 24, 9, 24, 25 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 24, 9, 24, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "count"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 24, 17, 24, 25 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 24, 17, 24, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "count"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 24, 25, 24, 25 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      }, {
+        "kind" : "WhileStmt",
+        "location" : [ 26, 9, 34, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 26, 15, 26, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 26, 15, 26, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "x"
+          },
+          "operator" : "<=",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 26, 20, 26, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 0
+          }
+        },
+        "body" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 27, 13, 34, 8 ],
+          "condition" : {
+            "kind" : "MemberExpr",
+            "location" : [ 27, 16, 27, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 27, 16, 27, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bar"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 27, 21, 27, 21 ],
+              "name" : "p"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 28, 17, 28, 29 ],
+            "targets" : [ {
+              "kind" : "IndexExpr",
+              "location" : [ 28, 17, 28, 21 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "list" : {
+                "kind" : "Identifier",
+                "location" : [ 28, 17, 28, 18 ],
+                "inferredType" : {
+                  "kind" : "ListValueType",
+                  "elementType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  }
+                },
+                "name" : "xx"
+              },
+              "index" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 28, 20, 28, 20 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 0
+              }
+            } ],
+            "value" : {
+              "kind" : "IndexExpr",
+              "location" : [ 28, 25, 28, 29 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "list" : {
+                "kind" : "Identifier",
+                "location" : [ 28, 25, 28, 26 ],
+                "inferredType" : {
+                  "kind" : "ListValueType",
+                  "elementType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  }
+                },
+                "name" : "xx"
+              },
+              "index" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 28, 28, 28, 28 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            }
+          }, {
+            "kind" : "AssignStmt",
+            "location" : [ 29, 17, 29, 35 ],
+            "targets" : [ {
+              "kind" : "MemberExpr",
+              "location" : [ 29, 17, 29, 22 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 29, 17, 29, 20 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bar"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 29, 22, 29, 22 ],
+                "name" : "p"
+              }
+            } ],
+            "value" : {
+              "kind" : "UnaryExpr",
+              "location" : [ 29, 26, 29, 35 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "operator" : "not",
+              "operand" : {
+                "kind" : "MemberExpr",
+                "location" : [ 29, 30, 29, 35 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 29, 30, 29, 33 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bar"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 29, 35, 29, 35 ],
+                  "name" : "p"
+                }
+              }
+            }
+          }, {
+            "kind" : "AssignStmt",
+            "location" : [ 30, 17, 30, 25 ],
+            "targets" : [ {
+              "kind" : "Identifier",
+              "location" : [ 30, 17, 30, 17 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            } ],
+            "value" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 30, 21, 30, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 30, 21, 30, 21 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "x"
+              },
+              "operator" : "+",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 30, 25, 30, 25 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            }
+          } ],
+          "elseBody" : [ {
+            "kind" : "IfStmt",
+            "location" : [ 31, 13, 34, 8 ],
+            "condition" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 31, 18, 31, 36 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "left" : {
+                "kind" : "CallExpr",
+                "location" : [ 31, 18, 31, 31 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "function" : {
+                  "kind" : "Identifier",
+                  "location" : [ 31, 18, 31, 20 ],
+                  "inferredType" : {
+                    "kind" : "FuncType",
+                    "parameters" : [ {
+                      "kind" : "ClassValueType",
+                      "className" : "str"
+                    } ],
+                    "returnType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    }
+                  },
+                  "name" : "foo"
+                },
+                "args" : [ {
+                  "kind" : "IndexExpr",
+                  "location" : [ 31, 22, 31, 30 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "str"
+                  },
+                  "list" : {
+                    "kind" : "StringLiteral",
+                    "location" : [ 31, 22, 31, 27 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "str"
+                    },
+                    "value" : "Long"
+                  },
+                  "index" : {
+                    "kind" : "IntegerLiteral",
+                    "location" : [ 31, 29, 31, 29 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    },
+                    "value" : 0
+                  }
+                } ]
+              },
+              "operator" : "==",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 31, 36, 31, 36 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            },
+            "thenBody" : [ {
+              "kind" : "AssignStmt",
+              "location" : [ 32, 17, 32, 37 ],
+              "targets" : [ {
+                "kind" : "MemberExpr",
+                "location" : [ 32, 17, 32, 22 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 17, 32, 20 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bar"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 22, 32, 22 ],
+                  "name" : "p"
+                }
+              } ],
+              "value" : {
+                "kind" : "BinaryExpr",
+                "location" : [ 32, 26, 32, 37 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "left" : {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 26, 32, 29 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bar"
+                  },
+                  "name" : "self"
+                },
+                "operator" : "is",
+                "right" : {
+                  "kind" : "NoneLiteral",
+                  "location" : [ 32, 34, 32, 37 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : ""
+                  }
+                }
+              }
+            } ],
+            "elseBody" : [ ]
+          } ]
+        } ]
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 34, 9, 34, 21 ],
+        "value" : {
+          "kind" : "StringLiteral",
+          "location" : [ 34, 16, 34, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "Nope"
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 36, 1, 36, 23 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 36, 1, 36, 23 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 36, 1, 36, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : ""
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 36, 7, 36, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 36, 7, 36, 15 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "bar"
+            }, {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }
+          },
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 36, 7, 36, 11 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bar"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 36, 7, 36, 9 ],
+              "name" : "bar"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 36, 13, 36, 15 ],
+            "name" : "baz"
+          }
+        },
+        "args" : [ {
+          "kind" : "ListExpr",
+          "location" : [ 36, 17, 36, 21 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 36, 18, 36, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 36, 20, 36, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 2
+          } ]
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_assign_expr.py b/src/test/data/pa2/sample/bad_assign_expr.py
new file mode 100644
index 0000000..9e68917
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_assign_expr.py
@@ -0,0 +1,11 @@
+x:int = 0
+y:int = 0
+z:bool = False
+
+x = z = 1    # Only one error here (assignment to `x = 1` should succeed)
+x = y = None
+x = y = []
+x = a = None
+x = a = []
+x = y = True
+
diff --git a/src/test/data/pa2/sample/bad_assign_expr.py.ast b/src/test/data/pa2/sample/bad_assign_expr.py.ast
new file mode 100644
index 0000000..6651bd2
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_assign_expr.py.ast
@@ -0,0 +1,177 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 13 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 6 ],
+        "className" : "bool"
+      }
+    },
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 3, 10, 3, 14 ],
+      "value" : false
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 9 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 9, 5, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 12 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 6, 5, 6, 5 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 6, 9, 6, 12 ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 5 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 9, 7, 10 ],
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 5 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 8, 9, 8, 12 ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 9, 5, 9, 5 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 9, 9, 9, 10 ],
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 12 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 10, 1, 10, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 10, 5, 10, 5 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 10, 9, 10, 12 ],
+      "value" : true
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_assign_expr.py.ast.typed b/src/test/data/pa2/sample/bad_assign_expr.py.ast.typed
new file mode 100644
index 0000000..2f99fae
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_assign_expr.py.ast.typed
@@ -0,0 +1,301 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 13 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 6 ],
+        "className" : "bool"
+      }
+    },
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 3, 10, 3, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : false
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 9 ],
+    "errorMsg" : "Expected type `bool`; got type `int`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 9, 5, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 12 ],
+    "errorMsg" : "Expected type `int`; got type ``",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 6, 5, 6, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 6, 9, 6, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 10 ],
+    "errorMsg" : "Expected type `int`; got type ``",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 9, 7, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "errorMsg" : "Expected type `int`; got type ``",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 5 ],
+      "errorMsg" : "Not a variable: a",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 8, 9, 8, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 10 ],
+    "errorMsg" : "Expected type `int`; got type ``",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 9, 5, 9, 5 ],
+      "errorMsg" : "Not a variable: a",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 9, 9, 9, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 12 ],
+    "errorMsg" : "Expected type `int`; got type `bool`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 10, 1, 10, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 10, 5, 10, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 10, 9, 10, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : true
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 9 ],
+      "message" : "Expected type `bool`; got type `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 12 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 1, 7, 10 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 1, 8, 12 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 5, 8, 5 ],
+      "message" : "Not a variable: a"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 1, 9, 10 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 5, 9, 5 ],
+      "message" : "Not a variable: a"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 10, 1, 10, 12 ],
+      "message" : "Expected type `int`; got type `bool`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_attr.py b/src/test/data/pa2/sample/bad_class_attr.py
new file mode 100644
index 0000000..b30eb7c
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_attr.py
@@ -0,0 +1,13 @@
+class A(object):
+    x:int = 1
+
+    def foo(self:"A") -> int:
+        return 0
+
+class B(A):
+    x:int = 2  # Bad
+    foo:str = "" # Bad
+
+A()
+
+
diff --git a/src/test/data/pa2/sample/bad_class_attr.py.ast b/src/test/data/pa2/sample/bad_class_attr.py.ast
new file mode 100644
index 0000000..ec25404
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_attr.py.ast
@@ -0,0 +1,155 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 11, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 13, 4, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 13, 4, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 18, 4, 20 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 26, 4, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 16, 5, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 9, 23 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 8, 5, 8, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 13, 8, 13 ],
+        "value" : 2
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 16 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 7 ],
+          "name" : "foo"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 9, 9, 11 ],
+          "className" : "str"
+        }
+      },
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 9, 15, 9, 16 ],
+        "value" : ""
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_attr.py.ast.typed b/src/test/data/pa2/sample/bad_class_attr.py.ast.typed
new file mode 100644
index 0000000..5ea1e74
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_attr.py.ast.typed
@@ -0,0 +1,165 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 11, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 13, 4, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 13, 4, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 18, 4, 20 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 26, 4, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 16, 5, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 9, 23 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 8, 5, 8, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "errorMsg" : "Cannot re-define attribute: x",
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 13, 8, 13 ],
+        "value" : 2
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 16 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 7 ],
+          "errorMsg" : "Cannot re-define attribute: foo",
+          "name" : "foo"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 9, 9, 11 ],
+          "className" : "str"
+        }
+      },
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 9, 15, 9, 16 ],
+        "value" : ""
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 8, 5, 8, 5 ],
+      "message" : "Cannot re-define attribute: x"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 5, 9, 7 ],
+      "message" : "Cannot re-define attribute: foo"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_attr_type.py b/src/test/data/pa2/sample/bad_class_attr_type.py
new file mode 100644
index 0000000..5a7bee7
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_attr_type.py
@@ -0,0 +1,4 @@
+class A(object):
+    x:int = True
+
+A()
diff --git a/src/test/data/pa2/sample/bad_class_attr_type.py.ast b/src/test/data/pa2/sample/bad_class_attr_type.py.ast
new file mode 100644
index 0000000..6b9d252
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_attr_type.py.ast
@@ -0,0 +1,60 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 16 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 13, 2, 16 ],
+        "value" : true
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_attr_type.py.ast.typed b/src/test/data/pa2/sample/bad_class_attr_type.py.ast.typed
new file mode 100644
index 0000000..f0a9461
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_attr_type.py.ast.typed
@@ -0,0 +1,73 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 16 ],
+      "errorMsg" : "Expected type `int`; got type `bool`",
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 13, 2, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 2, 5, 2, 16 ],
+      "message" : "Expected type `int`; got type `bool`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_init_override.py b/src/test/data/pa2/sample/bad_class_init_override.py
new file mode 100644
index 0000000..ceb612c
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_init_override.py
@@ -0,0 +1,8 @@
+class A(object):
+    x:int = 1
+
+    def __init__(self:"A", x:int): # Bad override
+        pass
+
+A(1)
+
diff --git a/src/test/data/pa2/sample/bad_class_init_override.py.ast b/src/test/data/pa2/sample/bad_class_init_override.py.ast
new file mode 100644
index 0000000..bdd151d
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_init_override.py.ast
@@ -0,0 +1,106 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 5 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 18, 4, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 18, 4, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 23, 4, 25 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 28, 4, 32 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 28, 4, 28 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 32 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 34, 4, 34 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 4 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 4 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 1 ],
+        "name" : "A"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 3, 7, 3 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_init_override.py.ast.typed b/src/test/data/pa2/sample/bad_class_init_override.py.ast.typed
new file mode 100644
index 0000000..9daa89c
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_init_override.py.ast.typed
@@ -0,0 +1,111 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 5 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 16 ],
+        "errorMsg" : "Method overridden with different type signature: __init__",
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 18, 4, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 18, 4, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 23, 4, 25 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 28, 4, 32 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 28, 4, 28 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 32 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 34, 4, 34 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 4 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 4 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 1 ],
+        "name" : "A"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 3, 7, 3 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 4, 9, 4, 16 ],
+      "message" : "Method overridden with different type signature: __init__"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_init_return.py b/src/test/data/pa2/sample/bad_class_init_return.py
new file mode 100644
index 0000000..cc6eb34
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_init_return.py
@@ -0,0 +1,5 @@
+class A(object):
+    def __init__(self:"A"):
+        return 1 # Bad
+
+A()
diff --git a/src/test/data/pa2/sample/bad_class_init_return.py.ast b/src/test/data/pa2/sample/bad_class_init_return.py.ast
new file mode 100644
index 0000000..24e972f
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_init_return.py.ast
@@ -0,0 +1,75 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 5, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 2, 5, 3, 23 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 2, 18, 2, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 18, 2, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 23, 2, 25 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 27, 2, 27 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 16, 3, 16 ],
+          "value" : 1
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_init_return.py.ast.typed b/src/test/data/pa2/sample/bad_class_init_return.py.ast.typed
new file mode 100644
index 0000000..cf0cde2
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_init_return.py.ast.typed
@@ -0,0 +1,88 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 5, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 2, 5, 3, 23 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 2, 18, 2, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 18, 2, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 23, 2, 25 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 27, 2, 27 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "errorMsg" : "Expected type ``; got type `int`",
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 16, 3, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 3, 9, 3, 16 ],
+      "message" : "Expected type ``; got type `int`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_member_expr.py b/src/test/data/pa2/sample/bad_class_member_expr.py
new file mode 100644
index 0000000..bbfa1c1
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_member_expr.py
@@ -0,0 +1,6 @@
+x:int = 0
+o:object = None
+
+x.foo
+o.bar
+o.baz = 1
diff --git a/src/test/data/pa2/sample/bad_class_member_expr.py.ast b/src/test/data/pa2/sample/bad_class_member_expr.py.ast
new file mode 100644
index 0000000..4949375
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_member_expr.py.ast
@@ -0,0 +1,110 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 10 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 12, 2, 15 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 5 ],
+    "expr" : {
+      "kind" : "MemberExpr",
+      "location" : [ 4, 1, 4, 5 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "x"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 3, 4, 5 ],
+        "name" : "foo"
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "expr" : {
+      "kind" : "MemberExpr",
+      "location" : [ 5, 1, 5, 5 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "o"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 3, 5, 5 ],
+        "name" : "bar"
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 9 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 6, 1, 6, 5 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "name" : "o"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 3, 6, 5 ],
+        "name" : "baz"
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 9, 6, 9 ],
+      "value" : 1
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_member_expr.py.ast.typed b/src/test/data/pa2/sample/bad_class_member_expr.py.ast.typed
new file mode 100644
index 0000000..4e570c0
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_member_expr.py.ast.typed
@@ -0,0 +1,161 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 10 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 12, 2, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 5 ],
+    "expr" : {
+      "kind" : "MemberExpr",
+      "location" : [ 4, 1, 4, 5 ],
+      "errorMsg" : "There is no attribute named `foo` in class `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 3, 4, 5 ],
+        "name" : "foo"
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "expr" : {
+      "kind" : "MemberExpr",
+      "location" : [ 5, 1, 5, 5 ],
+      "errorMsg" : "There is no attribute named `bar` in class `object`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "name" : "o"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 3, 5, 5 ],
+        "name" : "bar"
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 9 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 6, 1, 6, 5 ],
+      "errorMsg" : "There is no attribute named `baz` in class `object`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "name" : "o"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 3, 6, 5 ],
+        "name" : "baz"
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 9, 6, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 4, 1, 4, 5 ],
+      "message" : "There is no attribute named `foo` in class `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 5 ],
+      "message" : "There is no attribute named `bar` in class `object`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 5 ],
+      "message" : "There is no attribute named `baz` in class `object`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method.py b/src/test/data/pa2/sample/bad_class_method.py
new file mode 100644
index 0000000..d5a10d8
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method.py
@@ -0,0 +1,14 @@
+class A(object):
+    x:int = 1
+
+    def foo(self:"A") -> int: # OK
+        return 0
+
+    def bar() -> int: # Needs self param
+        return 0
+
+    def baz(self:int) -> int: # Incorrect self type
+        return 0
+
+A()
+
diff --git a/src/test/data/pa2/sample/bad_class_method.py.ast b/src/test/data/pa2/sample/bad_class_method.py.ast
new file mode 100644
index 0000000..7c359ef
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method.py.ast
@@ -0,0 +1,158 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 13, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 13, 4, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 13, 4, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 18, 4, 20 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 26, 4, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 16, 5, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 18, 7, 20 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 8, 9, 8, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 16, 8, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 11 ],
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 13, 10, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 13, 10, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 18, 10, 20 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 26, 10, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 11, 9, 11, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 16, 11, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method.py.ast.typed b/src/test/data/pa2/sample/bad_class_method.py.ast.typed
new file mode 100644
index 0000000..9e08da8
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method.py.ast.typed
@@ -0,0 +1,168 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 13, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 13, 4, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 13, 4, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 18, 4, 20 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 26, 4, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 16, 5, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 11 ],
+        "errorMsg" : "First parameter of the following method must be of the enclosing class: bar",
+        "name" : "bar"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 18, 7, 20 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 8, 9, 8, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 16, 8, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 11 ],
+        "errorMsg" : "First parameter of the following method must be of the enclosing class: baz",
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 13, 10, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 13, 10, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 18, 10, 20 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 26, 10, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 11, 9, 11, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 16, 11, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 7, 9, 7, 11 ],
+      "message" : "First parameter of the following method must be of the enclosing class: bar"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 10, 9, 10, 11 ],
+      "message" : "First parameter of the following method must be of the enclosing class: baz"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method_invoke.py b/src/test/data/pa2/sample/bad_class_method_invoke.py
new file mode 100644
index 0000000..d5bb97c
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_invoke.py
@@ -0,0 +1,30 @@
+class A(object):
+    x:int = 1
+
+    def get_A(self: "A") -> int:
+        return self.x
+
+class B(A):
+    def __init__(self: "B"):
+        pass
+
+class C(B):
+    z:bool = True
+
+    def set_A(self: "C", val: int) -> object:
+        self.x = val
+
+a:A = None
+b:B = None
+c:C = None
+
+a = A()
+b = B()
+c = C()
+
+a.get_A(1)
+b.get_Z()
+c.set_A()
+c.set_A(False)
+c.set_A(None)
+
diff --git a/src/test/data/pa2/sample/bad_class_method_invoke.py.ast b/src/test/data/pa2/sample/bad_class_method_invoke.py.ast
new file mode 100644
index 0000000..e01db23
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_invoke.py.ast
@@ -0,0 +1,474 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 29, 14 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 13 ],
+        "name" : "get_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 15, 4, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 15, 4, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 21, 4, 23 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 29, 4, 31 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 21 ],
+        "value" : {
+          "kind" : "MemberExpr",
+          "location" : [ 5, 16, 5, 21 ],
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 16, 5, 19 ],
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 21, 5, 21 ],
+            "name" : "x"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 11, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 8, 5, 9, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 8, 18, 8, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 18, 8, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 24, 8, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 28, 8, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 11, 1, 17, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 7, 11, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 9, 11, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 12, 5, 12, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 12, 5, 12, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 12, 7, 12, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 12, 14, 12, 17 ],
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 14, 5, 15, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 9, 14, 13 ],
+        "name" : "set_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 14, 15, 14, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 15, 14, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 21, 14, 23 ],
+          "className" : "C"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 14, 26, 14, 33 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 26, 14, 28 ],
+          "name" : "val"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 31, 14, 33 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 14, 39, 14, 44 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 15, 9, 15, 20 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 15, 9, 15, 14 ],
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 9, 15, 12 ],
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 14, 15, 14 ],
+            "name" : "x"
+          }
+        } ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 18, 15, 20 ],
+          "name" : "val"
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 17, 1, 17, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 17, 1, 17, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 3, 17, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 17, 7, 17, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 18, 1, 18, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 18, 1, 18, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 18, 3, 18, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 18, 7, 18, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 19, 1, 19, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 19, 1, 19, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 19, 3, 19, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 19, 7, 19, 10 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 21, 1, 21, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 21, 1, 21, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 21, 5, 21, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 5, 21, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 22, 1, 22, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 22, 1, 22, 1 ],
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 22, 5, 22, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 5, 22, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 23, 1, 23, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 23, 1, 23, 1 ],
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 23, 5, 23, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 23, 5, 23, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 25, 1, 25, 10 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 25, 1, 25, 10 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 25, 1, 25, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 1, 25, 1 ],
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 3, 25, 7 ],
+          "name" : "get_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 25, 9, 25, 9 ],
+        "value" : 1
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 26, 1, 26, 9 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 26, 1, 26, 9 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 26, 1, 26, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 1, 26, 1 ],
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 3, 26, 7 ],
+          "name" : "get_Z"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 27, 1, 27, 9 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 27, 1, 27, 9 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 27, 1, 27, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 1, 27, 1 ],
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 3, 27, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 28, 1, 28, 14 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 28, 1, 28, 14 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 28, 1, 28, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 28, 1, 28, 1 ],
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 28, 3, 28, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 28, 9, 28, 13 ],
+        "value" : false
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 29, 1, 29, 13 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 29, 1, 29, 13 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 29, 1, 29, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 1, 29, 1 ],
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 3, 29, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "NoneLiteral",
+        "location" : [ 29, 9, 29, 12 ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method_invoke.py.ast.typed b/src/test/data/pa2/sample/bad_class_method_invoke.py.ast.typed
new file mode 100644
index 0000000..77867db
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_invoke.py.ast.typed
@@ -0,0 +1,668 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 29, 14 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 13 ],
+        "name" : "get_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 15, 4, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 15, 4, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 21, 4, 23 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 29, 4, 31 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 21 ],
+        "value" : {
+          "kind" : "MemberExpr",
+          "location" : [ 5, 16, 5, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 16, 5, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "A"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 21, 5, 21 ],
+            "name" : "x"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 11, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 8, 5, 9, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 8, 18, 8, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 18, 8, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 24, 8, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 28, 8, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 11, 1, 17, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 7, 11, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 9, 11, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 12, 5, 12, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 12, 5, 12, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 12, 7, 12, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 12, 14, 12, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 14, 5, 15, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 9, 14, 13 ],
+        "name" : "set_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 14, 15, 14, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 15, 14, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 21, 14, 23 ],
+          "className" : "C"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 14, 26, 14, 33 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 26, 14, 28 ],
+          "name" : "val"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 31, 14, 33 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 14, 39, 14, 44 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 15, 9, 15, 20 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 15, 9, 15, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 9, 15, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "C"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 14, 15, 14 ],
+            "name" : "x"
+          }
+        } ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 18, 15, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "val"
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 17, 1, 17, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 17, 1, 17, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 3, 17, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 17, 7, 17, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 18, 1, 18, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 18, 1, 18, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 18, 3, 18, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 18, 7, 18, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 19, 1, 19, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 19, 1, 19, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 19, 3, 19, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 19, 7, 19, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 21, 1, 21, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 21, 1, 21, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 21, 5, 21, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 5, 21, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 22, 1, 22, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 22, 1, 22, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 22, 5, 22, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 5, 22, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 23, 1, 23, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 23, 1, 23, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 23, 5, 23, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 23, 5, 23, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 25, 1, 25, 10 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 25, 1, 25, 10 ],
+      "errorMsg" : "Expected 0 arguments; got 1",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 25, 1, 25, 7 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 1, 25, 1 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 3, 25, 7 ],
+          "name" : "get_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 25, 9, 25, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 26, 1, 26, 9 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 26, 1, 26, 9 ],
+      "errorMsg" : "There is no method named `get_Z` in class `B`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 26, 1, 26, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 1, 26, 1 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 3, 26, 7 ],
+          "name" : "get_Z"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 27, 1, 27, 9 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 27, 1, 27, 9 ],
+      "errorMsg" : "Expected 1 arguments; got 0",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 27, 1, 27, 7 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 1, 27, 1 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          },
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 3, 27, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 28, 1, 28, 14 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 28, 1, 28, 14 ],
+      "errorMsg" : "Expected type `int`; got type `bool` in parameter 1",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 28, 1, 28, 7 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 28, 1, 28, 1 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          },
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 28, 3, 28, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 28, 9, 28, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 29, 1, 29, 13 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 29, 1, 29, 13 ],
+      "errorMsg" : "Expected type `int`; got type `` in parameter 1",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 29, 1, 29, 7 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 1, 29, 1 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          },
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 3, 29, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "NoneLiteral",
+        "location" : [ 29, 9, 29, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 25, 1, 25, 10 ],
+      "message" : "Expected 0 arguments; got 1"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 26, 1, 26, 9 ],
+      "message" : "There is no method named `get_Z` in class `B`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 27, 1, 27, 9 ],
+      "message" : "Expected 1 arguments; got 0"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 28, 1, 28, 14 ],
+      "message" : "Expected type `int`; got type `bool` in parameter 1"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 29, 1, 29, 13 ],
+      "message" : "Expected type `int`; got type `` in parameter 1"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method_override.py b/src/test/data/pa2/sample/bad_class_method_override.py
new file mode 100644
index 0000000..3f76544
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_override.py
@@ -0,0 +1,33 @@
+class A(object):
+    def foo(self:"A", x:int) -> int:
+        return x
+
+    def bar(self:"A", x:int) -> int:
+        return x
+
+    def baz(self:"A", x:int) -> int:
+        return x
+
+    def qux(self:"A", x:int) -> int:
+        return x
+
+class B(A):
+
+    # OK override
+    def foo(self:"B", x:int) -> int:
+        return 0
+
+    # Bad override
+    def bar(self:"B") -> int:
+        return 0
+
+    # Bad override
+    def baz(self:"B", x:int) -> bool:
+        return True
+
+    # Bad override
+    def qux(self:"B", x:bool) -> int:
+        return 0
+
+B()
+
diff --git a/src/test/data/pa2/sample/bad_class_method_override.py.ast b/src/test/data/pa2/sample/bad_class_method_override.py.ast
new file mode 100644
index 0000000..e82a758
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_override.py.ast
@@ -0,0 +1,439 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 32, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 14, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 2, 5, 3, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 2, 13, 2, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 13, 2, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 18, 2, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 2, 23, 2, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 23, 2, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 25, 2, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 33, 2, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 16, 3, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 13, 5, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 13, 5, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 18, 5, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 5, 23, 5, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 23, 5, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 25, 5, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 33, 5, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 6, 9, 6, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 16, 6, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 8, 5, 9, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 11 ],
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 8, 13, 8, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 13, 8, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 18, 8, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 8, 23, 8, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 23, 8, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 25, 8, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 33, 8, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 9, 9, 9, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 16, 9, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 11, 5, 12, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 9, 11, 11 ],
+        "name" : "qux"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 11, 13, 11, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 13, 11, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 11, 18, 11, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 11, 23, 11, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 23, 11, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 11, 25, 11, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 33, 11, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 12, 9, 12, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 16, 12, 16 ],
+          "name" : "x"
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 14, 1, 32, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 14, 7, 14, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 14, 9, 14, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 17, 5, 18, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 9, 17, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 17, 13, 17, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 13, 17, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 17, 18, 17, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 17, 23, 17, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 23, 17, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 17, 25, 17, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 33, 17, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 18, 9, 18, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 18, 16, 18, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 21, 5, 22, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 9, 21, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 21, 13, 21, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 13, 21, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 21, 18, 21, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 21, 26, 21, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 22, 9, 22, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 22, 16, 22, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 25, 5, 26, 20 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 9, 25, 11 ],
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 25, 13, 25, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 13, 25, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 25, 18, 25, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 25, 23, 25, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 23, 25, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 25, 25, 25, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 25, 33, 25, 36 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 26, 9, 26, 19 ],
+        "value" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 26, 16, 26, 19 ],
+          "value" : true
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 29, 5, 30, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 29, 9, 29, 11 ],
+        "name" : "qux"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 29, 13, 29, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 13, 29, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 29, 18, 29, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 29, 23, 29, 28 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 23, 29, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 29, 25, 29, 28 ],
+          "className" : "bool"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 29, 34, 29, 36 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 30, 9, 30, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 30, 16, 30, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 32, 1, 32, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 32, 1, 32, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 32, 1, 32, 1 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method_override.py.ast.typed b/src/test/data/pa2/sample/bad_class_method_override.py.ast.typed
new file mode 100644
index 0000000..68716c5
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_override.py.ast.typed
@@ -0,0 +1,454 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 32, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 14, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 2, 5, 3, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 2, 13, 2, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 13, 2, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 18, 2, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 2, 23, 2, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 23, 2, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 25, 2, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 33, 2, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 16, 3, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 13, 5, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 13, 5, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 18, 5, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 5, 23, 5, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 23, 5, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 25, 5, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 33, 5, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 6, 9, 6, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 16, 6, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 8, 5, 9, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 11 ],
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 8, 13, 8, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 13, 8, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 18, 8, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 8, 23, 8, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 23, 8, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 25, 8, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 33, 8, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 9, 9, 9, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 16, 9, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 11, 5, 12, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 9, 11, 11 ],
+        "name" : "qux"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 11, 13, 11, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 13, 11, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 11, 18, 11, 20 ],
+          "className" : "A"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 11, 23, 11, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 23, 11, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 11, 25, 11, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 33, 11, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 12, 9, 12, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 16, 12, 16 ],
+          "name" : "x"
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 14, 1, 32, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 14, 7, 14, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 14, 9, 14, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 17, 5, 18, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 9, 17, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 17, 13, 17, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 13, 17, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 17, 18, 17, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 17, 23, 17, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 23, 17, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 17, 25, 17, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 33, 17, 35 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 18, 9, 18, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 18, 16, 18, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 21, 5, 22, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 9, 21, 11 ],
+        "errorMsg" : "Method overridden with different type signature: bar",
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 21, 13, 21, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 13, 21, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 21, 18, 21, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 21, 26, 21, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 22, 9, 22, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 22, 16, 22, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 25, 5, 26, 20 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 9, 25, 11 ],
+        "errorMsg" : "Method overridden with different type signature: baz",
+        "name" : "baz"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 25, 13, 25, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 13, 25, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 25, 18, 25, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 25, 23, 25, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 23, 25, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 25, 25, 25, 27 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 25, 33, 25, 36 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 26, 9, 26, 19 ],
+        "value" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 26, 16, 26, 19 ],
+          "value" : true
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 29, 5, 30, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 29, 9, 29, 11 ],
+        "errorMsg" : "Method overridden with different type signature: qux",
+        "name" : "qux"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 29, 13, 29, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 13, 29, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 29, 18, 29, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 29, 23, 29, 28 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 23, 29, 23 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 29, 25, 29, 28 ],
+          "className" : "bool"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 29, 34, 29, 36 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 30, 9, 30, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 30, 16, 30, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 32, 1, 32, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 32, 1, 32, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 32, 1, 32, 1 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 21, 9, 21, 11 ],
+      "message" : "Method overridden with different type signature: bar"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 25, 9, 25, 11 ],
+      "message" : "Method overridden with different type signature: baz"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 29, 9, 29, 11 ],
+      "message" : "Method overridden with different type signature: qux"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method_override_attr.py b/src/test/data/pa2/sample/bad_class_method_override_attr.py
new file mode 100644
index 0000000..52c01bd
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_override_attr.py
@@ -0,0 +1,8 @@
+class A(object):
+	f:int = 3
+
+class B(A):
+	def f(self:B) -> int:
+		return 3
+
+A()
diff --git a/src/test/data/pa2/sample/bad_class_method_override_attr.py.ast b/src/test/data/pa2/sample/bad_class_method_override_attr.py.ast
new file mode 100644
index 0000000..1574d53
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_override_attr.py.ast
@@ -0,0 +1,111 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 2, 2, 10 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 2, 2, 6 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 2, 2, 2 ],
+          "name" : "f"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 10, 2, 10 ],
+        "value" : 3
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 2, 6, 11 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 6, 5, 6 ],
+        "name" : "f"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 8, 5, 13 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 8, 5, 11 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 13, 5, 13 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 19, 5, 21 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 6, 3, 6, 10 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 6, 10, 6, 10 ],
+          "value" : 3
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_method_override_attr.py.ast.typed b/src/test/data/pa2/sample/bad_class_method_override_attr.py.ast.typed
new file mode 100644
index 0000000..fcfb779
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_method_override_attr.py.ast.typed
@@ -0,0 +1,116 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 2, 2, 10 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 2, 2, 6 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 2, 2, 2 ],
+          "name" : "f"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 10, 2, 10 ],
+        "value" : 3
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 2, 6, 11 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 6, 5, 6 ],
+        "errorMsg" : "Cannot re-define attribute: f",
+        "name" : "f"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 8, 5, 13 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 8, 5, 11 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 13, 5, 13 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 19, 5, 21 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 6, 3, 6, 10 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 6, 10, 6, 10 ],
+          "value" : 3
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 5, 6, 5, 6 ],
+      "message" : "Cannot re-define attribute: f"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_super.py b/src/test/data/pa2/sample/bad_class_super.py
new file mode 100644
index 0000000..9701776
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_super.py
@@ -0,0 +1,15 @@
+# Super is not defined
+class A(B):
+    x:int = 1
+
+z:int = 2
+
+# Super is not a class
+class B(z):
+    x:int = 1
+
+# Cannot extend special classes
+class C(int):
+    x:int = 1
+
+A()
diff --git a/src/test/data/pa2/sample/bad_class_super.py.ast b/src/test/data/pa2/sample/bad_class_super.py.ast
new file mode 100644
index 0000000..4aed62a
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_super.py.ast
@@ -0,0 +1,154 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 15, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 2, 1, 3, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 7, 2, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 9, 2, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 7, 3, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 13, 3, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 3, 5, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 9, 5, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "z"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 13, 9, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 12, 1, 13, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 12, 7, 12, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 12, 9, 12, 11 ],
+      "name" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 13, 5, 13, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 13, 5, 13, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 5, 13, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 7, 13, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 13, 13, 13 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_class_super.py.ast.typed b/src/test/data/pa2/sample/bad_class_super.py.ast.typed
new file mode 100644
index 0000000..128383f
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_class_super.py.ast.typed
@@ -0,0 +1,169 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 15, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 2, 1, 3, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 7, 2, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 9, 2, 9 ],
+      "errorMsg" : "Super-class not defined: B",
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 7, 3, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 13, 3, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 3, 5, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 9, 5, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "errorMsg" : "Super-class must be a class: z",
+      "name" : "z"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 13, 9, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 12, 1, 13, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 12, 7, 12, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 12, 9, 12, 11 ],
+      "errorMsg" : "Cannot extend special class: int",
+      "name" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 13, 5, 13, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 13, 5, 13, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 5, 13, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 7, 13, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 13, 13, 13 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 2, 9, 2, 9 ],
+      "message" : "Super-class not defined: B"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 9, 8, 9 ],
+      "message" : "Super-class must be a class: z"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 12, 9, 12, 11 ],
+      "message" : "Cannot extend special class: int"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_concat.py b/src/test/data/pa2/sample/bad_concat.py
new file mode 100644
index 0000000..56e7802
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_concat.py
@@ -0,0 +1,3 @@
+"Hello" + ["World"]
+1 + [2]
+[] + [1]
diff --git a/src/test/data/pa2/sample/bad_concat.py.ast b/src/test/data/pa2/sample/bad_concat.py.ast
new file mode 100644
index 0000000..0fdfbd6
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_concat.py.ast
@@ -0,0 +1,77 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 9 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 19 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 19 ],
+      "left" : {
+        "kind" : "StringLiteral",
+        "location" : [ 1, 1, 1, 7 ],
+        "value" : "Hello"
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 1, 11, 1, 19 ],
+        "elements" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 1, 12, 1, 18 ],
+          "value" : "World"
+        } ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 7 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 1, 2, 7 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 1, 2, 1 ],
+        "value" : 1
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 2, 5, 2, 7 ],
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 6, 2, 6 ],
+          "value" : 2
+        } ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 8 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 8 ],
+      "left" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 1, 3, 2 ],
+        "elements" : [ ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 6, 3, 8 ],
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 7, 3, 7 ],
+          "value" : 1
+        } ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_concat.py.ast.typed b/src/test/data/pa2/sample/bad_concat.py.ast.typed
new file mode 100644
index 0000000..60f5b0c
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_concat.py.ast.typed
@@ -0,0 +1,149 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 9 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 19 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 19 ],
+      "errorMsg" : "Cannot apply operator `+` on types `str` and `[str]`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "left" : {
+        "kind" : "StringLiteral",
+        "location" : [ 1, 1, 1, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 1, 11, 1, 19 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "elements" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 1, 12, 1, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "World"
+        } ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 7 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 1, 2, 7 ],
+      "errorMsg" : "Cannot apply operator `+` on types `int` and `[int]`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 1, 2, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 2, 5, 2, 7 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 6, 2, 6 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 2
+        } ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 8 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 8 ],
+      "errorMsg" : "Cannot apply operator `+` on types `` and `[int]`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "left" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 1, 3, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        },
+        "elements" : [ ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 6, 3, 8 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 7, 3, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        } ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 1, 1, 1, 19 ],
+      "message" : "Cannot apply operator `+` on types `str` and `[str]`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 2, 1, 2, 7 ],
+      "message" : "Cannot apply operator `+` on types `int` and `[int]`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 3, 1, 3, 8 ],
+      "message" : "Cannot apply operator `+` on types `` and `[int]`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_class.py b/src/test/data/pa2/sample/bad_duplicate_class.py
new file mode 100644
index 0000000..8f8dd05
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_class.py
@@ -0,0 +1,18 @@
+class A(object):
+    x:int = 1
+
+z:bool = True
+
+# Duplicate
+class A(object):
+    x:int = 1
+
+# Duplicate
+class str(object):
+    x:int = 1
+
+# Duplicate
+class z(object):
+    x:int = 1
+
+A()
diff --git a/src/test/data/pa2/sample/bad_duplicate_class.py.ast b/src/test/data/pa2/sample/bad_duplicate_class.py.ast
new file mode 100644
index 0000000..547360b
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_class.py.ast
@@ -0,0 +1,190 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 6 ],
+        "className" : "bool"
+      }
+    },
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 4, 10, 4, 13 ],
+      "value" : true
+    }
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 8, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 8, 5, 8, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 13, 8, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 11, 1, 12, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 7, 11, 9 ],
+      "name" : "str"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 11, 11, 16 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 12, 5, 12, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 12, 5, 12, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 12, 7, 12, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 12, 13, 12, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 15, 1, 16, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 15, 7, 15, 7 ],
+      "name" : "z"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 15, 9, 15, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 16, 5, 16, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 16, 5, 16, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 5, 16, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 16, 7, 16, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 16, 13, 16, 13 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_class.py.ast.typed b/src/test/data/pa2/sample/bad_duplicate_class.py.ast.typed
new file mode 100644
index 0000000..3791ada
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_class.py.ast.typed
@@ -0,0 +1,205 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 6 ],
+        "className" : "bool"
+      }
+    },
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 4, 10, 4, 13 ],
+      "value" : true
+    }
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 8, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "errorMsg" : "Duplicate declaration of identifier in same scope: A",
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 8, 5, 8, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 13, 8, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 11, 1, 12, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 7, 11, 9 ],
+      "errorMsg" : "Duplicate declaration of identifier in same scope: str",
+      "name" : "str"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 11, 11, 16 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 12, 5, 12, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 12, 5, 12, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 12, 7, 12, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 12, 13, 12, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 15, 1, 16, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 15, 7, 15, 7 ],
+      "errorMsg" : "Duplicate declaration of identifier in same scope: z",
+      "name" : "z"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 15, 9, 15, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 16, 5, 16, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 16, 5, 16, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 5, 16, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 16, 7, 16, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 16, 13, 16, 13 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 7, 7, 7, 7 ],
+      "message" : "Duplicate declaration of identifier in same scope: A"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 11, 7, 11, 9 ],
+      "message" : "Duplicate declaration of identifier in same scope: str"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 15, 7, 15, 7 ],
+      "message" : "Duplicate declaration of identifier in same scope: z"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_class_member.py b/src/test/data/pa2/sample/bad_duplicate_class_member.py
new file mode 100644
index 0000000..7a5026f
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_class_member.py
@@ -0,0 +1,12 @@
+class A(object):
+    x:int = 1 # OK
+
+    def foo(self: "A") -> int: # OK
+        return 0
+
+    x:int = 1 # Duplicate
+
+    def foo(self: "A") -> int: # Duplicate
+        return 0
+
+A()
diff --git a/src/test/data/pa2/sample/bad_duplicate_class_member.py.ast b/src/test/data/pa2/sample/bad_duplicate_class_member.py.ast
new file mode 100644
index 0000000..58b0ddb
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_class_member.py.ast
@@ -0,0 +1,156 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 12, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 13, 4, 21 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 13, 4, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 19, 4, 21 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 27, 4, 29 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 16, 5, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 7, 7, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 13, 7, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 10, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 9, 13, 9, 21 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 13, 9, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 19, 9, 21 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 27, 9, 29 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 10, 9, 10, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 10, 16, 10, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_class_member.py.ast.typed b/src/test/data/pa2/sample/bad_duplicate_class_member.py.ast.typed
new file mode 100644
index 0000000..cb97ac4
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_class_member.py.ast.typed
@@ -0,0 +1,166 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 12, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 13, 4, 21 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 13, 4, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 19, 4, 21 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 27, 4, 29 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 16, 5, 16 ],
+          "value" : 0
+        }
+      } ]
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "errorMsg" : "Duplicate declaration of identifier in same scope: x",
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 7, 7, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 13, 7, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 10, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "errorMsg" : "Duplicate declaration of identifier in same scope: foo",
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 9, 13, 9, 21 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 13, 9, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 19, 9, 21 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 27, 9, 29 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 10, 9, 10, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 10, 16, 10, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 3 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 7, 5, 7, 5 ],
+      "message" : "Duplicate declaration of identifier in same scope: x"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 9, 9, 11 ],
+      "message" : "Duplicate declaration of identifier in same scope: foo"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_global.py b/src/test/data/pa2/sample/bad_duplicate_global.py
new file mode 100644
index 0000000..4b293ea
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_global.py
@@ -0,0 +1,18 @@
+x:int = 1
+
+def foo() -> object:
+    pass
+
+# `foo` cannot be redefined in the same scope
+def foo() -> object:
+    pass
+
+# `print` cannot be redefined in the same scope
+def print(val:object) -> object:
+    pass
+
+# `x` cannot be redefined in the same scope
+x:int = 2
+
+
+foo()
diff --git a/src/test/data/pa2/sample/bad_duplicate_global.py.ast b/src/test/data/pa2/sample/bad_duplicate_global.py.ast
new file mode 100644
index 0000000..76e6707
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_global.py.ast
@@ -0,0 +1,129 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 6 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 4, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 14, 3, 19 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 7, 1, 8, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 7, 14, 7, 19 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 11, 1, 12, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 5, 11, 9 ],
+      "name" : "print"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 11, 11, 11, 20 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 11, 11, 13 ],
+        "name" : "val"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 15, 11, 20 ],
+        "className" : "object"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 11, 26, 11, 31 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 15, 1, 15, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 15, 1, 15, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 15, 3, 15, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 15, 9, 15, 9 ],
+      "value" : 2
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_global.py.ast.typed b/src/test/data/pa2/sample/bad_duplicate_global.py.ast.typed
new file mode 100644
index 0000000..7d72792
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_global.py.ast.typed
@@ -0,0 +1,144 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 6 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 4, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 14, 3, 19 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 7, 1, 8, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 7 ],
+      "errorMsg" : "Duplicate declaration of identifier in same scope: foo",
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 7, 14, 7, 19 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 11, 1, 12, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 5, 11, 9 ],
+      "errorMsg" : "Duplicate declaration of identifier in same scope: print",
+      "name" : "print"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 11, 11, 11, 20 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 11, 11, 13 ],
+        "name" : "val"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 15, 11, 20 ],
+        "className" : "object"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 11, 26, 11, 31 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 15, 1, 15, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 15, 1, 15, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 1 ],
+        "errorMsg" : "Duplicate declaration of identifier in same scope: x",
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 15, 3, 15, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 15, 9, 15, 9 ],
+      "value" : 2
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 7, 5, 7, 7 ],
+      "message" : "Duplicate declaration of identifier in same scope: foo"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 11, 5, 11, 9 ],
+      "message" : "Duplicate declaration of identifier in same scope: print"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 15, 1, 15, 1 ],
+      "message" : "Duplicate declaration of identifier in same scope: x"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_global_2.py b/src/test/data/pa2/sample/bad_duplicate_global_2.py
new file mode 100644
index 0000000..62ee129
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_global_2.py
@@ -0,0 +1,6 @@
+class x(object):
+    pass
+
+x:int = 5
+
+pass
diff --git a/src/test/data/pa2/sample/bad_duplicate_global_2.py.ast b/src/test/data/pa2/sample/bad_duplicate_global_2.py.ast
new file mode 100644
index 0000000..c3a5985
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_global_2.py.ast
@@ -0,0 +1,47 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 5 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "x"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 9, 4, 9 ],
+      "value" : 5
+    }
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_global_2.py.ast.typed b/src/test/data/pa2/sample/bad_duplicate_global_2.py.ast.typed
new file mode 100644
index 0000000..506a6ca
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_global_2.py.ast.typed
@@ -0,0 +1,52 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 5 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "x"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "errorMsg" : "Duplicate declaration of identifier in same scope: x",
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 9, 4, 9 ],
+      "value" : 5
+    }
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 4, 1, 4, 1 ],
+      "message" : "Duplicate declaration of identifier in same scope: x"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_local.py b/src/test/data/pa2/sample/bad_duplicate_local.py
new file mode 100644
index 0000000..bb25faf
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_local.py
@@ -0,0 +1,21 @@
+x:int = 1
+y:int = 2
+z:int = 3
+
+def foo(x:int) -> object:
+    y:int = 4  # OK
+    x:int = 5  # Duplicate declaration
+    global z   # OK
+    global y   # Duplicate declaration
+
+    def x() -> int: # Duplicate declaration
+        return 0
+
+    pass
+
+def bar(x:int, x:int) -> int: # Duplicate params
+    return x
+
+
+foo(1)
+
diff --git a/src/test/data/pa2/sample/bad_duplicate_local.py.ast b/src/test/data/pa2/sample/bad_duplicate_local.py.ast
new file mode 100644
index 0000000..53f6fad
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_local.py.ast
@@ -0,0 +1,257 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 20, 7 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 9 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 14, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 5, 9, 5, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 11, 5, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 19, 5, 24 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 4
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 7, 7, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 13, 7, 13 ],
+        "value" : 5
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 8, 5, 8, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 12, 8, 12 ],
+        "name" : "z"
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 9, 5, 9, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 12, 9, 12 ],
+        "name" : "y"
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 11, 5, 12, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 9, 11, 9 ],
+        "name" : "x"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 16, 11, 18 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 12, 9, 12, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 12, 16, 12, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ],
+    "statements" : [ ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 16, 1, 17, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 16, 5, 16, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 16, 9, 16, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 9, 16, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 11, 16, 13 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 16, 16, 16, 20 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 16, 16, 16 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 18, 16, 20 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 16, 26, 16, 28 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 17, 5, 17, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 12, 17, 12 ],
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 20, 1, 20, 6 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 20, 1, 20, 6 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 1, 20, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 20, 5, 20, 5 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_duplicate_local.py.ast.typed b/src/test/data/pa2/sample/bad_duplicate_local.py.ast.typed
new file mode 100644
index 0000000..1559865
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_duplicate_local.py.ast.typed
@@ -0,0 +1,277 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 20, 7 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 9 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 14, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 5, 9, 5, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 11, 5, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 19, 5, 24 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 4
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "errorMsg" : "Duplicate declaration of identifier in same scope: x",
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 7, 7, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 13, 7, 13 ],
+        "value" : 5
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 8, 5, 8, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 12, 8, 12 ],
+        "name" : "z"
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 9, 5, 9, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 12, 9, 12 ],
+        "errorMsg" : "Duplicate declaration of identifier in same scope: y",
+        "name" : "y"
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 11, 5, 12, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 9, 11, 9 ],
+        "errorMsg" : "Duplicate declaration of identifier in same scope: x",
+        "name" : "x"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 16, 11, 18 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 12, 9, 12, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 12, 16, 12, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ],
+    "statements" : [ ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 16, 1, 17, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 16, 5, 16, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 16, 9, 16, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 9, 16, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 11, 16, 13 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 16, 16, 16, 20 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 16, 16, 16 ],
+        "errorMsg" : "Duplicate declaration of identifier in same scope: x",
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 18, 16, 20 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 16, 26, 16, 28 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 17, 5, 17, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 12, 17, 12 ],
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 20, 1, 20, 6 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 20, 1, 20, 6 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 1, 20, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 20, 5, 20, 5 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 7, 5, 7, 5 ],
+      "message" : "Duplicate declaration of identifier in same scope: x"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 12, 9, 12 ],
+      "message" : "Duplicate declaration of identifier in same scope: y"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 11, 9, 11, 9 ],
+      "message" : "Duplicate declaration of identifier in same scope: x"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 16, 16, 16, 16 ],
+      "message" : "Duplicate declaration of identifier in same scope: x"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_expr_binary.py b/src/test/data/pa2/sample/bad_expr_binary.py
new file mode 100644
index 0000000..1668849
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_binary.py
@@ -0,0 +1,13 @@
+1 and 2
+1 or 2
+True - False
+True < False
+1 + True
+False + 0
+1 == True
+False != 0
+1 is 1
+True is False
+None + None
+None == None
+None is None
diff --git a/src/test/data/pa2/sample/bad_expr_binary.py.ast b/src/test/data/pa2/sample/bad_expr_binary.py.ast
new file mode 100644
index 0000000..c55893a
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_binary.py.ast
@@ -0,0 +1,239 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 13 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 7 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 7 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 1, 1, 1 ],
+        "value" : 1
+      },
+      "operator" : "and",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 7, 1, 7 ],
+        "value" : 2
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 6 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 1, 2, 6 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 1, 2, 1 ],
+        "value" : 1
+      },
+      "operator" : "or",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 6, 2, 6 ],
+        "value" : 2
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 12 ],
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 1, 3, 4 ],
+        "value" : true
+      },
+      "operator" : "-",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 8, 3, 12 ],
+        "value" : false
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 4, 1, 4, 12 ],
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 4, 1, 4, 4 ],
+        "value" : true
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 4, 8, 4, 12 ],
+        "value" : false
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 8 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 5, 1, 5, 8 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 1, 5, 1 ],
+        "value" : 1
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 5, 5, 8 ],
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 9 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 6, 1, 6, 9 ],
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 6, 1, 6, 5 ],
+        "value" : false
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 9 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 7, 1, 7, 9 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 1, 7, 1 ],
+        "value" : 1
+      },
+      "operator" : "==",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 6, 7, 9 ],
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 10 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 8, 1, 8, 10 ],
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 1, 8, 5 ],
+        "value" : false
+      },
+      "operator" : "!=",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 10, 8, 10 ],
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 6 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 9, 1, 9, 6 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 1, 9, 1 ],
+        "value" : 1
+      },
+      "operator" : "is",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 6, 9, 6 ],
+        "value" : 1
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 13 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 10, 1, 10, 13 ],
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 10, 1, 10, 4 ],
+        "value" : true
+      },
+      "operator" : "is",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 10, 9, 10, 13 ],
+        "value" : false
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 11 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 11, 1, 11, 11 ],
+      "left" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 11, 1, 11, 4 ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 11, 8, 11, 11 ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 12, 1, 12, 12 ],
+      "left" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 12, 1, 12, 4 ]
+      },
+      "operator" : "==",
+      "right" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 12, 9, 12, 12 ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 13, 1, 13, 12 ],
+      "left" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 13, 1, 13, 4 ]
+      },
+      "operator" : "is",
+      "right" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 13, 9, 13, 12 ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_expr_binary.py.ast.typed b/src/test/data/pa2/sample/bad_expr_binary.py.ast.typed
new file mode 100644
index 0000000..851cc92
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_binary.py.ast.typed
@@ -0,0 +1,455 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 13 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 7 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 7 ],
+      "errorMsg" : "Cannot apply operator `and` on types `int` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 1, 1, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "and",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 7, 1, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 6 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 1, 2, 6 ],
+      "errorMsg" : "Cannot apply operator `or` on types `int` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 1, 2, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "or",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 6, 2, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 12 ],
+      "errorMsg" : "Cannot apply operator `-` on types `bool` and `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 1, 3, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      },
+      "operator" : "-",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 8, 3, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 4, 1, 4, 12 ],
+      "errorMsg" : "Cannot apply operator `<` on types `bool` and `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 4, 1, 4, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 4, 8, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 8 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 5, 1, 5, 8 ],
+      "errorMsg" : "Cannot apply operator `+` on types `int` and `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 1, 5, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 5, 5, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 9 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 6, 1, 6, 9 ],
+      "errorMsg" : "Cannot apply operator `+` on types `bool` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 9 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 7, 1, 7, 9 ],
+      "errorMsg" : "Cannot apply operator `==` on types `int` and `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 1, 7, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "==",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 6, 7, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 10 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 8, 1, 8, 10 ],
+      "errorMsg" : "Cannot apply operator `!=` on types `bool` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      },
+      "operator" : "!=",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 10, 8, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 6 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 9, 1, 9, 6 ],
+      "errorMsg" : "Cannot apply operator `is` on types `int` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 1, 9, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "is",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 6, 9, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 13 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 10, 1, 10, 13 ],
+      "errorMsg" : "Cannot apply operator `is` on types `bool` and `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 10, 1, 10, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      },
+      "operator" : "is",
+      "right" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 10, 9, 10, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 11 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 11, 1, 11, 11 ],
+      "errorMsg" : "Cannot apply operator `+` on types `` and ``",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "left" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 11, 1, 11, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 11, 8, 11, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 12, 1, 12, 12 ],
+      "errorMsg" : "Cannot apply operator `==` on types `` and ``",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 12, 1, 12, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      },
+      "operator" : "==",
+      "right" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 12, 9, 12, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 12 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 13, 1, 13, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 13, 1, 13, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      },
+      "operator" : "is",
+      "right" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 13, 9, 13, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 1, 1, 1, 7 ],
+      "message" : "Cannot apply operator `and` on types `int` and `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 2, 1, 2, 6 ],
+      "message" : "Cannot apply operator `or` on types `int` and `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 3, 1, 3, 12 ],
+      "message" : "Cannot apply operator `-` on types `bool` and `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 4, 1, 4, 12 ],
+      "message" : "Cannot apply operator `<` on types `bool` and `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 8 ],
+      "message" : "Cannot apply operator `+` on types `int` and `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 9 ],
+      "message" : "Cannot apply operator `+` on types `bool` and `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 1, 7, 9 ],
+      "message" : "Cannot apply operator `==` on types `int` and `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 1, 8, 10 ],
+      "message" : "Cannot apply operator `!=` on types `bool` and `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 1, 9, 6 ],
+      "message" : "Cannot apply operator `is` on types `int` and `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 10, 1, 10, 13 ],
+      "message" : "Cannot apply operator `is` on types `bool` and `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 11, 1, 11, 11 ],
+      "message" : "Cannot apply operator `+` on types `` and ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 12, 1, 12, 12 ],
+      "message" : "Cannot apply operator `==` on types `` and ``"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_expr_if.py b/src/test/data/pa2/sample/bad_expr_if.py
new file mode 100644
index 0000000..4ae5fbe
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_if.py
@@ -0,0 +1,2 @@
+x: int = 0
+x = "Hello" if 2 > 3 else 3
diff --git a/src/test/data/pa2/sample/bad_expr_if.py.ast b/src/test/data/pa2/sample/bad_expr_if.py.ast
new file mode 100644
index 0000000..24d9ed3
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_if.py.ast
@@ -0,0 +1,70 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 28 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 4, 1, 6 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 10, 1, 10 ],
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 2, 1, 2, 27 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 2, 1, 2, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "IfExpr",
+      "location" : [ 2, 5, 2, 27 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 2, 16, 2, 20 ],
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 16, 2, 16 ],
+          "value" : 2
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 20, 2, 20 ],
+          "value" : 3
+        }
+      },
+      "thenExpr" : {
+        "kind" : "StringLiteral",
+        "location" : [ 2, 5, 2, 11 ],
+        "value" : "Hello"
+      },
+      "elseExpr" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 27, 2, 27 ],
+        "value" : 3
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_expr_if.py.ast.typed b/src/test/data/pa2/sample/bad_expr_if.py.ast.typed
new file mode 100644
index 0000000..0da86f1
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_if.py.ast.typed
@@ -0,0 +1,107 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 28 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 4, 1, 6 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 10, 1, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 2, 1, 2, 27 ],
+    "errorMsg" : "Expected type `int`; got type `object`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 2, 1, 2, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "IfExpr",
+      "location" : [ 2, 5, 2, 27 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 2, 16, 2, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 16, 2, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 2
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 20, 2, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        }
+      },
+      "thenExpr" : {
+        "kind" : "StringLiteral",
+        "location" : [ 2, 5, 2, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      },
+      "elseExpr" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 27, 2, 27 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 2, 1, 2, 27 ],
+      "message" : "Expected type `int`; got type `object`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_expr_unary.py b/src/test/data/pa2/sample/bad_expr_unary.py
new file mode 100644
index 0000000..0b113ac
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_unary.py
@@ -0,0 +1,4 @@
+not "Bad"
+-True
+-None
+not []
diff --git a/src/test/data/pa2/sample/bad_expr_unary.py.ast b/src/test/data/pa2/sample/bad_expr_unary.py.ast
new file mode 100644
index 0000000..7632c06
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_unary.py.ast
@@ -0,0 +1,62 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 7 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 9 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 1, 1, 1, 9 ],
+      "operator" : "not",
+      "operand" : {
+        "kind" : "StringLiteral",
+        "location" : [ 1, 5, 1, 9 ],
+        "value" : "Bad"
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 5 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 2, 1, 2, 5 ],
+      "operator" : "-",
+      "operand" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 2, 2, 5 ],
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 5 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 3, 1, 3, 5 ],
+      "operator" : "-",
+      "operand" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 3, 2, 3, 5 ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 6 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 4, 1, 4, 6 ],
+      "operator" : "not",
+      "operand" : {
+        "kind" : "ListExpr",
+        "location" : [ 4, 5, 4, 6 ],
+        "elements" : [ ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_expr_unary.py.ast.typed b/src/test/data/pa2/sample/bad_expr_unary.py.ast.typed
new file mode 100644
index 0000000..f366c93
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_expr_unary.py.ast.typed
@@ -0,0 +1,114 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 7 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 9 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 1, 1, 1, 9 ],
+      "errorMsg" : "Cannot apply operator `not` on type `str`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "operator" : "not",
+      "operand" : {
+        "kind" : "StringLiteral",
+        "location" : [ 1, 5, 1, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Bad"
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 5 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 2, 1, 2, 5 ],
+      "errorMsg" : "Cannot apply operator `-` on type `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "operator" : "-",
+      "operand" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 2, 2, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 5 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 3, 1, 3, 5 ],
+      "errorMsg" : "Cannot apply operator `-` on type ``",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "operator" : "-",
+      "operand" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 3, 2, 3, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 6 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 4, 1, 4, 6 ],
+      "errorMsg" : "Cannot apply operator `not` on type ``",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "operator" : "not",
+      "operand" : {
+        "kind" : "ListExpr",
+        "location" : [ 4, 5, 4, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        },
+        "elements" : [ ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 1, 1, 1, 9 ],
+      "message" : "Cannot apply operator `not` on type `str`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 2, 1, 2, 5 ],
+      "message" : "Cannot apply operator `-` on type `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 3, 1, 3, 5 ],
+      "message" : "Cannot apply operator `-` on type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 4, 1, 4, 6 ],
+      "message" : "Cannot apply operator `not` on type ``"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_func_def_call.py b/src/test/data/pa2/sample/bad_func_def_call.py
new file mode 100644
index 0000000..a929805
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_func_def_call.py
@@ -0,0 +1,13 @@
+def foo(x:str, y:bool) -> int:
+    return bar()
+
+def bar() -> int:
+    return 1
+
+# All of the below are bad calls
+foo("Hello")
+foo("Hello", False, 3)
+foo("Hello", 3)
+foo(1, "Hello")
+baz()
+
diff --git a/src/test/data/pa2/sample/bad_func_def_call.py.ast b/src/test/data/pa2/sample/bad_func_def_call.py.ast
new file mode 100644
index 0000000..64c0e9d
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_func_def_call.py.ast
@@ -0,0 +1,187 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 6 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 18, 1, 21 ],
+        "className" : "bool"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 27, 1, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 16 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 12, 2, 16 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 12, 2, 14 ],
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 14, 4, 16 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 12 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 8, 5, 8, 11 ],
+        "value" : "Hello"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 22 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 1, 9, 22 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 9, 5, 9, 11 ],
+        "value" : "Hello"
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 18 ],
+        "value" : false
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 21, 9, 21 ],
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 1, 10, 15 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 10, 5, 10, 11 ],
+        "value" : "Hello"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 10, 14, 10, 14 ],
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 15 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 5, 11, 5 ],
+        "value" : 1
+      }, {
+        "kind" : "StringLiteral",
+        "location" : [ 11, 8, 11, 14 ],
+        "value" : "Hello"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 3 ],
+        "name" : "baz"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_func_def_call.py.ast.typed b/src/test/data/pa2/sample/bad_func_def_call.py.ast.typed
new file mode 100644
index 0000000..e9dc647
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_func_def_call.py.ast.typed
@@ -0,0 +1,336 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 6 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 18, 1, 21 ],
+        "className" : "bool"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 27, 1, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 16 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 12, 2, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 12, 2, 14 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 14, 4, 16 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 12 ],
+      "errorMsg" : "Expected 2 arguments; got 1",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 8, 5, 8, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 22 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 1, 9, 22 ],
+      "errorMsg" : "Expected 2 arguments; got 3",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 9, 5, 9, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 21, 9, 21 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 1, 10, 15 ],
+      "errorMsg" : "Expected type `bool`; got type `int` in parameter 1",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 10, 5, 10, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 10, 14, 10, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 15 ],
+      "errorMsg" : "Expected type `str`; got type `int` in parameter 0",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 5, 11, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "StringLiteral",
+        "location" : [ 11, 8, 11, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 5 ],
+      "errorMsg" : "Not a function or class: baz",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 3 ],
+        "name" : "baz"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 8, 1, 8, 12 ],
+      "message" : "Expected 2 arguments; got 1"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 1, 9, 22 ],
+      "message" : "Expected 2 arguments; got 3"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 10, 1, 10, 15 ],
+      "message" : "Expected type `bool`; got type `int` in parameter 1"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 11, 1, 11, 15 ],
+      "message" : "Expected type `str`; got type `int` in parameter 0"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 12, 1, 12, 5 ],
+      "message" : "Not a function or class: baz"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_func_def_return.py b/src/test/data/pa2/sample/bad_func_def_return.py
new file mode 100644
index 0000000..efccffb
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_func_def_return.py
@@ -0,0 +1,10 @@
+def foo(x:str, y:bool) -> int:
+    return None
+
+def bar() -> bool:
+    return 1
+
+def baz() -> str:
+    return
+
+foo("Hello", False)
diff --git a/src/test/data/pa2/sample/bad_func_def_return.py.ast b/src/test/data/pa2/sample/bad_func_def_return.py.ast
new file mode 100644
index 0000000..e7aaa31
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_func_def_return.py.ast
@@ -0,0 +1,125 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 20 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 18, 1, 21 ],
+        "className" : "bool"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 27, 1, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 15 ],
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 2, 12, 2, 15 ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 14, 4, 17 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 7, 1, 8, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 7 ],
+      "name" : "baz"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 7, 14, 7, 16 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 8, 5, 8, 10 ],
+      "value" : null
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 1, 10, 19 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 10, 5, 10, 11 ],
+        "value" : "Hello"
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 10, 14, 10, 18 ],
+        "value" : false
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_func_def_return.py.ast.typed b/src/test/data/pa2/sample/bad_func_def_return.py.ast.typed
new file mode 100644
index 0000000..8dafad8
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_func_def_return.py.ast.typed
@@ -0,0 +1,174 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 20 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 18, 1, 21 ],
+        "className" : "bool"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 27, 1, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 15 ],
+      "errorMsg" : "Expected type `int`; got type ``",
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 2, 12, 2, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        }
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 14, 4, 17 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "errorMsg" : "Expected type `bool`; got type `int`",
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 7, 1, 8, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 7 ],
+      "name" : "baz"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 7, 14, 7, 16 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 8, 5, 8, 10 ],
+      "errorMsg" : "Expected type `str`; got `None`",
+      "value" : null
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 1, 10, 19 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 10, 5, 10, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 10, 14, 10, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 2, 5, 2, 15 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 5, 5, 5, 12 ],
+      "message" : "Expected type `bool`; got type `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 5, 8, 10 ],
+      "message" : "Expected type `str`; got `None`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_list_assign.py b/src/test/data/pa2/sample/bad_list_assign.py
new file mode 100644
index 0000000..f85c242
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_list_assign.py
@@ -0,0 +1,6 @@
+x:[int] = None
+y:[object] = None
+
+x = [1, 2, 3]
+y = x
+y = [1]
diff --git a/src/test/data/pa2/sample/bad_list_assign.py.ast b/src/test/data/pa2/sample/bad_list_assign.py.ast
new file mode 100644
index 0000000..5fa5dd5
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_list_assign.py.ast
@@ -0,0 +1,116 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 8 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 10 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 10 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 9 ],
+          "className" : "object"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 14, 2, 17 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 4, 5, 4, 13 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 6, 4, 6 ],
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 9, 4, 9 ],
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 12, 4, 12 ],
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "name" : "x"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 7 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 6, 6, 6 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_list_assign.py.ast.typed b/src/test/data/pa2/sample/bad_list_assign.py.ast.typed
new file mode 100644
index 0000000..b07e2b3
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_list_assign.py.ast.typed
@@ -0,0 +1,192 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 8 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 10 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 10 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 9 ],
+          "className" : "object"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 14, 2, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 4, 5, 4, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 6, 4, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 9, 4, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 12, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "errorMsg" : "Expected type `[object]`; got type `[int]`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        }
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 7 ],
+    "errorMsg" : "Expected type `[object]`; got type `[int]`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        }
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 7 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 6, 6, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 5 ],
+      "message" : "Expected type `[object]`; got type `[int]`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 7 ],
+      "message" : "Expected type `[object]`; got type `[int]`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_list_index.py b/src/test/data/pa2/sample/bad_list_index.py
new file mode 100644
index 0000000..7b0c708
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_list_index.py
@@ -0,0 +1,7 @@
+x:[int] = None
+
+x = [1, 2, 3]
+x[True]   # Bad
+False[0]  # Bad
+[][0]     # Bad
+x[True] = x[False] = 1
diff --git a/src/test/data/pa2/sample/bad_list_index.py.ast b/src/test/data/pa2/sample/bad_list_index.py.ast
new file mode 100644
index 0000000..b805e51
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_list_index.py.ast
@@ -0,0 +1,147 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 23 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 3, 1, 3, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 3, 5, 3, 13 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 6, 3, 6 ],
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 9, 3, 9 ],
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 12, 3, 12 ],
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 7 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 4, 1, 4, 7 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 4, 3, 4, 6 ],
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 8 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 5, 1, 5, 8 ],
+      "list" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 1, 5, 5 ],
+        "value" : false
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 7, 5, 7 ],
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 5 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 6, 1, 6, 5 ],
+      "list" : {
+        "kind" : "ListExpr",
+        "location" : [ 6, 1, 6, 2 ],
+        "elements" : [ ]
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 4, 6, 4 ],
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 22 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 1, 7, 7 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 3, 7, 6 ],
+        "value" : true
+      }
+    }, {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 11, 7, 18 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 11, 7, 11 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 13, 7, 17 ],
+        "value" : false
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 7, 22, 7, 22 ],
+      "value" : 1
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_list_index.py.ast.typed b/src/test/data/pa2/sample/bad_list_index.py.ast.typed
new file mode 100644
index 0000000..fa390f3
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_list_index.py.ast.typed
@@ -0,0 +1,275 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 23 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 3, 1, 3, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 3, 5, 3, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 6, 3, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 9, 3, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 12, 3, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 7 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 4, 1, 4, 7 ],
+      "errorMsg" : "Index is of non-integer type `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 4, 3, 4, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 8 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 5, 1, 5, 8 ],
+      "errorMsg" : "Cannot index into type `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "list" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 7, 5, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 5 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 6, 1, 6, 5 ],
+      "errorMsg" : "Cannot index into type ``",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "list" : {
+        "kind" : "ListExpr",
+        "location" : [ 6, 1, 6, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : ""
+        },
+        "elements" : [ ]
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 4, 6, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 22 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 1, 7, 7 ],
+      "errorMsg" : "Index is of non-integer type `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 3, 7, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 11, 7, 18 ],
+      "errorMsg" : "Index is of non-integer type `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 11, 7, 11 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 13, 7, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 7, 22, 7, 22 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 4, 1, 4, 7 ],
+      "message" : "Index is of non-integer type `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 8 ],
+      "message" : "Cannot index into type `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 5 ],
+      "message" : "Cannot index into type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 1, 7, 7 ],
+      "message" : "Index is of non-integer type `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 11, 7, 18 ],
+      "message" : "Index is of non-integer type `bool`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_local_assign.py b/src/test/data/pa2/sample/bad_local_assign.py
new file mode 100644
index 0000000..77f3420
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_local_assign.py
@@ -0,0 +1,23 @@
+x:int = 1
+y:int = 2
+z:int = 3
+
+def foo(x:int) -> object:
+    y:int = 4  # OK
+    global z   # OK
+
+    def qux() -> int: 
+        y = 1  # Bad, nonlocal not declared
+        return 0
+
+    z = 1 # OK
+
+    pass
+
+def bar(x:int) -> int: 
+    z = 1 # Bad, global not declared
+    return x
+
+
+foo(1)
+
diff --git a/src/test/data/pa2/sample/bad_local_assign.py.ast b/src/test/data/pa2/sample/bad_local_assign.py.ast
new file mode 100644
index 0000000..ffac6b5
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_local_assign.py.ast
@@ -0,0 +1,253 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 22, 7 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 9 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 15, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 5, 9, 5, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 11, 5, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 19, 5, 24 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 4
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 7, 5, 7, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 12, 7, 12 ],
+        "name" : "z"
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 11, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "qux"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 18, 9, 20 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 10, 9, 10, 13 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 10, 9, 10, 9 ],
+          "name" : "y"
+        } ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 10, 13, 10, 13 ],
+          "value" : 1
+        }
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 11, 9, 11, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 16, 11, 16 ],
+          "value" : 0
+        }
+      } ]
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 13, 5, 13, 9 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 13, 5, 13, 5 ],
+        "name" : "z"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 9, 13, 9 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 17, 1, 19, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 17, 5, 17, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 17, 9, 17, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 9, 17, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 11, 17, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 17, 19, 17, 21 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 18, 5, 18, 9 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 18, 5, 18, 5 ],
+        "name" : "z"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 18, 9, 18, 9 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 19, 5, 19, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 12, 19, 12 ],
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 22, 1, 22, 6 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 22, 1, 22, 6 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 1, 22, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 22, 5, 22, 5 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_local_assign.py.ast.typed b/src/test/data/pa2/sample/bad_local_assign.py.ast.typed
new file mode 100644
index 0000000..ec39de4
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_local_assign.py.ast.typed
@@ -0,0 +1,330 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 22, 7 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 2
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 3
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 15, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 5, 9, 5, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 11, 5, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 19, 5, 24 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 4
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 7, 5, 7, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 12, 7, 12 ],
+        "name" : "z"
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 11, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "qux"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 18, 9, 20 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 10, 9, 10, 13 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 10, 9, 10, 9 ],
+          "errorMsg" : "Cannot assign to variable that is not explicitly declared in this scope: y",
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        } ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 10, 13, 10, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 11, 9, 11, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 16, 11, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      } ]
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 13, 5, 13, 9 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 13, 5, 13, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "z"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 9, 13, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 17, 1, 19, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 17, 5, 17, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 17, 9, 17, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 9, 17, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 11, 17, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 17, 19, 17, 21 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 18, 5, 18, 9 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 18, 5, 18, 5 ],
+        "errorMsg" : "Cannot assign to variable that is not explicitly declared in this scope: z",
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "z"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 18, 9, 18, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 19, 5, 19, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 12, 19, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 22, 1, 22, 6 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 22, 1, 22, 6 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 1, 22, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 22, 5, 22, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 10, 9, 10, 9 ],
+      "message" : "Cannot assign to variable that is not explicitly declared in this scope: y"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 18, 5, 18, 5 ],
+      "message" : "Cannot assign to variable that is not explicitly declared in this scope: z"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_none_assign.py b/src/test/data/pa2/sample/bad_none_assign.py
new file mode 100644
index 0000000..fc0ec3f
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_none_assign.py
@@ -0,0 +1,14 @@
+class A(object):
+    x:int = 1
+
+y:[bool] = None
+z:str = ""
+a:A = None
+
+a = A()
+
+# Cannot assign None to integer/bool/str types
+z = None
+a.x = None
+y[0] = None
+
diff --git a/src/test/data/pa2/sample/bad_none_assign.py.ast b/src/test/data/pa2/sample/bad_none_assign.py.ast
new file mode 100644
index 0000000..a0a1246
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_none_assign.py.ast
@@ -0,0 +1,187 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 12 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 4, 3, 4, 8 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 4, 4, 7 ],
+          "className" : "bool"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 12, 4, 15 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 3, 5, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 5, 9, 5, 10 ],
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 6, 1, 6, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 6, 1, 6, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 3, 6, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 6, 7, 6, 10 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 5, 8, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 5, 8, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 11, 1, 11, 1 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 5, 11, 8 ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 12, 1, 12, 10 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 12, 1, 12, 3 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 3, 12, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 11 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 13, 1, 13, 4 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "y"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 3, 13, 3 ],
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 8, 13, 11 ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_none_assign.py.ast.typed b/src/test/data/pa2/sample/bad_none_assign.py.ast.typed
new file mode 100644
index 0000000..2edc3c2
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_none_assign.py.ast.typed
@@ -0,0 +1,265 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 12 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 4, 3, 4, 8 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 4, 4, 7 ],
+          "className" : "bool"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 12, 4, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 3, 5, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 5, 9, 5, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 6, 1, 6, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 6, 1, 6, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 3, 6, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 6, 7, 6, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 5, 8, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 5, 8, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 8 ],
+    "errorMsg" : "Expected type `str`; got type ``",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 11, 1, 11, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 5, 11, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 12, 1, 12, 10 ],
+    "errorMsg" : "Expected type `int`; got type ``",
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 12, 1, 12, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "A"
+        },
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 3, 12, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 11 ],
+    "errorMsg" : "Expected type `bool`; got type ``",
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 13, 1, 13, 4 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          }
+        },
+        "name" : "y"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 3, 13, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 8, 13, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 11, 1, 11, 8 ],
+      "message" : "Expected type `str`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 12, 1, 12, 10 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 13, 1, 13, 11 ],
+      "message" : "Expected type `bool`; got type ``"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_nonlocal_global.py b/src/test/data/pa2/sample/bad_nonlocal_global.py
new file mode 100644
index 0000000..98eea5c
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_nonlocal_global.py
@@ -0,0 +1,25 @@
+x:int = 1
+y:int = 2
+z:int = 3
+
+def foo() -> object:
+    global x # OK
+    nonlocal y # No such nonlocal var
+    global w # No such global var
+    global int # No such global var
+
+    z:bool = True # OK
+
+    def bar() -> object:
+        global x # OK
+        nonlocal z # OK
+        nonlocal y # No such nonlocal var
+        global foo # No such global var
+        nonlocal bar # No such nonlocal var
+
+        pass
+
+    bar()
+
+foo()
+
diff --git a/src/test/data/pa2/sample/bad_nonlocal_global.py.ast b/src/test/data/pa2/sample/bad_nonlocal_global.py.ast
new file mode 100644
index 0000000..dce287d
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_nonlocal_global.py.ast
@@ -0,0 +1,229 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 24, 6 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 9 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 22, 10 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 14, 5, 19 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "GlobalDecl",
+      "location" : [ 6, 5, 6, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 12, 6, 12 ],
+        "name" : "x"
+      }
+    }, {
+      "kind" : "NonLocalDecl",
+      "location" : [ 7, 5, 7, 14 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 14, 7, 14 ],
+        "name" : "y"
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 8, 5, 8, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 12, 8, 12 ],
+        "name" : "w"
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 9, 5, 9, 14 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 12, 9, 14 ],
+        "name" : "int"
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 11, 5, 11, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 11, 5, 11, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 5, 11, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 11, 7, 11, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 11, 14, 11, 17 ],
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 20, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 18, 13, 23 ],
+        "className" : "object"
+      },
+      "declarations" : [ {
+        "kind" : "GlobalDecl",
+        "location" : [ 14, 9, 14, 16 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 16, 14, 16 ],
+          "name" : "x"
+        }
+      }, {
+        "kind" : "NonLocalDecl",
+        "location" : [ 15, 9, 15, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 18, 15, 18 ],
+          "name" : "z"
+        }
+      }, {
+        "kind" : "NonLocalDecl",
+        "location" : [ 16, 9, 16, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 18, 16, 18 ],
+          "name" : "y"
+        }
+      }, {
+        "kind" : "GlobalDecl",
+        "location" : [ 17, 9, 17, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 16, 17, 18 ],
+          "name" : "foo"
+        }
+      }, {
+        "kind" : "NonLocalDecl",
+        "location" : [ 18, 9, 18, 20 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 18, 18, 20 ],
+          "name" : "bar"
+        }
+      } ],
+      "statements" : [ ]
+    } ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 22, 5, 22, 9 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 22, 5, 22, 9 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 22, 5, 22, 7 ],
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 24, 1, 24, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 24, 1, 24, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 24, 1, 24, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_nonlocal_global.py.ast.typed b/src/test/data/pa2/sample/bad_nonlocal_global.py.ast.typed
new file mode 100644
index 0000000..3b80c08
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_nonlocal_global.py.ast.typed
@@ -0,0 +1,259 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 24, 6 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 9 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 22, 10 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 14, 5, 19 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "GlobalDecl",
+      "location" : [ 6, 5, 6, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 12, 6, 12 ],
+        "name" : "x"
+      }
+    }, {
+      "kind" : "NonLocalDecl",
+      "location" : [ 7, 5, 7, 14 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 14, 7, 14 ],
+        "errorMsg" : "Not a nonlocal variable: y",
+        "name" : "y"
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 8, 5, 8, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 12, 8, 12 ],
+        "errorMsg" : "Not a global variable: w",
+        "name" : "w"
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 9, 5, 9, 14 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 12, 9, 14 ],
+        "errorMsg" : "Not a global variable: int",
+        "name" : "int"
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 11, 5, 11, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 11, 5, 11, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 5, 11, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 11, 7, 11, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 11, 14, 11, 17 ],
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 20, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 18, 13, 23 ],
+        "className" : "object"
+      },
+      "declarations" : [ {
+        "kind" : "GlobalDecl",
+        "location" : [ 14, 9, 14, 16 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 16, 14, 16 ],
+          "name" : "x"
+        }
+      }, {
+        "kind" : "NonLocalDecl",
+        "location" : [ 15, 9, 15, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 18, 15, 18 ],
+          "name" : "z"
+        }
+      }, {
+        "kind" : "NonLocalDecl",
+        "location" : [ 16, 9, 16, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 18, 16, 18 ],
+          "errorMsg" : "Not a nonlocal variable: y",
+          "name" : "y"
+        }
+      }, {
+        "kind" : "GlobalDecl",
+        "location" : [ 17, 9, 17, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 16, 17, 18 ],
+          "errorMsg" : "Not a global variable: foo",
+          "name" : "foo"
+        }
+      }, {
+        "kind" : "NonLocalDecl",
+        "location" : [ 18, 9, 18, 20 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 18, 18, 20 ],
+          "errorMsg" : "Not a nonlocal variable: bar",
+          "name" : "bar"
+        }
+      } ],
+      "statements" : [ ]
+    } ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 22, 5, 22, 9 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 22, 5, 22, 9 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 22, 5, 22, 7 ],
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 24, 1, 24, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 24, 1, 24, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 24, 1, 24, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 7, 14, 7, 14 ],
+      "message" : "Not a nonlocal variable: y"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 12, 8, 12 ],
+      "message" : "Not a global variable: w"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 12, 9, 14 ],
+      "message" : "Not a global variable: int"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 16, 18, 16, 18 ],
+      "message" : "Not a nonlocal variable: y"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 17, 16, 17, 18 ],
+      "message" : "Not a global variable: foo"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 18, 18, 18, 20 ],
+      "message" : "Not a nonlocal variable: bar"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_return_missing.py b/src/test/data/pa2/sample/bad_return_missing.py
new file mode 100644
index 0000000..9200f93
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_return_missing.py
@@ -0,0 +1,6 @@
+def foo() -> int:
+    if True:
+        return 1
+    # Bad: all paths MUST return int
+
+foo()
diff --git a/src/test/data/pa2/sample/bad_return_missing.py.ast b/src/test/data/pa2/sample/bad_return_missing.py.ast
new file mode 100644
index 0000000..8efc035
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_return_missing.py.ast
@@ -0,0 +1,58 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 6 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 6, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 14, 1, 16 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "IfStmt",
+      "location" : [ 2, 5, 6, 0 ],
+      "condition" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 8, 2, 11 ],
+        "value" : true
+      },
+      "thenBody" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 16, 3, 16 ],
+          "value" : 1
+        }
+      } ],
+      "elseBody" : [ ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_return_missing.py.ast.typed b/src/test/data/pa2/sample/bad_return_missing.py.ast.typed
new file mode 100644
index 0000000..627d4f3
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_return_missing.py.ast.typed
@@ -0,0 +1,63 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 6 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 6, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "errorMsg" : "All paths in this function/method must have a return statement: foo",
+      "name" : "foo"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 14, 1, 16 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "IfStmt",
+      "location" : [ 2, 5, 6, 0 ],
+      "condition" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 8, 2, 11 ],
+        "value" : true
+      },
+      "thenBody" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 16, 3, 16 ],
+          "value" : 1
+        }
+      } ],
+      "elseBody" : [ ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 5 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 5 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 1, 5, 1, 7 ],
+      "message" : "All paths in this function/method must have a return statement: foo"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_return_top.py b/src/test/data/pa2/sample/bad_return_top.py
new file mode 100644
index 0000000..ca0d0e0
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_return_top.py
@@ -0,0 +1,3 @@
+x:int = 0
+
+return x
diff --git a/src/test/data/pa2/sample/bad_return_top.py.ast b/src/test/data/pa2/sample/bad_return_top.py.ast
new file mode 100644
index 0000000..992907a
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_return_top.py.ast
@@ -0,0 +1,41 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ReturnStmt",
+    "location" : [ 3, 1, 3, 8 ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 8, 3, 8 ],
+      "name" : "x"
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_return_top.py.ast.typed b/src/test/data/pa2/sample/bad_return_top.py.ast.typed
new file mode 100644
index 0000000..56df1de
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_return_top.py.ast.typed
@@ -0,0 +1,50 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ReturnStmt",
+    "location" : [ 3, 1, 3, 8 ],
+    "errorMsg" : "Return statement cannot appear at the top level",
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 8, 3, 8 ],
+      "name" : "x"
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 3, 1, 3, 8 ],
+      "message" : "Return statement cannot appear at the top level"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_shadow_local.py b/src/test/data/pa2/sample/bad_shadow_local.py
new file mode 100644
index 0000000..9fc916b
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_shadow_local.py
@@ -0,0 +1,14 @@
+class A(object):
+    x:int = 1
+
+def foo(x:int, bool:str) -> object: # Second param uses an invalid name
+    y:int = 4       # OK
+    A:int = 5       # Invalid name
+    object:str = "" # Invalid name
+
+    def str() -> bool: # Invalid name
+        return False
+
+    pass
+
+pass
diff --git a/src/test/data/pa2/sample/bad_shadow_local.py.ast b/src/test/data/pa2/sample/bad_shadow_local.py.ast
new file mode 100644
index 0000000..cff93dc
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_shadow_local.py.ast
@@ -0,0 +1,179 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 14, 5 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 12, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 4, 9, 4, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 11, 4, 13 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 4, 16, 4, 23 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 16, 4, 19 ],
+        "name" : "bool"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 21, 4, 23 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 29, 4, 34 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 13, 5, 13 ],
+        "value" : 4
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "A"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 5
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 19 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 14 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 10 ],
+          "name" : "object"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 12, 7, 14 ],
+          "className" : "str"
+        }
+      },
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 7, 18, 7, 19 ],
+        "value" : ""
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 10, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "str"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 18, 9, 21 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 10, 9, 10, 20 ],
+        "value" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 10, 16, 10, 20 ],
+          "value" : false
+        }
+      } ]
+    } ],
+    "statements" : [ ]
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_shadow_local.py.ast.typed b/src/test/data/pa2/sample/bad_shadow_local.py.ast.typed
new file mode 100644
index 0000000..3cc9b9b
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_shadow_local.py.ast.typed
@@ -0,0 +1,199 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 14, 5 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 12, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 4, 9, 4, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 11, 4, 13 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 4, 16, 4, 23 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 16, 4, 19 ],
+        "errorMsg" : "Cannot shadow class name: bool",
+        "name" : "bool"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 21, 4, 23 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 29, 4, 34 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 13, 5, 13 ],
+        "value" : 4
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "errorMsg" : "Cannot shadow class name: A",
+          "name" : "A"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 5
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 7, 5, 7, 19 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 7, 5, 7, 14 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 10 ],
+          "errorMsg" : "Cannot shadow class name: object",
+          "name" : "object"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 12, 7, 14 ],
+          "className" : "str"
+        }
+      },
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 7, 18, 7, 19 ],
+        "value" : ""
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 10, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "errorMsg" : "Cannot shadow class name: str",
+        "name" : "str"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 18, 9, 21 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 10, 9, 10, 20 ],
+        "value" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 10, 16, 10, 20 ],
+          "value" : false
+        }
+      } ]
+    } ],
+    "statements" : [ ]
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 4, 16, 4, 19 ],
+      "message" : "Cannot shadow class name: bool"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 5, 6, 5 ],
+      "message" : "Cannot shadow class name: A"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 5, 7, 10 ],
+      "message" : "Cannot shadow class name: object"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 9, 9, 11 ],
+      "message" : "Cannot shadow class name: str"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_shadow_local_2.py b/src/test/data/pa2/sample/bad_shadow_local_2.py
new file mode 100644
index 0000000..67a327e
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_shadow_local_2.py
@@ -0,0 +1,8 @@
+def foo(x:int) -> object: 
+    A:int = 5       # Invalid name
+    pass
+
+class A(object):
+    x:int = 1
+
+pass
diff --git a/src/test/data/pa2/sample/bad_shadow_local_2.py.ast b/src/test/data/pa2/sample/bad_shadow_local_2.py.ast
new file mode 100644
index 0000000..5eb5b2e
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_shadow_local_2.py.ast
@@ -0,0 +1,98 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 5 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 3, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 19, 1, 24 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "A"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 5
+      }
+    } ],
+    "statements" : [ ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 5, 1, 6, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 7, 5, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 9, 5, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_shadow_local_2.py.ast.typed b/src/test/data/pa2/sample/bad_shadow_local_2.py.ast.typed
new file mode 100644
index 0000000..ff6ef1b
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_shadow_local_2.py.ast.typed
@@ -0,0 +1,103 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 5 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 3, 9 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 19, 1, 24 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "errorMsg" : "Cannot shadow class name: A",
+          "name" : "A"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 5
+      }
+    } ],
+    "statements" : [ ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 5, 1, 6, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 7, 5, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 9, 5, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 2, 5, 2, 5 ],
+      "message" : "Cannot shadow class name: A"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_strings.py b/src/test/data/pa2/sample/bad_strings.py
new file mode 100644
index 0000000..86e0e16
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_strings.py
@@ -0,0 +1,10 @@
+x:str = "Hello"
+y:str = "World"
+z:str = ""
+
+1 + x
+z = x + 1
+z = x[0] = y
+x[1] = y
+x[True]
+
diff --git a/src/test/data/pa2/sample/bad_strings.py.ast b/src/test/data/pa2/sample/bad_strings.py.ast
new file mode 100644
index 0000000..04473bf
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_strings.py.ast
@@ -0,0 +1,183 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 8 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 1, 9, 1, 15 ],
+      "value" : "Hello"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 15 ],
+      "value" : "World"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 3, 9, 3, 10 ],
+      "value" : ""
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 5, 1, 5, 5 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 1, 5, 1 ],
+        "value" : 1
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 5, 5, 5 ],
+        "name" : "x"
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 9 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 6, 5, 6, 9 ],
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 5, 6, 5 ],
+        "name" : "x"
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "value" : 1
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 12 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "name" : "z"
+    }, {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 5, 7, 8 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 5 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 7, 7, 7 ],
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 12, 7, 12 ],
+      "name" : "y"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 8, 1, 8, 4 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 3, 8, 3 ],
+        "value" : 1
+      }
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 8, 8, 8 ],
+      "name" : "y"
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 7 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 9, 1, 9, 7 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 3, 9, 6 ],
+        "value" : true
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_strings.py.ast.typed b/src/test/data/pa2/sample/bad_strings.py.ast.typed
new file mode 100644
index 0000000..f6f2fbe
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_strings.py.ast.typed
@@ -0,0 +1,301 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 8 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 1, 9, 1, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "Hello"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "World"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 3, 9, 3, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 5, 1, 5, 5 ],
+      "errorMsg" : "Cannot apply operator `+` on types `int` and `str`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 1, 5, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 5, 5, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 9 ],
+    "errorMsg" : "Expected type `str`; got type `int`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 6, 5, 6, 9 ],
+      "errorMsg" : "Cannot apply operator `+` on types `str` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 5, 6, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 12 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    }, {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 5, 7, 8 ],
+      "errorMsg" : "`str` is not a list type",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 7, 7, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 12, 7, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "y"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 8, 1, 8, 4 ],
+      "errorMsg" : "`str` is not a list type",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 3, 8, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 8, 8, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "y"
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 7 ],
+    "expr" : {
+      "kind" : "IndexExpr",
+      "location" : [ 9, 1, 9, 7 ],
+      "errorMsg" : "Index is of non-integer type `bool`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 3, 9, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 5 ],
+      "message" : "Cannot apply operator `+` on types `int` and `str`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 5, 6, 9 ],
+      "message" : "Cannot apply operator `+` on types `str` and `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 9 ],
+      "message" : "Expected type `str`; got type `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 5, 7, 8 ],
+      "message" : "`str` is not a list type"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 1, 8, 4 ],
+      "message" : "`str` is not a list type"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 9, 1, 9, 7 ],
+      "message" : "Index is of non-integer type `bool`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_type_annotation.py b/src/test/data/pa2/sample/bad_type_annotation.py
new file mode 100644
index 0000000..a25abb6
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_type_annotation.py
@@ -0,0 +1,7 @@
+x:A = None
+
+def foo(x:B) -> C:
+    y:D = None
+    return
+
+pass
diff --git a/src/test/data/pa2/sample/bad_type_annotation.py.ast b/src/test/data/pa2/sample/bad_type_annotation.py.ast
new file mode 100644
index 0000000..e42cf91
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_type_annotation.py.ast
@@ -0,0 +1,86 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 5 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 7, 1, 10 ]
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 5, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 3, 9, 3, 11 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 9, 3, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 11, 3, 11 ],
+        "className" : "B"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 17, 3, 17 ],
+      "className" : "C"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 4, 5, 4, 14 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 4, 5, 4, 7 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 7, 4, 7 ],
+          "className" : "D"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 4, 11, 4, 14 ]
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 10 ],
+      "value" : null
+    } ]
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_type_annotation.py.ast.typed b/src/test/data/pa2/sample/bad_type_annotation.py.ast.typed
new file mode 100644
index 0000000..221ad45
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_type_annotation.py.ast.typed
@@ -0,0 +1,106 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 5 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 3 ],
+        "errorMsg" : "Invalid type annotation; there is no class named: A",
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 7, 1, 10 ]
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 5, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 3, 9, 3, 11 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 9, 3, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 11, 3, 11 ],
+        "errorMsg" : "Invalid type annotation; there is no class named: B",
+        "className" : "B"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 17, 3, 17 ],
+      "errorMsg" : "Invalid type annotation; there is no class named: C",
+      "className" : "C"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 4, 5, 4, 14 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 4, 5, 4, 7 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 7, 4, 7 ],
+          "errorMsg" : "Invalid type annotation; there is no class named: D",
+          "className" : "D"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 4, 11, 4, 14 ]
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 10 ],
+      "value" : null
+    } ]
+  } ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 1, 3, 1, 3 ],
+      "message" : "Invalid type annotation; there is no class named: A"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 3, 11, 3, 11 ],
+      "message" : "Invalid type annotation; there is no class named: B"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 3, 17, 3, 17 ],
+      "message" : "Invalid type annotation; there is no class named: C"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 4, 7, 4, 7 ],
+      "message" : "Invalid type annotation; there is no class named: D"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_type_id.py b/src/test/data/pa2/sample/bad_type_id.py
new file mode 100644
index 0000000..0f931fb
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_type_id.py
@@ -0,0 +1 @@
+x - 1
diff --git a/src/test/data/pa2/sample/bad_type_id.py.ast b/src/test/data/pa2/sample/bad_type_id.py.ast
new file mode 100644
index 0000000..ff5c46d
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_type_id.py.ast
@@ -0,0 +1,29 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 6 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 5 ],
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "operator" : "-",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 5, 1, 5 ],
+        "value" : 1
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_type_id.py.ast.typed b/src/test/data/pa2/sample/bad_type_id.py.ast.typed
new file mode 100644
index 0000000..5200116
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_type_id.py.ast.typed
@@ -0,0 +1,51 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 6 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 5 ],
+      "errorMsg" : "Cannot apply operator `-` on types `object` and `int`",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "errorMsg" : "Not a variable: x",
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "name" : "x"
+      },
+      "operator" : "-",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 5, 1, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 1, 1, 1, 1 ],
+      "message" : "Not a variable: x"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 1, 1, 1, 5 ],
+      "message" : "Cannot apply operator `-` on types `object` and `int`"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_var_assign.py b/src/test/data/pa2/sample/bad_var_assign.py
new file mode 100644
index 0000000..a383775
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_var_assign.py
@@ -0,0 +1,8 @@
+x:int = 1
+y:bool = True
+
+x = False
+y = 2
+z = 3
+x = z = 4
+x = z = None
diff --git a/src/test/data/pa2/sample/bad_var_assign.py.ast b/src/test/data/pa2/sample/bad_var_assign.py.ast
new file mode 100644
index 0000000..6dabcbd
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_var_assign.py.ast
@@ -0,0 +1,127 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 13 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 6 ],
+        "className" : "bool"
+      }
+    },
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 2, 10, 2, 13 ],
+      "value" : true
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 9 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 4, 5, 4, 9 ],
+      "value" : false
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 5, 5, 5 ],
+      "value" : 2
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 5 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 5, 6, 5 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 9 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 5 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 7, 9, 7, 9 ],
+      "value" : 4
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 5 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 8, 9, 8, 12 ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/bad_var_assign.py.ast.typed b/src/test/data/pa2/sample/bad_var_assign.py.ast.typed
new file mode 100644
index 0000000..d8217b8
--- /dev/null
+++ b/src/test/data/pa2/sample/bad_var_assign.py.ast.typed
@@ -0,0 +1,213 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 13 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 6 ],
+        "className" : "bool"
+      }
+    },
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 2, 10, 2, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : true
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 9 ],
+    "errorMsg" : "Expected type `int`; got type `bool`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 4, 5, 4, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : false
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 5 ],
+    "errorMsg" : "Expected type `bool`; got type `int`",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 5, 5, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 2
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 5 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "errorMsg" : "Not a variable: z",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 5, 6, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 3
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 9 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 5 ],
+      "errorMsg" : "Not a variable: z",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 7, 9, 7, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 4
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "errorMsg" : "Expected type `int`; got type ``",
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 5 ],
+      "errorMsg" : "Not a variable: z",
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 8, 9, 8, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ {
+      "kind" : "CompilerError",
+      "location" : [ 4, 1, 4, 9 ],
+      "message" : "Expected type `int`; got type `bool`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 5, 1, 5, 5 ],
+      "message" : "Expected type `bool`; got type `int`"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 6, 1, 6, 1 ],
+      "message" : "Not a variable: z"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 7, 5, 7, 5 ],
+      "message" : "Not a variable: z"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 1, 8, 12 ],
+      "message" : "Expected type `int`; got type ``"
+    }, {
+      "kind" : "CompilerError",
+      "location" : [ 8, 5, 8, 5 ],
+      "message" : "Not a variable: z"
+    } ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_assign.py b/src/test/data/pa2/sample/class_def_assign.py
new file mode 100644
index 0000000..44459ff
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_assign.py
@@ -0,0 +1,18 @@
+class A(object):
+    x:int = 1
+
+class B(A):
+    def __init__(self: "B"):
+        pass
+
+class C(B):
+    z:bool = True
+
+a:A = None
+b:B = None
+c:C = None
+
+a = A()
+a = B()
+b = a = c = C()
+c = None
diff --git a/src/test/data/pa2/sample/class_def_assign.py.ast b/src/test/data/pa2/sample/class_def_assign.py.ast
new file mode 100644
index 0000000..92ae3a1
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_assign.py.ast
@@ -0,0 +1,263 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 9 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 18, 5, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 18, 5, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 24, 5, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 28, 5, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 17 ],
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 12, 1, 12, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 12, 1, 12, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 12, 3, 12, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 13, 1, 13, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 13, 1, 13, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 3, 13, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 7, 13, 10 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 16, 1, 16, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 5, 16, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 5, 16, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 15 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 17, 1, 17, 1 ],
+      "name" : "b"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 17, 5, 17, 5 ],
+      "name" : "a"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 17, 9, 17, 9 ],
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 13, 17, 15 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 13, 17, 13 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 18, 1, 18, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 18, 1, 18, 1 ],
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 18, 5, 18, 8 ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_assign.py.ast.typed b/src/test/data/pa2/sample/class_def_assign.py.ast.typed
new file mode 100644
index 0000000..e012a95
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_assign.py.ast.typed
@@ -0,0 +1,323 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 9 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 18, 5, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 18, 5, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 24, 5, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 28, 5, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 12, 1, 12, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 12, 1, 12, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 12, 3, 12, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 13, 1, 13, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 13, 1, 13, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 3, 13, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 7, 13, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 16, 1, 16, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 5, 16, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 5, 16, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 15 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 17, 1, 17, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 17, 5, 17, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 17, 9, 17, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 13, 17, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 13, 17, 13 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 18, 1, 18, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 18, 1, 18, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 18, 5, 18, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_attr.py b/src/test/data/pa2/sample/class_def_attr.py
new file mode 100644
index 0000000..9a5d948
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_attr.py
@@ -0,0 +1,22 @@
+class A(object):
+    x:int = 1
+
+class B(A):
+    def __init__(self: "B"):
+        pass
+
+class C(B):
+    z:bool = True
+
+a:A = None
+b:B = None
+c:C = None
+
+a = A()
+b = B()
+c = C()
+
+a.x = 1
+b.x = a.x
+c.z = a.x == b.x
+
diff --git a/src/test/data/pa2/sample/class_def_attr.py.ast b/src/test/data/pa2/sample/class_def_attr.py.ast
new file mode 100644
index 0000000..b4dcc19
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_attr.py.ast
@@ -0,0 +1,346 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 21, 17 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 18, 5, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 18, 5, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 24, 5, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 28, 5, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 17 ],
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 12, 1, 12, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 12, 1, 12, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 12, 3, 12, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 13, 1, 13, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 13, 1, 13, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 3, 13, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 7, 13, 10 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 16, 1, 16, 1 ],
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 5, 16, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 5, 16, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 17, 1, 17, 1 ],
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 5, 17, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 5, 17, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 19, 1, 19, 7 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 19, 1, 19, 3 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 1 ],
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 3, 19, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 19, 7, 19, 7 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 20, 1, 20, 9 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 20, 1, 20, 3 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 1, 20, 1 ],
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 3, 20, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "MemberExpr",
+      "location" : [ 20, 7, 20, 9 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 7, 20, 7 ],
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 9, 20, 9 ],
+        "name" : "x"
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 21, 1, 21, 16 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 21, 1, 21, 3 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 1, 21, 1 ],
+        "name" : "c"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 3, 21, 3 ],
+        "name" : "z"
+      }
+    } ],
+    "value" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 21, 7, 21, 16 ],
+      "left" : {
+        "kind" : "MemberExpr",
+        "location" : [ 21, 7, 21, 9 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 7, 21, 7 ],
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 9, 21, 9 ],
+          "name" : "x"
+        }
+      },
+      "operator" : "==",
+      "right" : {
+        "kind" : "MemberExpr",
+        "location" : [ 21, 14, 21, 16 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 14, 21, 14 ],
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 16, 21, 16 ],
+          "name" : "x"
+        }
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_attr.py.ast.typed b/src/test/data/pa2/sample/class_def_attr.py.ast.typed
new file mode 100644
index 0000000..600032c
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_attr.py.ast.typed
@@ -0,0 +1,446 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 21, 17 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 18, 5, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 18, 5, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 24, 5, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 28, 5, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 12, 1, 12, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 12, 1, 12, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 12, 3, 12, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 13, 1, 13, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 13, 1, 13, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 3, 13, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 7, 13, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 16, 1, 16, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 5, 16, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 5, 16, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 17, 1, 17, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 5, 17, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 5, 17, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 19, 1, 19, 7 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 19, 1, 19, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "A"
+        },
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 3, 19, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 19, 7, 19, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 20, 1, 20, 9 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 20, 1, 20, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 1, 20, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 3, 20, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "MemberExpr",
+      "location" : [ 20, 7, 20, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 7, 20, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "A"
+        },
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 9, 20, 9 ],
+        "name" : "x"
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 21, 1, 21, 16 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 21, 1, 21, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 1, 21, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "C"
+        },
+        "name" : "c"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 3, 21, 3 ],
+        "name" : "z"
+      }
+    } ],
+    "value" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 21, 7, 21, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "MemberExpr",
+        "location" : [ 21, 7, 21, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 7, 21, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 9, 21, 9 ],
+          "name" : "x"
+        }
+      },
+      "operator" : "==",
+      "right" : {
+        "kind" : "MemberExpr",
+        "location" : [ 21, 14, 21, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 14, 21, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 16, 21, 16 ],
+          "name" : "x"
+        }
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_init.py b/src/test/data/pa2/sample/class_def_init.py
new file mode 100644
index 0000000..733f489
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_init.py
@@ -0,0 +1,17 @@
+class A(object):
+    x:int = 1
+
+class B(A):
+    def __init__(self: "B"):
+        pass
+
+class C(B):
+    z:bool = True
+
+a:A = None
+b:B = None
+c:C = None
+
+a = A()
+b = B()
+c = C()
diff --git a/src/test/data/pa2/sample/class_def_init.py.ast b/src/test/data/pa2/sample/class_def_init.py.ast
new file mode 100644
index 0000000..2cf1bba
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_init.py.ast
@@ -0,0 +1,243 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 17, 8 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 18, 5, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 18, 5, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 24, 5, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 28, 5, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 17 ],
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 12, 1, 12, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 12, 1, 12, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 12, 3, 12, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 13, 1, 13, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 13, 1, 13, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 3, 13, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 7, 13, 10 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 16, 1, 16, 1 ],
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 5, 16, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 5, 16, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 17, 1, 17, 1 ],
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 5, 17, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 5, 17, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_init.py.ast.typed b/src/test/data/pa2/sample/class_def_init.py.ast.typed
new file mode 100644
index 0000000..c2f9d72
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_init.py.ast.typed
@@ -0,0 +1,287 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 17, 8 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 6, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 5, 18, 5, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 18, 5, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 24, 5, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 28, 5, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 7, 8, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 9, 8, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 9, 5, 9, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 9, 5, 9, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 7, 9, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 14, 9, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 12, 1, 12, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 12, 1, 12, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 12, 3, 12, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 12, 7, 12, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 13, 1, 13, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 13, 1, 13, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 3, 13, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 13, 7, 13, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 16, 1, 16, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 5, 16, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 5, 16, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 17, 1, 17, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 5, 17, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 5, 17, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_methods.py b/src/test/data/pa2/sample/class_def_methods.py
new file mode 100644
index 0000000..a8d70f1
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_methods.py
@@ -0,0 +1,28 @@
+class A(object):
+    x:int = 1
+
+    def get_A(self: "A") -> int:
+        return self.x
+
+class B(A):
+    def __init__(self: "B"):
+        pass
+
+class C(B):
+    z:bool = True
+
+    def set_A(self: "C", val: int) -> object:
+        self.x = val
+
+a:A = None
+b:B = None
+c:C = None
+
+a = A()
+b = B()
+c = C()
+
+b.x = a.get_A()
+a.x = b.get_A()
+c.set_A(0)
+
diff --git a/src/test/data/pa2/sample/class_def_methods.py.ast b/src/test/data/pa2/sample/class_def_methods.py.ast
new file mode 100644
index 0000000..2ddc48e
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_methods.py.ast
@@ -0,0 +1,451 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 27, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 13 ],
+        "name" : "get_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 15, 4, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 15, 4, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 21, 4, 23 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 29, 4, 31 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 21 ],
+        "value" : {
+          "kind" : "MemberExpr",
+          "location" : [ 5, 16, 5, 21 ],
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 16, 5, 19 ],
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 21, 5, 21 ],
+            "name" : "x"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 11, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 8, 5, 9, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 8, 18, 8, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 18, 8, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 24, 8, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 28, 8, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 11, 1, 17, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 7, 11, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 9, 11, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 12, 5, 12, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 12, 5, 12, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 12, 7, 12, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 12, 14, 12, 17 ],
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 14, 5, 15, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 9, 14, 13 ],
+        "name" : "set_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 14, 15, 14, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 15, 14, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 21, 14, 23 ],
+          "className" : "C"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 14, 26, 14, 33 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 26, 14, 28 ],
+          "name" : "val"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 31, 14, 33 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 14, 39, 14, 44 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 15, 9, 15, 20 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 15, 9, 15, 14 ],
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 9, 15, 12 ],
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 14, 15, 14 ],
+            "name" : "x"
+          }
+        } ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 18, 15, 20 ],
+          "name" : "val"
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 17, 1, 17, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 17, 1, 17, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 3, 17, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 17, 7, 17, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 18, 1, 18, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 18, 1, 18, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 18, 3, 18, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 18, 7, 18, 10 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 19, 1, 19, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 19, 1, 19, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 19, 3, 19, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 19, 7, 19, 10 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 21, 1, 21, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 21, 1, 21, 1 ],
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 21, 5, 21, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 5, 21, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 22, 1, 22, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 22, 1, 22, 1 ],
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 22, 5, 22, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 5, 22, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 23, 1, 23, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 23, 1, 23, 1 ],
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 23, 5, 23, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 23, 5, 23, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 25, 1, 25, 15 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 25, 1, 25, 3 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 1, 25, 1 ],
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 3, 25, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 25, 7, 25, 15 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 25, 7, 25, 13 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 7, 25, 7 ],
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 9, 25, 13 ],
+          "name" : "get_A"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 26, 1, 26, 15 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 26, 1, 26, 3 ],
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 26, 1, 26, 1 ],
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 26, 3, 26, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 26, 7, 26, 15 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 26, 7, 26, 13 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 7, 26, 7 ],
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 9, 26, 13 ],
+          "name" : "get_A"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 27, 1, 27, 10 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 27, 1, 27, 10 ],
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 27, 1, 27, 7 ],
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 1, 27, 1 ],
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 3, 27, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 27, 9, 27, 9 ],
+        "value" : 0
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/class_def_methods.py.ast.typed b/src/test/data/pa2/sample/class_def_methods.py.ast.typed
new file mode 100644
index 0000000..1f58660
--- /dev/null
+++ b/src/test/data/pa2/sample/class_def_methods.py.ast.typed
@@ -0,0 +1,595 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 27, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 7, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 7, 1, 7 ],
+      "name" : "A"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 9, 1, 14 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 5, 2, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 5, 2, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 7, 2, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 13, 2, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 13 ],
+        "name" : "get_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 15, 4, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 15, 4, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 21, 4, 23 ],
+          "className" : "A"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 29, 4, 31 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 21 ],
+        "value" : {
+          "kind" : "MemberExpr",
+          "location" : [ 5, 16, 5, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 16, 5, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "A"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 21, 5, 21 ],
+            "name" : "x"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 11, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 7, 7, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 9, 7, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 8, 5, 9, 13 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 8, 18, 8, 26 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 18, 8, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 24, 8, 26 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 28, 8, 28 ],
+        "className" : ""
+      },
+      "declarations" : [ ],
+      "statements" : [ ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 11, 1, 17, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 7, 11, 7 ],
+      "name" : "C"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 9, 11, 9 ],
+      "name" : "B"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 12, 5, 12, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 12, 5, 12, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 12, 7, 12, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 12, 14, 12, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 14, 5, 15, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 9, 14, 13 ],
+        "name" : "set_A"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 14, 15, 14, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 15, 14, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 21, 14, 23 ],
+          "className" : "C"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 14, 26, 14, 33 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 26, 14, 28 ],
+          "name" : "val"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 31, 14, 33 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 14, 39, 14, 44 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 15, 9, 15, 20 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 15, 9, 15, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 9, 15, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "C"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 14, 15, 14 ],
+            "name" : "x"
+          }
+        } ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 18, 15, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "val"
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 17, 1, 17, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 17, 1, 17, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 3, 17, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 17, 7, 17, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 18, 1, 18, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 18, 1, 18, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 18, 3, 18, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 18, 7, 18, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 19, 1, 19, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 19, 1, 19, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 19, 3, 19, 3 ],
+        "className" : "C"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 19, 7, 19, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 21, 1, 21, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 21, 1, 21, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 21, 5, 21, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 21, 5, 21, 5 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 22, 1, 22, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 22, 1, 22, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 22, 5, 22, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 5, 22, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 23, 1, 23, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 23, 1, 23, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 23, 5, 23, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "C"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 23, 5, 23, 5 ],
+        "name" : "C"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 25, 1, 25, 15 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 25, 1, 25, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 1, 25, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 3, 25, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 25, 7, 25, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 25, 7, 25, 13 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 7, 25, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 9, 25, 13 ],
+          "name" : "get_A"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 26, 1, 26, 15 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 26, 1, 26, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 26, 1, 26, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "A"
+        },
+        "name" : "a"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 26, 3, 26, 3 ],
+        "name" : "x"
+      }
+    } ],
+    "value" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 26, 7, 26, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 26, 7, 26, 13 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 7, 26, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 9, 26, 13 ],
+          "name" : "get_A"
+        }
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 27, 1, 27, 10 ],
+    "expr" : {
+      "kind" : "MethodCallExpr",
+      "location" : [ 27, 1, 27, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "method" : {
+        "kind" : "MemberExpr",
+        "location" : [ 27, 1, 27, 7 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 1, 27, 1 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "C"
+          },
+          "name" : "c"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 3, 27, 7 ],
+          "name" : "set_A"
+        }
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 27, 9, 27, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/decl_global_forward.py b/src/test/data/pa2/sample/decl_global_forward.py
new file mode 100644
index 0000000..b364535
--- /dev/null
+++ b/src/test/data/pa2/sample/decl_global_forward.py
@@ -0,0 +1,9 @@
+def set_x() -> int:
+    global x
+    x = 1
+    return x
+
+x:int = 0
+
+set_x()
+print(x)
diff --git a/src/test/data/pa2/sample/decl_global_forward.py.ast b/src/test/data/pa2/sample/decl_global_forward.py.ast
new file mode 100644
index 0000000..a450fe6
--- /dev/null
+++ b/src/test/data/pa2/sample/decl_global_forward.py.ast
@@ -0,0 +1,108 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 9 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 4, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 9 ],
+      "name" : "set_x"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 16, 1, 18 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "GlobalDecl",
+      "location" : [ 2, 5, 2, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 12, 2, 12 ],
+        "name" : "x"
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 3, 5, 3, 9 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 3, 5, 3, 5 ],
+        "name" : "x"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 9, 3, 9 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 4, 5, 4, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 12, 4, 12 ],
+        "name" : "x"
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 6, 1, 6, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 6, 1, 6, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 3, 6, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 9, 6, 9 ],
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 7 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 7 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "name" : "set_x"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 1, 9, 8 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 5 ],
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 9, 7, 9, 7 ],
+        "name" : "x"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/decl_global_forward.py.ast.typed b/src/test/data/pa2/sample/decl_global_forward.py.ast.typed
new file mode 100644
index 0000000..4d32ce7
--- /dev/null
+++ b/src/test/data/pa2/sample/decl_global_forward.py.ast.typed
@@ -0,0 +1,155 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 9 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 4, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 9 ],
+      "name" : "set_x"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 16, 1, 18 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "GlobalDecl",
+      "location" : [ 2, 5, 2, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 12, 2, 12 ],
+        "name" : "x"
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 3, 5, 3, 9 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 3, 5, 3, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 9, 3, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 4, 5, 4, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 12, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 6, 1, 6, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 6, 1, 6, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 3, 6, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 9, 6, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 7 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "set_x"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 1, 9, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : ""
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 9, 7, 9, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/decl_nonlocal_forward.py b/src/test/data/pa2/sample/decl_nonlocal_forward.py
new file mode 100644
index 0000000..b1ff307
--- /dev/null
+++ b/src/test/data/pa2/sample/decl_nonlocal_forward.py
@@ -0,0 +1,10 @@
+def outer() -> int:
+    def inner() -> int:
+        nonlocal x
+        x = 1
+        return x
+    x:int = 0
+    inner()
+    return x
+
+print(outer())
diff --git a/src/test/data/pa2/sample/decl_nonlocal_forward.py.ast b/src/test/data/pa2/sample/decl_nonlocal_forward.py.ast
new file mode 100644
index 0000000..1b5f11b
--- /dev/null
+++ b/src/test/data/pa2/sample/decl_nonlocal_forward.py.ast
@@ -0,0 +1,137 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 15 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 8, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 9 ],
+      "name" : "outer"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 16, 1, 18 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 2, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 13 ],
+        "name" : "inner"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 20, 2, 22 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "NonLocalDecl",
+        "location" : [ 3, 9, 3, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 18, 3, 18 ],
+          "name" : "x"
+        }
+      } ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 4, 9, 4, 13 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 9, 4, 9 ],
+          "name" : "x"
+        } ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 13, 4, 13 ],
+          "value" : 1
+        }
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 16, 5, 16 ],
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "value" : 0
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 7, 5, 7, 11 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 7, 5, 7, 11 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 9 ],
+          "name" : "inner"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 8, 5, 8, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 12, 8, 12 ],
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 1, 10, 14 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 5 ],
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 10, 7, 10, 13 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 7, 10, 11 ],
+          "name" : "outer"
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/decl_nonlocal_forward.py.ast.typed b/src/test/data/pa2/sample/decl_nonlocal_forward.py.ast.typed
new file mode 100644
index 0000000..f5781a7
--- /dev/null
+++ b/src/test/data/pa2/sample/decl_nonlocal_forward.py.ast.typed
@@ -0,0 +1,196 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 15 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 8, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 9 ],
+      "name" : "outer"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 16, 1, 18 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "FuncDef",
+      "location" : [ 2, 5, 5, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 13 ],
+        "name" : "inner"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 20, 2, 22 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "NonLocalDecl",
+        "location" : [ 3, 9, 3, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 18, 3, 18 ],
+          "name" : "x"
+        }
+      } ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 4, 9, 4, 13 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 9, 4, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        } ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 13, 4, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 5, 9, 5, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 16, 5, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ]
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 6, 5, 6, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 6, 5, 6, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 5 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 7, 6, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 13, 6, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 7, 5, 7, 11 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 7, 5, 7, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "inner"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 8, 5, 8, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 12, 8, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 10, 1, 10, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 1, 10, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : ""
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 10, 7, 10, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 7, 10, 11 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "outer"
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_binary.py b/src/test/data/pa2/sample/expr_binary.py
new file mode 100644
index 0000000..b35b22d
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_binary.py
@@ -0,0 +1,2 @@
+1 + 2 * 3 > 13 // 3 % 2 or 1 != 1 and False == False
+
diff --git a/src/test/data/pa2/sample/expr_binary.py.ast b/src/test/data/pa2/sample/expr_binary.py.ast
new file mode 100644
index 0000000..3e59d31
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_binary.py.ast
@@ -0,0 +1,109 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 53 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 52 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 52 ],
+      "left" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 1, 1, 23 ],
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 1, 1, 9 ],
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 1, 1, 1 ],
+            "value" : 1
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 1, 5, 1, 9 ],
+            "left" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 5, 1, 5 ],
+              "value" : 2
+            },
+            "operator" : "*",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 9, 1, 9 ],
+              "value" : 3
+            }
+          }
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 13, 1, 23 ],
+          "left" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 1, 13, 1, 19 ],
+            "left" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 13, 1, 14 ],
+              "value" : 13
+            },
+            "operator" : "//",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 19, 1, 19 ],
+              "value" : 3
+            }
+          },
+          "operator" : "%",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 23, 1, 23 ],
+            "value" : 2
+          }
+        }
+      },
+      "operator" : "or",
+      "right" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 28, 1, 52 ],
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 28, 1, 33 ],
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 28, 1, 28 ],
+            "value" : 1
+          },
+          "operator" : "!=",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 33, 1, 33 ],
+            "value" : 1
+          }
+        },
+        "operator" : "and",
+        "right" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 39, 1, 52 ],
+          "left" : {
+            "kind" : "BooleanLiteral",
+            "location" : [ 1, 39, 1, 43 ],
+            "value" : false
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "BooleanLiteral",
+            "location" : [ 1, 48, 1, 52 ],
+            "value" : false
+          }
+        }
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_binary.py.ast.typed b/src/test/data/pa2/sample/expr_binary.py.ast.typed
new file mode 100644
index 0000000..146d277
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_binary.py.ast.typed
@@ -0,0 +1,185 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 53 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 52 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 52 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 1, 1, 23 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 1, 1, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 1, 1, 1 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 1, 5, 1, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 5, 1, 5 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 2
+            },
+            "operator" : "*",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 9, 1, 9 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 3
+            }
+          }
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 13, 1, 23 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 1, 13, 1, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 13, 1, 14 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 13
+            },
+            "operator" : "//",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 1, 19, 1, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 3
+            }
+          },
+          "operator" : "%",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 23, 1, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 2
+          }
+        }
+      },
+      "operator" : "or",
+      "right" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 28, 1, 52 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 28, 1, 33 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 28, 1, 28 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          },
+          "operator" : "!=",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 33, 1, 33 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        },
+        "operator" : "and",
+        "right" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 39, 1, 52 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "BooleanLiteral",
+            "location" : [ 1, 39, 1, 43 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "value" : false
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "BooleanLiteral",
+            "location" : [ 1, 48, 1, 52 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "value" : false
+          }
+        }
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_concat.py b/src/test/data/pa2/sample/expr_concat.py
new file mode 100644
index 0000000..68c41a0
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_concat.py
@@ -0,0 +1,3 @@
+[1, 2] + [3, 4]
+"Hello " + "World"
+[1, 2] + [True]
diff --git a/src/test/data/pa2/sample/expr_concat.py.ast b/src/test/data/pa2/sample/expr_concat.py.ast
new file mode 100644
index 0000000..064862b
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_concat.py.ast
@@ -0,0 +1,93 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 16 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 15 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 15 ],
+      "left" : {
+        "kind" : "ListExpr",
+        "location" : [ 1, 1, 1, 6 ],
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 2, 1, 2 ],
+          "value" : 1
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 5, 1, 5 ],
+          "value" : 2
+        } ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 1, 10, 1, 15 ],
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 11, 1, 11 ],
+          "value" : 3
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 14, 1, 14 ],
+          "value" : 4
+        } ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 18 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 1, 2, 18 ],
+      "left" : {
+        "kind" : "StringLiteral",
+        "location" : [ 2, 1, 2, 8 ],
+        "value" : "Hello "
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "StringLiteral",
+        "location" : [ 2, 12, 2, 18 ],
+        "value" : "World"
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 15 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 15 ],
+      "left" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 1, 3, 6 ],
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 2, 3, 2 ],
+          "value" : 1
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 5, 3, 5 ],
+          "value" : 2
+        } ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 10, 3, 15 ],
+        "elements" : [ {
+          "kind" : "BooleanLiteral",
+          "location" : [ 3, 11, 3, 14 ],
+          "value" : true
+        } ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_concat.py.ast.typed b/src/test/data/pa2/sample/expr_concat.py.ast.typed
new file mode 100644
index 0000000..4c61b0e
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_concat.py.ast.typed
@@ -0,0 +1,175 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 16 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 15 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 15 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "left" : {
+        "kind" : "ListExpr",
+        "location" : [ 1, 1, 1, 6 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 2, 1, 2 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 5, 1, 5 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 2
+        } ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 1, 10, 1, 15 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 11, 1, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 14, 1, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 4
+        } ]
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 18 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 1, 2, 18 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "left" : {
+        "kind" : "StringLiteral",
+        "location" : [ 2, 1, 2, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello "
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "StringLiteral",
+        "location" : [ 2, 12, 2, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "World"
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 15 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 15 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        }
+      },
+      "left" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 1, 3, 6 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 2, 3, 2 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 5, 3, 5 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 2
+        } ]
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 3, 10, 3, 15 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          }
+        },
+        "elements" : [ {
+          "kind" : "BooleanLiteral",
+          "location" : [ 3, 11, 3, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        } ]
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_id.py b/src/test/data/pa2/sample/expr_id.py
new file mode 100644
index 0000000..c6fcd80
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_id.py
@@ -0,0 +1,3 @@
+x:int = 1
+
+x - 1
diff --git a/src/test/data/pa2/sample/expr_id.py.ast b/src/test/data/pa2/sample/expr_id.py.ast
new file mode 100644
index 0000000..0f6ab04
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_id.py.ast
@@ -0,0 +1,51 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 6 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 5 ],
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "x"
+      },
+      "operator" : "-",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 5, 3, 5 ],
+        "value" : 1
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_id.py.ast.typed b/src/test/data/pa2/sample/expr_id.py.ast.typed
new file mode 100644
index 0000000..cdefa39
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_id.py.ast.typed
@@ -0,0 +1,67 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 6 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 3, 1, 3, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      },
+      "operator" : "-",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 5, 3, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_if.py b/src/test/data/pa2/sample/expr_if.py
new file mode 100644
index 0000000..e9e9c26
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_if.py
@@ -0,0 +1 @@
+3 if 1 > 2 else 4
diff --git a/src/test/data/pa2/sample/expr_if.py.ast b/src/test/data/pa2/sample/expr_if.py.ast
new file mode 100644
index 0000000..0ed9a55
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_if.py.ast
@@ -0,0 +1,43 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 18 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 17 ],
+    "expr" : {
+      "kind" : "IfExpr",
+      "location" : [ 1, 1, 1, 17 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 6, 1, 10 ],
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 6, 1, 6 ],
+          "value" : 1
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 10, 1, 10 ],
+          "value" : 2
+        }
+      },
+      "thenExpr" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 1, 1, 1 ],
+        "value" : 3
+      },
+      "elseExpr" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 17, 1, 17 ],
+        "value" : 4
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_if.py.ast.typed b/src/test/data/pa2/sample/expr_if.py.ast.typed
new file mode 100644
index 0000000..3aa7a5f
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_if.py.ast.typed
@@ -0,0 +1,67 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 18 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 17 ],
+    "expr" : {
+      "kind" : "IfExpr",
+      "location" : [ 1, 1, 1, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 6, 1, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 6, 1, 6 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 10, 1, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 2
+        }
+      },
+      "thenExpr" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 1, 1, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      },
+      "elseExpr" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 17, 1, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 4
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_int.py b/src/test/data/pa2/sample/expr_int.py
new file mode 100644
index 0000000..f39d689
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_int.py
@@ -0,0 +1 @@
+6 * 9
diff --git a/src/test/data/pa2/sample/expr_int.py.ast b/src/test/data/pa2/sample/expr_int.py.ast
new file mode 100644
index 0000000..2eb3e50
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_int.py.ast
@@ -0,0 +1,29 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 6 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 5 ],
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 1, 1, 1 ],
+        "value" : 6
+      },
+      "operator" : "*",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 5, 1, 5 ],
+        "value" : 9
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_int.py.ast.typed b/src/test/data/pa2/sample/expr_int.py.ast.typed
new file mode 100644
index 0000000..55a6721
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_int.py.ast.typed
@@ -0,0 +1,41 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 6 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 5 ],
+    "expr" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 1, 1, 1, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 1, 1, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 6
+      },
+      "operator" : "*",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 5, 1, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 9
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_list_index.py b/src/test/data/pa2/sample/expr_list_index.py
new file mode 100644
index 0000000..b9d97e3
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_list_index.py
@@ -0,0 +1,12 @@
+x:[int] = None
+y:int = 0
+z:[bool] = None
+o:object = None
+
+x = [1, 2, 3]
+z = [False, True]
+
+y = x[0]
+x[0] = 1
+z[1] = z[0]
+o = x[1]
diff --git a/src/test/data/pa2/sample/expr_list_index.py.ast b/src/test/data/pa2/sample/expr_list_index.py.ast
new file mode 100644
index 0000000..5cb5c50
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_list_index.py.ast
@@ -0,0 +1,247 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 8 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 7 ],
+          "className" : "bool"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 12, 3, 15 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 12, 4, 15 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 13 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 6, 6, 6 ],
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 12, 6, 12 ],
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 5, 7, 17 ],
+      "elements" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 6, 7, 10 ],
+        "value" : false
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 13, 7, 16 ],
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "IndexExpr",
+      "location" : [ 9, 5, 9, 8 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 5, 9, 5 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 7, 9, 7 ],
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 10, 1, 10, 4 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 10, 3, 10, 3 ],
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 10, 8, 10, 8 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 11 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 11, 1, 11, 4 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "z"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 3, 11, 3 ],
+        "value" : 1
+      }
+    } ],
+    "value" : {
+      "kind" : "IndexExpr",
+      "location" : [ 11, 8, 11, 11 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 8, 11, 8 ],
+        "name" : "z"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 10, 11, 10 ],
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 12, 1, 12, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 12, 1, 12, 1 ],
+      "name" : "o"
+    } ],
+    "value" : {
+      "kind" : "IndexExpr",
+      "location" : [ 12, 5, 12, 8 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 5, 12, 5 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 12, 7, 12, 7 ],
+        "value" : 1
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_list_index.py.ast.typed b/src/test/data/pa2/sample/expr_list_index.py.ast.typed
new file mode 100644
index 0000000..28fbe48
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_list_index.py.ast.typed
@@ -0,0 +1,398 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 9, 2, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 8 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 7 ],
+          "className" : "bool"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 12, 3, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 12, 4, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 6, 6, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 12, 6, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 5, 7, 17 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        }
+      },
+      "elements" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 6, 7, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 13, 7, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "IndexExpr",
+      "location" : [ 9, 5, 9, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 5, 9, 5 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 7, 9, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 10, 1, 10, 4 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 10, 3, 10, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 10, 8, 10, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 11 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 11, 1, 11, 4 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          }
+        },
+        "name" : "z"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 3, 11, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ],
+    "value" : {
+      "kind" : "IndexExpr",
+      "location" : [ 11, 8, 11, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 8, 11, 8 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          }
+        },
+        "name" : "z"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 10, 11, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 12, 1, 12, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 12, 1, 12, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "o"
+    } ],
+    "value" : {
+      "kind" : "IndexExpr",
+      "location" : [ 12, 5, 12, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 5, 12, 5 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 12, 7, 12, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_lists.py b/src/test/data/pa2/sample/expr_lists.py
new file mode 100644
index 0000000..2268a54
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_lists.py
@@ -0,0 +1,12 @@
+x:[int] = None
+y:[object] = None
+z:[bool] = None
+o:object = None
+
+x = [1, 2, 3]
+x = []
+y = [1, True]
+z = [False, True]
+x = None
+o = x
+o = x = [1]
diff --git a/src/test/data/pa2/sample/expr_lists.py.ast b/src/test/data/pa2/sample/expr_lists.py.ast
new file mode 100644
index 0000000..5930b97
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_lists.py.ast
@@ -0,0 +1,233 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 12 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 10 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 10 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 9 ],
+          "className" : "object"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 14, 2, 17 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 8 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 7 ],
+          "className" : "bool"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 12, 3, 15 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 12, 4, 15 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 13 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 6, 6, 6 ],
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 12, 6, 12 ],
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 6 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 5, 7, 6 ],
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 8, 5, 8, 13 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 6, 8, 6 ],
+        "value" : 1
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 9, 8, 12 ],
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 9, 5, 9, 17 ],
+      "elements" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 6, 9, 10 ],
+        "value" : false
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 13, 9, 16 ],
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 10, 1, 10, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 5, 10, 8 ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 5 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 11, 1, 11, 1 ],
+      "name" : "o"
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 5, 11, 5 ],
+      "name" : "x"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 12, 1, 12, 11 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 12, 1, 12, 1 ],
+      "name" : "o"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 12, 5, 12, 5 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 12, 9, 12, 11 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 12, 10, 12, 10 ],
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_lists.py.ast.typed b/src/test/data/pa2/sample/expr_lists.py.ast.typed
new file mode 100644
index 0000000..e8c37bd
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_lists.py.ast.typed
@@ -0,0 +1,374 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 12, 12 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 10 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 10 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 9 ],
+          "className" : "object"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 14, 2, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 8 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 7 ],
+          "className" : "bool"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 12, 3, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 12, 4, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 6, 6, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 9, 6, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 12, 6, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 6 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 5, 7, 6 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 8, 1, 8, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 8, 1, 8, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        }
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 8, 5, 8, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 8, 6, 8, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 9, 8, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 9, 5, 9, 17 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        }
+      },
+      "elements" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 6, 9, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 9, 13, 9, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 10, 1, 10, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 5, 10, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 5 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 11, 1, 11, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "o"
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 11, 5, 11, 5 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 12, 1, 12, 11 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 12, 1, 12, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "o"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 12, 5, 12, 5 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 12, 9, 12, 11 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 12, 10, 12, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_unary.py b/src/test/data/pa2/sample/expr_unary.py
new file mode 100644
index 0000000..58d9627
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_unary.py
@@ -0,0 +1,2 @@
+-1
+not False
diff --git a/src/test/data/pa2/sample/expr_unary.py.ast b/src/test/data/pa2/sample/expr_unary.py.ast
new file mode 100644
index 0000000..4f1abf3
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_unary.py.ast
@@ -0,0 +1,37 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 10 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 2 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 1, 1, 1, 2 ],
+      "operator" : "-",
+      "operand" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 2, 1, 2 ],
+        "value" : 1
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 9 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 2, 1, 2, 9 ],
+      "operator" : "not",
+      "operand" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 5, 2, 9 ],
+        "value" : false
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_unary.py.ast.typed b/src/test/data/pa2/sample/expr_unary.py.ast.typed
new file mode 100644
index 0000000..77b0fd0
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_unary.py.ast.typed
@@ -0,0 +1,53 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 10 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 2 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 1, 1, 1, 2 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "operator" : "-",
+      "operand" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 2, 1, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 9 ],
+    "expr" : {
+      "kind" : "UnaryExpr",
+      "location" : [ 2, 1, 2, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "operator" : "not",
+      "operand" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 5, 2, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_var_assign.py b/src/test/data/pa2/sample/expr_var_assign.py
new file mode 100644
index 0000000..3b8ebfe
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_var_assign.py
@@ -0,0 +1,4 @@
+x:int = 1
+o:object = None
+
+x = o = 42
diff --git a/src/test/data/pa2/sample/expr_var_assign.py.ast b/src/test/data/pa2/sample/expr_var_assign.py.ast
new file mode 100644
index 0000000..5b8093e
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_var_assign.py.ast
@@ -0,0 +1,71 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 11 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 12, 2, 15 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 5 ],
+      "name" : "o"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 9, 4, 10 ],
+      "value" : 42
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/expr_var_assign.py.ast.typed b/src/test/data/pa2/sample/expr_var_assign.py.ast.typed
new file mode 100644
index 0000000..950866b
--- /dev/null
+++ b/src/test/data/pa2/sample/expr_var_assign.py.ast.typed
@@ -0,0 +1,91 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 11 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "o"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 12, 2, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "o"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 9, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/func_def_call.py b/src/test/data/pa2/sample/func_def_call.py
new file mode 100644
index 0000000..e5f4e8b
--- /dev/null
+++ b/src/test/data/pa2/sample/func_def_call.py
@@ -0,0 +1,7 @@
+def foo(x:str, y:bool) -> int:
+    return bar()
+
+def bar() -> int:
+    return 1
+
+foo("Hello", False)
diff --git a/src/test/data/pa2/sample/func_def_call.py.ast b/src/test/data/pa2/sample/func_def_call.py.ast
new file mode 100644
index 0000000..b6194bd
--- /dev/null
+++ b/src/test/data/pa2/sample/func_def_call.py.ast
@@ -0,0 +1,111 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 20 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 18, 1, 21 ],
+        "className" : "bool"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 27, 1, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 16 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 12, 2, 16 ],
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 12, 2, 14 ],
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 14, 4, 16 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 19 ],
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 3 ],
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 7, 5, 7, 11 ],
+        "value" : "Hello"
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 14, 7, 18 ],
+        "value" : false
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/func_def_call.py.ast.typed b/src/test/data/pa2/sample/func_def_call.py.ast.typed
new file mode 100644
index 0000000..20e0bde
--- /dev/null
+++ b/src/test/data/pa2/sample/func_def_call.py.ast.typed
@@ -0,0 +1,153 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 20 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 9, 1, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 9, 1, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 11, 1, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 18, 1, 21 ],
+        "className" : "bool"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 27, 1, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 16 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 12, 2, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 12, 2, 14 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 7 ],
+      "name" : "bar"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 14, 4, 16 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 19 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 3 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "foo"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 7, 5, 7, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello"
+      }, {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 14, 7, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_for_lists.py b/src/test/data/pa2/sample/stmt_for_lists.py
new file mode 100644
index 0000000..235fb2f
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_for_lists.py
@@ -0,0 +1,4 @@
+x:int = 0
+
+for x in [1, 2, 3]:
+    x + 1
diff --git a/src/test/data/pa2/sample/stmt_for_lists.py.ast b/src/test/data/pa2/sample/stmt_for_lists.py.ast
new file mode 100644
index 0000000..3e6fb8f
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_for_lists.py.ast
@@ -0,0 +1,77 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 3, 1, 5, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 5 ],
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "ListExpr",
+      "location" : [ 3, 10, 3, 18 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 11, 3, 11 ],
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 14, 3, 14 ],
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 17, 3, 17 ],
+        "value" : 3
+      } ]
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 9 ],
+      "expr" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 5, 4, 9 ],
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "name" : "x"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 9, 4, 9 ],
+          "value" : 1
+        }
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_for_lists.py.ast.typed b/src/test/data/pa2/sample/stmt_for_lists.py.ast.typed
new file mode 100644
index 0000000..9bd4123
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_for_lists.py.ast.typed
@@ -0,0 +1,116 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 9, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 3, 1, 5, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "ListExpr",
+      "location" : [ 3, 10, 3, 18 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 11, 3, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 14, 3, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 17, 3, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 9 ],
+      "expr" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 5, 4, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 9, 4, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_for_strings.py b/src/test/data/pa2/sample/stmt_for_strings.py
new file mode 100644
index 0000000..b135f8b
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_for_strings.py
@@ -0,0 +1,4 @@
+s:str = "Hello"
+
+for s in s:
+    s[0]
diff --git a/src/test/data/pa2/sample/stmt_for_strings.py.ast b/src/test/data/pa2/sample/stmt_for_strings.py.ast
new file mode 100644
index 0000000..6e837a5
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_for_strings.py.ast
@@ -0,0 +1,64 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 1, 9, 1, 15 ],
+      "value" : "Hello"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 3, 1, 5, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 5 ],
+      "name" : "s"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 10, 3, 10 ],
+      "name" : "s"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 8 ],
+      "expr" : {
+        "kind" : "IndexExpr",
+        "location" : [ 4, 5, 4, 8 ],
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "name" : "s"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 7, 4, 7 ],
+          "value" : 0
+        }
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_for_strings.py.ast.typed b/src/test/data/pa2/sample/stmt_for_strings.py.ast.typed
new file mode 100644
index 0000000..0f36ad0
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_for_strings.py.ast.typed
@@ -0,0 +1,88 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 1, 9, 1, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "Hello"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 3, 1, 5, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "s"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 10, 3, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "s"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 8 ],
+      "expr" : {
+        "kind" : "IndexExpr",
+        "location" : [ 4, 5, 4, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_if.py b/src/test/data/pa2/sample/stmt_if.py
new file mode 100644
index 0000000..d5053bf
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_if.py
@@ -0,0 +1,7 @@
+if False:
+    pass
+elif True:
+    if 1 == 1:
+        pass
+else:
+    pass
diff --git a/src/test/data/pa2/sample/stmt_if.py.ast b/src/test/data/pa2/sample/stmt_if.py.ast
new file mode 100644
index 0000000..48c33f3
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_if.py.ast
@@ -0,0 +1,51 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 1 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "IfStmt",
+    "location" : [ 1, 1, 8, 1 ],
+    "condition" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 1, 4, 1, 8 ],
+      "value" : false
+    },
+    "thenBody" : [ ],
+    "elseBody" : [ {
+      "kind" : "IfStmt",
+      "location" : [ 3, 1, 8, 1 ],
+      "condition" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 6, 3, 9 ],
+        "value" : true
+      },
+      "thenBody" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 4, 5, 6, 0 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 4, 8, 4, 13 ],
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 8, 4, 8 ],
+            "value" : 1
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 13, 4, 13 ],
+            "value" : 1
+          }
+        },
+        "thenBody" : [ ],
+        "elseBody" : [ ]
+      } ],
+      "elseBody" : [ ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_if.py.ast.typed b/src/test/data/pa2/sample/stmt_if.py.ast.typed
new file mode 100644
index 0000000..3453f95
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_if.py.ast.typed
@@ -0,0 +1,71 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 1 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "IfStmt",
+    "location" : [ 1, 1, 8, 1 ],
+    "condition" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 1, 4, 1, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : false
+    },
+    "thenBody" : [ ],
+    "elseBody" : [ {
+      "kind" : "IfStmt",
+      "location" : [ 3, 1, 8, 1 ],
+      "condition" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 6, 3, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      },
+      "thenBody" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 4, 5, 6, 0 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 4, 8, 4, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 8, 4, 8 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 13, 4, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        },
+        "thenBody" : [ ],
+        "elseBody" : [ ]
+      } ],
+      "elseBody" : [ ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_list_assign.py b/src/test/data/pa2/sample/stmt_list_assign.py
new file mode 100644
index 0000000..34221dd
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_list_assign.py
@@ -0,0 +1,7 @@
+x:[int] = None
+y:[object] = None
+
+x = [1, 2]
+y = [None]
+x[0] = 3
+x[1] = y[0] = 4
diff --git a/src/test/data/pa2/sample/stmt_list_assign.py.ast b/src/test/data/pa2/sample/stmt_list_assign.py.ast
new file mode 100644
index 0000000..cac7d91
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_list_assign.py.ast
@@ -0,0 +1,155 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 16 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ]
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 10 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 10 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 9 ],
+          "className" : "object"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 14, 2, 17 ]
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 4, 5, 4, 10 ],
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 6, 4, 6 ],
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 9, 4, 9 ],
+        "value" : 2
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 5, 5, 5, 10 ],
+      "elements" : [ {
+        "kind" : "NoneLiteral",
+        "location" : [ 5, 6, 5, 9 ]
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 6, 1, 6, 4 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 3, 6, 3 ],
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 8, 6, 8 ],
+      "value" : 3
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 15 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 1, 7, 4 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 1 ],
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 3, 7, 3 ],
+        "value" : 1
+      }
+    }, {
+      "kind" : "IndexExpr",
+      "location" : [ 7, 8, 7, 11 ],
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 8, 7, 8 ],
+        "name" : "y"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 10, 7, 10 ],
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 7, 15, 7, 15 ],
+      "value" : 4
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa2/sample/stmt_list_assign.py.ast.typed b/src/test/data/pa2/sample/stmt_list_assign.py.ast.typed
new file mode 100644
index 0000000..5fefc31
--- /dev/null
+++ b/src/test/data/pa2/sample/stmt_list_assign.py.ast.typed
@@ -0,0 +1,256 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 16 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 3, 1, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 4, 1, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 1, 11, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 10 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 10 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 9 ],
+          "className" : "object"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 14, 2, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : ""
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "x"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 4, 5, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 6, 4, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 9, 4, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        }
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 5, 5, 5, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "