diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..21cc758a806c9378f9087be9df7e86c57a6c1137
--- /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/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1535d9f6676f06845c59a882426a4d527578495b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,85 @@
+# CS 164: Programming Assignment 3
+
+## Getting started
+
+Run the following command to build your compiler, and then run all the provided tests:
+
+```
+mvn clean package
+
+java -cp "chocopy-ref.jar:lib/venus164.jar:target/assignment.jar" chocopy.ChocoPy --pa3 chocopy.pa3.StudentCodeGen --run --dir src/test/data/pa3/sample/ --test
+```
+
+In the starter code, only one test should pass. Your objective is to implement a code generator that passes all the provided tests and meets the assignment specifications.
+
+### Generating assembly files
+
+You can also run the code generator on one input file at at time. In general, running the code generator on a ChocoPy program is a three-step process. 
+
+1. First, run the reference parser to get an AST JSON:
+```
+java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pa1 chocopy.reference.RefParser --in <chocopy_input_file> --out <ast_json_file>
+```
+
+2. Second, run the reference analysis on the AST JSON to get a typed AST JSON:
+```
+java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pa2 chocopy.reference.RefAnalysis --in <ast_json_file> --out <typed_ast_json_file>
+```
+
+3. Third, run your code generator on the typed AST JSON to get a RISC-V assembly file:
+```
+java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pa3 chocopy.pa3.StudentCodeGen --in <typed_ast_json_file> --out <assembly_file>
+```
+
+The `src/tests/data/pa3/sample` directory already contains the typed AST JSONs for the test programs (with extension `.out.typed`); therefore, you can skip the first two steps for the sample test programs.
+
+### Executing an assembly program using the Venus simulator
+
+To run a generated RISC-V program in the Venus-164 execution environment, run:
+
+```
+java -cp "chocopy-ref.jar:lib/venus164.jar:target/assignment.jar" chocopy.ChocoPy --run --in <assembly_file>
+```
+
+### Chained commands
+
+For quick development, you can chain all the stages `--pa1`, `--pa2`, `--pa3`, and `--run` to directly execute a ChocoPy program:
+
+```
+java -cp "chocopy-ref.jar:lib/venus164.jar:target/assignment.jar" chocopy.ChocoPy --pa1 chocopy.reference.RefParser --pa2 chocopy.reference.RefAnalysis --pa3 chocopy.pa3.StudentCodeGen --run --in <chocopy_input_file>
+```
+
+You can omit the `--run` in the above chain to print the generated assembly program instead of executing it.
+
+### Running the reference implementation
+
+To observe the output of the reference implementation of the code generator, replace the class `chocopy.pa3.StudentCodeGen` with `chocopy.reference.RefCodeGen` in any command where applicable.
+
+## Assignment specifications
+
+See `PA3.pdf` for a detailed specification of the assignment.
+
+Refer to `chocopy_language_reference.pdf` for specifications on the ChocoPy language. 
+
+Refer to `chocopy_implementation_guide.pdf` for information on the design of the reference implementation / starter code.
+
+## Receiving updates to this repository
+
+Add the `upstream` repository remotes (you only need to do this once in your local clone):
+
+```
+git remote add upstream https://github.com/cs164fall2018/pa3-chocopy-code-generation.git
+```
+
+To sync with updates upstream:
+```
+git pull upstream master
+```
+
+## Submission writeup
+
+Team member 1: 
+
+Team member 2: 
+
+(Students should edit this section with their write-up)
diff --git a/chocopy-ref.jar b/chocopy-ref.jar
new file mode 100644
index 0000000000000000000000000000000000000000..bbcd47c90ad93cdd4e4537a6b131d6c766a05d44
Binary files /dev/null and b/chocopy-ref.jar differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8059b1a2dfa724ab809b81a99cc815fe5b3dba3b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,325 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>chocopy</groupId>
+    <artifactId>chocopy</artifactId>
+    <packaging>jar</packaging>
+    <version>2.0-SNAPSHOT</version>
+    <name>chocopy</name>
+    <url>http://maven.apache.org</url>
+
+    <!-- Set this property to true on the command-line for very verbose output -->
+    <properties>
+        <chocopy.debug>false</chocopy.debug>
+    </properties>
+
+    <build>
+        <!-- Specify JFlex and CUP plugins here; execute in profiles -->
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>de.jflex</groupId>
+                    <artifactId>jflex-maven-plugin</artifactId>
+                    <version>1.6.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>com.github.vbmacher</groupId>
+                    <artifactId>cup-maven-plugin</artifactId>
+                    <version>11b-20160615</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-assembly-plugin</artifactId>
+                    <version>3.1.0</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>3.1.0</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <finalName>assignment</finalName>
+                    <appendAssemblyId>false</appendAssemblyId>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase> <!-- bind to the packaging phase -->
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.0</version>
+                <configuration>
+                    <encoding>UTF-8</encoding>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <parameters>true</parameters>
+                    <debug>true</debug>
+                </configuration>
+            </plugin>
+        </plugins>
+
+        <resources>
+          <resource>
+            <directory>src/main/java</directory>
+            <includes>
+              <include>**/asm/*.s</include>
+              <include>**/asm/*.os</include>
+            </includes>
+            <excludes>
+              <exclude>**/reference/codegen/asm/*.s</exclude>
+            </excludes>
+          </resource>
+        </resources>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>reference</id>
+            <activation>
+                <!-- This profile is activated whenever we have the reference sources available -->
+                <file>
+                    <exists>src/main/java/chocopy/reference/</exists>
+                </file>
+            </activation>
+            <build>
+                <plugins>
+                    <!-- Do not include student skeletons in the reference JAR -->
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <configuration>
+                            <excludes>
+                                <exclude>**/pa1/*</exclude>
+                                <exclude>**/pa2/*</exclude>
+                                <exclude>**/pa3/*</exclude>
+                            </excludes>
+                        </configuration>
+                    </plugin>
+                    <!-- Name the generated JAR differently so that it is different from the student version -->
+                    <plugin>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <configuration>
+                            <descriptorRefs>
+                                <descriptorRef>jar-with-dependencies</descriptorRef>
+                            </descriptorRefs>
+                            <finalName>chocopy-ref</finalName>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </plugin>
+                    <!-- Run JFlex to generate reference lexer -->
+                    <plugin>
+                        <groupId>de.jflex</groupId>
+                        <artifactId>jflex-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>jflex-reference</id>
+                                <goals>
+                                    <goal>generate</goal>
+                                </goals>
+                                <configuration>
+                                    <lexDefinitions>
+                                        <lexDefinition>src/main/jflex/chocopy/reference/ChocoPy.jflex</lexDefinition>
+                                    </lexDefinitions>
+                                    <dump>${chocopy.debug}</dump>
+                                    <verbose>true</verbose>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <!-- Run CUP to generate reference parser -->
+                    <plugin>
+                        <groupId>com.github.vbmacher</groupId>
+                        <artifactId>cup-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>cup-reference</id>
+                                <goals>
+                                    <goal>generate</goal>
+                                </goals>
+                                <configuration>
+                                    <cupDefinition>src/main/cup/chocopy/reference/ChocoPy.cup</cupDefinition>
+                                    <packageName>chocopy.reference</packageName>
+                                    <className>ChocoPyParser</className>
+                                    <symbolsName>ChocoPyTokens</symbolsName>
+                                    <dumpTables>${chocopy.debug}</dumpTables>
+                                    <dumpStates>${chocopy.debug}</dumpStates>
+                                    <dumpGrammar>${chocopy.debug}</dumpGrammar>
+                                    <locations>true</locations>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <!-- No debug -->
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <debug>true</debug>
+                        </configuration>
+                    </plugin>
+                    <!-- Copy dependencies to target/ -->
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <version>3.1.1</version>
+                        <executions>
+                            <execution>
+                                <id>copy-dependencies</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>copy-dependencies</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+
+        <profile>
+            <id>pa1</id>
+            <activation>
+                <!-- This profile is activated whenever we are in a PA1 distribution -->
+                <file>
+                    <exists>src/main/java/chocopy/pa1</exists>
+                </file>
+            </activation>
+            <build>
+                <plugins>
+                    <!-- Run JFlex on the student version -->
+                    <plugin>
+                        <groupId>de.jflex</groupId>
+                        <artifactId>jflex-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>jflex-pa1</id>
+                                <goals>
+                                    <goal>generate</goal>
+                                </goals>
+                                <configuration>
+                                    <lexDefinitions>
+                                        <lexDefinition>src/main/jflex/chocopy/pa1/ChocoPy.jflex</lexDefinition>
+                                    </lexDefinitions>
+                                    <dump>${chocopy.debug}</dump>
+                                    <verbose>true</verbose>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <!-- Run CUP on the student version -->
+                    <plugin>
+                        <groupId>com.github.vbmacher</groupId>
+                        <artifactId>cup-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>cup-pa1</id>
+                                <goals>
+                                    <goal>generate</goal>
+                                </goals>
+                                <configuration>
+                                    <cupDefinition>src/main/cup/chocopy/pa1/ChocoPy.cup</cupDefinition>
+                                    <packageName>chocopy.pa1</packageName>
+                                    <className>ChocoPyParser</className>
+                                    <symbolsName>ChocoPyTokens</symbolsName>
+                                    <dumpTables>${chocopy.debug}</dumpTables>
+                                    <dumpStates>${chocopy.debug}</dumpStates>
+                                    <dumpGrammar>${chocopy.debug}</dumpGrammar>
+                                    <locations>true</locations>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>pa2</id>
+            <activation>
+                <!-- This profile is activated whenever we are in a PA2 distribution -->
+                <file>
+                    <exists>src/main/java/chocopy/pa2</exists>
+                </file>
+            </activation>
+        </profile>
+        <profile>
+            <id>pa3</id>
+            <activation>
+                <!-- This profile is activated whenever we are in a PA3 distribution -->
+                <file>
+                    <exists>src/main/java/chocopy/pa3</exists>
+                </file>
+            </activation>
+        </profile>
+    </profiles>
+
+
+    <repositories>
+      <repository>
+        <id>cs164-repo</id>
+        <name>Repository for CS164 artifacts</name>
+        <url>http://inst.eecs.berkeley.edu/~cs164/maven</url>
+      </repository>
+    </repositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>net.sourceforge.argparse4j</groupId>
+            <artifactId>argparse4j</artifactId>
+            <version>0.8.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.9.8</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.module</groupId>
+            <artifactId>jackson-module-parameter-names</artifactId>
+            <version>2.9.8</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.vbmacher</groupId>
+            <artifactId>java-cup-runtime</artifactId>
+            <version>11b-20160615</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/de.jflex/jflex -->
+        <dependency>
+            <groupId>de.jflex</groupId>
+            <artifactId>jflex</artifactId>
+            <version>1.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains.kotlin</groupId>
+            <artifactId>kotlin-stdlib</artifactId>
+            <version>1.2.71</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.berkeley.eecs.venus164</groupId>
+            <artifactId>venus164</artifactId>
+            <version>0.2.3</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.sf.proguard</groupId>
+            <artifactId>proguard-base</artifactId>
+            <version>6.0.3</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/java/chocopy/common/Utils.java b/src/main/java/chocopy/common/Utils.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b292bdcb7a5af5ec3f01553b48622acaa0016d5
--- /dev/null
+++ b/src/main/java/chocopy/common/Utils.java
@@ -0,0 +1,56 @@
+package chocopy.common;
+
+import java.io.BufferedReader;
+import java.util.stream.Collectors;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+
+/** 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));
+            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 0000000000000000000000000000000000000000..18615e2d1908ea780b68099f98d7480a58bc0e8e
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/AbstractNodeAnalyzer.java
@@ -0,0 +1,176 @@
+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<T> implements NodeAnalyzer<T> {
+    @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 0000000000000000000000000000000000000000..c65e79ba5e4f457a6a7ea7d0583aa2dfb4cc7ffe
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/NodeAnalyzer.java
@@ -0,0 +1,67 @@
+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<T> 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 implmentations of analyzsis 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> {
+
+    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 0000000000000000000000000000000000000000..8e95e5a5a66ce3d7d51d31682683b882d22f729d
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/SymbolTable.java
@@ -0,0 +1,63 @@
+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<T> {
+
+    /** Contents of the current (innermost) region. */
+    private final Map<String, T> tab = new HashMap<>();
+    /** Enclosing block. */
+    private final SymbolTable<T> parent;
+
+    /** A table representing a region nested in that represented by
+     *  PARENT0. */
+    public SymbolTable(SymbolTable<T> 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<T> 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<String> getDeclaredSymbols() {
+        return tab.keySet();
+    }
+
+    /** Returns the parent, or null if this is the top level. */
+    public SymbolTable<T> 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 0000000000000000000000000000000000000000..6e91683fd9c6780f1a82fc682e43cfc0f48de643
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ClassValueType.java
@@ -0,0 +1,53 @@
+package chocopy.common.analysis.types;
+
+import java.util.Objects;
+
+import chocopy.common.astnodes.ClassType;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/** 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 0000000000000000000000000000000000000000..2dd0072f0e0b3bb212abe97e34cf6005c188624a
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/FuncType.java
@@ -0,0 +1,46 @@
+package chocopy.common.analysis.types;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+/** Semantic information for a function or method. */
+public class FuncType extends SymbolType {
+
+    /** Types of parameters. */
+    public final List<ValueType> parameters;
+    /** Function's return type. */
+    public final ValueType returnType;
+
+    /** Create a FuncType returning RETURNTYPE0, intiallly parapeterless. */
+    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<ValueType> 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 "<function>";
+    }
+
+}
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 0000000000000000000000000000000000000000..f189399b076706d172cb1a932f11bd13e4f69001
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ListValueType.java
@@ -0,0 +1,58 @@
+package chocopy.common.analysis.types;
+
+import java.util.Objects;
+
+import chocopy.common.astnodes.ListType;
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+/** 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(SymbolType elementType) {
+        this.elementType = (ValueType) elementType;
+    }
+
+    /** Represents [<type>], where <type> 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/SymbolType.java b/src/main/java/chocopy/common/analysis/types/SymbolType.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b5b0e115acb28d20b0677caa9186c66222cb3bc
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/SymbolType.java
@@ -0,0 +1,78 @@
+package chocopy.common.analysis.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * A symbol type represents the static types 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 SymbolType.
+ */
+@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 SymbolType {
+
+    /** 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("<None>");
+    /** The type of []. */
+    public static final ClassValueType EMPTY_TYPE =
+        new ClassValueType("<Empty>");
+
+
+    /** 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 0000000000000000000000000000000000000000..f4975cc24f76b03f40a34980b0cbeeacbbb5ea7d
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ValueType.java
@@ -0,0 +1,32 @@
+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 SymbolType {
+
+    /** 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 0000000000000000000000000000000000000000..02c2cfc2dba799b05578d943695252c8f92b1358
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/AssignStmt.java
@@ -0,0 +1,28 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Single and multiple assignments. */
+public class AssignStmt extends Stmt {
+    /** List of left-hand sides. */
+    public final List<Expr> 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<Expr> targets, Expr value) {
+        super(left, right);
+        this.targets = targets;
+        this.value = value;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..f9196524c029268663464a0bb220cf00c989d5a3
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/BinaryExpr.java
@@ -0,0 +1,30 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** <operand> <operator> <operand>. */
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..e087eb0efa24eba67a993cf6c2a119d0cd5e9cbc
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/BooleanLiteral.java
@@ -0,0 +1,23 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..1d523dea8867da3ad836f340f659ffab7bd1311a
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/CallExpr.java
@@ -0,0 +1,28 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** A function call. */
+public class CallExpr extends Expr {
+
+    /** The called function. */
+    public final Identifier function;
+    /** The actual parameter expressions. */
+    public final List<Expr> args;
+
+    /** AST for FUNCTION(ARGS) at [LEFT..RIGHT]. */
+    public CallExpr(Location left, Location right, Identifier function,
+                    List<Expr> args) {
+        super(left, right);
+        this.function = function;
+        this.args = args;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..dad7e2a4abcb2653da7bf79053d824d682e84095
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ClassDef.java
@@ -0,0 +1,41 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** 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<Declaration> declarations;
+
+    /** An AST for class
+     *    NAME(SUPERCLASS):
+     *       DECLARATIONS.
+     *  spanning source locations [LEFT..RIGHT].
+     */
+    public ClassDef(Location left, Location right,
+                    Identifier name, Identifier superClass,
+                    List<Declaration> declarations) {
+        super(left, right);
+        this.name = name;
+        this.superClass = superClass;
+        this.declarations = declarations;
+    }
+
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..1c1886d582f92bf0da3901a8a8f002329ede8c39
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ClassType.java
@@ -0,0 +1,22 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..092a1de9e9ac4acfb1f1c9a17a52d804ad17db46
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/CompilerError.java
@@ -0,0 +1,57 @@
+package chocopy.common.astnodes;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import java_cup.runtime.ComplexSymbolFactory.Location;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import chocopy.common.analysis.NodeAnalyzer;
+
+/** 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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..ca079d7ea45cc0ba9e9e5508925a656ae9a8caf4
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Declaration.java
@@ -0,0 +1,19 @@
+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 0000000000000000000000000000000000000000..644cfe3b1a6c9a32aeff22560d40be17c19ec887
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Errors.java
@@ -0,0 +1,72 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** 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<CompilerError> 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<CompilerError> 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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..6311bd680ec188345401d27390c2c0a15f717c81
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Expr.java
@@ -0,0 +1,48 @@
+package chocopy.common.astnodes;
+
+import chocopy.common.analysis.types.SymbolType;
+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 <tt>null</tt> after the parsing stage,
+     * but is populated by the typechecker in the semantic analysis
+     * stage.
+     *
+     * After typechecking this field may be <tt>null</tt> 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 SymbolType inferredType;
+
+    /** Set getInferredType() to TYPE, returning TYPE. */
+    public SymbolType setInferredType(SymbolType type) {
+        inferredType = type;
+        return type;
+    }
+
+    public SymbolType 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 0000000000000000000000000000000000000000..bb0ca3e2ca48b5a5672cf4d670620a37b333b1e3
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ExprStmt.java
@@ -0,0 +1,23 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..67d655693350595c4ca962678a501d0d9281c4b5
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ForStmt.java
@@ -0,0 +1,34 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** 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<Stmt> 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<Stmt> body) {
+        super(left, right);
+        this.identifier = identifier;
+        this.iterable = iterable;
+        this.body = body;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..6c1c20351ea3d1739145f268a41f261a0417b0b0
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/FuncDef.java
@@ -0,0 +1,48 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Def statements. */
+public class FuncDef extends Declaration {
+
+    /** Defined name. */
+    public final Identifier name;
+    /** Formal parameters. */
+    public final List<TypedVar> params;
+    /** Return type annotation. */
+    public final TypeAnnotation returnType;
+    /** Local-variable,inner-function, global, and nonlocal declarations. */
+    public final List<Declaration> declarations;
+    /** Other statements. */
+    public final List<Stmt> statements;
+
+    /** The AST for
+     *     def NAME(PARAMS) -> RETURNTYPE:
+     *         DECLARATIONS
+     *         STATEMENTS
+     *  spanning source locations [LEFT..RIGHT].
+     */
+    public FuncDef(Location left, Location right,
+                   Identifier name, List<TypedVar> params,
+                   TypeAnnotation returnType,
+                   List<Declaration> declarations, List<Stmt> statements) {
+        super(left, right);
+        this.name = name;
+        this.params = params;
+        this.returnType = returnType;
+        this.declarations = declarations;
+        this.statements = statements;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..71622e1d96c6d377cbbf1ea1cf5f8751d71c0ff1
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/GlobalDecl.java
@@ -0,0 +1,29 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..b7e43b460e2ea66162c5bdfdc52927ad09f897e8
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Identifier.java
@@ -0,0 +1,23 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..5fb2e0dee2622a6368f45e3d7240bead8a5867f4
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IfExpr.java
@@ -0,0 +1,31 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..2566ccff382a10868295e7d3673776cbd3de7fab
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IfStmt.java
@@ -0,0 +1,36 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Conditional statement. */
+public class IfStmt extends Stmt {
+    /** Test condition. */
+    public final Expr condition;
+    /** "True" branch. */
+    public final List<Stmt> thenBody;
+    /** "False" branch. */
+    public final List<Stmt> elseBody;
+
+    /** The AST for
+     *      if CONDITION:
+     *          THENBODY
+     *      else:
+     *          ELSEBODY
+     *  spanning source locations [LEFT..RIGHT].
+     */
+    public IfStmt(Location left, Location right,
+                  Expr condition, List<Stmt> thenBody, List<Stmt> elseBody) {
+        super(left, right);
+        this.condition = condition;
+        this.thenBody = thenBody;
+        this.elseBody = elseBody;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..22cb64c48308032b3ae666e0c45dc715502733c7
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IndexExpr.java
@@ -0,0 +1,28 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..734c9598f174b490c68a201454fa3c6592a9f2e1
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/IntegerLiteral.java
@@ -0,0 +1,23 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..3427d0c13f78920286af57aed0b56aa557efb392
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ListExpr.java
@@ -0,0 +1,27 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** List displays. */
+public final class ListExpr extends Expr {
+
+    /** List of element expressions. */
+    public final List<Expr> elements;
+
+    /** The AST for
+     *      [ ELEMENTS ].
+     *  spanning source locations [LEFT..RIGHT].
+     */
+    public ListExpr(Location left, Location right, List<Expr> elements) {
+        super(left, right);
+        this.elements = elements;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..551f1f8b3ce31e8ba6e0840beed0e7baa74a5fcf
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ListType.java
@@ -0,0 +1,25 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..f5881e6aa61b0cd47f9fd0a076aae531e9bdb2f0
--- /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 0000000000000000000000000000000000000000..395fc3e8d7053ba9176ee6d4756f5a78946b9bd0
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/MemberExpr.java
@@ -0,0 +1,29 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..b6d005c16cf69714fcdc34c7aa24096673eeec68
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/MethodCallExpr.java
@@ -0,0 +1,31 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Method calls. */
+public class MethodCallExpr extends Expr {
+
+    /** Expression for the bound method to be called. */
+    public final MemberExpr method;
+    /** Actual parameters. */
+    public final List<Expr> args;
+
+    /** The AST for
+     *      METHOD(ARGS).
+     *  spanning source locations [LEFT..RIGHT].
+     */
+    public MethodCallExpr(Location left, Location right,
+                          MemberExpr method, List<Expr> args) {
+        super(left, right);
+        this.method = method;
+        this.args = args;
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..48a5be769ce4962fc6fe1d26070cff6c1fc6eafc
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Node.java
@@ -0,0 +1,174 @@
+package chocopy.common.astnodes;
+
+import java.io.IOException;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+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;
+
+/**
+ * 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
+     *     { <first line>, <first column>, <last line>, <last column> }.
+     *  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> T dispatch(NodeAnalyzer<T> 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 fprmat. */
+    public String toJSON() throws JsonProcessingException {
+        return mapper.writeValueAsString(this);
+    }
+
+    /** Mapper to-and-from serialized JSON. */
+    private static ObjectMapper mapper = new ObjectMapper();
+
+    static {
+        mapper.enable(SerializationFeature.INDENT_OUTPUT);
+        mapper.registerModule(new ParameterNamesModule());
+    }
+
+    /** Returns a T from JSON, a JSON-eerialized T value with class
+     *  CLAS. */
+    public static <T> T fromJSON(String json, Class<T> 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> T fromJSON(JsonNode tree, Class<T> 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 0000000000000000000000000000000000000000..63202ee2094958e898f084ae0ac86d5c823207fe
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/NonLocalDecl.java
@@ -0,0 +1,29 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..b51a5819fe6238b74aff4e1511a41a51435829a5
--- /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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..a77f356db6051704629d0eb44a9535408be0191c
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Program.java
@@ -0,0 +1,56 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/** An entire Chocopy program. */
+public class Program extends Node {
+
+    /** Initial variable, class, and function declarations. */
+    public final List<Declaration> declarations;
+    /** Trailing statements. */
+    public final List<Stmt> 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<Declaration> declarations, List<Stmt> statements,
+                   Errors errors) {
+        super(left, right);
+        this.declarations = declarations;
+        this.statements = statements;
+        if (errors == null) {
+            this.errors = new Errors(new ArrayList<CompilerError>());
+        } else {
+            this.errors = errors;
+        }
+    }
+
+    public <T> T dispatch(NodeAnalyzer<T> 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<CompilerError> 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 0000000000000000000000000000000000000000..214d17a9aedb4706f9a84daf2a4ce9c6a651ec97
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/ReturnStmt.java
@@ -0,0 +1,25 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..dc63f633b2cbb9016d97066c34c92bc73f05cd9a
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/Stmt.java
@@ -0,0 +1,20 @@
+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 0000000000000000000000000000000000000000..de17dd10052b6871147c9a4e187c82cb0874f8fb
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/StringLiteral.java
@@ -0,0 +1,23 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..4ef66adbd86b306a376172ca2a9853f8721e12b4
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/TypeAnnotation.java
@@ -0,0 +1,14 @@
+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 0000000000000000000000000000000000000000..279890d1e1d877db661b0c26876cd5ded58e6c44
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/TypedVar.java
@@ -0,0 +1,29 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..42163804b33a0588a4b2ae7d0af7350325afc88d
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/UnaryExpr.java
@@ -0,0 +1,29 @@
+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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..27c093bd7204b0c95425117c27e1ff0df5cd7a08
--- /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> T dispatch(NodeAnalyzer<T> 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 0000000000000000000000000000000000000000..122b6d5e21792093a2303ec599fa004cb97343a0
--- /dev/null
+++ b/src/main/java/chocopy/common/astnodes/WhileStmt.java
@@ -0,0 +1,32 @@
+package chocopy.common.astnodes;
+
+import java.util.List;
+
+import chocopy.common.analysis.NodeAnalyzer;
+import java_cup.runtime.ComplexSymbolFactory.Location;
+
+/** Indefinite repetition construct. */
+public class WhileStmt extends Stmt {
+    /** Test for whether to continue. */
+    public final Expr condition;
+    /** Loop body. */
+    public final List<Stmt> body;
+
+    /** The AST for
+     *      while CONDITION:
+     *          BODY
+     *  spanning source locations [LEFT..RIGHT].
+     */
+    public WhileStmt(Location left, Location right,
+                     Expr condition, List<Stmt> body) {
+        super(left, right);
+        this.condition = condition;
+        this.body = body;
+    }
+
+
+    public <T> T dispatch(NodeAnalyzer<T> analyzer) {
+        return analyzer.analyze(this);
+    }
+
+}
diff --git a/src/main/java/chocopy/common/codegen/AttrInfo.java b/src/main/java/chocopy/common/codegen/AttrInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec005684283b232394fe1ad80808e7da691495bc
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/AttrInfo.java
@@ -0,0 +1,16 @@
+package chocopy.common.codegen;
+
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.Literal;
+
+/** Information concerning an instance variable. */
+public class AttrInfo extends VarInfo {
+
+    /**
+     * A descriptor for an attribute named ATTRNAME of type VARTYPE whose
+     * initial value, if any, is a constant specified by INITIALVALUE
+     * (it is otherwise null). */
+    public AttrInfo(String attrName, ValueType varType, Literal initialValue) {
+        super(attrName, varType, initialValue);
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/ClassInfo.java b/src/main/java/chocopy/common/codegen/ClassInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f362defa6d927ecd98901a32dfdc83f24de7acb
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/ClassInfo.java
@@ -0,0 +1,137 @@
+package chocopy.common.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Information for code generation a class. */
+public class ClassInfo extends SymbolInfo {
+
+    /** Name of class. */
+    protected final String className;
+
+    /** Information about instance variables of the class. */
+    public final List<AttrInfo> attributes;
+    /** Information about methods of the class. */
+    public final List<FuncInfo> methods;
+
+    /** Tag indicating type of value:
+     *      0: (reserved)
+     *      1: int
+     *      2: bool
+     *      3: str
+     *     -1: [T] for any T
+     *     >3: User-defined types.
+     */
+    protected final int typeTag;
+    /** Label of area containing initial instance values. */
+    protected Label prototypeLabel;
+    /** Label of area containing method-dispatching table. */
+    protected Label dispatchTableLabel;
+
+    /**
+     * A descriptor for a class named CLASSNAME identified by runtime tag
+     * TYPETAG, and having the class denoted by SUPERCLASSINFO as its
+     * superclass.  The latter is null iff the class is object.
+     */
+    public ClassInfo(String className, int typeTag, ClassInfo superClassInfo) {
+        this.className = className;
+        this.typeTag = typeTag;
+        prototypeLabel =
+            new Label(String.format("$%s$%s", className, "prototype"));
+        dispatchTableLabel =
+            new Label(String.format("$%s$%s", className, "dispatchTable"));
+        attributes = new ArrayList<>();
+        methods = new ArrayList<>();
+        if (superClassInfo != null) {
+            attributes.addAll(superClassInfo.attributes);
+            methods.addAll(superClassInfo.methods);
+        }
+    }
+
+    /** Add an attribute described by ATTRINFO. */
+    public void addAttribute(AttrInfo attrInfo) {
+        this.attributes.add(attrInfo);
+    }
+
+    /** Add a method described by FUNCINFO, overriding any inherited method of
+     *  that name if necessary. */
+    public void addMethod(FuncInfo funcInfo) {
+        String methodName = funcInfo.getBaseName();
+        int idx = this.getMethodIndex(methodName);
+        if (idx >= 0) {
+            this.methods.set(idx, funcInfo);
+        } else {
+            this.methods.add(funcInfo);
+        }
+    }
+
+    /** Return my type tag. */
+    public int getTypeTag() {
+        return typeTag;
+    }
+
+    /** Returns the address of this class's prototype object (a label). */
+    public Label getPrototypeLabel() {
+        return prototypeLabel;
+    }
+
+    /** Returns the address of this class's dispatch table (a label). */
+    public Label getDispatchTableLabel() {
+        return dispatchTableLabel;
+    }
+
+    /**
+     * Returns the index of the attribute named ATTRNAME in order of
+     * definition.
+     *
+     * This index takes into account inherited attribute and returns
+     * the index of an attribute as a slot index in its object
+     * layout (exlcuding the object header).  Attributes are numbered
+     * from 0; the result is an index, and not a byte offset.
+     */
+    public int getAttributeIndex(String attrName) {
+        for (int i = 0; i < attributes.size(); i++) {
+            if (attributes.get(i).getVarName().equals(attrName)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the method named METHODNAME in order of
+     * definition.
+     *
+     * This index takes into account inherited and overridden methods
+     * and returns the index of the method as a slot number (not a byte
+     * offset) in the dispatch table.
+     */
+    public int getMethodIndex(String methodName) {
+        for (int i = 0; i < methods.size(); i++) {
+            if (methods.get(i).getBaseName().equals(methodName)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Returns the list of attributes of this class,
+     * in order of the object's layout.
+     */
+    public List<AttrInfo> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Returns the list of methods of this class,
+     * in order of the object's dispatch table.
+     */
+    public List<FuncInfo> getMethods() {
+        return methods;
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/CodeGenBase.java b/src/main/java/chocopy/common/codegen/CodeGenBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e3e8f685f25e8819d20c892d950fdebab3a8883
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/CodeGenBase.java
@@ -0,0 +1,940 @@
+package chocopy.common.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.types.SymbolType;
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.BooleanLiteral;
+import chocopy.common.astnodes.ClassDef;
+import chocopy.common.astnodes.Declaration;
+import chocopy.common.astnodes.FuncDef;
+import chocopy.common.astnodes.GlobalDecl;
+import chocopy.common.astnodes.IntegerLiteral;
+import chocopy.common.astnodes.Literal;
+import chocopy.common.astnodes.NonLocalDecl;
+import chocopy.common.astnodes.Program;
+import chocopy.common.astnodes.Stmt;
+import chocopy.common.astnodes.TypedVar;
+import chocopy.common.astnodes.VarDef;
+import chocopy.common.analysis.AbstractNodeAnalyzer;
+
+import static chocopy.common.Utils.*;
+import static chocopy.common.codegen.RiscVBackend.Register.*;
+
+/**
+ * The code generator for a ChocoPy program.
+ *
+ * This class implements logic to analyze all declarations
+ * in a program and create descriptors for classes, functions,
+ * methods, variables (global and local), and attributes. This
+ * logic also builds symbol tables for globals and individual functions.
+ *
+ * This class also implements logic to emit global variables, object
+ * prototypes and dispatch tables, as well as int/str/bool constants.
+ *
+ * However, this class is abstract because it does not implement logic
+ * for emitting executable code in bodies of user-defined functions
+ * as well as in top-level statements. This class should be extended with
+ * implementations for such logic.
+ *
+ * All non-public members of this class are `protected`, and can be
+ * overridden by sub-classes to extend change functionality.
+ *
+ * The SymbolInfo classes can also be overridden. If say you want to use
+ * your own extended FuncInfo called MyFuncInfo (that extends FuncInfo),
+ * then override the makeFuncInfo() method of this class to
+ * `return new MyFuncInfo(...)` instead. This is probably not needed, though.
+ */
+public abstract class CodeGenBase {
+
+    /** The location of the text resources containing common library code. */
+    protected static final String LIBRARY_CODE_DIR
+        = "chocopy/common/codegen/asm/";
+
+    /** The backend that emits assembly. */
+    protected final RiscVBackend backend;
+
+    /** Convenience variable: the word size for the current back end. */
+    protected final int wordSize;
+
+    /** A counter for generating unique class type tags. */
+    protected int nextTypeTag = 0;
+
+    /** A counter used to generate unique local label names. */
+    protected int nextLabelSuffix = 0;
+
+    /** Predefined classes. The list "class" is a fake class; we use it only
+     *  to emit a prototype object for empty lists. */
+    protected ClassInfo
+        objectClass, intClass, boolClass, strClass, listClass;
+
+    /** Predefined functions. */
+    protected FuncInfo printFunc, lenFunc, inputFunc;
+
+    /**
+     * A list of global variables, whose initial values are
+     * emitted in the backend.
+     */
+    protected final List<GlobalVarInfo> globalVars = new ArrayList<>();
+
+    /**
+     * A list of program classes, whose prototype objects and dispatch
+     * tables are emitted in the backend.
+     */
+    protected final List<ClassInfo> classes = new ArrayList<>();
+
+    /**
+     * A list of functions (including methods and nested functions) whose
+     * bodies are emitted in the backend.
+     */
+    protected final List<FuncInfo> functions = new ArrayList<>();
+
+    /** Label for built-in routine: alloc. */
+    protected final Label objectAllocLabel = new Label("alloc");
+
+    /** Label for built-in routine: alloc2. */
+    protected final Label objectAllocResizeLabel = new Label("alloc2");
+
+    /** Label for built-in routine: abort. */
+    protected final Label abortLabel = new Label("abort");
+
+    /** Label for built-in routine: heap.init. */
+    protected final Label heapInitLabel = new Label("heap.init");
+
+    /** Error codes. */
+    protected final int ERROR_ARG = 1, ERROR_DIV_ZERO = 2, ERROR_OOB = 3,
+        ERROR_NONE = 4, ERROR_OOM = 5, ERROR_NYI = 6;
+
+    /** Size of heap memory. */
+    protected final int HEAP_SIZE_BYTES = 1024 * 1024 * 32;
+
+    /** Ecall numbers for intrinsic routines. */
+    protected final int
+        EXIT_ECALL = 10,
+        EXIT2_ECALL = 17,
+        PRINT_STRING_ECALL = 4,
+        PRINT_CHAR_ECALL = 11,
+        PRINT_INT_ECALL = 1,
+        SBRK_ECALL = 9;
+
+    /**
+     * The symbol table that maps global names to information about
+     * the bound global variables, global functions, or classes.
+     */
+    protected final SymbolTable<SymbolInfo> globalSymbols = new SymbolTable<>();
+
+    /**
+     * A utility for caching constants and generating labels for constants.
+     */
+    protected final Constants constants = new Constants();
+
+    /** The object header size, in words (includes type tag, size,
+     *  and dispatch table pointer). */
+    public static final int HEADER_SIZE = 3;
+
+    /**
+     * Initializes a code generator for ChocoPy that uses BACKEND to emit
+     * assembly code.
+     *
+     * The constructor creates Info objects for predefined functions,
+     * classes, methods, and built-in routines.
+     */
+    public CodeGenBase(RiscVBackend backend) {
+        this.backend = backend;
+        wordSize = backend.getWordSize();
+
+        initClasses();
+        initFunctions();
+        initAsmConstants();
+    }
+
+    /** Return a fresh type tag. */
+    protected int getNextTypeTag() {
+        return nextTypeTag++;
+    }
+
+    /** Returns the next unique label suffix. */
+    protected int getNextLabelSuffix() {
+        return nextLabelSuffix++;
+    }
+
+    /**
+     * Return a fresh label.
+     *
+     * This label is guaranteed to be unique amongst labels
+     * generated by invoking this method. All such labels
+     * have a prefix of `label_`.
+     *
+     * This is useful to generate local labels in
+     * function bodies (e.g. for targets of jumps),
+     * where the name does not matter in general.
+     */
+    protected Label generateLocalLabel() {
+        return new Label(String.format("label_%d", getNextLabelSuffix()));
+    }
+
+    /**
+     * Generates assembly code for PROGRAM.
+     *
+     * This is the main driver that calls internal methods for
+     * emitting DATA section (globals, constants, prototypes, etc)
+     * as well as the the CODE section (predefined functions, built-in
+     * routines, and user-defined functions).
+     */
+    public void generate(Program program) {
+        analyzeProgram(program);
+
+        backend.startData();
+
+        for (ClassInfo classInfo : this.classes) {
+            emitPrototype(classInfo);
+        }
+
+        for (ClassInfo classInfo : this.classes) {
+            emitDispatchTable(classInfo);
+        }
+
+        for (GlobalVarInfo global : this.globalVars) {
+            backend.emitGlobalLabel(global.getLabel());
+            emitConstant(global.getInitialValue(), global.getVarType(),
+                         String.format("Initial value of global var: %s",
+                                       global.getVarName()));
+        }
+
+        backend.startCode();
+
+        Label mainLabel = new Label("main");
+        backend.emitGlobalLabel(mainLabel);
+        backend.emitLUI(A0, HEAP_SIZE_BYTES >> 12,
+                        "Initialize heap size (in multiples of 4KB)");
+        backend.emitADD(S11, S11, A0, "Save heap size");
+        backend.emitJAL(heapInitLabel, "Call heap.init routine");
+        backend.emitMV(GP, A0, "Initialize heap pointer");
+        backend.emitMV(S10, GP, "Set beginning of heap");
+        backend.emitADD(S11, S10, S11,
+                        "Set end of heap (= start of heap + heap size)");
+        backend.emitMV(RA, ZERO, "No normal return from main program.");
+        backend.emitMV(FP, ZERO, "No preceding frame.");
+
+        emitTopLevel(program.statements);
+
+        for (FuncInfo funcInfo : this.functions) {
+            funcInfo.emitBody();
+        }
+
+        emitStdFunc("alloc");
+        emitStdFunc("alloc2");
+        emitStdFunc("abort");
+        emitStdFunc("heap.init");
+
+        emitCustomCode();
+
+        backend.startData();
+        emitConstants();
+    }
+
+    /** Create descriptors and symbols for builtin classes and methods. */
+    protected void initClasses() {
+        FuncInfo objectInit =
+            makeFuncInfo("object.__init__", 0, SymbolType.NONE_TYPE,
+                         globalSymbols, null, this::emitStdFunc);
+        objectInit.addParam(makeStackVarInfo("self", null, null, objectInit));
+        functions.add(objectInit);
+
+        objectClass = makeClassInfo("object", getNextTypeTag(), null);
+        objectClass.addMethod(objectInit);
+        classes.add(objectClass);
+        globalSymbols.put(objectClass.getClassName(), objectClass);
+
+        intClass = makeClassInfo("int", getNextTypeTag(), objectClass);
+        intClass.addAttribute(makeAttrInfo("__int__", null, null));
+        classes.add(intClass);
+        globalSymbols.put(intClass.getClassName(), intClass);
+
+        boolClass = makeClassInfo("bool", getNextTypeTag(), objectClass);
+        boolClass.addAttribute(makeAttrInfo("__bool__", null, null));
+        classes.add(boolClass);
+        globalSymbols.put(boolClass.getClassName(), boolClass);
+
+        strClass = makeClassInfo("str", getNextTypeTag(), objectClass);
+        strClass.addAttribute(makeAttrInfo("__len__", SymbolType.INT_TYPE,
+                                           new IntegerLiteral(null, null, 0)));
+        strClass.addAttribute(makeAttrInfo("__str__", null, null));
+        classes.add(strClass);
+        globalSymbols.put(strClass.getClassName(), strClass);
+
+        listClass = makeClassInfo(".list", -1, objectClass);
+        listClass.addAttribute(makeAttrInfo("__len__", SymbolType.INT_TYPE,
+                                            new IntegerLiteral(null, null, 0)));
+        classes.add(listClass);
+        listClass.dispatchTableLabel = null;
+    }
+
+    /** Create descriptors and symbols for builtin functions. */
+    protected void initFunctions() {
+        printFunc = makeFuncInfo("print", 0, SymbolType.NONE_TYPE,
+                                 globalSymbols, null, this::emitStdFunc);
+        printFunc.addParam(makeStackVarInfo("arg", null, null, printFunc));
+        functions.add(printFunc);
+        globalSymbols.put(printFunc.getBaseName(), printFunc);
+
+        lenFunc = makeFuncInfo("len", 0, SymbolType.INT_TYPE,
+                globalSymbols, null, this::emitStdFunc);
+        lenFunc.addParam(makeStackVarInfo("arg", null, null, lenFunc));
+        functions.add(lenFunc);
+        globalSymbols.put(lenFunc.getBaseName(), lenFunc);
+
+        inputFunc = makeFuncInfo("input", 0, SymbolType.STR_TYPE,
+                                 globalSymbols, null, this::emitStdFunc);
+        functions.add(inputFunc);
+        globalSymbols.put(inputFunc.getBaseName(), inputFunc);
+    }
+
+    /* Symbolic assembler constants defined here (to add others, override
+     * initAsmConstants in an extension of CodeGenBase):
+     * ecalls:
+     *   @print_string
+     *   @print_char
+     *   @print_int
+     *   @exit2
+     * Exit codes:
+     *   @error_div_zero: Division by 0.
+     *   @error_arg: Bad argument.
+     *   @error_oob: Out of bounds.
+     *   @error_none: Attempt to access attribute of None.
+     *   @error_oom: Out of memory.
+     *   @error_nyi: Unimplemented operation.
+     * Data-structure byte offsets:
+     *   @.__obj_size__: Offset of size of object.
+     *   @.__len__: Offset of length in chars or words.
+     *   @.__str__: Offset of string data.
+     *   @.__elts__: Offset of first list item.
+     *   @.__int__: Offset of integer value.
+     *   @.__bool__: Offset of boolean (1/0) value.
+     */
+
+    /** Define @-constants to be used in assembly code. */
+    protected void initAsmConstants() {
+        backend.defineSym("sbrk", SBRK_ECALL);
+        backend.defineSym("print_string", PRINT_STRING_ECALL);
+        backend.defineSym("print_char", PRINT_CHAR_ECALL);
+        backend.defineSym("print_int", PRINT_INT_ECALL);
+        backend.defineSym("exit2", EXIT2_ECALL);
+
+        backend.defineSym(".__obj_size__", 4);
+        backend.defineSym(".__len__", 12);
+        backend.defineSym(".__int__", 12);
+        backend.defineSym(".__bool__", 12);
+        backend.defineSym(".__str__", 16);
+        backend.defineSym(".__elts__", 16);
+
+        backend.defineSym("error_div_zero", ERROR_DIV_ZERO);
+        backend.defineSym("error_arg", ERROR_ARG);
+        backend.defineSym("error_oob", ERROR_OOB);
+        backend.defineSym("error_none", ERROR_NONE);
+        backend.defineSym("error_oom", ERROR_OOM);
+        backend.defineSym("error_nyi", ERROR_NYI);
+    }
+
+    /*-----------------------------------------------------------*/
+    /*                                                           */
+    /*          FACTORY METHODS TO CREATE INFO OBJECTS           */
+    /*                                                           */
+    /*-----------------------------------------------------------*/
+
+    /**
+     * A factory method that returns a descriptor for function or method
+     * FUNCNAME returning type RETURNTYPE at nesting level DEPTH in the
+     * region corresponding to PARENTSYMBOLTABLE.
+
+     * PARENTFUNCINFO is a descriptor of the enclosing function and is null
+     * for global functions and methods.
+
+     * EMITTER is a method that emits the function's body (usually a
+     * generic emitter for user-defined functions/methods, and a
+     * special emitter for pre-defined functions/methods).
+     *
+     * Sub-classes of CodeGenBase can override this method
+     * if they wish to use a sub-class of FuncInfo with more
+     * functionality.
+     */
+    protected FuncInfo makeFuncInfo(String funcName, int depth,
+                                    SymbolType returnType,
+                                    SymbolTable<SymbolInfo> parentSymbolTable,
+                                    FuncInfo parentFuncInfo,
+                                    Consumer<FuncInfo> emitter) {
+        return new FuncInfo(funcName, depth, returnType, parentSymbolTable,
+                            parentFuncInfo, emitter);
+    }
+
+    /**
+     * Return a descriptor for a class named CLASSNAME having type tag
+     * TYPETAG and superclass SUPERCLASSINFO (null for `object' only).
+     *
+     * Sub-classes of CodeGenBase can override this method
+     * if they wish to use a sub-class of ClassInfo with more
+     * functionality.
+     */
+    public ClassInfo makeClassInfo(String className, int typeTag,
+                                   ClassInfo superClassInfo) {
+        return new ClassInfo(className, typeTag, superClassInfo);
+    }
+
+    /**
+     * A factory method that returns a descriptor for an attribute named
+     * ATTRNAME of type ATTRTYPE and with an initial value specified
+     * by INITIALVALUE, which may be null to indicate a default initialization.
+     *
+     * Sub-classes of CodeGenBase can override this method
+     * if they wish to use a sub-class of AttrInfo with more
+     * functionality.
+     */
+    public AttrInfo makeAttrInfo(String attrName, ValueType attrType,
+                                 Literal initialValue) {
+        return new AttrInfo(attrName, attrType, initialValue);
+    }
+
+    /**
+     * A factory method that returns a descriptor for a local variable or
+     * parameter named VARNAME of type VARTYPE, whose initial value is
+     * specified by INITIALVALUE (if non-null) and which is defined
+     * immediately within the function given by FUNCINFO.
+     *
+     * These variables are allocated on the stack in activation
+     * frames.
+     *
+     * Sub-classes of CodeGenBase can override this method
+     * if they wish to use a sub-class of StackVarInfo with more
+     * functionality.
+     *
+     */
+    public StackVarInfo makeStackVarInfo(String varName, ValueType varType,
+                                         Literal initialValue,
+                                         FuncInfo funcInfo) {
+        return new StackVarInfo(varName, varType, initialValue, funcInfo);
+    }
+
+    /**
+     * A factory method that returns a descriptor for a global variable with
+     * name VARNAME and type VARTYPE, whose initial value is specified by
+     * INITIALVALUE (if non-null).
+     *
+     * Sub-classes of CodeGenBase can override this method
+     * if they wish to use a sub-class of GlobalVarInfo with more
+     * functionality.
+     */
+    public GlobalVarInfo makeGlobalVarInfo(String varName, ValueType varType,
+                                           Literal initialValue) {
+        return new GlobalVarInfo(varName, varType, initialValue);
+    }
+
+    /*-----------------------------------------------------------*
+     *                                                           *
+     *             ANALYSIS OF AST INTO INFO OBJECTS             *
+     *   (Students can ignore these methods as all the work has  *
+     *    been done and does not need to be modified/extended)   *
+     *                                                           *
+     *-----------------------------------------------------------*/
+
+
+    /**
+     * Analyze PROGRAM, creating Info objects for all symbols.
+     * Populate the global symbol table.
+     */
+    protected void analyzeProgram(Program program) {
+        /* Proceed in phases:
+         * 1. Analyze all global variable declarations.
+         *    Do this first so that global variables are in the symbol
+         *    table before we encounter `global x` declarations.
+         * 2. Analyze classes and global functions now that global variables
+         *    are in the symbol table.
+         */
+        for (Declaration decl : program.declarations) {
+            if (decl instanceof VarDef) {
+                VarDef varDef = (VarDef) decl;
+                ValueType varType
+                    = ValueType.annotationToValueType(varDef.var.type);
+                GlobalVarInfo globalVar =
+                    makeGlobalVarInfo(varDef.var.identifier.name, varType,
+                                      varDef.value);
+
+                this.globalVars.add(globalVar);
+
+                this.globalSymbols.put(globalVar.getVarName(), globalVar);
+            }
+        }
+
+        for (Declaration decl : program.declarations) {
+            if (decl instanceof ClassDef) {
+                ClassDef classDef = (ClassDef) decl;
+                ClassInfo classInfo = analyzeClass(classDef);
+
+                this.classes.add(classInfo);
+
+                this.globalSymbols.put(classInfo.getClassName(), classInfo);
+            } else if (decl instanceof FuncDef) {
+                FuncDef funcDef = (FuncDef) decl;
+                FuncInfo funcInfo = analyzeFunction(null, funcDef, 0,
+                        globalSymbols, null);
+
+                this.functions.add(funcInfo);
+
+                this.globalSymbols.put(funcInfo.getBaseName(), funcInfo);
+            }
+        }
+    }
+
+    /**
+     * Analyze a class definition CLASSDEF and return the resulting
+     * Info object. Also creates Info objects for attributes/methods
+     * and stores them in the ClassInfo. Methods are recursively
+     * analyzed using analyzeFunction().
+     */
+    protected ClassInfo analyzeClass(ClassDef classDef) {
+        String className = classDef.name.name;
+        String superClassName = classDef.superClass.name;
+        SymbolInfo superSymbolInfo = globalSymbols.get(superClassName);
+        assert superSymbolInfo instanceof ClassInfo
+            : "Semantic analysis should ensure that super-class is defined";
+        ClassInfo superClassInfo = (ClassInfo) superSymbolInfo;
+        ClassInfo classInfo = makeClassInfo(className, getNextTypeTag(),
+                                            superClassInfo);
+
+        for (Declaration decl : classDef.declarations) {
+            if (decl instanceof VarDef) {
+                VarDef attrDef = (VarDef) decl;
+                ValueType attrType
+                    = ValueType.annotationToValueType(attrDef.var.type);
+                AttrInfo attrInfo =
+                    makeAttrInfo(attrDef.var.identifier.name, attrType,
+                                 attrDef.value);
+
+                classInfo.addAttribute(attrInfo);
+            } else if (decl instanceof FuncDef) {
+                FuncDef funcDef = (FuncDef) decl;
+                FuncInfo methodInfo = analyzeFunction(className, funcDef, 0,
+                        globalSymbols, null);
+
+                this.functions.add(methodInfo);
+
+                classInfo.addMethod(methodInfo);
+            }
+        }
+
+        return classInfo;
+    }
+
+
+    /**
+     * Analyze a function or method definition FUNCDEF at nesting depth DEPTH
+     * and return the resulting Info object.  Analyze any nested functions
+     * recursively. The FuncInfo's symbol table is completely populated
+     * by analyzing all the params, local vars, global and nonlocal var
+     * declarations.
+     *
+     * CONTAINER is the fully qualified name of the containing function/class,
+     * or null for global functions. PARENTSYMBOLTABLE symbol table contains
+     * symbols inherited from outer regions (that of the containing
+     * function/method for nested function definitions, and the
+     * global symbol table for global function / method definitions).
+     * PARENTFUNCINFO is the Info object for the parent function/method
+     * if this definition is nested, and otherwise null.
+     */
+    protected FuncInfo
+        analyzeFunction(String container, FuncDef funcDef,
+                        int depth,
+                        SymbolTable<SymbolInfo> parentSymbolTable,
+                        FuncInfo parentFuncInfo) {
+        /* We proceed in three steps.
+         *  1. Create the FuncInfo object to be returned.
+         *  2. Populate it by analyzing all the parameters and local var
+         *     definitions.
+         *  3. Now that the function's symbol table is built up, analyze
+         *     nested function definitions.
+         *  4. Add the body to the function descriptor for code gen.
+         */
+
+        String funcBaseName = funcDef.name.name;
+        String funcQualifiedName =
+            container != null
+            ? String.format("%s.%s", container, funcBaseName)
+            : funcBaseName;
+
+        FuncInfo funcInfo =
+            makeFuncInfo(funcQualifiedName, depth,
+                         ValueType.annotationToValueType(funcDef.returnType),
+                         parentSymbolTable, parentFuncInfo,
+                         this::emitUserDefinedFunction);
+
+        for (TypedVar param : funcDef.params) {
+            ValueType paramType
+                = ValueType.annotationToValueType(param.type);
+
+            StackVarInfo paramInfo =
+                makeStackVarInfo(param.identifier.name, paramType, null,
+                                 funcInfo);
+
+            funcInfo.addParam(paramInfo);
+        }
+
+        LocalDeclAnalyzer localDefs = new LocalDeclAnalyzer(funcInfo);
+
+        for (Declaration decl : funcDef.declarations) {
+            decl.dispatch(localDefs);
+        }
+
+        NestedFuncAnalyzer nestedFuncs = new NestedFuncAnalyzer(funcInfo);
+
+        for (Declaration decl : funcDef.declarations) {
+            decl.dispatch(nestedFuncs);
+        }
+
+        funcInfo.addBody(funcDef.statements);
+        return funcInfo;
+    }
+
+    /** Analyzer for local variable declarations in a function. */
+    protected class LocalDeclAnalyzer extends AbstractNodeAnalyzer<Void> {
+        /** The descriptor for the function being analyzed. */
+        private FuncInfo funcInfo;
+
+        /** A new analyzer for a function with descriptor FUNCINFO0. */
+        protected LocalDeclAnalyzer(FuncInfo funcInfo0) {
+            funcInfo = funcInfo0;
+        }
+
+        @Override
+        public Void analyze(VarDef localVarDef) {
+            ValueType localVarType
+                = ValueType.annotationToValueType(localVarDef.var.type);
+            StackVarInfo localVar =
+                makeStackVarInfo(localVarDef.var.identifier.name,
+                                 localVarType, localVarDef.value,
+                                 funcInfo);
+            funcInfo.addLocal(localVar);
+            return null;
+        }
+
+        @Override
+        public Void analyze(GlobalDecl decl) {
+            SymbolInfo symInfo =
+                globalSymbols.get(decl.getIdentifier().name);
+            assert symInfo instanceof GlobalVarInfo
+                : "Semantic analysis should ensure that global var exists";
+            GlobalVarInfo globalVar = (GlobalVarInfo) symInfo;
+            funcInfo.getSymbolTable().put(globalVar.getVarName(),
+                                          globalVar);
+            return null;
+        }
+
+        @Override
+        public Void analyze(NonLocalDecl decl) {
+            assert funcInfo.getSymbolTable().get(decl.getIdentifier().name)
+                instanceof StackVarInfo
+                : "Semantic analysis should ensure nonlocal var exists";
+            return null;
+        }
+    }
+
+    /** Analyzer for nested function declarations in a function. */
+    protected class NestedFuncAnalyzer extends AbstractNodeAnalyzer<Void> {
+        /** Descriptor for the function being analyzed. */
+        private FuncInfo funcInfo;
+
+        /** A new analyzer for a function with descriptor FUNCINFO0. */
+        protected NestedFuncAnalyzer(FuncInfo funcInfo0) {
+            funcInfo = funcInfo0;
+        }
+
+        @Override
+        public Void analyze(FuncDef nestedFuncDef) {
+            FuncInfo nestedFuncInfo =
+                analyzeFunction(funcInfo.getFuncName(), nestedFuncDef,
+                                funcInfo.getDepth() + 1,
+                                funcInfo.getSymbolTable(),
+                                funcInfo);
+
+            functions.add(nestedFuncInfo);
+
+            funcInfo.getSymbolTable().put(nestedFuncInfo.getBaseName(),
+                                          nestedFuncInfo);
+            return null;
+        }
+    }
+
+
+    /*------------------------------------------------------------*
+     *                                                            *
+     *  EMITING DATA SECTION FOR GLOBALS+PROTOTYPES+CONSTANTS     *
+     *   (Students can ignore these methods as all the work has   *
+     *    been done and does not need to be modified/extended)    *
+     *                                                            *
+     *------------------------------------------------------------*/
+
+
+    /** Emit code to align next data item to word boundary. */
+    protected void alignObject() {
+        int wordSizeLog2 =
+            31 - Integer.numberOfLeadingZeros(wordSize);
+        backend.alignNext(wordSizeLog2);
+    }
+
+    /** Emit the constant section containing the prototype FOR the class
+     *  defined by CLASSINFO. */
+    protected void emitPrototype(ClassInfo classInfo) {
+        backend.emitGlobalLabel(classInfo.getPrototypeLabel());
+        backend.emitWordLiteral(classInfo.getTypeTag(),
+                                String.format("Type tag for class: %s",
+                                              classInfo.getClassName()));
+        backend.emitWordLiteral(classInfo.attributes.size() + HEADER_SIZE,
+                                "Object size");
+        backend.emitWordAddress(classInfo.getDispatchTableLabel(),
+                                "Pointer to dispatch table");
+        for (VarInfo attr : classInfo.attributes) {
+            String cmnt = String.format("Initial value of attribute: %s",
+                                        attr.getVarName());
+            emitConstant(attr.getInitialValue(), attr.getVarType(), cmnt);
+        }
+        alignObject();
+    }
+
+    /** Emit a word containing a constant representing VALUE, assuming that
+     *  it will be interpreted as a value of static type TYPE. VALUE may be
+     *  null, indicating None. TYPE may be null, indicating object.
+     *  COMMENT is an optional comment.  */
+    protected void emitConstant(Literal value, ValueType type, String comment) {
+        if (type != null && type.equals(SymbolType.INT_TYPE)) {
+            backend.emitWordLiteral(((IntegerLiteral) value).value, comment);
+        } else if (type != null && type.equals(SymbolType.BOOL_TYPE)) {
+            backend.emitWordLiteral(((BooleanLiteral) value).value ? 1 : 0,
+                                    comment);
+        } else {
+            backend.emitWordAddress(constants.fromLiteral(value), comment);
+        }
+    }
+
+    /** Emit code for all constants. */
+    protected void emitConstants() {
+        backend.emitGlobalLabel(constants.falseConstant);
+        backend.emitWordLiteral(boolClass.getTypeTag(),
+                                "Type tag for class: bool");
+        backend.emitWordLiteral(boolClass.attributes.size() + HEADER_SIZE,
+                                "Object size");
+        backend.emitWordAddress(boolClass.getDispatchTableLabel(),
+                                "Pointer to dispatch table");
+        backend.emitWordLiteral(0, "Constant value of attribute: __bool__");
+        alignObject();
+
+        backend.emitGlobalLabel(constants.trueConstant);
+        backend.emitWordLiteral(boolClass.getTypeTag(),
+                                "Type tag for class: bool");
+        backend.emitWordLiteral(boolClass.attributes.size() + HEADER_SIZE,
+                                "Object size");
+        backend.emitWordAddress(boolClass.getDispatchTableLabel(),
+                                "Pointer to dispatch table");
+        backend.emitWordLiteral(1, "Constant value of attribute: __bool__");
+        alignObject();
+
+        for (Map.Entry<String, Label> e : constants.strConstants.entrySet()) {
+            String value = e.getKey();
+            Label label = e.getValue();
+            int numWordsForCharacters =
+                value.length() / wordSize + 1;
+            backend.emitGlobalLabel(label);
+            backend.emitWordLiteral(strClass.getTypeTag(),
+                                    "Type tag for class: str");
+            backend.emitWordLiteral(3 + 1 + numWordsForCharacters,
+                                    "Object size");
+            backend.emitWordAddress(strClass.getDispatchTableLabel(),
+                                    "Pointer to dispatch table");
+            backend.emitWordLiteral(value.length(),
+                                    "Constant value of attribute: __len__");
+            backend.emitString(value, "Constant value of attribute: __str__");
+            alignObject();
+        }
+
+        for (Map.Entry<Integer, Label> e : constants.intConstants.entrySet()) {
+            Integer value = e.getKey();
+            Label label = e.getValue();
+            backend.emitGlobalLabel(label);
+            backend.emitWordLiteral(intClass.getTypeTag(),
+                                    "Type tag for class: int");
+            backend.emitWordLiteral(intClass.attributes.size() + HEADER_SIZE,
+                                    "Object size");
+            backend.emitWordAddress(intClass.getDispatchTableLabel(),
+                                    "Pointer to dispatch table");
+            backend.emitWordLiteral(value,
+                                    "Constant value of attribute: __int__");
+            alignObject();
+        }
+    }
+
+
+    /** Emit the method dispatching table for CLASSINFO. */
+    protected void emitDispatchTable(ClassInfo classInfo) {
+        Label dispatchTableLabel = classInfo.getDispatchTableLabel();
+        if (dispatchTableLabel == null) {
+            return;
+        }
+        backend.emitGlobalLabel(dispatchTableLabel);
+        for (FuncInfo method : classInfo.methods) {
+            String cmnt = String.format("Implementation for method: %s.%s",
+                                        classInfo.getClassName(),
+                                        method.getBaseName());
+            backend.emitWordAddress(method.getCodeLabel(), cmnt);
+        }
+    }
+
+    /*------------------------------------------------------------*
+     *                                                            *
+     *   UTILITY METHODS TO GET BYTE OFFSETS IN OBJECT LAYOUT     *
+     *   (Students will find these methods helpful to use in      *
+     *   their sub-class when generating code for expressions)    *
+     *                                                            *
+     *------------------------------------------------------------*/
+
+
+    /** Return offset of the type-tag field in an object.  */
+    protected int getTypeTagOffset() {
+        return 0 * wordSize;
+    }
+
+    /** Return offset of the size field in an object. */
+    protected int getObjectSizeOffset() {
+        return 1 * wordSize;
+    }
+
+    /** Return offset of the start of the pointer to the method-dispatching
+     *  table in an object. */
+    protected int getDispatchTableOffset() {
+        return 2 * wordSize;
+    }
+
+    /** Return the offset of the ATTRNAME attribute of an object of type
+     *  described by CLASSINFO. */
+    protected int getAttrOffset(ClassInfo classInfo, String attrName) {
+        int attrIndex = classInfo.getAttributeIndex(attrName);
+        assert attrIndex >= 0
+            : "Type checker ensures that attributes are valid";
+        return wordSize * (HEADER_SIZE + attrIndex);
+    }
+
+    /** Return the offset of the method named METHODNAME in the
+     *  method-dispatching table for the class described by CLASSINFO. */
+    protected int getMethodOffset(ClassInfo classInfo, String methodName) {
+        int methodIndex = classInfo.getMethodIndex(methodName);
+        assert methodIndex >= 0
+            : "Type checker ensures that attributes are valid";
+        return wordSize * methodIndex;
+    }
+
+    /*------------------------------------------------------------*
+     *                                                            *
+     *        UNIMPLEMENTED METHODS (should be extended)          *
+     *                                                            *
+     *------------------------------------------------------------*/
+
+
+    /** Emits code for STATEMENTS, assumed to be at the top level. */
+    protected abstract void emitTopLevel(List<Stmt> statements);
+
+    /** Emits code for the body of user-defined function FUNCINFO. */
+    protected abstract void emitUserDefinedFunction(FuncInfo funcInfo);
+
+    /**
+     * Emits code outside the ChocoPy program.
+     *
+     * Custom assembly routines (that may be jumpable from
+     * program statements) can be emitted here.
+     */
+    protected abstract void emitCustomCode();
+
+    /*------------------------------------------------------------*
+     *                                                            *
+     *             PREDEFINED FUNCTIONS AND ROUTINES              *
+     *   (Students may find a cursory read of these methods to    *
+     *    be useful to get an idea for how code can be emitted)   *
+     *                                                            *
+     *------------------------------------------------------------*/
+
+    /** Return Risc V assembler code for function NAME from
+     *  directory LIB, or null if it does not exist. LIB must end in
+     *  '/'. */
+    protected String getStandardLibraryCode(String name, String lib) {
+        String simpleName = name.replace("$", "") + ".s";
+        return getResourceFileAsString(lib + simpleName);
+    }
+
+    /** Emit label and body for the function LABEL, taking the
+     *  source from directory LIB (must end in '/'). */
+    protected void emitStdFunc(Label label, String lib) {
+        emitStdFunc(label, label.toString(), lib);
+    }
+
+    /** Emit label and body for the function LABEL, taking the
+     *  source from SOURCEFILE.s in directory LIB (must end in '/'). */
+    protected void emitStdFunc(Label label, String sourceFile, String lib) {
+        String source = getStandardLibraryCode(sourceFile, lib);
+        if (source == null) {
+            throw fatal("Code for %s is missing.", sourceFile);
+        }
+        backend.emitGlobalLabel(label);
+        backend.emit(convertLiterals(source));
+    }
+
+    /** Emit label and body for the function LABEL, taking the
+     *  source from from the default library directory. */
+    protected void emitStdFunc(Label label) {
+        emitStdFunc(label, LIBRARY_CODE_DIR);
+    }
+
+    /** Emit label and body for the function named NAME, taking the
+     *  source from from directory LIB (must end in '/'). */
+    protected void emitStdFunc(String name, String lib) {
+        emitStdFunc(new Label(name), lib);
+    }
+
+    /** Emit label and body for the function NAME, taking the
+     *  source from from the default library directory. */
+    protected void emitStdFunc(String name) {
+        emitStdFunc(name, LIBRARY_CODE_DIR);
+    }
+
+    /** Emit label and body for the function described by FUNCINFO, taking the
+     *  source from from directory LIB (must end in '/'). */
+    protected void emitStdFunc(FuncInfo funcInfo, String lib) {
+        emitStdFunc(funcInfo.getCodeLabel(), lib);
+    }
+
+    /** Emit label and body for the function described by FUNCINFO, taking the
+     *  source from from the default library directory. */
+    protected void emitStdFunc(FuncInfo funcInfo) {
+        emitStdFunc(funcInfo, LIBRARY_CODE_DIR);
+    }
+
+    /** Pattern matching STRING["..."]. */
+    private static final Pattern STRING_LITERAL_PATN =
+        Pattern.compile("STRING\\[\"(.*?)\"\\]");
+
+    /** Return result of converting STRING["..."] notations in SOURCE to
+     *  labels of string constants, adding those constants to the pool. */
+    private String convertLiterals(String source) {
+        Matcher matcher = STRING_LITERAL_PATN.matcher(source);
+        StringBuffer result = new StringBuffer();
+        while (matcher.find()) {
+            String r = constants.getStrConstant(matcher.group(1)).toString();
+            matcher.appendReplacement(result,
+                                      pad(r, ' ',
+                                          matcher.end(0) - matcher.start(0),
+                                          false));
+        }
+        return matcher.appendTail(result).toString();
+    }
+
+}
diff --git a/src/main/java/chocopy/common/codegen/Constants.java b/src/main/java/chocopy/common/codegen/Constants.java
new file mode 100644
index 0000000000000000000000000000000000000000..01019a3f27c91f6b19e850a66cb6e6d49f6ab704
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/Constants.java
@@ -0,0 +1,121 @@
+package chocopy.common.codegen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import chocopy.common.astnodes.BooleanLiteral;
+import chocopy.common.astnodes.IntegerLiteral;
+import chocopy.common.astnodes.Literal;
+import chocopy.common.astnodes.NoneLiteral;
+import chocopy.common.astnodes.StringLiteral;
+
+/**
+ * A store for caching and re-using program constants that are represented
+ * as immutable objects.
+ *
+ * Constants are emitted in assembly in the DATA section,
+ * and therefore are represented by their labels.
+ */
+public class Constants {
+
+    /** A counter used to generate unique label names for constants. */
+    protected int nextLabelSuffix = 0;
+
+    /** The constant representing the boolean `False`. */
+    final Label falseConstant = generateConstantLabel();
+
+    /** The constant representing the boolean `True`.  This immediately
+     *  follows falseConstant in static memory. */
+    final Label trueConstant = generateConstantLabel();
+
+    /** A cache for integer-valued constants. */
+    final Map<Integer, Label> intConstants = new HashMap<>();
+
+    /** A cache for string-valued constants. */
+    final Map<String, Label> strConstants = new HashMap<>();
+
+    /**
+     * Returns the next unique label suffix for constants.
+     *
+     * @return the next unique label suffix for constants
+     */
+    protected int getNextLabelSuffix() {
+        return nextLabelSuffix++;
+    }
+
+    /**
+     * Generates a fresh label for constants.
+     *
+     * This label is guaranteed to be unique amongst labels
+     * generated by invoking this method. All such labels
+     * have a prefix of `const_`.
+     *
+     * @return a fresh label
+     */
+    public Label generateConstantLabel() {
+        return new Label(String.format("const_%d", getNextLabelSuffix()));
+    }
+
+    /**
+     * Returns the label for a `bool` constant.
+     *
+     * @param value the boolean value
+     * @return the label for the boolean value
+     */
+    public Label getBoolConstant(boolean value) {
+        return value ? trueConstant : falseConstant;
+    }
+
+    /**
+     * Returns the label for am `int` constant.
+     *
+     * @param value the integer value
+     * @return the label for the integer value
+     */
+    public Label getIntConstant(int value) {
+        if (intConstants.containsKey(value)) {
+            return intConstants.get(value);
+        } else {
+            Label newLabel = generateConstantLabel();
+            intConstants.put(value, newLabel);
+            return newLabel;
+        }
+    }
+
+    /**
+     * Returns the label for a `str` constant.
+     *
+     * @param value the string value
+     * @return the label for the string value
+     */
+    public Label getStrConstant(String value) {
+        if (strConstants.containsKey(value)) {
+            return strConstants.get(value);
+        } else {
+            Label newLabel = generateConstantLabel();
+            strConstants.put(value, newLabel);
+            return newLabel;
+        }
+    }
+
+    /**
+     * Converts a constant literal in the AST to a constant
+     * for code generation.
+     *
+     * @param literal the literal expression in the AST
+     * @return a {@link Label} representing a constant int/str/bool,
+     *         or `null` representing the None literal
+     */
+    public Label fromLiteral(Literal literal) {
+        if (literal instanceof IntegerLiteral) {
+            return getIntConstant(((IntegerLiteral) literal).value);
+        } else if (literal instanceof StringLiteral) {
+            return getStrConstant(((StringLiteral) literal).value);
+        } else if (literal instanceof BooleanLiteral) {
+            return getBoolConstant(((BooleanLiteral) literal).value);
+        } else {
+            assert literal == null || literal instanceof NoneLiteral;
+            return null;
+        }
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/FuncInfo.java b/src/main/java/chocopy/common/codegen/FuncInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6bf02eff6902f88614cfff03525f1fd12793b44
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/FuncInfo.java
@@ -0,0 +1,217 @@
+package chocopy.common.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.types.SymbolType;
+import chocopy.common.astnodes.Stmt;
+
+/**
+ * A descriptor for function and method definitions.
+ *
+ * This class stores information required for code generation
+ * such as the information about a function's parameters, local variables,
+ * the local symbol table, the function body, and the label where the code
+ * for the body is generated.
+ */
+public class FuncInfo extends SymbolInfo {
+
+    /**
+     * The fully-qualified name of the function.
+     *
+     * All functions in a ChocoPy program have a unique fully-qualified name.
+     * Global functions defined with name `f` have fully-qualified name `f`.
+     * Methods `m` in a class `C` have fully-qualified name `C.m`.
+     * Functions `f` nested inside another function
+     * with fully-qualified name `F` have a fully-qualified name of `F.f`.
+     */
+    protected final String funcName;
+
+    /**
+     * The static depth of a function.
+     *
+     * Global functions and class methods have a static depth of 0.
+     * Nested functions that are defined in the body of a function
+     * with static depth `D` have a static depth of `D+1`.
+     */
+    protected final int depth;
+
+    /**
+     * This function's return type.
+     */
+    protected final SymbolType returnType;
+
+    /** A list of parameter names. */
+    protected final List<String> params = new ArrayList<>();
+
+    /** A list of local variable descriptors. */
+    protected final List<StackVarInfo> locals = new ArrayList<>();
+
+    /** The function body. */
+    protected final List<Stmt> statements = new ArrayList<>();
+
+    /** The local symbol table that binds identifiers seen in the
+     *  function's body. */
+    protected final SymbolTable<SymbolInfo> symbolTable;
+
+    /** The label of the generated code for the function's body. */
+    protected final Label codeLabel;
+
+    /** The descriptor of the enclosing function (this is only non-null
+     *  for nested functions). */
+    protected final FuncInfo parentFuncInfo;
+
+    /**
+     * A method that is invoked to emit the function's body.
+     *
+     * The method should accept one parameter of type `FuncInfo`.
+     */
+    protected Consumer<FuncInfo> emitter;
+
+    /**
+     * Creates a descriptor for a function or method with fully qualified name
+     * FUNCNAME returning type RETURNTYPE that is at nesting depth DEPTH.
+     * The code label is formed from FUNCNAME by prepending a $ sign to
+     * prevent collisions.
+     * PARENTSYMBOLTABLE is the symbol table of the containing region.
+     * PARENTFUNCINFO is the descriptor of the enclosing function
+     * (null for global functions and methods).
+     * EMITTER encapsulates a method that emits the function's body (this is
+     * usually a generic emitter for user-defined functions/methods,
+     * and a special emitter for pre-defined functions/methods). */
+    public FuncInfo(String funcName, int depth, SymbolType returnType,
+                    SymbolTable<SymbolInfo> parentSymbolTable,
+                    FuncInfo parentFuncInfo, Consumer<FuncInfo> emitter) {
+        this.funcName = funcName;
+        this.codeLabel = new Label(String.format("$%s", funcName));
+        this.depth = depth;
+        this.returnType = returnType;
+        this.symbolTable = new SymbolTable<>(parentSymbolTable);
+        this.parentFuncInfo = parentFuncInfo;
+        this.emitter = emitter;
+    }
+
+    /** Adds parameter with descriptor PARAMINFO to this function. */
+    public void addParam(StackVarInfo paramInfo) {
+        this.params.add(paramInfo.getVarName());
+        this.symbolTable.put(paramInfo.getVarName(), paramInfo);
+    }
+
+    /** Adds a local variable with descriptor STACKVARINFO to this function. */
+    public void addLocal(StackVarInfo stackVarInfo) {
+        this.locals.add(stackVarInfo);
+        this.symbolTable.put(stackVarInfo.getVarName(), stackVarInfo);
+    }
+
+    /** Adds STMTS to the function's body. */
+    public void addBody(List<Stmt> stmts) {
+        statements.addAll(stmts);
+    }
+
+    /**
+     * Returns the index of parameter or local variable NAME in the function's
+     * activation record.
+     *
+     * The convention is that for a function with N params
+     * and K local vars, the i`th param is at index `i`
+     * and the j`th local var is at index `N+j+2`. In all,
+     * a function stores N+K+2 variables contiguously in
+     * its activation record, where the N+1st is the frame pointer
+     * and the N+2nd is the return address.
+     *
+     * Caution: this is an index (starting at 0), and not an offset in
+     * number of bytes.
+     */
+    public int getVarIndex(String name) {
+        int idx = params.indexOf(name);
+        if (idx >= 0) {
+            return idx;
+        }
+        for (int i = 0; i < locals.size(); i++) {
+            if (locals.get(i).getVarName().equals(name)) {
+                return i + params.size() + 2;
+            }
+        }
+        String msg =
+            String.format("%s is not a var defined in function %s",
+                          name, funcName);
+        throw new IllegalArgumentException(msg);
+    }
+
+    /** Returns the label corresponding to the function's body in assembly. */
+    public Label getCodeLabel() {
+        return codeLabel;
+    }
+
+    /**
+     * Returns the function's defined name in the program.
+     * This is the last component of the dot-separated
+     * fully-qualified name.
+     */
+    public String getBaseName() {
+        int rightmostDotIndex = funcName.lastIndexOf('.');
+        if (rightmostDotIndex == -1) {
+            return funcName;
+        } else {
+            return funcName.substring(rightmostDotIndex + 1);
+        }
+    }
+
+    /** Returns the function's fully-qualified name. */
+    public String getFuncName() {
+        return funcName;
+    }
+
+    /** Returns the function's static nesting depth. */
+    public int getDepth() {
+        return depth;
+    }
+
+    /** Returns the function's parameters in order of definition. */
+    public List<String> getParams() {
+        return params;
+    }
+
+    /** Returns the return type of this function. */
+    public SymbolType getReturnType() {
+        return returnType;
+    }
+
+    /**
+     * Returns the function's explicitly defined local variables, excluding
+     * parameters.
+     *
+     * This list is mainly used in generating code for
+     * initializing local variables that are not parameters.
+     */
+    public List<StackVarInfo> getLocals() {
+        return locals;
+    }
+
+    /** Returns the list of statements in the function's body. */
+    public List<Stmt> getStatements() {
+        return statements;
+    }
+
+    /**
+     * Returns the function's local symbol table.
+     *
+     * @return the function's local symbol table
+     */
+    public SymbolTable<SymbolInfo> getSymbolTable() {
+        return symbolTable;
+    }
+
+    /** Returns the parent function's descriptor for nested functions,
+     *  and null if this function is not nested.  */
+    public FuncInfo getParentFuncInfo() {
+        return parentFuncInfo;
+    }
+
+    /** Emits the function's body. */
+    public void emitBody() {
+        emitter.accept(this);
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/GlobalVarInfo.java b/src/main/java/chocopy/common/codegen/GlobalVarInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf0abcda5f723242dd9437d5b8537fe5d79d50fc
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/GlobalVarInfo.java
@@ -0,0 +1,27 @@
+package chocopy.common.codegen;
+
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.Literal;
+
+/** Code-generation related information about a global variable. */
+public class GlobalVarInfo extends VarInfo {
+
+    /** This variable resides in static storage tagged with LABEL. The
+     *  label is prepended with "$" to prevent name clashes. */
+    protected final Label label;
+
+    /**
+     * A descriptor for a global variable named VARNAME of type VARTYPE
+     * whose initial value is labeled with INITIALVALUE (null if
+     * no initializtion value). */
+    public GlobalVarInfo(String varName, ValueType varType,
+                         Literal initialValue) {
+        super(varName, varType, initialValue);
+        this.label = new Label(String.format("$%s", varName));
+    }
+
+    /** Return the code location of this variable. */
+    public Label getLabel() {
+        return label;
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/Label.java b/src/main/java/chocopy/common/codegen/Label.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb678e273df1d011e886af25238108c9ba8b07d1
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/Label.java
@@ -0,0 +1,48 @@
+package chocopy.common.codegen;
+
+import java.util.Objects;
+
+/**
+ * A label in assembly.
+ */
+public class Label {
+
+    /** The name of the label. */
+    public final String labelName;
+
+    /** A new label with name LABELNAME. */
+    public Label(String labelName) {
+        this.labelName = labelName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        Label label = (Label) o;
+        return Objects.equals(labelName, label.labelName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hash(labelName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return labelName;
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/RiscVBackend.java b/src/main/java/chocopy/common/codegen/RiscVBackend.java
new file mode 100644
index 0000000000000000000000000000000000000000..669075a6f6badc1f5233ff35b3e41fba2fa007ec
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/RiscVBackend.java
@@ -0,0 +1,719 @@
+package chocopy.common.codegen;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** RISC V assembly-language generation utilities. */
+public class RiscVBackend {
+
+    /** Accumulator for assembly code output. */
+    protected final StringWriter asmText = new StringWriter();
+
+    /** Allows print, println, and printf of assmebly code. */
+    private final PrintWriter out = new PrintWriter(asmText);
+
+    /** The word size in bytes for RISC-V 32-bit. */
+    protected static final int WORD_SIZE = 4;
+
+    /** Mappung from @-symbols to values. */
+    private HashMap<String, String> defns = new HashMap<>();
+
+    /** The RISC-V registers. */
+    public enum Register {
+
+        A0("a0"), A1("a1"), A2("a2"), A3("a3"), A4("a4"), A5("a5"), A6("a6"),
+        A7("a7"),
+        T0("t0"), T1("t1"), T2("t2"), T3("t3"), T4("t4"), T5("t5"), T6("t6"),
+        S1("s1"), S2("s2"), S3("s3"), S4("s4"), S5("s5"),
+        S6("s6"), S7("s7"), S8("s8"), S9("s9"), S10("s10"), S11("s11"),
+        FP("fp"), SP("sp"), GP("gp"), RA("ra"), ZERO("zero");
+
+        /** The name of the register used in assembly. */
+        protected final String name;
+
+        /** This register's code representation is NAME. */
+        Register(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return this.name;
+        }
+
+    }
+
+    /** Matches a reference to an assembler symbol, and possibly a trailing
+     *  +CONST or -CONST. */
+    static final Pattern ASM_SYM_REF_PATN =
+        Pattern.compile("@(.[a-zA-Z_0-9.$]*)(?:\\s*([-+]\\d+))?|(#.*)|(\r?\n)");
+    /** Matches a decimal numeral with optional sign. */
+    static final Pattern SIGNED_INT_PATN = Pattern.compile("[-+]?\\d+");
+
+    @Override
+    public String toString() {
+        return asmText.toString();
+    }
+
+    /** Return the accumulated assembly code.  It is an error if the
+     *  accumulated code contains any '@' references to undefined symbols. */
+    protected String oldToString() {
+        int deltaSpace;
+        StringBuffer result = new StringBuffer();
+        deltaSpace = 0;
+        Matcher refs = ASM_SYM_REF_PATN.matcher(asmText.toString());
+        while (refs.find()) {
+            if (refs.group(3) != null) {
+                String repl = refs.group(3);
+                refs.appendReplacement(result, "");
+                while (deltaSpace < 0) {
+                    result.append(" ");
+                    deltaSpace += 1;
+                }
+                result.append(repl);
+            } else if (refs.group(4) != null) {
+                deltaSpace = 0;
+                refs.appendReplacement(result, refs.group(4));
+            } else {
+                String repl;
+                repl = defns.get(refs.group(1));
+                if (repl == null) {
+                    throw new IllegalStateException("undefined symbol: @"
+                                                    + refs.group(1));
+                }
+                if (refs.group(2) != null) {
+                    if (SIGNED_INT_PATN.matcher(repl).matches()) {
+                        int val = Integer.parseInt(repl)
+                            + Integer.parseInt(refs.group(2));
+                        repl = Integer.toString(val);
+                    } else {
+                        repl += refs.group(2);
+                    }
+                }
+                refs.appendReplacement(result, repl);
+                deltaSpace += repl.length() - refs.end(0) + refs.start(0);
+            }
+        }
+        refs.appendTail(result);
+
+        return result.toString();
+    }
+
+    /** Define @NAME to have the value VALUE.  Here, NAME is assumed to be
+     *  an identifier consisting of letters, digits, underscores, and any of
+     *  the charcters '$' or '.', and that does not start with a digit.  Value
+     *  may be a numeral or another symbol.
+     */
+    public void defineSym(String name, String value) {
+        if (name.startsWith("@")) {
+            emitInsn(String.format(".equiv %s, %s", name, value), null);
+        } else {
+            emitInsn(String.format(".equiv @%s, %s", name, value), null);
+        }
+    }
+
+    /** Define @NAME to have the value VALUE, where value is converted to
+     *  a string.  See {@link #defineSym(java.lang.String, java.lang.String)}.
+     */
+    public void defineSym(String name, int value) {
+        defineSym(name, Integer.toString(value));
+    }
+
+    /**
+     * Returns the word size in bytes.
+     *
+     * This method is used instead of directly accessing the
+     * static field {@link #WORD_SIZE}, so that this class
+     * may be extended with alternate word sizes.
+     */
+    public int getWordSize() {
+        return WORD_SIZE;
+    }
+
+    /**
+     * Emit the text STR to the output stream verbatim.  STR should have no
+     * trailing newline.
+     */
+    protected void emit(String str) {
+        out.println(str);
+    }
+
+    /**
+     * Emit instruction or directive INSN along with COMMENT as a one-line
+     * comment, if non-null.
+     */
+    public void emitInsn(String insn, String comment) {
+        if (comment != null) {
+            emit(String.format("  %-40s # %s", insn, comment));
+        } else {
+            emitInsn(insn);
+        }
+    }
+
+    /**
+     * Emit instruction or directive INSN without a comment.
+     */
+    protected void emitInsn(String insn) {
+        emit(String.format("  %s", insn));
+    }
+
+    /**
+     * Emit a local label marker for LABEL with one-line comment COMMENT (null
+     * if missing).  Invoke only once per unique label.
+     */
+    public void emitLocalLabel(Label label, String comment) {
+        if (comment != null) {
+            emit(String.format("%-42s # %s", label + ":", comment));
+        } else {
+            emit(String.format("%s:", label + ":"));
+        }
+    }
+
+    /**
+     * Emit a global label marker for LABEL. Invoke only once per
+     * unique label.
+     */
+    public void emitGlobalLabel(Label label) {
+        emit(String.format("\n.globl %s", label));
+        emit(String.format("%s:", label));
+    }
+
+    /**
+     * Emit a data word containing VALUE as an integer value.  COMMENT is
+     * a emitted as a one-line comment, if non-null.
+     */
+    public void emitWordLiteral(Integer value, String comment) {
+        emitInsn(String.format(".word %s", value), comment);
+    }
+
+    /**
+     * Emit a data word containing the address ADDR, or 0 if LABEL is null.
+     * COMMENT is a emitted as a one-line comment, if non-null.
+     */
+    public void emitWordAddress(Label addr, String comment) {
+        if (addr == null) {
+            emitWordLiteral(0, comment);
+        } else {
+            emitInsn(String.format(".word %s", addr), comment);
+        }
+    }
+
+
+    /**
+     * Emit VALUE as an ASCII null-terminated string constant, with
+     * COMMENT as its one-line comment, if non-null.
+     */
+    public void emitString(String value, String comment) {
+        String quoted = value
+                .replace("\\", "\\\\")
+                .replace("\n", "\\n")
+                .replace("\t", "\\t")
+                .replace("\"", "\\\"");
+        emitInsn(String.format(".string \"%s\"", quoted), comment);
+    }
+
+    /**
+     * Mark the start of a data section.
+     */
+    public void startData() {
+        emit("\n.data");
+    }
+
+    /**
+     * Mark the start of a code/text section.
+     */
+    public void startCode() {
+        emit("\n.text");
+    }
+
+    /**
+     * Align the next instruction/word in memory to
+     * a multiple of 2**POW bytes.
+     */
+    public void alignNext(int pow) {
+        emitInsn(String.format(".align %d", pow));
+    }
+
+    /**
+     * Emit an ecall instruction, with one-line comment COMMENT,
+     * if non-null.
+     */
+    public void emitEcall(String comment) {
+        emitInsn("ecall", comment);
+    }
+
+    /**
+     * Emit a load-address instruction with destination RD and source
+     * LABEL.  COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitLA(Register rd, Label label, String comment) {
+        emitInsn(String.format("la %s, %s", rd, label), comment);
+    }
+
+    /**
+     * Emit a load-immediate pseudo-op to set RD to IMM.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitLI(Register rd, Integer imm, String comment) {
+        emitInsn(String.format("li %s, %d", rd, imm), comment);
+    }
+
+    /**
+     * Emit a load-upper-immediate instruction to set the upper 20 bits
+     * of RD to IMM, where 0 <= IMM < 2**20. COMMENT is an optional
+     * one-line comment (null if missing).
+     */
+    public void emitLUI(Register rd, Integer imm, String comment) {
+        emitInsn(String.format("lui %s, %d", rd, imm), comment);
+    }
+
+    /**
+     * Emit a move instruction to set RD to the contents of RS.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitMV(Register rd, Register rs, String comment) {
+        emitInsn(String.format("mv %s, %s", rd, rs), comment);
+    }
+
+    /**
+     * Emit a jump-register (computed jump) instruction to the address in
+     * RS.  COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitJR(Register rs, String comment) {
+        emitInsn(String.format("jr %s", rs), comment);
+    }
+
+    /**
+     * Emit a jump (unconditional jump) instruction to LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitJ(Label label, String comment) {
+        emitInsn(String.format("j %s", label), comment);
+    }
+
+
+    /**
+     * Emit a jump-and-link instruction to LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitJAL(Label label, String comment) {
+        emitInsn(String.format("jal %s", label), comment);
+    }
+
+    /**
+     * Emit a computed-jump-and-link instruction to the address in RS.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitJALR(Register rs, String comment) {
+        emitInsn(String.format("jalr %s", rs), comment);
+    }
+
+    /**
+     * Emit an add-immediate instruction performing RD = RS + IMM.
+     * Requires -2048 <= IMM < 2048. COMMENT is an optional one-line
+     * comment (null if missing).
+     */
+    public void emitADDI(Register rd, Register rs, Integer imm,
+                         String comment) {
+        emitInsn(String.format("addi %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit an add-immediate instruction performing RD = RS + IMM.
+     * Here, IMM is a string generally containing a symbolic assembler
+     * constant (see defineSym) representing an integer value, or an
+     * expression of the form @NAME+NUM or @NAME-NUM.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitADDI(Register rd, Register rs, String imm,
+                         String comment) {
+        emitInsn(String.format("addi %s, %s, %s", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit an add instruction performing RD = RS1 + RS2 mod 2**32.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitADD(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("add %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a subtract instruction performing RD = RS1 - RS2 mod 2**32.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSUB(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("sub %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a multiply instruction performing RD = RS1 * RS2 mod 2**32.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitMUL(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("mul %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a signed integer divide instruction performing
+     * RD = RS1 / RS2 mod 2**32, rounding the result toward 0.
+     * If RS2 == 0, sets RD to -1. If RS1 == -2**31 and RS2 == -1,
+     * sets RD to -2**31.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitDIV(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("div %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a remainder instruction: RD = RS1 rem RS2 defined so that
+     * (RS1 / RS2) * RS2 + (RS1 rem RS2) == RS1, where / is as for
+     * emitDIV.  COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitREM(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("rem %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit an xor instruction: RD = RS1 ^ RS2. COMMENT is an optional
+     * one-line comment (null if missing).
+     */
+    public void emitXOR(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("xor %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit an xor-immediate instruction: RD = RS ^ IMM, where
+     * -2048 <= IMM < 2048.  COMMENT is an optional
+     * one-line comment (null if missing).
+     */
+    public void emitXORI(Register rd, Register rs, Integer imm,
+                         String comment) {
+        emitInsn(String.format("xori %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit a bitwise and instruction: RD = RS1 & RS2.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitAND(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("and %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a bitwise and-immediate instruction: RD = RS & IMM, where
+     * -2048 <= IMM < 2048.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitANDI(Register rd, Register rs, Integer imm,
+                         String comment) {
+        emitInsn(String.format("andi %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit a bitwise or instruction: RD = RS1 | RS2.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitOR(Register rd, Register rs1, Register rs2,
+                       String comment) {
+        emitInsn(String.format("or %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a bitwise or-immediate instruction: RD = RS | IMM, where
+     * -2048 <= IMM < 2048.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitORI(Register rd, Register rs, Integer imm,
+                        String comment) {
+        emitInsn(String.format("ori %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit a logical left shift instruction: RD = RS1 << (RS2 & 0x31).
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSLL(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("sll %s, %s, %d", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a logical left shift instruction: RD = RS << (IMM & 0x31).
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSLLI(Register rd, Register rs, Integer imm,
+                        String comment) {
+        emitInsn(String.format("slli %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit a logical right shift instruction: RD = RS1 >>> (RS2 & 0x31).
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSRL(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("srl %s, %s, %d", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a logical right shift instruction: RD = RS >>> (IMM & 0x31).
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSRLI(Register rd, Register rs, Integer imm,
+                        String comment) {
+        emitInsn(String.format("srli %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit an arithmetic right shift instruction: RD = RS1 >> (RS2 & 0x31).
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSRA(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("sra %s, %s, %d", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit an arithmetic right shift instruction: RD = RS >> (IMM & 0x31).
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSRAI(Register rd, Register rs, Integer imm,
+                        String comment) {
+        emitInsn(String.format("srai %s, %s, %d", rd, rs, imm), comment);
+    }
+
+    /**
+     * Emit a load-word instruction: RD = MEMORY[RS + IMM]:4, where
+     * -2048 <= IMM < 2048.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitLW(Register rd, Register rs, Integer imm,
+                       String comment) {
+        emitInsn(String.format("lw %s, %d(%s)", rd, imm, rs), comment);
+    }
+
+    /**
+     * Emit a load-word instruction: RD = MEMORY[RS + IMM]:4, where
+     * -2048 <= IMM < 2048.  Here, IMM is symbolic constant expression
+     * (see emitADDI).  COMMENT is an optional one-line
+     * comment (null if missing).
+     */
+    public void emitLW(Register rd, Register rs, String imm,
+                       String comment) {
+        emitInsn(String.format("lw %s, %s(%s)", rd, imm, rs), comment);
+    }
+
+    /**
+     * Emit a store-word instruction: MEMORY[RS1 + IMM]:4 = RS2, where
+     * -2048 <= IMM < 2048.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSW(Register rs2, Register rs1, Integer imm,
+                       String comment) {
+        emitInsn(String.format("sw %s, %d(%s)", rs2, imm, rs1), comment);
+    }
+
+    /**
+     * Emit a store-word instruction: MEMORY[RS1 + IMM]:4 = RS2, where
+     * -2048 <= IMM < 2048.  Here, IMM is symbolic constant expression
+     * (see emitADDI).  COMMENT is an optional one-line
+     * comment (null if missing).
+     */
+    public void emitSW(Register rs2, Register rs1, String imm,
+                       String comment) {
+        emitInsn(String.format("sw %s, %s(%s)", rs2, imm, rs1), comment);
+    }
+
+    /**
+     * Emit a load-word instruction for globals: RD = MEMORY[LABEL]:4.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitLW(Register rd, Label label, String comment) {
+        emitInsn(String.format("lw %s, %s", rd, label), comment);
+    }
+
+    /**
+     * Emit a store-word instruction for globals: MEMORY[LABEL]:4 = RS,
+     * using TMP as a temporary register.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSW(Register rs, Label label, Register tmp,
+                       String comment) {
+        emitInsn(String.format("sw %s, %s, %s", rs, label, tmp), comment);
+    }
+
+    /**
+     * Emit a load-byte instruction: RD = MEMORY[RS + IMM]:1, where
+     * -2048 <= IMM < 2048.  Sign extends the byte loaded.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitLB(Register rd, Register rs, Integer imm,
+                       String comment) {
+        emitInsn(String.format("lb %s, %d(%s)", rd, imm, rs), comment);
+    }
+
+    /**
+     * Emit a load-byte-unsigned instruction: RD = MEMORY[RS + IMM]:1, where
+     * -2048 <= IMM < 2048.  Zero-extends the byte loaded.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitLBU(Register rd, Register rs, Integer imm,
+                        String comment) {
+        emitInsn(String.format("lbu %s, %d(%s)", rd, imm, rs), comment);
+    }
+
+    /**
+     * Emit a store-byte instruction: MEMORY[RS1 + IMM]:1 = RS2, where
+     * -2048 <= IMM < 2048.  Assigns the low-order byte of RS2 to memory.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSB(Register rs2, Register rs1, Integer imm,
+                       String comment) {
+        emitInsn(String.format("sb %s, %d(%s)", rs2, imm, rs1), comment);
+    }
+
+    /**
+     * Emit a branch-if-equal instruction: if RS1 == RS2 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBEQ(Register rs1, Register rs2, Label label,
+                        String comment) {
+        emitInsn(String.format("beq %s, %s, %s", rs1, rs2, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-unequal instruction: if RS1 != RS2 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBNE(Register rs1, Register rs2, Label label,
+                        String comment) {
+        emitInsn(String.format("bne %s, %s, %s", rs1, rs2, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-greater-or-equal (signed) instruction:
+     * if RS1 >= RS2 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBGE(Register rs1, Register rs2, Label label,
+                         String comment) {
+        emitInsn(String.format("bge %s, %s, %s", rs1, rs2, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-greater-or-equal (unsigned) instruction:
+     * if RS1 >= RS2 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBGEU(Register rs1, Register rs2, Label label,
+                         String comment) {
+        emitInsn(String.format("bgeu %s, %s, %s", rs1, rs2, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-greater-or-equal (signed) instruction:
+     * if RS1 >= RS2 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBLT(Register rs1, Register rs2, Label label,
+                         String comment) {
+        emitInsn(String.format("blt %s, %s, %s", rs1, rs2, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-greater-or-equal (unsigned) instruction:
+     * if RS1 >= RS2 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBLTU(Register rs1, Register rs2, Label label,
+                         String comment) {
+        emitInsn(String.format("bltu %s, %s, %s", rs1, rs2, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-zero instruction: if RS == 0 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBEQZ(Register rs, Label label, String comment) {
+        emitInsn(String.format("beqz %s, %s", rs, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-not-zero instruction: if RS != 0 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBNEZ(Register rs, Label label, String comment) {
+        emitInsn(String.format("bnez %s, %s", rs, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-less-than-zero instruction: if RS < 0 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBLTZ(Register rs, Label label, String comment) {
+        emitInsn(String.format("bltz %s, %s", rs, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-greater-than-zero instruction: if RS > 0 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBGTZ(Register rs, Label label, String comment) {
+        emitInsn(String.format("bgtz %s, %s", rs, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-less-than-equal-to-zero instruction:
+     * if RS <= 0 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBLEZ(Register rs, Label label, String comment) {
+        emitInsn(String.format("blez %s, %s", rs, label), comment);
+    }
+
+    /**
+     * Emit a branch-if-greater-than-equal-to-zero instruction:
+     * if RS >= 0 goto LABEL.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitBGEZ(Register rs, Label label, String comment) {
+        emitInsn(String.format("bgez %s, %s", rs, label), comment);
+    }
+
+    /**
+     * Emit a set-less-than instruction: RD = 1 if RS1 < RS2 else 0.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSLT(Register rd, Register rs1, Register rs2,
+                        String comment) {
+        emitInsn(String.format("slt %s, %s, %s", rd, rs1, rs2), comment);
+    }
+
+    /**
+     * Emit a set-if-zero instruction: RD = 1 if RS == 0 else 0.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSEQZ(Register rd, Register rs, String comment) {
+        emitInsn(String.format("seqz %s, %s", rd, rs), comment);
+    }
+
+    /**
+     * Emit a set-if-not-zero instruction: RD = 1 if RS != 0 else 0.
+     * COMMENT is an optional one-line comment (null if missing).
+     */
+    public void emitSNEZ(Register rd, Register rs, String comment) {
+        emitInsn(String.format("snez %s, %s", rd, rs), comment);
+    }
+
+}
diff --git a/src/main/java/chocopy/common/codegen/StackVarInfo.java b/src/main/java/chocopy/common/codegen/StackVarInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..066ee7ddb4d8c311627e0de041737d0ee1c07f98
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/StackVarInfo.java
@@ -0,0 +1,30 @@
+package chocopy.common.codegen;
+
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.Literal;
+
+/** Code-generation information about a local variable or parameter. */
+public class StackVarInfo extends VarInfo {
+
+    /** Information about the enclosing function. */
+    protected final FuncInfo funcInfo;
+
+    /**
+     * A descriptor for a local variable or parameter VARNAME of type VARTYPE,
+     * whose initial value is given by INITIALVALUE (null if no initial value),
+     * and which is nested immediately within the function described
+     * by FUNCINFO.
+     */
+    public StackVarInfo(String varName, ValueType varType, Literal initialValue,
+                        FuncInfo funcInfo) {
+        super(varName, varType, initialValue);
+        this.funcInfo = funcInfo;
+    }
+
+    /**
+     * Returns the descriptor of the function in which this var is defined.
+     */
+    public FuncInfo getFuncInfo() {
+        return funcInfo;
+    }
+}
diff --git a/src/main/java/chocopy/common/codegen/SymbolInfo.java b/src/main/java/chocopy/common/codegen/SymbolInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a2fd0a389333f123d547ffbf1b58150817ee625
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/SymbolInfo.java
@@ -0,0 +1,9 @@
+package chocopy.common.codegen;
+
+/**
+ * Abstract base class for all the Info classes that
+ * store information about a symbol during code generation.
+ */
+public abstract class SymbolInfo {
+
+}
diff --git a/src/main/java/chocopy/common/codegen/VarInfo.java b/src/main/java/chocopy/common/codegen/VarInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4357656bf7dd81ec9c1091bb70540a5e14b5bb7
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/VarInfo.java
@@ -0,0 +1,41 @@
+package chocopy.common.codegen;
+
+import chocopy.common.analysis.types.ValueType;
+import chocopy.common.astnodes.Literal;
+
+/** Information about a variable or attribute. */
+public abstract class VarInfo extends SymbolInfo {
+
+    /** Name of variable or attribute. */
+    protected final String varName;
+    /** Runtime location of initial value for this variable or attribute. */
+    protected final Literal initialValue;
+    /** Static type of the variable. */
+    protected final ValueType varType;
+
+    /**
+     * A descriptor for variable or attribute VARNAME with VARTYPE as its static
+     * type and INITIALVALUE as its initial value (or null if None).
+     */
+    public VarInfo(String varName, ValueType varType, Literal initialValue) {
+        this.varName = varName;
+        this.varType = varType;
+        this.initialValue = initialValue;
+    }
+
+    /** Returns the name of this variable or attribute. */
+    public String getVarName() {
+        return varName;
+    }
+
+    /** Returns the type of this variable or attribute. */
+    public ValueType getVarType() {
+        return varType;
+    }
+
+    /** Returns the initial value of this variable or attribute. */
+    public Literal getInitialValue() {
+        return initialValue;
+    }
+
+}
diff --git a/src/main/java/chocopy/common/codegen/asm/abort.s b/src/main/java/chocopy/common/codegen/asm/abort.s
new file mode 100644
index 0000000000000000000000000000000000000000..fa8148a0e4e29da25088fd9b5b67e80462d952fd
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/abort.s
@@ -0,0 +1,12 @@
+# Runtime support function abort (does not return).
+  mv t0, a0                                # Save exit code in temp
+  li a0, @print_string                     # Code for print_string ecall
+  ecall                                    # Print error message in a1
+  li a1, 10                                # Load newline character
+  li a0, @print_char                       # Code for print_char ecall
+  ecall                                    # Print newline
+  mv a1, t0                                # Move exit code to a1
+  li a0, @exit2                            # Code for exit2 ecall
+  ecall                                    # Exit with code
+abort_17:                                  # Infinite loop
+  j abort_17                               # Prevent fallthrough
diff --git a/src/main/java/chocopy/common/codegen/asm/alloc.s b/src/main/java/chocopy/common/codegen/asm/alloc.s
new file mode 100644
index 0000000000000000000000000000000000000000..da54abe7a056a175bd7c48b1613b256d51f56e34
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/alloc.s
@@ -0,0 +1,4 @@
+# Runtime support function alloc.
+        # Prototype address is in a0.
+  lw a1, 4(a0)                             # Get size of object in words
+  j alloc2                                 # Allocate object with exact size
diff --git a/src/main/java/chocopy/common/codegen/asm/alloc2.s b/src/main/java/chocopy/common/codegen/asm/alloc2.s
new file mode 100644
index 0000000000000000000000000000000000000000..9540512bbda5cfa24c5d96e426ecc460bc86c763
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/alloc2.s
@@ -0,0 +1,27 @@
+# Runtime support function alloc2 (realloc).
+        # Prototype address is in a0.
+        # Number of words to allocate is in a1.
+  li a2, 4                                 # Word size in bytes
+  mul a2, a1, a2                           # Calculate number of bytes to allocate
+  add a2, gp, a2                           # Estimate where GP will move
+  bgeu a2, s11, alloc2_15                  # Go to OOM handler if too large
+  lw t0, @.__obj_size__(a0)                # Get size of object in words
+  mv t2, a0                                # Initialize src ptr
+  mv t3, gp                                # Initialize dest ptr
+alloc2_16:                                 # Copy-loop header
+  lw t1, 0(t2)                             # Load next word from src
+  sw t1, 0(t3)                             # Store next word to dest
+  addi t2, t2, 4                           # Increment src
+  addi t3, t3, 4                           # Increment dest
+  addi t0, t0, -1                          # Decrement counter
+  bne t0, zero, alloc2_16                  # Loop if more words left to copy
+  mv a0, gp                                # Save new object's address to return
+  sw a1, @.__obj_size__(a0)                # Set size of new object in words
+                                           # (same as requested size)
+  mv gp, a2                                # Set next free slot in the heap
+  jr ra                                    # Return to caller
+alloc2_15:                                 # OOM handler
+  li a0, @error_oom                        # Exit code for: Out of memory
+  la a1, STRING["Out of memory"]           # Load error message as str
+  addi a1, a1, @.__str__                   # Load address of attribute __str__
+  j abort                                  # Abort
diff --git a/src/main/java/chocopy/common/codegen/asm/heap.init.s b/src/main/java/chocopy/common/codegen/asm/heap.init.s
new file mode 100644
index 0000000000000000000000000000000000000000..5dfe9a8b5b5c79b96bc61752295a93324b8148d6
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/heap.init.s
@@ -0,0 +1,5 @@
+# Runtime support function heap.init.
+  mv a1, a0                                # Move requested size to A1
+  li a0, @sbrk                             # Code for ecall: sbrk
+  ecall                                    # Request A1 bytes
+  jr ra                                    # Return to caller
diff --git a/src/main/java/chocopy/common/codegen/asm/input.s b/src/main/java/chocopy/common/codegen/asm/input.s
new file mode 100644
index 0000000000000000000000000000000000000000..0e282ea0d211b9582a4d579011e6563be3f812c3
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/input.s
@@ -0,0 +1,5 @@
+# Function input
+  li a0, @error_nyi                        # Exit code for: Unsupported operation
+  la a1, STRING["Unsupported operation"]   # Load error message as str
+  addi a1, a1, @.__str__                   # Load address of attribute __str__
+  j abort                                  # Abort
diff --git a/src/main/java/chocopy/common/codegen/asm/len.s b/src/main/java/chocopy/common/codegen/asm/len.s
new file mode 100644
index 0000000000000000000000000000000000000000..72e9bea49018c1a730ab2c5375098ed1c4dba4f7
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/len.s
@@ -0,0 +1,20 @@
+# Function len
+      # We do not save/restore fp/ra for this function
+      # because we know that it does not use the stack or does not
+      # call other functions.
+
+  lw a0, 0(sp)                             # Load arg
+  beq a0, zero, len_12                     # None is an illegal argument
+  lw t0, 0(a0)                             # Get type tag of arg
+  li t1, 3                                 # Load type tag of `str`
+  beq t0, t1, len_13                       # Go to len(str)
+  li t1, -1                                # Load type tag for list objects
+  beq t0, t1, len_13                       # Go to len(list)
+len_12:                                    # Invalid argument
+  li a0, @error_arg                        # Exit code for: Invalid argument
+  la a1, STRING["Invalid argument"]        # Load error message as str
+  addi a1, a1, @.__str__                   # Load address of attribute __str__
+  j abort                                  # Abort
+len_13:                                    # Get length of string
+  lw a0, @.__len__(a0)                     # Load attribute: __len__
+  jr ra                                    # Return to caller
diff --git a/src/main/java/chocopy/common/codegen/asm/object.__init__.s b/src/main/java/chocopy/common/codegen/asm/object.__init__.s
new file mode 100644
index 0000000000000000000000000000000000000000..e326950ec539677b0aae6ad51873c2afce0b2b5f
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/object.__init__.s
@@ -0,0 +1,3 @@
+# Init method for type object.	
+  mv a0, zero                              # `None` constant
+  jr ra                                    # Return
diff --git a/src/main/java/chocopy/common/codegen/asm/print.s b/src/main/java/chocopy/common/codegen/asm/print.s
new file mode 100644
index 0000000000000000000000000000000000000000..4a9d3767bf61e50d5843a0759e90ee19b57dec00
--- /dev/null
+++ b/src/main/java/chocopy/common/codegen/asm/print.s
@@ -0,0 +1,52 @@
+# Function print
+  lw a0, 0(sp)                             # Load arg
+  beq a0, zero, print_6                    # None is an illegal argument
+  lw t0, 0(a0)                             # Get type tag of arg
+  li t1, 1                                 # Load type tag of `int`
+  beq t0, t1, print_7                      # Go to print(int)
+  li t1, 3                                 # Load type tag of `str`
+  beq t0, t1, print_8                      # Go to print(str)
+  li t1, 2                                 # Load type tag of `bool`
+  beq t0, t1, print_9                      # Go to print(bool)
+print_6:                                   # Invalid argument
+  li a0, 1                                 # Exit code for: Invalid argument
+  la a1, STRING["Invalid argument"]        # Load error message as str
+  addi a1, a1, @.__str__                   # Load address of attribute __str__
+  j abort                                  # Abort
+
+# Printing bools
+print_9:                                   # Print bool object in A0
+  lw a0, @.__bool__(a0)                    # Load attribute __bool__
+  beq a0, zero, print_10                   # Go to: print(False)
+  la a0, STRING["True"]                    # String representation: True
+  j print_8                                # Go to: print(str)
+print_10:                                  # Print False object in A0
+  la a0, STRING["False"]                   # String representation: False
+  j print_8                                # Go to: print(str)
+
+# Printing strs.
+print_8:                                   # Print str object in A0
+  addi a1, a0, @.__str__                   # Load address of attribute __str__
+  j print_11                               # Print the null-terminated string is now in A1
+  mv a0, zero                              # Load None
+  j print_5                                # Go to return
+print_11:                                  # Print null-terminated string in A1
+  li a0, @print_string                     # Code for ecall: print_string
+  ecall                                    # Print string
+  li a1, 10                                # Load newline character
+  li a0, @print_char                       # Code for ecall: print_char
+  ecall                                    # Print character
+  j print_5                                # Go to return
+
+# Printing ints.
+print_7:                                   # Print int object in A0
+  lw a1, @.__int__(a0)                     # Load attribute __int__
+  li a0, @print_int                        # Code for ecall: print_int
+  ecall                                    # Print integer
+  li a1, 10                                # Load newline character
+  li a0, 11                                # Code for ecall: print_char
+  ecall                                    # Print character
+
+print_5:                                   # End of function
+  mv a0, zero                              # Load None
+  jr ra                                    # Return to caller
diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d6c69f4b7d3c01a43b39c518efe97e5a2026c48
--- /dev/null
+++ b/src/main/java/chocopy/pa3/CodeGenImpl.java
@@ -0,0 +1,204 @@
+package chocopy.pa3;
+
+import java.util.List;
+
+import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.AbstractNodeAnalyzer;
+import chocopy.common.astnodes.Stmt;
+import chocopy.common.astnodes.ReturnStmt;
+import chocopy.common.codegen.CodeGenBase;
+import chocopy.common.codegen.FuncInfo;
+import chocopy.common.codegen.Label;
+import chocopy.common.codegen.RiscVBackend;
+import chocopy.common.codegen.SymbolInfo;
+
+import static chocopy.common.codegen.RiscVBackend.Register.*;
+
+/**
+ * This is where the main implementation of PA3 will live.
+ *
+ * A large part of the functionality has already been implemented
+ * in the base class, CodeGenBase. Make sure to read through that
+ * class, since you will want to use many of its fields
+ * and utility methods in this class when emitting code.
+ *
+ * Also read the PDF spec for details on what the base class does and
+ * what APIs it exposes for its sub-class (this one). Of particular
+ * importance is knowing what all the SymbolInfo classes contain.
+ */
+public class CodeGenImpl extends CodeGenBase {
+
+    /** A code generator emitting instructions to BACKEND. */
+    public CodeGenImpl(RiscVBackend backend) {
+        super(backend);
+    }
+
+    /** Operation on None. */
+    private final Label errorNone = new Label("error.None");
+    /** Division by zero. */
+    private final Label errorDiv = new Label("error.Div");
+    /** Index out of bounds. */
+    private final Label errorOob = new Label("error.OOB");
+
+    /**
+     * Emits the top level of the program.
+     *
+     * This method is invoked exactly once, and is surrounded
+     * by some boilerplate code that: (1) initializes the heap
+     * before the top-level begins and (2) exits after the top-level
+     * ends.
+     *
+     * You only need to generate code for statements.
+     *
+     * @param statements top level statements
+     */
+    protected void emitTopLevel(List<Stmt> statements) {
+        StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(null);
+        backend.emitADDI(SP, SP, -2 * backend.getWordSize(),
+                         "Saved FP and saved RA (unused at top level).");
+        backend.emitSW(ZERO, SP, 0, "Top saved FP is 0.");
+        backend.emitSW(ZERO, SP, 4, "Top saved RA is 0.");
+        backend.emitADDI(FP, SP, 2 * backend.getWordSize(),
+                         "Set FP to previous SP.");
+
+        for (Stmt stmt : statements) {
+            stmt.dispatch(stmtAnalyzer);
+        }
+        backend.emitLI(A0, EXIT_ECALL, "Code for ecall: exit");
+        backend.emitEcall(null);
+    }
+
+    /**
+     * Emits the code for a function described by FUNCINFO.
+     *
+     * This method is invoked once per function and method definition.
+     * At the code generation stage, nested functions are emitted as
+     * separate functions of their own. So if function `bar` is nested within
+     * function `foo`, you only emit `foo`'s code for `foo` and only emit
+     * `bar`'s code for `bar`.
+     */
+    protected void emitUserDefinedFunction(FuncInfo funcInfo) {
+        backend.emitGlobalLabel(funcInfo.getCodeLabel());
+        StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(funcInfo);
+
+        for (Stmt stmt : funcInfo.getStatements()) {
+            stmt.dispatch(stmtAnalyzer);
+        }
+
+        backend.emitMV(A0, ZERO, "Returning None implicitly");
+        backend.emitLocalLabel(stmtAnalyzer.epilogue, "Epilogue");
+
+        // FIXME: {... reset fp etc. ...}
+        backend.emitJR(RA, "Return to caller");
+    }
+
+    /** An analyzer that encapsulates code generation for statments. */
+    private class StmtAnalyzer extends AbstractNodeAnalyzer<Void> {
+        /*
+         * The symbol table has all the info you need to determine
+         * what a given identifier 'x' in the current scope is. You can
+         * use it as follows:
+         *   SymbolInfo x = sym.get("x");
+         *
+         * A SymbolInfo can be one the following:
+         * - ClassInfo: a descriptor for classes
+         * - FuncInfo: a descriptor for functions/methods
+         * - AttrInfo: a descriptor for attributes
+         * - GlobalVarInfo: a descriptor for global variables
+         * - StackVarInfo: a descriptor for variables allocated on the stack,
+         *      such as locals and parameters
+         *
+         * Since the input program is assumed to be semantically
+         * valid and well-typed at this stage, you can always assume that
+         * the symbol table contains valid information. For example, in
+         * an expression `foo()` you KNOW that sym.get("foo") will either be
+         * a FuncInfo or ClassInfo, but not any of the other infos
+         * and never null.
+         *
+         * The symbol table in funcInfo has already been populated in
+         * the base class: CodeGenBase. You do not need to add anything to
+         * the symbol table. Simply query it with an identifier name to
+         * get a descriptor for a function, class, variable, etc.
+         *
+         * The symbol table also maps nonlocal and global vars, so you
+         * only need to lookup one symbol table and it will fetch the
+         * appropriate info for the var that is currently in scope.
+         */
+
+        /** Symbol table for my statements. */
+        private SymbolTable<SymbolInfo> sym;
+
+        /** Label of code that exits from procedure. */
+        protected Label epilogue;
+
+        /** The descriptor for the current function, or null at the top
+         *  level. */
+        private FuncInfo funcInfo;
+
+        /** An analyzer for the function described by FUNCINFO0, which is null
+         *  for the top level. */
+        StmtAnalyzer(FuncInfo funcInfo0) {
+            funcInfo = funcInfo0;
+            if (funcInfo == null) {
+                sym = globalSymbols;
+            } else {
+                sym = funcInfo.getSymbolTable();
+            }
+            epilogue = generateLocalLabel();
+        }
+
+        // FIXME: Example of statement.
+        @Override
+        public Void analyze(ReturnStmt stmt) {
+            // FIXME: Here, we emit an instruction that does nothing. Clearly,
+            // this is wrong, and you'll have to fix it.
+            // This is here just to demonstrate how to emit a
+            // RISC-V instruction.
+            backend.emitMV(ZERO, ZERO, "No-op");
+            return null;
+        }
+
+        // FIXME: More, of course.
+
+    }
+
+    /**
+     * Emits custom code in the CODE segment.
+     *
+     * This method is called after emitting the top level and the
+     * function bodies for each function.
+     *
+     * You can use this method to emit anything you want outside of the
+     * top level or functions, e.g. custom routines that you may want to
+     * call from within your code to do common tasks. This is not strictly
+     * needed. You might not modify this at all and still complete
+     * the assignment.
+     *
+     * To start you off, here is an implementation of three routines that
+     * will be commonly needed from within the code you will generate
+     * for statements.
+     *
+     * The routines are error handlers for operations on None, index out
+     * of bounds, and division by zero. They never return to their caller.
+     * Just jump to one of these routines to throw an error and
+     * exit the program. For example, to throw an OOB error:
+     *   backend.emitJ(errorOob, "Go to out-of-bounds error and abort");
+     *
+     */
+    protected void emitCustomCode() {
+        emitErrorFunc(errorNone, "Operation on None");
+        emitErrorFunc(errorDiv, "Divison by zero");
+        emitErrorFunc(errorOob, "Index out of bounds");
+    }
+
+    /** Emit an error routine labeled ERRLABEL that aborts with message MSG. */
+    private void emitErrorFunc(Label errLabel, String msg) {
+        backend.emitGlobalLabel(errLabel);
+        backend.emitLI(A0, ERROR_NONE, "Exit code for: " + msg);
+        backend.emitLA(A1, constants.getStrConstant(msg),
+                       "Load error message as str");
+        backend.emitADDI(A1, A1, getAttrOffset(strClass, "__str__"),
+                         "Load address of attribute __str__");
+        backend.emitJ(abortLabel, "Abort");
+    }
+}
diff --git a/src/main/java/chocopy/pa3/StudentCodeGen.java b/src/main/java/chocopy/pa3/StudentCodeGen.java
new file mode 100644
index 0000000000000000000000000000000000000000..dac8b37aa80c2b86d6169c768bb326b153079e39
--- /dev/null
+++ b/src/main/java/chocopy/pa3/StudentCodeGen.java
@@ -0,0 +1,34 @@
+package chocopy.pa3;
+
+import chocopy.common.astnodes.Program;
+import chocopy.common.codegen.CodeGenBase;
+import chocopy.common.codegen.RiscVBackend;
+
+/** Interface to code generator. */
+public class StudentCodeGen {
+
+    /**
+     * Perform code generation from PROGRAM, assumed to be well-typed,
+     * to RISC-V, returning the assembly code.  DEBUG iff --debug was on the
+     * command line.
+     */
+    public static String process(Program program, boolean debug) {
+        /* Emit code into a ByteOutputStream, and convert to a string.
+         * If you need instructions not provided by RiscVBackend, simply
+         * use an extension of it. */
+        try {
+            RiscVBackend backend = new RiscVBackend();
+            CodeGenBase cgen = new CodeGenImpl(backend);
+            cgen.generate(program);
+
+            return backend.toString();
+        } catch (IllegalStateException | IllegalArgumentException e) {
+            System.err.println("Error performing code generation. "
+                               + "Re-run with --debug to see stack trace.");
+            if (debug) {
+                e.printStackTrace();
+            }
+            return null;
+        }
+    }
+}
diff --git a/src/test/data/pa3/benchmarks/exp.py b/src/test/data/pa3/benchmarks/exp.py
new file mode 100644
index 0000000000000000000000000000000000000000..3915517557d2ba61ff0f27cdd96de81298862506
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/exp.py
@@ -0,0 +1,25 @@
+# Compute x**y
+def exp(x: int, y: int) -> int:
+	a: int = 0
+	def f(i: int) -> int:
+		nonlocal a
+		def geta() -> int:
+			return a
+		if i <= 0:
+			return geta()
+		else:
+			a = a * x
+			return f(i-1)
+	a = 1
+	return f(y)
+
+# Input parameter
+n:int = 42
+
+# Run [0, n]
+i:int = 0
+
+# Crunch
+while i <= n:
+	print(exp(2, i % 31))
+	i = i + 1
\ No newline at end of file
diff --git a/src/test/data/pa3/benchmarks/exp.py.ast.typed b/src/test/data/pa3/benchmarks/exp.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..39a7fa153933277e3fb8f90adcae203f8b7882a5
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/exp.py.ast.typed
@@ -0,0 +1,562 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 26, 1 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 2, 1, 14, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 5, 2, 7 ],
+      "name" : "exp"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 2, 9, 2, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 12, 2, 14 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 2, 17, 2, 22 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 17, 2, 17 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 20, 2, 22 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 2, 28, 2, 30 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 2, 3, 11 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 2, 3, 7 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 2, 3, 2 ],
+          "name" : "a"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 5, 3, 7 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 11, 3, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 2, 13, 1 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 6, 4, 6 ],
+        "name" : "f"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 4, 8, 4, 13 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 8, 4, 8 ],
+          "name" : "i"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 11, 4, 13 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 19, 4, 21 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "NonLocalDecl",
+        "location" : [ 5, 3, 5, 12 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 12, 5, 12 ],
+          "name" : "a"
+        }
+      }, {
+        "kind" : "FuncDef",
+        "location" : [ 6, 3, 7, 12 ],
+        "name" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 7, 6, 10 ],
+          "name" : "geta"
+        },
+        "params" : [ ],
+        "returnType" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 17, 6, 19 ],
+          "className" : "int"
+        },
+        "declarations" : [ ],
+        "statements" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 7, 4, 7, 11 ],
+          "value" : {
+            "kind" : "Identifier",
+            "location" : [ 7, 11, 7, 11 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "a"
+          }
+        } ]
+      } ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 8, 3, 13, 1 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 8, 6, 8, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 6, 8, 6 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          },
+          "operator" : "<=",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 8, 11, 8, 11 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 0
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 9, 4, 9, 16 ],
+          "value" : {
+            "kind" : "CallExpr",
+            "location" : [ 9, 11, 9, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 9, 11, 9, 14 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "name" : "geta"
+            },
+            "args" : [ ]
+          }
+        } ],
+        "elseBody" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 11, 4, 11, 12 ],
+          "targets" : [ {
+            "kind" : "Identifier",
+            "location" : [ 11, 4, 11, 4 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "a"
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 11, 8, 11, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 11, 8, 11, 8 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "a"
+            },
+            "operator" : "*",
+            "right" : {
+              "kind" : "Identifier",
+              "location" : [ 11, 12, 11, 12 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            }
+          }
+        }, {
+          "kind" : "ReturnStmt",
+          "location" : [ 12, 4, 12, 16 ],
+          "value" : {
+            "kind" : "CallExpr",
+            "location" : [ 12, 11, 12, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 12, 11, 12, 11 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "name" : "f"
+            },
+            "args" : [ {
+              "kind" : "BinaryExpr",
+              "location" : [ 12, 13, 12, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 12, 13, 12, 13 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "i"
+              },
+              "operator" : "-",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 12, 15, 12, 15 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            } ]
+          }
+        } ]
+      } ]
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 13, 2, 13, 6 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 13, 2, 13, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "a"
+      } ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 13, 6, 13, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 14, 2, 14, 12 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 14, 9, 14, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 9, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "f"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 14, 11, 14, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        } ]
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 17, 1, 17, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 17, 1, 17, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 1 ],
+        "name" : "n"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 17, 3, 17, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 17, 9, 17, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 20, 1, 20, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 20, 1, 20, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 1, 20, 1 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 20, 3, 20, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 20, 9, 20, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "WhileStmt",
+    "location" : [ 23, 1, 26, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 23, 7, 23, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 23, 7, 23, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<=",
+      "right" : {
+        "kind" : "Identifier",
+        "location" : [ 23, 12, 23, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "n"
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 24, 2, 24, 22 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 24, 2, 24, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 24, 2, 24, 6 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "CallExpr",
+          "location" : [ 24, 8, 24, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 24, 8, 24, 10 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "exp"
+          },
+          "args" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 24, 12, 24, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 2
+          }, {
+            "kind" : "BinaryExpr",
+            "location" : [ 24, 15, 24, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 24, 15, 24, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "i"
+            },
+            "operator" : "%",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 24, 19, 24, 20 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 31
+            }
+          } ]
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 25, 2, 25, 10 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 25, 2, 25, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 25, 6, 25, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 6, 25, 6 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 25, 10, 25, 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/pa3/benchmarks/exp.py.ast.typed.s.result b/src/test/data/pa3/benchmarks/exp.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..6bce2e5ae037127d0bba256f026b0bfde1e45a2a
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/exp.py.ast.typed.s.result
@@ -0,0 +1,43 @@
+1
+2
+4
+8
+16
+32
+64
+128
+256
+512
+1024
+2048
+4096
+8192
+16384
+32768
+65536
+131072
+262144
+524288
+1048576
+2097152
+4194304
+8388608
+16777216
+33554432
+67108864
+134217728
+268435456
+536870912
+1073741824
+1
+2
+4
+8
+16
+32
+64
+128
+256
+512
+1024
+2048
diff --git a/src/test/data/pa3/benchmarks/prime.py b/src/test/data/pa3/benchmarks/prime.py
new file mode 100644
index 0000000000000000000000000000000000000000..7568705a8f7c1243492b2f90c4bae97acd9ef3e9
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/prime.py
@@ -0,0 +1,30 @@
+# Get the n-th prime starting from 2
+def get_prime(n:int) -> int:
+    candidate:int = 2
+    found:int = 0
+    while True:
+        if is_prime(candidate):
+            found = found + 1
+            if found == n:
+                return candidate
+        candidate = candidate + 1
+    return 0 # Never happens
+
+def is_prime(x:int) -> bool:
+    div:int = 2
+    while div < x:
+        if x % div == 0:
+            return False
+        div = div + 1
+    return True
+
+# Input parameter
+n:int = 15
+
+# Run [1, n]
+i:int = 1
+
+# Crunch
+while i <= n:
+    print(get_prime(i))
+    i = i + 1
diff --git a/src/test/data/pa3/benchmarks/prime.py.ast.typed b/src/test/data/pa3/benchmarks/prime.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..a3062b6d2d5e7302cb059a9ff6ac4e3f1a0d06cb
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/prime.py.ast.typed
@@ -0,0 +1,658 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 31, 1 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 2, 1, 11, 29 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 5, 2, 13 ],
+      "name" : "get_prime"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 2, 15, 2, 19 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 15, 2, 15 ],
+        "name" : "n"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 17, 2, 19 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 2, 25, 2, 27 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 21 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 17 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 13 ],
+          "name" : "candidate"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 15, 3, 17 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 21, 3, 21 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 4, 5, 4, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 4, 5, 4, 13 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 9 ],
+          "name" : "found"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 11, 4, 13 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 17, 4, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "WhileStmt",
+      "location" : [ 5, 5, 11, 4 ],
+      "condition" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 11, 5, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      },
+      "body" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 6, 9, 10, 8 ],
+        "condition" : {
+          "kind" : "CallExpr",
+          "location" : [ 6, 12, 6, 30 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 6, 12, 6, 19 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              }
+            },
+            "name" : "is_prime"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 6, 21, 6, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "candidate"
+          } ]
+        },
+        "thenBody" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 7, 13, 7, 29 ],
+          "targets" : [ {
+            "kind" : "Identifier",
+            "location" : [ 7, 13, 7, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "found"
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 7, 21, 7, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 7, 21, 7, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "found"
+            },
+            "operator" : "+",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 7, 29, 7, 29 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 1
+            }
+          }
+        }, {
+          "kind" : "IfStmt",
+          "location" : [ 8, 13, 10, 8 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 8, 16, 8, 25 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 8, 16, 8, 20 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "found"
+            },
+            "operator" : "==",
+            "right" : {
+              "kind" : "Identifier",
+              "location" : [ 8, 25, 8, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "n"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "ReturnStmt",
+            "location" : [ 9, 17, 9, 32 ],
+            "value" : {
+              "kind" : "Identifier",
+              "location" : [ 9, 24, 9, 32 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "candidate"
+            }
+          } ],
+          "elseBody" : [ ]
+        } ],
+        "elseBody" : [ ]
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 10, 9, 10, 33 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 10, 9, 10, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "candidate"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 10, 21, 10, 33 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 10, 21, 10, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "candidate"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 10, 33, 10, 33 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      } ]
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 11, 5, 11, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 12, 11, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 13, 1, 19, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 13, 5, 13, 12 ],
+      "name" : "is_prime"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 13, 14, 13, 18 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 14, 13, 14 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 16, 13, 18 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 13, 24, 13, 27 ],
+      "className" : "bool"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 14, 5, 14, 15 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 14, 5, 14, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 5, 14, 7 ],
+          "name" : "div"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 9, 14, 11 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 14, 15, 14, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "WhileStmt",
+      "location" : [ 15, 5, 19, 4 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 15, 11, 15, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 11, 15, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "div"
+        },
+        "operator" : "<",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 17, 15, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      },
+      "body" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 16, 9, 18, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 16, 12, 16, 23 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 16, 12, 16, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 12, 16, 12 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : "%",
+            "right" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 16, 16, 18 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "div"
+            }
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 16, 23, 16, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 0
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 17, 13, 17, 24 ],
+          "value" : {
+            "kind" : "BooleanLiteral",
+            "location" : [ 17, 20, 17, 24 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "value" : false
+          }
+        } ],
+        "elseBody" : [ ]
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 18, 9, 18, 21 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 18, 9, 18, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "div"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 18, 15, 18, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 18, 15, 18, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "div"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 18, 21, 18, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      } ]
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 19, 5, 19, 15 ],
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 19, 12, 19, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 22, 1, 22, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 22, 1, 22, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 1, 22, 1 ],
+        "name" : "n"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 22, 3, 22, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 22, 9, 22, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 15
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 25, 1, 25, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 25, 1, 25, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 1, 25, 1 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 25, 3, 25, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 25, 9, 25, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "WhileStmt",
+    "location" : [ 28, 1, 31, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 28, 7, 28, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 28, 7, 28, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<=",
+      "right" : {
+        "kind" : "Identifier",
+        "location" : [ 28, 12, 28, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "n"
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 29, 5, 29, 23 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 29, 5, 29, 23 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 5, 29, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "CallExpr",
+          "location" : [ 29, 11, 29, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 29, 11, 29, 19 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "get_prime"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 29, 21, 29, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          } ]
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 30, 5, 30, 13 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 30, 5, 30, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 30, 9, 30, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 30, 9, 30, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 30, 13, 30, 13 ],
+          "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/pa3/benchmarks/prime.py.ast.typed.s.result b/src/test/data/pa3/benchmarks/prime.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..6beaeaa3fdbbf1e2aba655e4b8868991975823d0
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/prime.py.ast.typed.s.result
@@ -0,0 +1,15 @@
+2
+3
+5
+7
+11
+13
+17
+19
+23
+29
+31
+37
+41
+43
+47
diff --git a/src/test/data/pa3/benchmarks/sieve.py b/src/test/data/pa3/benchmarks/sieve.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6aa9776577d2c41450ca8d1869f318b22947638
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/sieve.py
@@ -0,0 +1,107 @@
+# A resizable list of integers
+class Vector(object):
+    items: [int] = None
+    size: int = 0
+
+    def __init__(self:"Vector"):
+        self.items = [0]
+
+    # Returns current capacity
+    def capacity(self:"Vector") -> int:
+        return len(self.items)
+
+    # Increases capacity of vector by one element
+    def increase_capacity(self:"Vector") -> int:
+        self.items = self.items + [0]
+        return self.capacity()
+
+    # Appends one item to end of vector
+    def append(self:"Vector", item: int) -> object:
+        if self.size == self.capacity():
+            self.increase_capacity()
+
+        self.items[self.size] = item
+        self.size = self.size + 1
+
+    # Appends many items to end of vector
+    def append_all(self:"Vector", new_items: [int]) -> object:
+        item:int = 0
+        for item in new_items:
+            self.append(item)
+
+    # Removes an item from the middle of vector
+    def remove_at(self:"Vector", idx: int) -> object:
+        if idx < 0:
+            return
+
+        while idx < self.size - 1:
+            self.items[idx] = self.items[idx + 1]
+            idx = idx + 1
+
+        self.size = self.size - 1
+
+    # Retrieves an item at a given index
+    def get(self:"Vector", idx: int) -> int:
+        return self.items[idx]
+
+    # Retrieves the current size of the vector
+    def length(self:"Vector") -> int:
+        return self.size
+
+# A faster (but more memory-consuming) implementation of vector
+class DoublingVector(Vector):
+    doubling_limit:int = 1000
+
+    # Overriding to do fewer resizes
+    def increase_capacity(self:"DoublingVector") -> int:
+        if (self.capacity() <= self.doubling_limit // 2):
+            self.items = self.items + self.items
+        else:
+            # If doubling limit has been reached, fall back to
+            # standard capacity increases
+            self.items = self.items + [0]
+        return self.capacity()
+
+# Makes a vector in the range [i, j)
+def vrange(i:int, j:int) -> Vector:
+    v:Vector = None
+    v = DoublingVector()
+    
+    while i < j:
+        v.append(i)
+        i = i + 1
+
+    return v
+
+# Sieve of Eratosthenes (not really)
+def sieve(v:Vector) -> object:
+    i:int = 0
+    j:int = 0
+    k:int = 0
+
+    while i < v.length():
+        k = v.get(i)
+        j = i + 1
+        while j < v.length():
+            if v.get(j) % k == 0:
+                v.remove_at(j)
+            else:
+                j = j + 1
+        i = i + 1
+
+# Input parameter
+n:int = 50
+
+# Data
+v:Vector = None
+i:int = 0
+
+# Crunch
+v = vrange(2, n)
+sieve(v)
+
+# Print
+while i < v.length():
+    print(v.get(i))
+    i = i + 1
+
diff --git a/src/test/data/pa3/benchmarks/sieve.py.ast.typed b/src/test/data/pa3/benchmarks/sieve.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..1c0eb6ca5485645de9eb2294e751556babd08f2c
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/sieve.py.ast.typed
@@ -0,0 +1,2816 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 108, 1 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 2, 1, 52, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 7, 2, 12 ],
+      "name" : "Vector"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 14, 2, 19 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 23 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 16 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 9 ],
+          "name" : "items"
+        },
+        "type" : {
+          "kind" : "ListType",
+          "location" : [ 3, 12, 3, 16 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 3, 13, 3, 15 ],
+            "className" : "int"
+          }
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 3, 20, 3, 23 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 4, 5, 4, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 4, 5, 4, 13 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 8 ],
+          "name" : "size"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 11, 4, 13 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 17, 4, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 6, 5, 7, 25 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 9, 6, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 6, 18, 6, 30 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 18, 6, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 23, 6, 30 ],
+          "className" : "Vector"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 32, 6, 32 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 7, 9, 7, 24 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 7, 9, 7, 18 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 7, 9, 7, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 7, 14, 7, 18 ],
+            "name" : "items"
+          }
+        } ],
+        "value" : {
+          "kind" : "ListExpr",
+          "location" : [ 7, 22, 7, 24 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 7, 23, 7, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 0
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 31 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 16 ],
+        "name" : "capacity"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 18, 10, 30 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 18, 10, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 23, 10, 30 ],
+          "className" : "Vector"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 36, 10, 38 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 11, 9, 11, 30 ],
+        "value" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 16, 11, 30 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 16, 11, 18 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "len"
+          },
+          "args" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 11, 20, 11, 29 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 11, 20, 11, 23 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 11, 25, 11, 29 ],
+              "name" : "items"
+            }
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 14, 5, 16, 31 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 9, 14, 25 ],
+        "name" : "increase_capacity"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 14, 27, 14, 39 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 27, 14, 30 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 32, 14, 39 ],
+          "className" : "Vector"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 14, 45, 14, 47 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 15, 9, 15, 37 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 15, 9, 15, 18 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 9, 15, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 14, 15, 18 ],
+            "name" : "items"
+          }
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 15, 22, 15, 37 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "left" : {
+            "kind" : "MemberExpr",
+            "location" : [ 15, 22, 15, 31 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 15, 22, 15, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 15, 27, 15, 31 ],
+              "name" : "items"
+            }
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "ListExpr",
+            "location" : [ 15, 35, 15, 37 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "elements" : [ {
+              "kind" : "IntegerLiteral",
+              "location" : [ 15, 36, 15, 36 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 0
+            } ]
+          }
+        }
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 16, 9, 16, 30 ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 16, 16, 16, 30 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 16, 16, 16, 28 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 16, 16, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 21, 16, 28 ],
+              "name" : "capacity"
+            }
+          },
+          "args" : [ ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 19, 5, 24, 34 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 9, 19, 14 ],
+        "name" : "append"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 19, 16, 19, 28 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 16, 19, 19 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 19, 21, 19, 28 ],
+          "className" : "Vector"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 19, 31, 19, 39 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 31, 19, 34 ],
+          "name" : "item"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 19, 37, 19, 39 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 19, 45, 19, 50 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 20, 9, 23, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 20, 12, 20, 39 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "MemberExpr",
+            "location" : [ 20, 12, 20, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 12, 20, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 20, 17, 20, 20 ],
+              "name" : "size"
+            }
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 20, 25, 20, 39 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 20, 25, 20, 37 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 20, 25, 20, 28 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 20, 30, 20, 37 ],
+                "name" : "capacity"
+              }
+            },
+            "args" : [ ]
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "ExprStmt",
+          "location" : [ 21, 13, 21, 36 ],
+          "expr" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 21, 13, 21, 36 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 21, 13, 21, 34 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 21, 13, 21, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 21, 18, 21, 34 ],
+                "name" : "increase_capacity"
+              }
+            },
+            "args" : [ ]
+          }
+        } ],
+        "elseBody" : [ ]
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 23, 9, 23, 36 ],
+        "targets" : [ {
+          "kind" : "IndexExpr",
+          "location" : [ 23, 9, 23, 29 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "list" : {
+            "kind" : "MemberExpr",
+            "location" : [ 23, 9, 23, 18 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 23, 9, 23, 12 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 23, 14, 23, 18 ],
+              "name" : "items"
+            }
+          },
+          "index" : {
+            "kind" : "MemberExpr",
+            "location" : [ 23, 20, 23, 28 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 23, 20, 23, 23 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 23, 25, 23, 28 ],
+              "name" : "size"
+            }
+          }
+        } ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 23, 33, 23, 36 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "item"
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 24, 9, 24, 33 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 24, 9, 24, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 24, 9, 24, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 24, 14, 24, 17 ],
+            "name" : "size"
+          }
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 24, 21, 24, 33 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "MemberExpr",
+            "location" : [ 24, 21, 24, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 24, 21, 24, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 24, 26, 24, 29 ],
+              "name" : "size"
+            }
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 24, 33, 24, 33 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 27, 5, 33, 4 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 27, 9, 27, 18 ],
+        "name" : "append_all"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 27, 20, 27, 32 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 20, 27, 23 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 27, 25, 27, 32 ],
+          "className" : "Vector"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 27, 35, 27, 50 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 27, 35, 27, 43 ],
+          "name" : "new_items"
+        },
+        "type" : {
+          "kind" : "ListType",
+          "location" : [ 27, 46, 27, 50 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 27, 47, 27, 49 ],
+            "className" : "int"
+          }
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 27, 56, 27, 61 ],
+        "className" : "object"
+      },
+      "declarations" : [ {
+        "kind" : "VarDef",
+        "location" : [ 28, 9, 28, 20 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 28, 9, 28, 16 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 28, 9, 28, 12 ],
+            "name" : "item"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 28, 14, 28, 16 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 28, 20, 28, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      } ],
+      "statements" : [ {
+        "kind" : "ForStmt",
+        "location" : [ 29, 9, 33, 4 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 13, 29, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "item"
+        },
+        "iterable" : {
+          "kind" : "Identifier",
+          "location" : [ 29, 21, 29, 29 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "new_items"
+        },
+        "body" : [ {
+          "kind" : "ExprStmt",
+          "location" : [ 30, 13, 30, 29 ],
+          "expr" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 30, 13, 30, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 30, 13, 30, 23 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                }, {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "object"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 30, 13, 30, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 30, 18, 30, 23 ],
+                "name" : "append"
+              }
+            },
+            "args" : [ {
+              "kind" : "Identifier",
+              "location" : [ 30, 25, 30, 28 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "item"
+            } ]
+          }
+        } ]
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 33, 5, 41, 34 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 33, 9, 33, 17 ],
+        "name" : "remove_at"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 33, 19, 33, 31 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 33, 19, 33, 22 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 33, 24, 33, 31 ],
+          "className" : "Vector"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 33, 34, 33, 41 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 33, 34, 33, 36 ],
+          "name" : "idx"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 33, 39, 33, 41 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 33, 47, 33, 52 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 34, 9, 37, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 34, 12, 34, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 34, 12, 34, 14 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "idx"
+          },
+          "operator" : "<",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 34, 18, 34, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 0
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 35, 13, 35, 18 ],
+          "value" : null
+        } ],
+        "elseBody" : [ ]
+      }, {
+        "kind" : "WhileStmt",
+        "location" : [ 37, 9, 41, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 37, 15, 37, 33 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 37, 15, 37, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "idx"
+          },
+          "operator" : "<",
+          "right" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 37, 21, 37, 33 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "MemberExpr",
+              "location" : [ 37, 21, 37, 29 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 37, 21, 37, 24 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 37, 26, 37, 29 ],
+                "name" : "size"
+              }
+            },
+            "operator" : "-",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 37, 33, 37, 33 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 1
+            }
+          }
+        },
+        "body" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 38, 13, 38, 49 ],
+          "targets" : [ {
+            "kind" : "IndexExpr",
+            "location" : [ 38, 13, 38, 27 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "list" : {
+              "kind" : "MemberExpr",
+              "location" : [ 38, 13, 38, 22 ],
+              "inferredType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 38, 13, 38, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 38, 18, 38, 22 ],
+                "name" : "items"
+              }
+            },
+            "index" : {
+              "kind" : "Identifier",
+              "location" : [ 38, 24, 38, 26 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "idx"
+            }
+          } ],
+          "value" : {
+            "kind" : "IndexExpr",
+            "location" : [ 38, 31, 38, 49 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "list" : {
+              "kind" : "MemberExpr",
+              "location" : [ 38, 31, 38, 40 ],
+              "inferredType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 38, 31, 38, 34 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 38, 36, 38, 40 ],
+                "name" : "items"
+              }
+            },
+            "index" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 38, 42, 38, 48 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 38, 42, 38, 44 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "idx"
+              },
+              "operator" : "+",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 38, 48, 38, 48 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            }
+          }
+        }, {
+          "kind" : "AssignStmt",
+          "location" : [ 39, 13, 39, 25 ],
+          "targets" : [ {
+            "kind" : "Identifier",
+            "location" : [ 39, 13, 39, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "idx"
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 39, 19, 39, 25 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 39, 19, 39, 21 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "idx"
+            },
+            "operator" : "+",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 39, 25, 39, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 1
+            }
+          }
+        } ]
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 41, 9, 41, 33 ],
+        "targets" : [ {
+          "kind" : "MemberExpr",
+          "location" : [ 41, 9, 41, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 41, 9, 41, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 41, 14, 41, 17 ],
+            "name" : "size"
+          }
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 41, 21, 41, 33 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "MemberExpr",
+            "location" : [ 41, 21, 41, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 41, 21, 41, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 41, 26, 41, 29 ],
+              "name" : "size"
+            }
+          },
+          "operator" : "-",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 41, 33, 41, 33 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 44, 5, 45, 31 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 44, 9, 44, 11 ],
+        "name" : "get"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 44, 13, 44, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 44, 13, 44, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 44, 18, 44, 25 ],
+          "className" : "Vector"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 44, 28, 44, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 44, 28, 44, 30 ],
+          "name" : "idx"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 44, 33, 44, 35 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 44, 41, 44, 43 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 45, 9, 45, 30 ],
+        "value" : {
+          "kind" : "IndexExpr",
+          "location" : [ 45, 16, 45, 30 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "list" : {
+            "kind" : "MemberExpr",
+            "location" : [ 45, 16, 45, 25 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 45, 16, 45, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 45, 21, 45, 25 ],
+              "name" : "items"
+            }
+          },
+          "index" : {
+            "kind" : "Identifier",
+            "location" : [ 45, 27, 45, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "idx"
+          }
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 48, 5, 49, 25 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 48, 9, 48, 14 ],
+        "name" : "length"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 48, 16, 48, 28 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 48, 16, 48, 19 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 48, 21, 48, 28 ],
+          "className" : "Vector"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 48, 34, 48, 36 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 49, 9, 49, 24 ],
+        "value" : {
+          "kind" : "MemberExpr",
+          "location" : [ 49, 16, 49, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 49, 16, 49, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            },
+            "name" : "self"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 49, 21, 49, 24 ],
+            "name" : "size"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 52, 1, 66, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 52, 7, 52, 20 ],
+      "name" : "DoublingVector"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 52, 22, 52, 27 ],
+      "name" : "Vector"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 53, 5, 53, 29 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 53, 5, 53, 22 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 53, 5, 53, 18 ],
+          "name" : "doubling_limit"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 53, 20, 53, 22 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 53, 26, 53, 29 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1000
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 56, 5, 63, 31 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 56, 9, 56, 25 ],
+        "name" : "increase_capacity"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 56, 27, 56, 47 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 56, 27, 56, 30 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 56, 32, 56, 47 ],
+          "className" : "DoublingVector"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 56, 53, 56, 55 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 57, 9, 63, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 57, 13, 57, 55 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 57, 13, 57, 27 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 57, 13, 57, 25 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 57, 13, 57, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "DoublingVector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 57, 18, 57, 25 ],
+                "name" : "capacity"
+              }
+            },
+            "args" : [ ]
+          },
+          "operator" : "<=",
+          "right" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 57, 32, 57, 55 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "MemberExpr",
+              "location" : [ 57, 32, 57, 50 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 57, 32, 57, 35 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "DoublingVector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 57, 37, 57, 50 ],
+                "name" : "doubling_limit"
+              }
+            },
+            "operator" : "//",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 57, 55, 57, 55 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 2
+            }
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 58, 13, 58, 48 ],
+          "targets" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 58, 13, 58, 22 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 58, 13, 58, 16 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "DoublingVector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 58, 18, 58, 22 ],
+              "name" : "items"
+            }
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 58, 26, 58, 48 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "left" : {
+              "kind" : "MemberExpr",
+              "location" : [ 58, 26, 58, 35 ],
+              "inferredType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 58, 26, 58, 29 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "DoublingVector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 58, 31, 58, 35 ],
+                "name" : "items"
+              }
+            },
+            "operator" : "+",
+            "right" : {
+              "kind" : "MemberExpr",
+              "location" : [ 58, 39, 58, 48 ],
+              "inferredType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 58, 39, 58, 42 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "DoublingVector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 58, 44, 58, 48 ],
+                "name" : "items"
+              }
+            }
+          }
+        } ],
+        "elseBody" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 62, 13, 62, 41 ],
+          "targets" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 62, 13, 62, 22 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 62, 13, 62, 16 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "DoublingVector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 62, 18, 62, 22 ],
+              "name" : "items"
+            }
+          } ],
+          "value" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 62, 26, 62, 41 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "left" : {
+              "kind" : "MemberExpr",
+              "location" : [ 62, 26, 62, 35 ],
+              "inferredType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 62, 26, 62, 29 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "DoublingVector"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 62, 31, 62, 35 ],
+                "name" : "items"
+              }
+            },
+            "operator" : "+",
+            "right" : {
+              "kind" : "ListExpr",
+              "location" : [ 62, 39, 62, 41 ],
+              "inferredType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "elements" : [ {
+                "kind" : "IntegerLiteral",
+                "location" : [ 62, 40, 62, 40 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 0
+              } ]
+            }
+          }
+        } ]
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 63, 9, 63, 30 ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 63, 16, 63, 30 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 63, 16, 63, 28 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 63, 16, 63, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "DoublingVector"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 63, 21, 63, 28 ],
+              "name" : "capacity"
+            }
+          },
+          "args" : [ ]
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 66, 1, 74, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 66, 5, 66, 10 ],
+      "name" : "vrange"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 66, 12, 66, 16 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 66, 12, 66, 12 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 66, 14, 66, 16 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 66, 19, 66, 23 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 66, 19, 66, 19 ],
+        "name" : "j"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 66, 21, 66, 23 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 66, 29, 66, 34 ],
+      "className" : "Vector"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 67, 5, 67, 19 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 67, 5, 67, 12 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 67, 5, 67, 5 ],
+          "name" : "v"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 67, 7, 67, 12 ],
+          "className" : "Vector"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 67, 16, 67, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 68, 5, 68, 24 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 68, 5, 68, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "Vector"
+        },
+        "name" : "v"
+      } ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 68, 9, 68, 24 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "DoublingVector"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 68, 9, 68, 22 ],
+          "name" : "DoublingVector"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "WhileStmt",
+      "location" : [ 70, 5, 74, 4 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 70, 11, 70, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 70, 11, 70, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "<",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 70, 15, 70, 15 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "j"
+        }
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 71, 9, 71, 19 ],
+        "expr" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 71, 9, 71, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 71, 9, 71, 16 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 71, 9, 71, 9 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "v"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 71, 11, 71, 16 ],
+              "name" : "append"
+            }
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 71, 18, 71, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          } ]
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 72, 9, 72, 17 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 72, 9, 72, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 72, 13, 72, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 72, 13, 72, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 72, 17, 72, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      } ]
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 74, 5, 74, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 74, 12, 74, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "Vector"
+        },
+        "name" : "v"
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 77, 1, 93, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 77, 5, 77, 9 ],
+      "name" : "sieve"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 77, 11, 77, 18 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 77, 11, 77, 11 ],
+        "name" : "v"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 77, 13, 77, 18 ],
+        "className" : "Vector"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 77, 24, 77, 29 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 78, 5, 78, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 78, 5, 78, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 78, 5, 78, 5 ],
+          "name" : "i"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 78, 7, 78, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 78, 13, 78, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 79, 5, 79, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 79, 5, 79, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 79, 5, 79, 5 ],
+          "name" : "j"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 79, 7, 79, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 79, 13, 79, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 80, 5, 80, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 80, 5, 80, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 80, 5, 80, 5 ],
+          "name" : "k"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 80, 7, 80, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 80, 13, 80, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "WhileStmt",
+      "location" : [ 82, 5, 93, 0 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 82, 11, 82, 24 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 82, 11, 82, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "<",
+        "right" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 82, 15, 82, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 82, 15, 82, 22 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 82, 15, 82, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "v"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 82, 17, 82, 22 ],
+              "name" : "length"
+            }
+          },
+          "args" : [ ]
+        }
+      },
+      "body" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 83, 9, 83, 20 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 83, 9, 83, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "k"
+        } ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 83, 13, 83, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 83, 13, 83, 17 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 83, 13, 83, 13 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "v"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 83, 15, 83, 17 ],
+              "name" : "get"
+            }
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 83, 19, 83, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          } ]
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 84, 9, 84, 17 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 84, 9, 84, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "j"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 84, 13, 84, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 84, 13, 84, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 84, 17, 84, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      }, {
+        "kind" : "WhileStmt",
+        "location" : [ 85, 9, 90, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 85, 15, 85, 28 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 85, 15, 85, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "j"
+          },
+          "operator" : "<",
+          "right" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 85, 19, 85, 28 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 85, 19, 85, 26 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 85, 19, 85, 19 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Vector"
+                },
+                "name" : "v"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 85, 21, 85, 26 ],
+                "name" : "length"
+              }
+            },
+            "args" : [ ]
+          }
+        },
+        "body" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 86, 13, 90, 8 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 86, 16, 86, 32 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 86, 16, 86, 27 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "MethodCallExpr",
+                "location" : [ 86, 16, 86, 23 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "method" : {
+                  "kind" : "MemberExpr",
+                  "location" : [ 86, 16, 86, 20 ],
+                  "inferredType" : {
+                    "kind" : "FuncType",
+                    "parameters" : [ {
+                      "kind" : "ClassValueType",
+                      "className" : "Vector"
+                    }, {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    } ],
+                    "returnType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    }
+                  },
+                  "object" : {
+                    "kind" : "Identifier",
+                    "location" : [ 86, 16, 86, 16 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "Vector"
+                    },
+                    "name" : "v"
+                  },
+                  "member" : {
+                    "kind" : "Identifier",
+                    "location" : [ 86, 18, 86, 20 ],
+                    "name" : "get"
+                  }
+                },
+                "args" : [ {
+                  "kind" : "Identifier",
+                  "location" : [ 86, 22, 86, 22 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  },
+                  "name" : "j"
+                } ]
+              },
+              "operator" : "%",
+              "right" : {
+                "kind" : "Identifier",
+                "location" : [ 86, 27, 86, 27 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "k"
+              }
+            },
+            "operator" : "==",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 86, 32, 86, 32 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 0
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "ExprStmt",
+            "location" : [ 87, 17, 87, 30 ],
+            "expr" : {
+              "kind" : "MethodCallExpr",
+              "location" : [ 87, 17, 87, 30 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              },
+              "method" : {
+                "kind" : "MemberExpr",
+                "location" : [ 87, 17, 87, 27 ],
+                "inferredType" : {
+                  "kind" : "FuncType",
+                  "parameters" : [ {
+                    "kind" : "ClassValueType",
+                    "className" : "Vector"
+                  }, {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  } ],
+                  "returnType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "object"
+                  }
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 87, 17, 87, 17 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "Vector"
+                  },
+                  "name" : "v"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 87, 19, 87, 27 ],
+                  "name" : "remove_at"
+                }
+              },
+              "args" : [ {
+                "kind" : "Identifier",
+                "location" : [ 87, 29, 87, 29 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "j"
+              } ]
+            }
+          } ],
+          "elseBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 89, 17, 89, 25 ],
+            "targets" : [ {
+              "kind" : "Identifier",
+              "location" : [ 89, 17, 89, 17 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "j"
+            } ],
+            "value" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 89, 21, 89, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 89, 21, 89, 21 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "j"
+              },
+              "operator" : "+",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 89, 25, 89, 25 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            }
+          } ]
+        } ]
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 90, 9, 90, 17 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 90, 9, 90, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 90, 13, 90, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 90, 13, 90, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 90, 17, 90, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 93, 1, 93, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 93, 1, 93, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 93, 1, 93, 1 ],
+        "name" : "n"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 93, 3, 93, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 93, 9, 93, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 50
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 96, 1, 96, 15 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 96, 1, 96, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 96, 1, 96, 1 ],
+        "name" : "v"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 96, 3, 96, 8 ],
+        "className" : "Vector"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 96, 12, 96, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 97, 1, 97, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 97, 1, 97, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 97, 1, 97, 1 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 97, 3, 97, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 97, 9, 97, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 100, 1, 100, 16 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 100, 1, 100, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "Vector"
+      },
+      "name" : "v"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 100, 5, 100, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "Vector"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 100, 5, 100, 10 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "Vector"
+          }
+        },
+        "name" : "vrange"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 100, 12, 100, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "Identifier",
+        "location" : [ 100, 15, 100, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "n"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 101, 1, 101, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 101, 1, 101, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 101, 1, 101, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "Vector"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "name" : "sieve"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 101, 7, 101, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "Vector"
+        },
+        "name" : "v"
+      } ]
+    }
+  }, {
+    "kind" : "WhileStmt",
+    "location" : [ 104, 1, 108, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 104, 7, 104, 20 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 104, 7, 104, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "MethodCallExpr",
+        "location" : [ 104, 11, 104, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 104, 11, 104, 18 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 104, 11, 104, 11 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Vector"
+            },
+            "name" : "v"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 104, 13, 104, 18 ],
+            "name" : "length"
+          }
+        },
+        "args" : [ ]
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 105, 5, 105, 19 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 105, 5, 105, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 105, 5, 105, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "MethodCallExpr",
+          "location" : [ 105, 11, 105, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 105, 11, 105, 15 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 105, 11, 105, 11 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Vector"
+              },
+              "name" : "v"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 105, 13, 105, 15 ],
+              "name" : "get"
+            }
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 105, 17, 105, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          } ]
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 106, 5, 106, 13 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 106, 5, 106, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 106, 9, 106, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 106, 9, 106, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 106, 13, 106, 13 ],
+          "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/pa3/benchmarks/sieve.py.ast.typed.s.result b/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..6beaeaa3fdbbf1e2aba655e4b8868991975823d0
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s.result
@@ -0,0 +1,15 @@
+2
+3
+5
+7
+11
+13
+17
+19
+23
+29
+31
+37
+41
+43
+47
diff --git a/src/test/data/pa3/benchmarks/stdlib.py b/src/test/data/pa3/benchmarks/stdlib.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7323bd1ac6ef90b13a8ac930ee0205a2176d3ed
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/stdlib.py
@@ -0,0 +1,77 @@
+# ChocoPy library functions
+def int_to_str(x: int) -> str:
+    digits:[str] = None 
+    result:str = ""
+
+    # Set-up digit mapping
+    digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
+
+    # Write sign if necessary
+    if x < 0:
+        result = "-"
+        x = -x
+
+    # Write digits using a recursive call
+    if x >= 10:
+        result = result + int_to_str(x // 10)
+    result = result + digits[x % 10]
+    return result
+
+def str_to_int(x: str) -> int:
+    result:int = 0
+    digit:int = 0
+    char:str = ""
+    sign:int = 1
+    first_char:bool = True
+
+    # Parse digits
+    for char in x:
+        if char == "-":
+            if not first_char:
+                return 0 # Error
+            sign = -1
+        elif char == "0":
+            digit = 0
+        elif char == "1":
+            digit = 1
+        elif char == "2":
+            digit = 2
+        elif char == "3":
+            digit = 3
+        elif char == "3":
+            digit = 3
+        elif char == "4":
+            digit = 4
+        elif char == "5":
+            digit = 5
+        elif char == "6":
+            digit = 6
+        elif char == "7":
+            digit = 7
+        elif char == "8":
+            digit = 8
+        elif char == "9":
+            digit = 9
+        else:
+            return 0 # On error
+        first_char = False
+        result = result * 10 + digit
+
+    # Compute result
+    return result * sign
+        
+# Input parameters
+c:int = 42
+n:int = 10
+
+# Run [-nc, nc] with step size c
+s:str = ""
+i:int = 0
+i = -n * c
+
+# Crunch
+while i <= n * c:
+    s = int_to_str(i)
+    print(s)
+    i = str_to_int(s) + c
+
diff --git a/src/test/data/pa3/benchmarks/stdlib.py.ast.typed b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..72079fff989e1dbca78e791aed78fee92caa73ea
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed
@@ -0,0 +1,1813 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 78, 1 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 2, 1, 18, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 5, 2, 14 ],
+      "name" : "int_to_str"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 2, 16, 2, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 16, 2, 16 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 19, 2, 21 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 2, 27, 2, 29 ],
+      "className" : "str"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 23 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 16 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 10 ],
+          "name" : "digits"
+        },
+        "type" : {
+          "kind" : "ListType",
+          "location" : [ 3, 12, 3, 16 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 3, 13, 3, 15 ],
+            "className" : "str"
+          }
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 3, 20, 3, 23 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 4, 5, 4, 19 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 4, 5, 4, 14 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 10 ],
+          "name" : "result"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 12, 4, 14 ],
+          "className" : "str"
+        }
+      },
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 4, 18, 4, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : ""
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 7, 5, 7, 63 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 10 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "digits"
+      } ],
+      "value" : {
+        "kind" : "ListExpr",
+        "location" : [ 7, 14, 7, 63 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "elements" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 15, 7, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "0"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 20, 7, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "1"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 25, 7, 27 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "2"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 30, 7, 32 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "3"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 35, 7, 37 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "4"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 40, 7, 42 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "5"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 45, 7, 47 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "6"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 50, 7, 52 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "7"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 55, 7, 57 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "8"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 7, 60, 7, 62 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "9"
+        } ]
+      }
+    }, {
+      "kind" : "IfStmt",
+      "location" : [ 10, 5, 15, 4 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 10, 8, 10, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 8, 10, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "<",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 10, 12, 10, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      },
+      "thenBody" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 11, 9, 11, 20 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 11, 9, 11, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "result"
+        } ],
+        "value" : {
+          "kind" : "StringLiteral",
+          "location" : [ 11, 18, 11, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "-"
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 12, 9, 12, 14 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 12, 9, 12, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        } ],
+        "value" : {
+          "kind" : "UnaryExpr",
+          "location" : [ 12, 13, 12, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "operator" : "-",
+          "operand" : {
+            "kind" : "Identifier",
+            "location" : [ 12, 14, 12, 14 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "x"
+          }
+        }
+      } ],
+      "elseBody" : [ ]
+    }, {
+      "kind" : "IfStmt",
+      "location" : [ 15, 5, 17, 4 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 15, 8, 15, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 8, 15, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : ">=",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 15, 13, 15, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 10
+        }
+      },
+      "thenBody" : [ {
+        "kind" : "AssignStmt",
+        "location" : [ 16, 9, 16, 45 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 16, 9, 16, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "result"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 16, 18, 16, 45 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 16, 18, 16, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "result"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "CallExpr",
+            "location" : [ 16, 27, 16, 45 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 27, 16, 36 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "str"
+                }
+              },
+              "name" : "int_to_str"
+            },
+            "args" : [ {
+              "kind" : "BinaryExpr",
+              "location" : [ 16, 38, 16, 44 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 16, 38, 16, 38 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "x"
+              },
+              "operator" : "//",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 16, 43, 16, 44 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 10
+              }
+            } ]
+          }
+        }
+      } ],
+      "elseBody" : [ ]
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 17, 5, 17, 36 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 17, 5, 17, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "result"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 17, 14, 17, 36 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 14, 17, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "result"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IndexExpr",
+          "location" : [ 17, 23, 17, 36 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "list" : {
+            "kind" : "Identifier",
+            "location" : [ 17, 23, 17, 28 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              }
+            },
+            "name" : "digits"
+          },
+          "index" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 17, 30, 17, 35 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 17, 30, 17, 30 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : "%",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 17, 34, 17, 35 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 10
+            }
+          }
+        }
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 18, 5, 18, 17 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 12, 18, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "result"
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 20, 1, 61, 25 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 20, 5, 20, 14 ],
+      "name" : "str_to_int"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 20, 16, 20, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 20, 16, 20, 16 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 20, 19, 20, 21 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 20, 27, 20, 29 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 21, 5, 21, 18 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 21, 5, 21, 14 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 21, 5, 21, 10 ],
+          "name" : "result"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 21, 12, 21, 14 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 21, 18, 21, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 22, 5, 22, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 22, 5, 22, 13 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 22, 5, 22, 9 ],
+          "name" : "digit"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 22, 11, 22, 13 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 22, 17, 22, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 23, 5, 23, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 23, 5, 23, 12 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 23, 5, 23, 8 ],
+          "name" : "char"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 23, 10, 23, 12 ],
+          "className" : "str"
+        }
+      },
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 23, 16, 23, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : ""
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 24, 5, 24, 16 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 24, 5, 24, 12 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 24, 5, 24, 8 ],
+          "name" : "sign"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 24, 10, 24, 12 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 24, 16, 24, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 25, 5, 25, 26 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 25, 5, 25, 19 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 25, 5, 25, 14 ],
+          "name" : "first_char"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 25, 16, 25, 19 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 25, 23, 25, 26 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ForStmt",
+      "location" : [ 28, 5, 61, 4 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 28, 9, 28, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "char"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 28, 17, 28, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "body" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 29, 9, 57, 8 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 29, 12, 29, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 29, 12, 29, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "char"
+          },
+          "operator" : "==",
+          "right" : {
+            "kind" : "StringLiteral",
+            "location" : [ 29, 20, 29, 22 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "-"
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 30, 13, 32, 12 ],
+          "condition" : {
+            "kind" : "UnaryExpr",
+            "location" : [ 30, 16, 30, 29 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "operator" : "not",
+            "operand" : {
+              "kind" : "Identifier",
+              "location" : [ 30, 20, 30, 29 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "name" : "first_char"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "ReturnStmt",
+            "location" : [ 31, 17, 31, 24 ],
+            "value" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 31, 24, 31, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 0
+            }
+          } ],
+          "elseBody" : [ ]
+        }, {
+          "kind" : "AssignStmt",
+          "location" : [ 32, 13, 32, 21 ],
+          "targets" : [ {
+            "kind" : "Identifier",
+            "location" : [ 32, 13, 32, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "sign"
+          } ],
+          "value" : {
+            "kind" : "UnaryExpr",
+            "location" : [ 32, 20, 32, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "operator" : "-",
+            "operand" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 32, 21, 32, 21 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 1
+            }
+          }
+        } ],
+        "elseBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 33, 9, 57, 8 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 33, 14, 33, 24 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 33, 14, 33, 17 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              },
+              "name" : "char"
+            },
+            "operator" : "==",
+            "right" : {
+              "kind" : "StringLiteral",
+              "location" : [ 33, 22, 33, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              },
+              "value" : "0"
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 34, 13, 34, 21 ],
+            "targets" : [ {
+              "kind" : "Identifier",
+              "location" : [ 34, 13, 34, 17 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "digit"
+            } ],
+            "value" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 34, 21, 34, 21 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 0
+            }
+          } ],
+          "elseBody" : [ {
+            "kind" : "IfStmt",
+            "location" : [ 35, 9, 57, 8 ],
+            "condition" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 35, 14, 35, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "left" : {
+                "kind" : "Identifier",
+                "location" : [ 35, 14, 35, 17 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "str"
+                },
+                "name" : "char"
+              },
+              "operator" : "==",
+              "right" : {
+                "kind" : "StringLiteral",
+                "location" : [ 35, 22, 35, 24 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "str"
+                },
+                "value" : "1"
+              }
+            },
+            "thenBody" : [ {
+              "kind" : "AssignStmt",
+              "location" : [ 36, 13, 36, 21 ],
+              "targets" : [ {
+                "kind" : "Identifier",
+                "location" : [ 36, 13, 36, 17 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "digit"
+              } ],
+              "value" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 36, 21, 36, 21 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            } ],
+            "elseBody" : [ {
+              "kind" : "IfStmt",
+              "location" : [ 37, 9, 57, 8 ],
+              "condition" : {
+                "kind" : "BinaryExpr",
+                "location" : [ 37, 14, 37, 24 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "left" : {
+                  "kind" : "Identifier",
+                  "location" : [ 37, 14, 37, 17 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "str"
+                  },
+                  "name" : "char"
+                },
+                "operator" : "==",
+                "right" : {
+                  "kind" : "StringLiteral",
+                  "location" : [ 37, 22, 37, 24 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "str"
+                  },
+                  "value" : "2"
+                }
+              },
+              "thenBody" : [ {
+                "kind" : "AssignStmt",
+                "location" : [ 38, 13, 38, 21 ],
+                "targets" : [ {
+                  "kind" : "Identifier",
+                  "location" : [ 38, 13, 38, 17 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  },
+                  "name" : "digit"
+                } ],
+                "value" : {
+                  "kind" : "IntegerLiteral",
+                  "location" : [ 38, 21, 38, 21 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  },
+                  "value" : 2
+                }
+              } ],
+              "elseBody" : [ {
+                "kind" : "IfStmt",
+                "location" : [ 39, 9, 57, 8 ],
+                "condition" : {
+                  "kind" : "BinaryExpr",
+                  "location" : [ 39, 14, 39, 24 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bool"
+                  },
+                  "left" : {
+                    "kind" : "Identifier",
+                    "location" : [ 39, 14, 39, 17 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "str"
+                    },
+                    "name" : "char"
+                  },
+                  "operator" : "==",
+                  "right" : {
+                    "kind" : "StringLiteral",
+                    "location" : [ 39, 22, 39, 24 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "str"
+                    },
+                    "value" : "3"
+                  }
+                },
+                "thenBody" : [ {
+                  "kind" : "AssignStmt",
+                  "location" : [ 40, 13, 40, 21 ],
+                  "targets" : [ {
+                    "kind" : "Identifier",
+                    "location" : [ 40, 13, 40, 17 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    },
+                    "name" : "digit"
+                  } ],
+                  "value" : {
+                    "kind" : "IntegerLiteral",
+                    "location" : [ 40, 21, 40, 21 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    },
+                    "value" : 3
+                  }
+                } ],
+                "elseBody" : [ {
+                  "kind" : "IfStmt",
+                  "location" : [ 41, 9, 57, 8 ],
+                  "condition" : {
+                    "kind" : "BinaryExpr",
+                    "location" : [ 41, 14, 41, 24 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "bool"
+                    },
+                    "left" : {
+                      "kind" : "Identifier",
+                      "location" : [ 41, 14, 41, 17 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "str"
+                      },
+                      "name" : "char"
+                    },
+                    "operator" : "==",
+                    "right" : {
+                      "kind" : "StringLiteral",
+                      "location" : [ 41, 22, 41, 24 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "str"
+                      },
+                      "value" : "3"
+                    }
+                  },
+                  "thenBody" : [ {
+                    "kind" : "AssignStmt",
+                    "location" : [ 42, 13, 42, 21 ],
+                    "targets" : [ {
+                      "kind" : "Identifier",
+                      "location" : [ 42, 13, 42, 17 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "int"
+                      },
+                      "name" : "digit"
+                    } ],
+                    "value" : {
+                      "kind" : "IntegerLiteral",
+                      "location" : [ 42, 21, 42, 21 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "int"
+                      },
+                      "value" : 3
+                    }
+                  } ],
+                  "elseBody" : [ {
+                    "kind" : "IfStmt",
+                    "location" : [ 43, 9, 57, 8 ],
+                    "condition" : {
+                      "kind" : "BinaryExpr",
+                      "location" : [ 43, 14, 43, 24 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "bool"
+                      },
+                      "left" : {
+                        "kind" : "Identifier",
+                        "location" : [ 43, 14, 43, 17 ],
+                        "inferredType" : {
+                          "kind" : "ClassValueType",
+                          "className" : "str"
+                        },
+                        "name" : "char"
+                      },
+                      "operator" : "==",
+                      "right" : {
+                        "kind" : "StringLiteral",
+                        "location" : [ 43, 22, 43, 24 ],
+                        "inferredType" : {
+                          "kind" : "ClassValueType",
+                          "className" : "str"
+                        },
+                        "value" : "4"
+                      }
+                    },
+                    "thenBody" : [ {
+                      "kind" : "AssignStmt",
+                      "location" : [ 44, 13, 44, 21 ],
+                      "targets" : [ {
+                        "kind" : "Identifier",
+                        "location" : [ 44, 13, 44, 17 ],
+                        "inferredType" : {
+                          "kind" : "ClassValueType",
+                          "className" : "int"
+                        },
+                        "name" : "digit"
+                      } ],
+                      "value" : {
+                        "kind" : "IntegerLiteral",
+                        "location" : [ 44, 21, 44, 21 ],
+                        "inferredType" : {
+                          "kind" : "ClassValueType",
+                          "className" : "int"
+                        },
+                        "value" : 4
+                      }
+                    } ],
+                    "elseBody" : [ {
+                      "kind" : "IfStmt",
+                      "location" : [ 45, 9, 57, 8 ],
+                      "condition" : {
+                        "kind" : "BinaryExpr",
+                        "location" : [ 45, 14, 45, 24 ],
+                        "inferredType" : {
+                          "kind" : "ClassValueType",
+                          "className" : "bool"
+                        },
+                        "left" : {
+                          "kind" : "Identifier",
+                          "location" : [ 45, 14, 45, 17 ],
+                          "inferredType" : {
+                            "kind" : "ClassValueType",
+                            "className" : "str"
+                          },
+                          "name" : "char"
+                        },
+                        "operator" : "==",
+                        "right" : {
+                          "kind" : "StringLiteral",
+                          "location" : [ 45, 22, 45, 24 ],
+                          "inferredType" : {
+                            "kind" : "ClassValueType",
+                            "className" : "str"
+                          },
+                          "value" : "5"
+                        }
+                      },
+                      "thenBody" : [ {
+                        "kind" : "AssignStmt",
+                        "location" : [ 46, 13, 46, 21 ],
+                        "targets" : [ {
+                          "kind" : "Identifier",
+                          "location" : [ 46, 13, 46, 17 ],
+                          "inferredType" : {
+                            "kind" : "ClassValueType",
+                            "className" : "int"
+                          },
+                          "name" : "digit"
+                        } ],
+                        "value" : {
+                          "kind" : "IntegerLiteral",
+                          "location" : [ 46, 21, 46, 21 ],
+                          "inferredType" : {
+                            "kind" : "ClassValueType",
+                            "className" : "int"
+                          },
+                          "value" : 5
+                        }
+                      } ],
+                      "elseBody" : [ {
+                        "kind" : "IfStmt",
+                        "location" : [ 47, 9, 57, 8 ],
+                        "condition" : {
+                          "kind" : "BinaryExpr",
+                          "location" : [ 47, 14, 47, 24 ],
+                          "inferredType" : {
+                            "kind" : "ClassValueType",
+                            "className" : "bool"
+                          },
+                          "left" : {
+                            "kind" : "Identifier",
+                            "location" : [ 47, 14, 47, 17 ],
+                            "inferredType" : {
+                              "kind" : "ClassValueType",
+                              "className" : "str"
+                            },
+                            "name" : "char"
+                          },
+                          "operator" : "==",
+                          "right" : {
+                            "kind" : "StringLiteral",
+                            "location" : [ 47, 22, 47, 24 ],
+                            "inferredType" : {
+                              "kind" : "ClassValueType",
+                              "className" : "str"
+                            },
+                            "value" : "6"
+                          }
+                        },
+                        "thenBody" : [ {
+                          "kind" : "AssignStmt",
+                          "location" : [ 48, 13, 48, 21 ],
+                          "targets" : [ {
+                            "kind" : "Identifier",
+                            "location" : [ 48, 13, 48, 17 ],
+                            "inferredType" : {
+                              "kind" : "ClassValueType",
+                              "className" : "int"
+                            },
+                            "name" : "digit"
+                          } ],
+                          "value" : {
+                            "kind" : "IntegerLiteral",
+                            "location" : [ 48, 21, 48, 21 ],
+                            "inferredType" : {
+                              "kind" : "ClassValueType",
+                              "className" : "int"
+                            },
+                            "value" : 6
+                          }
+                        } ],
+                        "elseBody" : [ {
+                          "kind" : "IfStmt",
+                          "location" : [ 49, 9, 57, 8 ],
+                          "condition" : {
+                            "kind" : "BinaryExpr",
+                            "location" : [ 49, 14, 49, 24 ],
+                            "inferredType" : {
+                              "kind" : "ClassValueType",
+                              "className" : "bool"
+                            },
+                            "left" : {
+                              "kind" : "Identifier",
+                              "location" : [ 49, 14, 49, 17 ],
+                              "inferredType" : {
+                                "kind" : "ClassValueType",
+                                "className" : "str"
+                              },
+                              "name" : "char"
+                            },
+                            "operator" : "==",
+                            "right" : {
+                              "kind" : "StringLiteral",
+                              "location" : [ 49, 22, 49, 24 ],
+                              "inferredType" : {
+                                "kind" : "ClassValueType",
+                                "className" : "str"
+                              },
+                              "value" : "7"
+                            }
+                          },
+                          "thenBody" : [ {
+                            "kind" : "AssignStmt",
+                            "location" : [ 50, 13, 50, 21 ],
+                            "targets" : [ {
+                              "kind" : "Identifier",
+                              "location" : [ 50, 13, 50, 17 ],
+                              "inferredType" : {
+                                "kind" : "ClassValueType",
+                                "className" : "int"
+                              },
+                              "name" : "digit"
+                            } ],
+                            "value" : {
+                              "kind" : "IntegerLiteral",
+                              "location" : [ 50, 21, 50, 21 ],
+                              "inferredType" : {
+                                "kind" : "ClassValueType",
+                                "className" : "int"
+                              },
+                              "value" : 7
+                            }
+                          } ],
+                          "elseBody" : [ {
+                            "kind" : "IfStmt",
+                            "location" : [ 51, 9, 57, 8 ],
+                            "condition" : {
+                              "kind" : "BinaryExpr",
+                              "location" : [ 51, 14, 51, 24 ],
+                              "inferredType" : {
+                                "kind" : "ClassValueType",
+                                "className" : "bool"
+                              },
+                              "left" : {
+                                "kind" : "Identifier",
+                                "location" : [ 51, 14, 51, 17 ],
+                                "inferredType" : {
+                                  "kind" : "ClassValueType",
+                                  "className" : "str"
+                                },
+                                "name" : "char"
+                              },
+                              "operator" : "==",
+                              "right" : {
+                                "kind" : "StringLiteral",
+                                "location" : [ 51, 22, 51, 24 ],
+                                "inferredType" : {
+                                  "kind" : "ClassValueType",
+                                  "className" : "str"
+                                },
+                                "value" : "8"
+                              }
+                            },
+                            "thenBody" : [ {
+                              "kind" : "AssignStmt",
+                              "location" : [ 52, 13, 52, 21 ],
+                              "targets" : [ {
+                                "kind" : "Identifier",
+                                "location" : [ 52, 13, 52, 17 ],
+                                "inferredType" : {
+                                  "kind" : "ClassValueType",
+                                  "className" : "int"
+                                },
+                                "name" : "digit"
+                              } ],
+                              "value" : {
+                                "kind" : "IntegerLiteral",
+                                "location" : [ 52, 21, 52, 21 ],
+                                "inferredType" : {
+                                  "kind" : "ClassValueType",
+                                  "className" : "int"
+                                },
+                                "value" : 8
+                              }
+                            } ],
+                            "elseBody" : [ {
+                              "kind" : "IfStmt",
+                              "location" : [ 53, 9, 57, 8 ],
+                              "condition" : {
+                                "kind" : "BinaryExpr",
+                                "location" : [ 53, 14, 53, 24 ],
+                                "inferredType" : {
+                                  "kind" : "ClassValueType",
+                                  "className" : "bool"
+                                },
+                                "left" : {
+                                  "kind" : "Identifier",
+                                  "location" : [ 53, 14, 53, 17 ],
+                                  "inferredType" : {
+                                    "kind" : "ClassValueType",
+                                    "className" : "str"
+                                  },
+                                  "name" : "char"
+                                },
+                                "operator" : "==",
+                                "right" : {
+                                  "kind" : "StringLiteral",
+                                  "location" : [ 53, 22, 53, 24 ],
+                                  "inferredType" : {
+                                    "kind" : "ClassValueType",
+                                    "className" : "str"
+                                  },
+                                  "value" : "9"
+                                }
+                              },
+                              "thenBody" : [ {
+                                "kind" : "AssignStmt",
+                                "location" : [ 54, 13, 54, 21 ],
+                                "targets" : [ {
+                                  "kind" : "Identifier",
+                                  "location" : [ 54, 13, 54, 17 ],
+                                  "inferredType" : {
+                                    "kind" : "ClassValueType",
+                                    "className" : "int"
+                                  },
+                                  "name" : "digit"
+                                } ],
+                                "value" : {
+                                  "kind" : "IntegerLiteral",
+                                  "location" : [ 54, 21, 54, 21 ],
+                                  "inferredType" : {
+                                    "kind" : "ClassValueType",
+                                    "className" : "int"
+                                  },
+                                  "value" : 9
+                                }
+                              } ],
+                              "elseBody" : [ {
+                                "kind" : "ReturnStmt",
+                                "location" : [ 56, 13, 56, 20 ],
+                                "value" : {
+                                  "kind" : "IntegerLiteral",
+                                  "location" : [ 56, 20, 56, 20 ],
+                                  "inferredType" : {
+                                    "kind" : "ClassValueType",
+                                    "className" : "int"
+                                  },
+                                  "value" : 0
+                                }
+                              } ]
+                            } ]
+                          } ]
+                        } ]
+                      } ]
+                    } ]
+                  } ]
+                } ]
+              } ]
+            } ]
+          } ]
+        } ]
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 57, 9, 57, 26 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 57, 9, 57, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "name" : "first_char"
+        } ],
+        "value" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 57, 22, 57, 26 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        }
+      }, {
+        "kind" : "AssignStmt",
+        "location" : [ 58, 9, 58, 36 ],
+        "targets" : [ {
+          "kind" : "Identifier",
+          "location" : [ 58, 9, 58, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "result"
+        } ],
+        "value" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 58, 18, 58, 36 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 58, 18, 58, 28 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 58, 18, 58, 23 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "result"
+            },
+            "operator" : "*",
+            "right" : {
+              "kind" : "IntegerLiteral",
+              "location" : [ 58, 27, 58, 28 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "value" : 10
+            }
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "Identifier",
+            "location" : [ 58, 32, 58, 36 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "digit"
+          }
+        }
+      } ]
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 61, 5, 61, 24 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 61, 12, 61, 24 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 61, 12, 61, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "result"
+        },
+        "operator" : "*",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 61, 21, 61, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "sign"
+        }
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 64, 1, 64, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 64, 1, 64, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 64, 1, 64, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 64, 3, 64, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 64, 9, 64, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 65, 1, 65, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 65, 1, 65, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 65, 1, 65, 1 ],
+        "name" : "n"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 65, 3, 65, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 65, 9, 65, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 10
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 68, 1, 68, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 68, 1, 68, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 68, 1, 68, 1 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 68, 3, 68, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 68, 9, 68, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 69, 1, 69, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 69, 1, 69, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 69, 1, 69, 1 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 69, 3, 69, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 69, 9, 69, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 70, 1, 70, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 70, 1, 70, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "i"
+    } ],
+    "value" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 70, 5, 70, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "left" : {
+        "kind" : "UnaryExpr",
+        "location" : [ 70, 5, 70, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "operator" : "-",
+        "operand" : {
+          "kind" : "Identifier",
+          "location" : [ 70, 6, 70, 6 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "n"
+        }
+      },
+      "operator" : "*",
+      "right" : {
+        "kind" : "Identifier",
+        "location" : [ 70, 10, 70, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "c"
+      }
+    }
+  }, {
+    "kind" : "WhileStmt",
+    "location" : [ 73, 1, 78, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 73, 7, 73, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 73, 7, 73, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<=",
+      "right" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 73, 12, 73, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 73, 12, 73, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "n"
+        },
+        "operator" : "*",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 73, 16, 73, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "c"
+        }
+      }
+    },
+    "body" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 74, 5, 74, 21 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 74, 5, 74, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "s"
+      } ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 74, 9, 74, 21 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 74, 9, 74, 18 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }
+          },
+          "name" : "int_to_str"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 74, 20, 74, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 75, 5, 75, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 75, 5, 75, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 75, 5, 75, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 75, 11, 75, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 76, 5, 76, 25 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 76, 5, 76, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 76, 9, 76, 25 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "CallExpr",
+          "location" : [ 76, 9, 76, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 76, 9, 76, 18 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "str_to_int"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 76, 20, 76, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "s"
+          } ]
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 76, 25, 76, 25 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "c"
+        }
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s.result b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..3a07fa481f008f09d098a921b3144282dd4b90a5
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s.result
@@ -0,0 +1,21 @@
+-420
+-378
+-336
+-294
+-252
+-210
+-168
+-126
+-84
+-42
+0
+42
+84
+126
+168
+210
+252
+294
+336
+378
+420
diff --git a/src/test/data/pa3/benchmarks/tree.py b/src/test/data/pa3/benchmarks/tree.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f337fd92d229e3c24c54bf3d5098e92f259cd43
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/tree.py
@@ -0,0 +1,83 @@
+# Binary-search trees
+class TreeNode(object):
+	value:int = 0
+	left:"TreeNode" = None
+	right:"TreeNode" = None
+
+	def insert(self:"TreeNode", x:int) -> bool:
+		if x < self.value:
+			if self.left is None:
+				self.left = makeNode(x)
+				return True
+			else:
+				return self.left.insert(x)
+		elif x > self.value:
+			if self.right is None:
+				self.right = makeNode(x)
+				return True
+			else:
+				return self.right.insert(x)
+		return False
+
+	def contains(self:"TreeNode", x:int) -> bool:
+		if x < self.value:
+			if self.left is None:
+				return False
+			else:
+				return self.left.contains(x)
+		elif x > self.value:
+			if self.right is None:
+				return False
+			else:
+				return self.right.contains(x)
+		else:
+			return True
+
+class Tree(object):
+	root:TreeNode = None
+	size:int = 0
+
+	def insert(self:"Tree", x:int) -> object:
+		if self.root is None:
+			self.root = makeNode(x)
+			self.size = 1
+		else:
+			if self.root.insert(x):
+				self.size = self.size + 1
+
+	def contains(self:"Tree", x:int) -> bool:
+		if self.root is None:
+			return False
+		else:
+			return self.root.contains(x)
+
+def makeNode(x: int) -> TreeNode:
+	b:TreeNode = None
+	b = TreeNode()
+	b.value = x
+	return b
+
+
+# Input parameters
+n:int = 100
+c:int = 4
+
+# Data
+t:Tree = None
+i:int = 0
+k:int = 37813
+
+# Crunch
+t = Tree()
+while i < n:
+	t.insert(k)
+	k = (k * 37813) % 37831
+	if i % c != 0:
+		t.insert(i)
+	i = i + 1
+
+print(t.size)
+
+for i in [4, 8, 15, 16, 23, 42]:
+	if t.contains(i):
+		print(i)
diff --git a/src/test/data/pa3/benchmarks/tree.py.ast.typed b/src/test/data/pa3/benchmarks/tree.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..a8d3cb334aa3750ff25c8ed2665ed621ec2315c4
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/tree.py.ast.typed
@@ -0,0 +1,2301 @@
+{
+  "kind" : "Program",
+  "location" : [ 2, 1, 84, 2 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 2, 1, 36, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 7, 2, 14 ],
+      "name" : "TreeNode"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 16, 2, 21 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 2, 3, 14 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 2, 3, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 2, 3, 6 ],
+          "name" : "value"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 8, 3, 10 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 14, 3, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 4, 2, 4, 23 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 4, 2, 4, 16 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 2, 4, 5 ],
+          "name" : "left"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 7, 4, 16 ],
+          "className" : "TreeNode"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 4, 20, 4, 23 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 5, 2, 5, 24 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 2, 5, 17 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 2, 5, 6 ],
+          "name" : "right"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 8, 5, 17 ],
+          "className" : "TreeNode"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 5, 21, 5, 24 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 2, 20, 15 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 6, 7, 11 ],
+        "name" : "insert"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 13, 7, 27 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 13, 7, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 18, 7, 27 ],
+          "className" : "TreeNode"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 7, 30, 7, 34 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 30, 7, 30 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 32, 7, 34 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 40, 7, 43 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 8, 3, 20, 2 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 8, 6, 8, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 6, 8, 6 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "x"
+          },
+          "operator" : "<",
+          "right" : {
+            "kind" : "MemberExpr",
+            "location" : [ 8, 10, 8, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 8, 10, 8, 13 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "TreeNode"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 8, 15, 8, 19 ],
+              "name" : "value"
+            }
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 9, 4, 14, 2 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 9, 7, 9, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "MemberExpr",
+              "location" : [ 9, 7, 9, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "TreeNode"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 9, 7, 9, 10 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 9, 12, 9, 15 ],
+                "name" : "left"
+              }
+            },
+            "operator" : "is",
+            "right" : {
+              "kind" : "NoneLiteral",
+              "location" : [ 9, 20, 9, 23 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 10, 5, 10, 27 ],
+            "targets" : [ {
+              "kind" : "MemberExpr",
+              "location" : [ 10, 5, 10, 13 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "TreeNode"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 10, 5, 10, 8 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 10, 10, 10, 13 ],
+                "name" : "left"
+              }
+            } ],
+            "value" : {
+              "kind" : "CallExpr",
+              "location" : [ 10, 17, 10, 27 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "TreeNode"
+              },
+              "function" : {
+                "kind" : "Identifier",
+                "location" : [ 10, 17, 10, 24 ],
+                "inferredType" : {
+                  "kind" : "FuncType",
+                  "parameters" : [ {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  } ],
+                  "returnType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  }
+                },
+                "name" : "makeNode"
+              },
+              "args" : [ {
+                "kind" : "Identifier",
+                "location" : [ 10, 26, 10, 26 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "x"
+              } ]
+            }
+          }, {
+            "kind" : "ReturnStmt",
+            "location" : [ 11, 5, 11, 15 ],
+            "value" : {
+              "kind" : "BooleanLiteral",
+              "location" : [ 11, 12, 11, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "value" : true
+            }
+          } ],
+          "elseBody" : [ {
+            "kind" : "ReturnStmt",
+            "location" : [ 13, 5, 13, 30 ],
+            "value" : {
+              "kind" : "MethodCallExpr",
+              "location" : [ 13, 12, 13, 30 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "method" : {
+                "kind" : "MemberExpr",
+                "location" : [ 13, 12, 13, 27 ],
+                "inferredType" : {
+                  "kind" : "FuncType",
+                  "parameters" : [ {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  }, {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  } ],
+                  "returnType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bool"
+                  }
+                },
+                "object" : {
+                  "kind" : "MemberExpr",
+                  "location" : [ 13, 12, 13, 20 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  },
+                  "object" : {
+                    "kind" : "Identifier",
+                    "location" : [ 13, 12, 13, 15 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    },
+                    "name" : "self"
+                  },
+                  "member" : {
+                    "kind" : "Identifier",
+                    "location" : [ 13, 17, 13, 20 ],
+                    "name" : "left"
+                  }
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 13, 22, 13, 27 ],
+                  "name" : "insert"
+                }
+              },
+              "args" : [ {
+                "kind" : "Identifier",
+                "location" : [ 13, 29, 13, 29 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "x"
+              } ]
+            }
+          } ]
+        } ],
+        "elseBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 14, 3, 20, 2 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 14, 8, 14, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 8, 14, 8 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : ">",
+            "right" : {
+              "kind" : "MemberExpr",
+              "location" : [ 14, 12, 14, 21 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 14, 12, 14, 15 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 14, 17, 14, 21 ],
+                "name" : "value"
+              }
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "IfStmt",
+            "location" : [ 15, 4, 20, 2 ],
+            "condition" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 15, 7, 15, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "left" : {
+                "kind" : "MemberExpr",
+                "location" : [ 15, 7, 15, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 15, 7, 15, 10 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 15, 12, 15, 16 ],
+                  "name" : "right"
+                }
+              },
+              "operator" : "is",
+              "right" : {
+                "kind" : "NoneLiteral",
+                "location" : [ 15, 21, 15, 24 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "<None>"
+                }
+              }
+            },
+            "thenBody" : [ {
+              "kind" : "AssignStmt",
+              "location" : [ 16, 5, 16, 28 ],
+              "targets" : [ {
+                "kind" : "MemberExpr",
+                "location" : [ 16, 5, 16, 14 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 16, 5, 16, 8 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 16, 10, 16, 14 ],
+                  "name" : "right"
+                }
+              } ],
+              "value" : {
+                "kind" : "CallExpr",
+                "location" : [ 16, 18, 16, 28 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "function" : {
+                  "kind" : "Identifier",
+                  "location" : [ 16, 18, 16, 25 ],
+                  "inferredType" : {
+                    "kind" : "FuncType",
+                    "parameters" : [ {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    } ],
+                    "returnType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    }
+                  },
+                  "name" : "makeNode"
+                },
+                "args" : [ {
+                  "kind" : "Identifier",
+                  "location" : [ 16, 27, 16, 27 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  },
+                  "name" : "x"
+                } ]
+              }
+            }, {
+              "kind" : "ReturnStmt",
+              "location" : [ 17, 5, 17, 15 ],
+              "value" : {
+                "kind" : "BooleanLiteral",
+                "location" : [ 17, 12, 17, 15 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "value" : true
+              }
+            } ],
+            "elseBody" : [ {
+              "kind" : "ReturnStmt",
+              "location" : [ 19, 5, 19, 31 ],
+              "value" : {
+                "kind" : "MethodCallExpr",
+                "location" : [ 19, 12, 19, 31 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "method" : {
+                  "kind" : "MemberExpr",
+                  "location" : [ 19, 12, 19, 28 ],
+                  "inferredType" : {
+                    "kind" : "FuncType",
+                    "parameters" : [ {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    }, {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    } ],
+                    "returnType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "bool"
+                    }
+                  },
+                  "object" : {
+                    "kind" : "MemberExpr",
+                    "location" : [ 19, 12, 19, 21 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    },
+                    "object" : {
+                      "kind" : "Identifier",
+                      "location" : [ 19, 12, 19, 15 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "TreeNode"
+                      },
+                      "name" : "self"
+                    },
+                    "member" : {
+                      "kind" : "Identifier",
+                      "location" : [ 19, 17, 19, 21 ],
+                      "name" : "right"
+                    }
+                  },
+                  "member" : {
+                    "kind" : "Identifier",
+                    "location" : [ 19, 23, 19, 28 ],
+                    "name" : "insert"
+                  }
+                },
+                "args" : [ {
+                  "kind" : "Identifier",
+                  "location" : [ 19, 30, 19, 30 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  },
+                  "name" : "x"
+                } ]
+              }
+            } ]
+          } ],
+          "elseBody" : [ ]
+        } ]
+      }, {
+        "kind" : "ReturnStmt",
+        "location" : [ 20, 3, 20, 14 ],
+        "value" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 20, 10, 20, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 22, 2, 36, 0 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 22, 6, 22, 13 ],
+        "name" : "contains"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 22, 15, 22, 29 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 22, 15, 22, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 22, 20, 22, 29 ],
+          "className" : "TreeNode"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 22, 32, 22, 36 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 22, 32, 22, 32 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 22, 34, 22, 36 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 22, 42, 22, 45 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 23, 3, 36, 0 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 23, 6, 23, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 23, 6, 23, 6 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "x"
+          },
+          "operator" : "<",
+          "right" : {
+            "kind" : "MemberExpr",
+            "location" : [ 23, 10, 23, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 23, 10, 23, 13 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "TreeNode"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 23, 15, 23, 19 ],
+              "name" : "value"
+            }
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 24, 4, 28, 2 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 24, 7, 24, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "MemberExpr",
+              "location" : [ 24, 7, 24, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "TreeNode"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 24, 7, 24, 10 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 24, 12, 24, 15 ],
+                "name" : "left"
+              }
+            },
+            "operator" : "is",
+            "right" : {
+              "kind" : "NoneLiteral",
+              "location" : [ 24, 20, 24, 23 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "ReturnStmt",
+            "location" : [ 25, 5, 25, 16 ],
+            "value" : {
+              "kind" : "BooleanLiteral",
+              "location" : [ 25, 12, 25, 16 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "value" : false
+            }
+          } ],
+          "elseBody" : [ {
+            "kind" : "ReturnStmt",
+            "location" : [ 27, 5, 27, 32 ],
+            "value" : {
+              "kind" : "MethodCallExpr",
+              "location" : [ 27, 12, 27, 32 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "method" : {
+                "kind" : "MemberExpr",
+                "location" : [ 27, 12, 27, 29 ],
+                "inferredType" : {
+                  "kind" : "FuncType",
+                  "parameters" : [ {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  }, {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  } ],
+                  "returnType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bool"
+                  }
+                },
+                "object" : {
+                  "kind" : "MemberExpr",
+                  "location" : [ 27, 12, 27, 20 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  },
+                  "object" : {
+                    "kind" : "Identifier",
+                    "location" : [ 27, 12, 27, 15 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    },
+                    "name" : "self"
+                  },
+                  "member" : {
+                    "kind" : "Identifier",
+                    "location" : [ 27, 17, 27, 20 ],
+                    "name" : "left"
+                  }
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 27, 22, 27, 29 ],
+                  "name" : "contains"
+                }
+              },
+              "args" : [ {
+                "kind" : "Identifier",
+                "location" : [ 27, 31, 27, 31 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "name" : "x"
+              } ]
+            }
+          } ]
+        } ],
+        "elseBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 28, 3, 36, 0 ],
+          "condition" : {
+            "kind" : "BinaryExpr",
+            "location" : [ 28, 8, 28, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 28, 8, 28, 8 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : ">",
+            "right" : {
+              "kind" : "MemberExpr",
+              "location" : [ 28, 12, 28, 21 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 28, 12, 28, 15 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 28, 17, 28, 21 ],
+                "name" : "value"
+              }
+            }
+          },
+          "thenBody" : [ {
+            "kind" : "IfStmt",
+            "location" : [ 29, 4, 33, 2 ],
+            "condition" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 29, 7, 29, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "left" : {
+                "kind" : "MemberExpr",
+                "location" : [ 29, 7, 29, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 29, 7, 29, 10 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "TreeNode"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 29, 12, 29, 16 ],
+                  "name" : "right"
+                }
+              },
+              "operator" : "is",
+              "right" : {
+                "kind" : "NoneLiteral",
+                "location" : [ 29, 21, 29, 24 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "<None>"
+                }
+              }
+            },
+            "thenBody" : [ {
+              "kind" : "ReturnStmt",
+              "location" : [ 30, 5, 30, 16 ],
+              "value" : {
+                "kind" : "BooleanLiteral",
+                "location" : [ 30, 12, 30, 16 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "value" : false
+              }
+            } ],
+            "elseBody" : [ {
+              "kind" : "ReturnStmt",
+              "location" : [ 32, 5, 32, 33 ],
+              "value" : {
+                "kind" : "MethodCallExpr",
+                "location" : [ 32, 12, 32, 33 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "method" : {
+                  "kind" : "MemberExpr",
+                  "location" : [ 32, 12, 32, 30 ],
+                  "inferredType" : {
+                    "kind" : "FuncType",
+                    "parameters" : [ {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    }, {
+                      "kind" : "ClassValueType",
+                      "className" : "int"
+                    } ],
+                    "returnType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "bool"
+                    }
+                  },
+                  "object" : {
+                    "kind" : "MemberExpr",
+                    "location" : [ 32, 12, 32, 21 ],
+                    "inferredType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "TreeNode"
+                    },
+                    "object" : {
+                      "kind" : "Identifier",
+                      "location" : [ 32, 12, 32, 15 ],
+                      "inferredType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "TreeNode"
+                      },
+                      "name" : "self"
+                    },
+                    "member" : {
+                      "kind" : "Identifier",
+                      "location" : [ 32, 17, 32, 21 ],
+                      "name" : "right"
+                    }
+                  },
+                  "member" : {
+                    "kind" : "Identifier",
+                    "location" : [ 32, 23, 32, 30 ],
+                    "name" : "contains"
+                  }
+                },
+                "args" : [ {
+                  "kind" : "Identifier",
+                  "location" : [ 32, 32, 32, 32 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "int"
+                  },
+                  "name" : "x"
+                } ]
+              }
+            } ]
+          } ],
+          "elseBody" : [ {
+            "kind" : "ReturnStmt",
+            "location" : [ 34, 4, 34, 14 ],
+            "value" : {
+              "kind" : "BooleanLiteral",
+              "location" : [ 34, 11, 34, 14 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "value" : true
+            }
+          } ]
+        } ]
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 36, 1, 54, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 36, 7, 36, 10 ],
+      "name" : "Tree"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 36, 12, 36, 17 ],
+      "name" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 37, 2, 37, 21 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 37, 2, 37, 14 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 37, 2, 37, 5 ],
+          "name" : "root"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 37, 7, 37, 14 ],
+          "className" : "TreeNode"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 37, 18, 37, 21 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    }, {
+      "kind" : "VarDef",
+      "location" : [ 38, 2, 38, 13 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 38, 2, 38, 9 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 38, 2, 38, 5 ],
+          "name" : "size"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 38, 7, 38, 9 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 38, 13, 38, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 40, 2, 48, 1 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 40, 6, 40, 11 ],
+        "name" : "insert"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 40, 13, 40, 23 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 40, 13, 40, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 40, 18, 40, 23 ],
+          "className" : "Tree"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 40, 26, 40, 30 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 40, 26, 40, 26 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 40, 28, 40, 30 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 40, 36, 40, 41 ],
+        "className" : "object"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 41, 3, 48, 1 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 41, 6, 41, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "MemberExpr",
+            "location" : [ 41, 6, 41, 14 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "TreeNode"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 41, 6, 41, 9 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Tree"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 41, 11, 41, 14 ],
+              "name" : "root"
+            }
+          },
+          "operator" : "is",
+          "right" : {
+            "kind" : "NoneLiteral",
+            "location" : [ 41, 19, 41, 22 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "AssignStmt",
+          "location" : [ 42, 4, 42, 26 ],
+          "targets" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 42, 4, 42, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "TreeNode"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 42, 4, 42, 7 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Tree"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 42, 9, 42, 12 ],
+              "name" : "root"
+            }
+          } ],
+          "value" : {
+            "kind" : "CallExpr",
+            "location" : [ 42, 16, 42, 26 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "TreeNode"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 42, 16, 42, 23 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                }
+              },
+              "name" : "makeNode"
+            },
+            "args" : [ {
+              "kind" : "Identifier",
+              "location" : [ 42, 25, 42, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            } ]
+          }
+        }, {
+          "kind" : "AssignStmt",
+          "location" : [ 43, 4, 43, 16 ],
+          "targets" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 43, 4, 43, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 43, 4, 43, 7 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Tree"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 43, 9, 43, 12 ],
+              "name" : "size"
+            }
+          } ],
+          "value" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 43, 16, 43, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }
+        } ],
+        "elseBody" : [ {
+          "kind" : "IfStmt",
+          "location" : [ 45, 4, 48, 1 ],
+          "condition" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 45, 7, 45, 25 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 45, 7, 45, 22 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                }, {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                }
+              },
+              "object" : {
+                "kind" : "MemberExpr",
+                "location" : [ 45, 7, 45, 15 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 45, 7, 45, 10 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "Tree"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 45, 12, 45, 15 ],
+                  "name" : "root"
+                }
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 45, 17, 45, 22 ],
+                "name" : "insert"
+              }
+            },
+            "args" : [ {
+              "kind" : "Identifier",
+              "location" : [ 45, 24, 45, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            } ]
+          },
+          "thenBody" : [ {
+            "kind" : "AssignStmt",
+            "location" : [ 46, 5, 46, 29 ],
+            "targets" : [ {
+              "kind" : "MemberExpr",
+              "location" : [ 46, 5, 46, 13 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 46, 5, 46, 8 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "Tree"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 46, 10, 46, 13 ],
+                "name" : "size"
+              }
+            } ],
+            "value" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 46, 17, 46, 29 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "left" : {
+                "kind" : "MemberExpr",
+                "location" : [ 46, 17, 46, 25 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 46, 17, 46, 20 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "Tree"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 46, 22, 46, 25 ],
+                  "name" : "size"
+                }
+              },
+              "operator" : "+",
+              "right" : {
+                "kind" : "IntegerLiteral",
+                "location" : [ 46, 29, 46, 29 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                },
+                "value" : 1
+              }
+            }
+          } ],
+          "elseBody" : [ ]
+        } ]
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 48, 2, 54, 0 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 48, 6, 48, 13 ],
+        "name" : "contains"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 48, 15, 48, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 48, 15, 48, 18 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 48, 20, 48, 25 ],
+          "className" : "Tree"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 48, 28, 48, 32 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 48, 28, 48, 28 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 48, 30, 48, 32 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 48, 38, 48, 41 ],
+        "className" : "bool"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "IfStmt",
+        "location" : [ 49, 3, 54, 0 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 49, 6, 49, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "MemberExpr",
+            "location" : [ 49, 6, 49, 14 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "TreeNode"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 49, 6, 49, 9 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Tree"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 49, 11, 49, 14 ],
+              "name" : "root"
+            }
+          },
+          "operator" : "is",
+          "right" : {
+            "kind" : "NoneLiteral",
+            "location" : [ 49, 19, 49, 22 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 50, 4, 50, 15 ],
+          "value" : {
+            "kind" : "BooleanLiteral",
+            "location" : [ 50, 11, 50, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "value" : false
+          }
+        } ],
+        "elseBody" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 52, 4, 52, 31 ],
+          "value" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 52, 11, 52, 31 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 52, 11, 52, 28 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                }, {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                }
+              },
+              "object" : {
+                "kind" : "MemberExpr",
+                "location" : [ 52, 11, 52, 19 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "TreeNode"
+                },
+                "object" : {
+                  "kind" : "Identifier",
+                  "location" : [ 52, 11, 52, 14 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "Tree"
+                  },
+                  "name" : "self"
+                },
+                "member" : {
+                  "kind" : "Identifier",
+                  "location" : [ 52, 16, 52, 19 ],
+                  "name" : "root"
+                }
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 52, 21, 52, 28 ],
+                "name" : "contains"
+              }
+            },
+            "args" : [ {
+              "kind" : "Identifier",
+              "location" : [ 52, 30, 52, 30 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            } ]
+          }
+        } ]
+      } ]
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 54, 1, 58, 10 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 54, 5, 54, 12 ],
+      "name" : "makeNode"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 54, 14, 54, 19 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 54, 14, 54, 14 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 54, 17, 54, 19 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 54, 25, 54, 32 ],
+      "className" : "TreeNode"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 55, 2, 55, 18 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 55, 2, 55, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 55, 2, 55, 2 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 55, 4, 55, 11 ],
+          "className" : "TreeNode"
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 55, 15, 55, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 56, 2, 56, 15 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 56, 2, 56, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "TreeNode"
+        },
+        "name" : "b"
+      } ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 56, 6, 56, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "TreeNode"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 56, 6, 56, 13 ],
+          "name" : "TreeNode"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 57, 2, 57, 12 ],
+      "targets" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 57, 2, 57, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 57, 2, 57, 2 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "TreeNode"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 57, 4, 57, 8 ],
+          "name" : "value"
+        }
+      } ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 57, 12, 57, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 58, 2, 58, 9 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 58, 9, 58, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "TreeNode"
+        },
+        "name" : "b"
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 62, 1, 62, 11 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 62, 1, 62, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 62, 1, 62, 1 ],
+        "name" : "n"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 62, 3, 62, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 62, 9, 62, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 100
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 63, 1, 63, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 63, 1, 63, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 63, 1, 63, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 63, 3, 63, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 63, 9, 63, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 4
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 66, 1, 66, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 66, 1, 66, 6 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 66, 1, 66, 1 ],
+        "name" : "t"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 66, 3, 66, 6 ],
+        "className" : "Tree"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 66, 10, 66, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 67, 1, 67, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 67, 1, 67, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 67, 1, 67, 1 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 67, 3, 67, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 67, 9, 67, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 68, 1, 68, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 68, 1, 68, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 68, 1, 68, 1 ],
+        "name" : "k"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 68, 3, 68, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 68, 9, 68, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 37813
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 71, 1, 71, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 71, 1, 71, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "Tree"
+      },
+      "name" : "t"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 71, 5, 71, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "Tree"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 71, 5, 71, 8 ],
+        "name" : "Tree"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "WhileStmt",
+    "location" : [ 72, 1, 79, 0 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 72, 7, 72, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 72, 7, 72, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "Identifier",
+        "location" : [ 72, 11, 72, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "n"
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 73, 2, 73, 12 ],
+      "expr" : {
+        "kind" : "MethodCallExpr",
+        "location" : [ 73, 2, 73, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 73, 2, 73, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "Tree"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            }
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 73, 2, 73, 2 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Tree"
+            },
+            "name" : "t"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 73, 4, 73, 9 ],
+            "name" : "insert"
+          }
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 73, 11, 73, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "k"
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 74, 2, 74, 24 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 74, 2, 74, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "k"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 74, 6, 74, 24 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 74, 7, 74, 15 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 74, 7, 74, 7 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "k"
+          },
+          "operator" : "*",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 74, 11, 74, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 37813
+          }
+        },
+        "operator" : "%",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 74, 20, 74, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 37831
+        }
+      }
+    }, {
+      "kind" : "IfStmt",
+      "location" : [ 75, 2, 77, 1 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 75, 5, 75, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 75, 5, 75, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 75, 5, 75, 5 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          },
+          "operator" : "%",
+          "right" : {
+            "kind" : "Identifier",
+            "location" : [ 75, 9, 75, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "c"
+          }
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 75, 14, 75, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      },
+      "thenBody" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 76, 3, 76, 13 ],
+        "expr" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 76, 3, 76, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 76, 3, 76, 10 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "Tree"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 76, 3, 76, 3 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "Tree"
+              },
+              "name" : "t"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 76, 5, 76, 10 ],
+              "name" : "insert"
+            }
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 76, 12, 76, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          } ]
+        }
+      } ],
+      "elseBody" : [ ]
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 77, 2, 77, 10 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 77, 2, 77, 2 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 77, 6, 77, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 77, 6, 77, 6 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 77, 10, 77, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }
+    } ]
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 79, 1, 79, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 79, 1, 79, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 79, 1, 79, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 79, 7, 79, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 79, 7, 79, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "Tree"
+          },
+          "name" : "t"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 79, 9, 79, 12 ],
+          "name" : "size"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ForStmt",
+    "location" : [ 81, 1, 84, 2 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 81, 5, 81, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "i"
+    },
+    "iterable" : {
+      "kind" : "ListExpr",
+      "location" : [ 81, 10, 81, 31 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 81, 11, 81, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 4
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 81, 14, 81, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 8
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 81, 17, 81, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 15
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 81, 21, 81, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 16
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 81, 25, 81, 26 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 23
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 81, 29, 81, 30 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      } ]
+    },
+    "body" : [ {
+      "kind" : "IfStmt",
+      "location" : [ 82, 2, 84, 1 ],
+      "condition" : {
+        "kind" : "MethodCallExpr",
+        "location" : [ 82, 5, 82, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 82, 5, 82, 14 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "Tree"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "object" : {
+            "kind" : "Identifier",
+            "location" : [ 82, 5, 82, 5 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "Tree"
+            },
+            "name" : "t"
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 82, 7, 82, 14 ],
+            "name" : "contains"
+          }
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 82, 16, 82, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        } ]
+      },
+      "thenBody" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 83, 3, 83, 10 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 83, 3, 83, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 83, 3, 83, 7 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 83, 9, 83, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          } ]
+        }
+      } ],
+      "elseBody" : [ ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/benchmarks/tree.py.ast.typed.s.result b/src/test/data/pa3/benchmarks/tree.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..bc9d65b9b8028026df5bccc46165992ba537816b
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/tree.py.ast.typed.s.result
@@ -0,0 +1,4 @@
+175
+15
+23
+42
diff --git a/src/test/data/pa3/sample/call.py b/src/test/data/pa3/sample/call.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b9ba643a68dd9aaa437c96f928025f094da715d
--- /dev/null
+++ b/src/test/data/pa3/sample/call.py
@@ -0,0 +1,17 @@
+def f() -> int:
+    print("start f")
+    g()
+    print("end f")
+    return 42
+
+    
+def g() -> object:
+    print("start g")
+    h()
+    print("end g")
+
+def h() -> object:
+    print("start h")
+    print("end h")
+
+print(f())
diff --git a/src/test/data/pa3/sample/call.py.ast.typed b/src/test/data/pa3/sample/call.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..dd6d3f17c7a2ba8ff6b10544ccd5d241b9e1abfe
--- /dev/null
+++ b/src/test/data/pa3/sample/call.py.ast.typed
@@ -0,0 +1,386 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 17, 11 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 5, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 5 ],
+      "name" : "f"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 12, 1, 14 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 2, 5, 2, 20 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 5, 2, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 2, 11, 2, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "start f"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 3, 5, 3, 7 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 3, 5, 3, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 5 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            }
+          },
+          "name" : "g"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 18 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 4, 5, 4, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 4, 11, 4, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "end f"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 13 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 8, 1, 11, 19 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 5 ],
+      "name" : "g"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 8, 12, 8, 17 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 9, 5, 9, 20 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 9, 5, 9, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 5, 9, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 9, 11, 9, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "start g"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 10, 5, 10, 7 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 10, 5, 10, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 5, 10, 5 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            }
+          },
+          "name" : "h"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 11, 5, 11, 18 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 11, 5, 11, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 5, 11, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 11, 11, 11, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "end g"
+        } ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 13, 1, 15, 19 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 13, 5, 13, 5 ],
+      "name" : "h"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 13, 12, 13, 17 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 14, 5, 14, 20 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 14, 5, 14, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 5, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 14, 11, 14, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "start h"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 15, 5, 15, 18 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 15, 5, 15, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 5, 15, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 15, 11, 15, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "end h"
+        } ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 17, 1, 17, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 1, 17, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 17, 7, 17, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 7, 17, 7 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "f"
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/call.py.ast.typed.s.result b/src/test/data/pa3/sample/call.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ff1eea8bdb5e706f06aa2b4d2bd7591600889f2f
--- /dev/null
+++ b/src/test/data/pa3/sample/call.py.ast.typed.s.result
@@ -0,0 +1,7 @@
+start f
+start g
+start h
+end h
+end g
+end f
+42
diff --git a/src/test/data/pa3/sample/call_with_args.py b/src/test/data/pa3/sample/call_with_args.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc9b16a9cabc1e5482ee5b10518fc7b544793cdc
--- /dev/null
+++ b/src/test/data/pa3/sample/call_with_args.py
@@ -0,0 +1,19 @@
+def f(x:int) -> int:
+    print("start f")
+    print(x)
+    g(1, x)
+    print("end f")
+    return x
+
+    
+def g(y:int, z:int) -> object:
+    print("start g")
+    print(y)
+    print(z)
+    h("h")
+    print("end g")
+
+def h(msg: str) -> object:
+    print(msg)
+
+print(f(4))
diff --git a/src/test/data/pa3/sample/call_with_args.py.ast.typed b/src/test/data/pa3/sample/call_with_args.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..0ff917c727b8dd0a2939ee1c4fa29dc1c7750ae6
--- /dev/null
+++ b/src/test/data/pa3/sample/call_with_args.py.ast.typed
@@ -0,0 +1,554 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 19, 12 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 6, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 5 ],
+      "name" : "f"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 7, 1, 11 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 7, 1, 7 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 9, 1, 11 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 17, 1, 19 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 2, 5, 2, 20 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 5, 2, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 2, 11, 2, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "start f"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 3, 5, 3, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 3, 5, 3, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 3, 11, 3, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 11 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 4, 5, 4, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 5 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            }
+          },
+          "name" : "g"
+        },
+        "args" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 4, 10, 4, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 5, 5, 5, 18 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 5, 5, 5, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 5, 11, 5, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "end f"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 6, 5, 6, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 12, 6, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 9, 1, 14, 19 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 9, 5, 9, 5 ],
+      "name" : "g"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 9, 7, 9, 11 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 7, 9, 7 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 9, 9, 11 ],
+        "className" : "int"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 9, 14, 9, 18 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 14, 9, 14 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 16, 9, 18 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 9, 24, 9, 29 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 10, 5, 10, 20 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 10, 5, 10, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 5, 10, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 10, 11, 10, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "start g"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 11, 5, 11, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 11, 5, 11, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 5, 11, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 11, 11, 11, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 12, 5, 12, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 12, 5, 12, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 12, 11, 12, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "z"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 13, 5, 13, 10 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 13, 5, 13, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 5, 13, 5 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            }
+          },
+          "name" : "h"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 13, 7, 13, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "h"
+        } ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 14, 5, 14, 18 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 14, 5, 14, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 5, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 14, 11, 14, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "end g"
+        } ]
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 16, 1, 17, 15 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 16, 5, 16, 5 ],
+      "name" : "h"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 16, 7, 16, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 7, 16, 9 ],
+        "name" : "msg"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 12, 16, 14 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 16, 20, 16, 25 ],
+      "className" : "object"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 17, 5, 17, 14 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 17, 5, 17, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 5, 17, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 17, 11, 17, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "msg"
+        } ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 19, 1, 19, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 19, 1, 19, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 19, 7, 19, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 7, 19, 7 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "f"
+        },
+        "args" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 19, 9, 19, 9 ],
+          "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/pa3/sample/call_with_args.py.ast.typed.s.result b/src/test/data/pa3/sample/call_with_args.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..816ee293fc8d48435e138fa7be302fdea74a4be1
--- /dev/null
+++ b/src/test/data/pa3/sample/call_with_args.py.ast.typed.s.result
@@ -0,0 +1,9 @@
+start f
+4
+start g
+1
+4
+h
+end g
+end f
+4
diff --git a/src/test/data/pa3/sample/error_div_zero.py b/src/test/data/pa3/sample/error_div_zero.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4481c6c66e01bd68ba6d1c85cec8cee806386f1
--- /dev/null
+++ b/src/test/data/pa3/sample/error_div_zero.py
@@ -0,0 +1 @@
+print(42 // 0)
diff --git a/src/test/data/pa3/sample/error_div_zero.py.ast.typed b/src/test/data/pa3/sample/error_div_zero.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..c498a39ade005706126079e359bf8cdbd85389d4
--- /dev/null
+++ b/src/test/data/pa3/sample/error_div_zero.py.ast.typed
@@ -0,0 +1,65 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 15 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 7, 1, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 42
+        },
+        "operator" : "//",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 13, 1, 13 ],
+          "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/pa3/sample/error_div_zero.py.ast.typed.s.result b/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ffe81ab4a18af055fbdfe2b0ade6010caa2a702b
--- /dev/null
+++ b/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Divison by zero
+Exited with error code 2
diff --git a/src/test/data/pa3/sample/error_invalid_print.py b/src/test/data/pa3/sample/error_invalid_print.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca057e542cfb7d6a22087f26a5130b537623ce09
--- /dev/null
+++ b/src/test/data/pa3/sample/error_invalid_print.py
@@ -0,0 +1 @@
+print(None)
diff --git a/src/test/data/pa3/sample/error_invalid_print.py.ast.typed b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..311e64ad2270e6292af4a17d911b6a23a68e7309
--- /dev/null
+++ b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed
@@ -0,0 +1,46 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 12 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "NoneLiteral",
+        "location" : [ 1, 7, 1, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s.result b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..cfb08fa492633dd4bf615a2ae7cc311d4af1b78d
--- /dev/null
+++ b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Invalid argument
+Exited with error code 1
diff --git a/src/test/data/pa3/sample/error_mod_zero.py b/src/test/data/pa3/sample/error_mod_zero.py
new file mode 100644
index 0000000000000000000000000000000000000000..09cfbef9a40f803906704f39cfa796adc93894e2
--- /dev/null
+++ b/src/test/data/pa3/sample/error_mod_zero.py
@@ -0,0 +1 @@
+print(42 % 0)
diff --git a/src/test/data/pa3/sample/error_mod_zero.py.ast.typed b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..371eb364238238ae48423338095c74a88b69c96e
--- /dev/null
+++ b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed
@@ -0,0 +1,65 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 14 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 7, 1, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 42
+        },
+        "operator" : "%",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 12, 1, 12 ],
+          "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/pa3/sample/error_mod_zero.py.ast.typed.s.result b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ffe81ab4a18af055fbdfe2b0ade6010caa2a702b
--- /dev/null
+++ b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Divison by zero
+Exited with error code 2
diff --git a/src/test/data/pa3/sample/expr_if.py b/src/test/data/pa3/sample/expr_if.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0f07640ce17b770082f84b927fc68406f74bda6
--- /dev/null
+++ b/src/test/data/pa3/sample/expr_if.py
@@ -0,0 +1,2 @@
+print(3 if True else 4)
+print(3 if False else 4)
diff --git a/src/test/data/pa3/sample/expr_if.py.ast.typed b/src/test/data/pa3/sample/expr_if.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..3b06e260a0b9d4d249a400ebf855d24bcae8a534
--- /dev/null
+++ b/src/test/data/pa3/sample/expr_if.py.ast.typed
@@ -0,0 +1,135 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 25 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 23 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 23 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IfExpr",
+        "location" : [ 1, 7, 1, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "condition" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 1, 12, 1, 15 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        },
+        "thenExpr" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 7, 1, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        },
+        "elseExpr" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 22, 1, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 4
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 24 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 24 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IfExpr",
+        "location" : [ 2, 7, 2, 23 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "condition" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 2, 12, 2, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        },
+        "thenExpr" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 7, 2, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        },
+        "elseExpr" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 2, 23, 2, 23 ],
+          "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/pa3/sample/expr_if.py.ast.typed.s.result b/src/test/data/pa3/sample/expr_if.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..b94473479cd96f84ea5fdd389a9f4f9d3786b8c1
--- /dev/null
+++ b/src/test/data/pa3/sample/expr_if.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+3
+4
diff --git a/src/test/data/pa3/sample/id_global.py b/src/test/data/pa3/sample/id_global.py
new file mode 100644
index 0000000000000000000000000000000000000000..d72c7d228cb84d2b0297a6a0a90c86433f77d1ed
--- /dev/null
+++ b/src/test/data/pa3/sample/id_global.py
@@ -0,0 +1,2 @@
+x:int = 42
+print(x)
diff --git a/src/test/data/pa3/sample/id_global.py.ast.typed b/src/test/data/pa3/sample/id_global.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..96059367138e5afb087a33fe43280778da97208a
--- /dev/null
+++ b/src/test/data/pa3/sample/id_global.py.ast.typed
@@ -0,0 +1,73 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 2, 7, 2, 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/pa3/sample/id_global.py.ast.typed.s.result b/src/test/data/pa3/sample/id_global.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..d81cc0710eb6cf9efd5b920a8453e1e07157b6cd
--- /dev/null
+++ b/src/test/data/pa3/sample/id_global.py.ast.typed.s.result
@@ -0,0 +1 @@
+42
diff --git a/src/test/data/pa3/sample/id_local.py b/src/test/data/pa3/sample/id_local.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff6dec8e14698f2179a98120de5827877295c236
--- /dev/null
+++ b/src/test/data/pa3/sample/id_local.py
@@ -0,0 +1,5 @@
+def f() -> int:
+  x:int = 1
+  return x
+
+print(f())
diff --git a/src/test/data/pa3/sample/id_local.py.ast.typed b/src/test/data/pa3/sample/id_local.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..472aa172c794fa092dcf2010fc7d2482af3dc317
--- /dev/null
+++ b/src/test/data/pa3/sample/id_local.py.ast.typed
@@ -0,0 +1,114 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 11 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 3, 11 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 5 ],
+      "name" : "f"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 12, 1, 14 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 2, 3, 2, 11 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 2, 3, 2, 7 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 3, 2, 3 ],
+          "name" : "x"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 5, 2, 7 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 11, 2, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 3, 3, 3, 10 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 10, 3, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 5, 7, 5, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 7, 5, 7 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "f"
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/id_local.py.ast.typed.s.result b/src/test/data/pa3/sample/id_local.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
--- /dev/null
+++ b/src/test/data/pa3/sample/id_local.py.ast.typed.s.result
@@ -0,0 +1 @@
+1
diff --git a/src/test/data/pa3/sample/len_invalid_1.py b/src/test/data/pa3/sample/len_invalid_1.py
new file mode 100644
index 0000000000000000000000000000000000000000..1dfa59849ff66625a15cfa1696d96f719535e57a
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_1.py
@@ -0,0 +1,3 @@
+x:[int] = None
+
+print(len(x))
diff --git a/src/test/data/pa3/sample/len_invalid_1.py.ast.typed b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..170d7eec8ab3831d9aa488b347b74ca2d52efc52
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed
@@ -0,0 +1,103 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 14 ],
+  "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" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 3, 1, 3, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 3, 7, 3, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 7, 3, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 3, 11, 3, 11 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "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/pa3/sample/len_invalid_1.py.ast.typed.s.result b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..cfb08fa492633dd4bf615a2ae7cc311d4af1b78d
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Invalid argument
+Exited with error code 1
diff --git a/src/test/data/pa3/sample/len_invalid_2.py b/src/test/data/pa3/sample/len_invalid_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..de46502a6163504b903835bc9e55fe8db22495ee
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_2.py
@@ -0,0 +1,3 @@
+x:int = 1
+
+print(len(x))
diff --git a/src/test/data/pa3/sample/len_invalid_2.py.ast.typed b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..afc264d8c987bcff023f4ac199cb814d58867d02
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed
@@ -0,0 +1,97 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 14 ],
+  "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, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 3, 1, 3, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 3, 7, 3, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 7, 3, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 3, 11, 3, 11 ],
+          "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/pa3/sample/len_invalid_2.py.ast.typed.s.result b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..cfb08fa492633dd4bf615a2ae7cc311d4af1b78d
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Invalid argument
+Exited with error code 1
diff --git a/src/test/data/pa3/sample/list_concat.py b/src/test/data/pa3/sample/list_concat.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2ef21da6f8aa57f24bccdcd58fc04630d57b0f1
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat.py
@@ -0,0 +1,12 @@
+def concat(x:[int], y:[int]) -> [int]:
+    return x + y
+
+z:[int] = None
+i:int = 0
+
+z = concat([1,2,3], [4,5,6])
+
+while i < len(z):
+    print(z[i])
+    i = i + 1
+
diff --git a/src/test/data/pa3/sample/list_concat.py.ast.typed b/src/test/data/pa3/sample/list_concat.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..38ba198012128a9dd7a43c4b880da08881c7500a
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat.py.ast.typed
@@ -0,0 +1,437 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 1 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 2, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 10 ],
+      "name" : "concat"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 12, 1, 18 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 12, 1, 12 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 14, 1, 18 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 15, 1, 17 ],
+          "className" : "int"
+        }
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 1, 21, 1, 27 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 21, 1, 21 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 23, 1, 27 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 24, 1, 26 ],
+          "className" : "int"
+        }
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ListType",
+      "location" : [ 1, 33, 1, 37 ],
+      "elementType" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 34, 1, 36 ],
+        "className" : "int"
+      }
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 2, 5, 2, 16 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 2, 12, 2, 16 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 12, 2, 12 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 16, 2, 16 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "y"
+        }
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 4, 3, 4, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 4, 4, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 11, 4, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 3, 5, 5 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 9, 5, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 28 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 5, 7, 28 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 10 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          }, {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          } ],
+          "returnType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          }
+        },
+        "name" : "concat"
+      },
+      "args" : [ {
+        "kind" : "ListExpr",
+        "location" : [ 7, 12, 7, 18 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 13, 7, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 15, 7, 15 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 2
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 17, 7, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        } ]
+      }, {
+        "kind" : "ListExpr",
+        "location" : [ 7, 21, 7, 27 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 22, 7, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 4
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 24, 7, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 5
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 26, 7, 26 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 6
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "WhileStmt",
+    "location" : [ 9, 1, 13, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 9, 7, 9, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 7, 9, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "CallExpr",
+        "location" : [ 9, 11, 9, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 11, 9, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 9, 15, 9, 15 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "z"
+        } ]
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 10, 5, 10, 15 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 10, 5, 10, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 5, 10, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "IndexExpr",
+          "location" : [ 10, 11, 10, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "list" : {
+            "kind" : "Identifier",
+            "location" : [ 10, 11, 10, 11 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "z"
+          },
+          "index" : {
+            "kind" : "Identifier",
+            "location" : [ 10, 13, 10, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          }
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 11, 5, 11, 13 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 11, 5, 11, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 11, 9, 11, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 9, 11, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 11, 13, 11, 13 ],
+          "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/pa3/sample/list_concat.py.ast.typed.s.result b/src/test/data/pa3/sample/list_concat.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..b414108e81e5091fe0974a1858b4d0d22b107f70
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat.py.ast.typed.s.result
@@ -0,0 +1,6 @@
+1
+2
+3
+4
+5
+6
diff --git a/src/test/data/pa3/sample/list_concat_2.py b/src/test/data/pa3/sample/list_concat_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed0826ce27a8d75274afa8b8dba24032ed3136fa
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_2.py
@@ -0,0 +1,8 @@
+z:[int] = None
+i:int = 0
+
+z = [1,2,3] + [4,5,6] + [7,8,9]
+
+while i < len(z):
+    print(z[i])
+    i = i + 1
diff --git a/src/test/data/pa3/sample/list_concat_2.py.ast.typed b/src/test/data/pa3/sample/list_concat_2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..f5a28b0fa6a5e938df196cf5a8702f8bfb28f27a
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_2.py.ast.typed
@@ -0,0 +1,366 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 1 ],
+  "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" : "z"
+      },
+      "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" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 9 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "i"
+      },
+      "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
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 31 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 4, 1, 4, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 4, 5, 4, 31 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "left" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 5, 4, 21 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "left" : {
+          "kind" : "ListExpr",
+          "location" : [ 4, 5, 4, 11 ],
+          "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, 8, 4, 8 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 2
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 10, 4, 10 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 3
+          } ]
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "ListExpr",
+          "location" : [ 4, 15, 4, 21 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 16, 4, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 4
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 18, 4, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 5
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 20, 4, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 6
+          } ]
+        }
+      },
+      "operator" : "+",
+      "right" : {
+        "kind" : "ListExpr",
+        "location" : [ 4, 25, 4, 31 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 26, 4, 26 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 7
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 28, 4, 28 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 8
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 30, 4, 30 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 9
+        } ]
+      }
+    }
+  }, {
+    "kind" : "WhileStmt",
+    "location" : [ 6, 1, 9, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 6, 7, 6, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 7, 6, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "CallExpr",
+        "location" : [ 6, 11, 6, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 11, 6, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 6, 15, 6, 15 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "z"
+        } ]
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 7, 5, 7, 15 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 7, 5, 7, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "IndexExpr",
+          "location" : [ 7, 11, 7, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "list" : {
+            "kind" : "Identifier",
+            "location" : [ 7, 11, 7, 11 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "z"
+          },
+          "index" : {
+            "kind" : "Identifier",
+            "location" : [ 7, 13, 7, 13 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "i"
+          }
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 8, 5, 8, 13 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 8, 5, 8, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "i"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 8, 9, 8, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 9, 8, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 13, 8, 13 ],
+          "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/pa3/sample/list_concat_2.py.ast.typed.s.result b/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..07193989308c972f8a2d0f1b3a15c29ea4ac565b
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s.result
@@ -0,0 +1,9 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
diff --git a/src/test/data/pa3/sample/list_concat_none.py b/src/test/data/pa3/sample/list_concat_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad0a31050d294685c3409462844f0c3cf8419abd
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_none.py
@@ -0,0 +1,4 @@
+x:[int] = None
+y:[int] = None
+
+print(len(x+y))
diff --git a/src/test/data/pa3/sample/list_concat_none.py.ast.typed b/src/test/data/pa3/sample/list_concat_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..5c50b2ac1ce38ef1ea379b3543eb93a6b0850c39
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_none.py.ast.typed
@@ -0,0 +1,156 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 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" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 11, 2, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 4, 7, 4, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "BinaryExpr",
+          "location" : [ 4, 11, 4, 13 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 4, 11, 4, 11 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "x"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "Identifier",
+            "location" : [ 4, 13, 4, 13 ],
+            "inferredType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "y"
+          }
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s.result b/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ae52477deb467a7ad909a282522c592e696c63b9
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/list_get_element.py b/src/test/data/pa3/sample/list_get_element.py
new file mode 100644
index 0000000000000000000000000000000000000000..54a38352bf64c8076f198ad3b6e654747b8c4119
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element.py
@@ -0,0 +1,6 @@
+x:[int] = None
+
+x = [1, 2, 3]
+print(x[0])
+print(x[1])
+print(x[2])
diff --git a/src/test/data/pa3/sample/list_get_element.py.ast.typed b/src/test/data/pa3/sample/list_get_element.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..71a94cbe564a51c007858254efcffd7d36050127
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element.py.ast.typed
@@ -0,0 +1,259 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 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" : "<None>"
+      }
+    }
+  } ],
+  "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, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 4, 7, 4, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 9, 4, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 5, 7, 5, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 7, 5, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 9, 5, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 6, 7, 6, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 7, 6, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 6, 9, 6, 9 ],
+          "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/pa3/sample/list_get_element.py.ast.typed.s.result b/src/test/data/pa3/sample/list_get_element.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+1
+2
+3
diff --git a/src/test/data/pa3/sample/list_get_element_complex.py b/src/test/data/pa3/sample/list_get_element_complex.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe03e8d42c3379077533a77d69f486ea98f9e862
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_complex.py
@@ -0,0 +1,11 @@
+next:int = 0
+
+def next_int() -> int:
+    global next
+    next = next + 1
+    return next
+
+def make_list() -> [int]:
+    return [next_int(), next_int(), next_int()]
+
+print(make_list()[next_int() - 3])
diff --git a/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..f3c48bba83df257a576e2a971f76c3f53c0b9d6a
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed
@@ -0,0 +1,313 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 11, 35 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 12 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 4 ],
+        "name" : "next"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 6, 1, 8 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 12, 1, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 0
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 3, 1, 6, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 12 ],
+      "name" : "next_int"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 3, 19, 3, 21 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "GlobalDecl",
+      "location" : [ 4, 5, 4, 15 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 12, 4, 15 ],
+        "name" : "next"
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 5, 5, 5, 19 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 5, 5, 5, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "next"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 5, 12, 5, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 12, 5, 15 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "next"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 19, 5, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 6, 5, 6, 15 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 12, 6, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "next"
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 8, 1, 9, 48 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 13 ],
+      "name" : "make_list"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ListType",
+      "location" : [ 8, 20, 8, 24 ],
+      "elementType" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 21, 8, 23 ],
+        "className" : "int"
+      }
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 9, 5, 9, 47 ],
+      "value" : {
+        "kind" : "ListExpr",
+        "location" : [ 9, 12, 9, 47 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "CallExpr",
+          "location" : [ 9, 13, 9, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 13, 9, 20 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "next_int"
+          },
+          "args" : [ ]
+        }, {
+          "kind" : "CallExpr",
+          "location" : [ 9, 25, 9, 34 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 25, 9, 32 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "next_int"
+          },
+          "args" : [ ]
+        }, {
+          "kind" : "CallExpr",
+          "location" : [ 9, 37, 9, 46 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 37, 9, 44 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "next_int"
+          },
+          "args" : [ ]
+        } ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 34 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 34 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 11, 7, 11, 33 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 7, 11, 17 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 7, 11, 15 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ListValueType",
+                "elementType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              }
+            },
+            "name" : "make_list"
+          },
+          "args" : [ ]
+        },
+        "index" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 11, 19, 11, 32 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "CallExpr",
+            "location" : [ 11, 19, 11, 28 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 11, 19, 11, 26 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "name" : "next_int"
+            },
+            "args" : [ ]
+          },
+          "operator" : "-",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 11, 32, 11, 32 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 3
+          }
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s.result b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..0cfbf08886fca9a91cb753ec8734c84fcbe52c9f
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s.result
@@ -0,0 +1 @@
+2
diff --git a/src/test/data/pa3/sample/list_get_element_none.py b/src/test/data/pa3/sample/list_get_element_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..871b395d7cbc20f71aaef4dcb788155c1ebb8dee
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_none.py
@@ -0,0 +1,3 @@
+x:[int] = None
+
+print(x[0])
diff --git a/src/test/data/pa3/sample/list_get_element_none.py.ast.typed b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..a95c8134d9eb5d3a58bc8a7f742c014229ee239b
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed
@@ -0,0 +1,96 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 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" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 3, 1, 3, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 3, 7, 3, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 7, 3, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 9, 3, 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/pa3/sample/list_get_element_none.py.ast.typed.s.result b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ae52477deb467a7ad909a282522c592e696c63b9
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/list_get_element_oob_1.py b/src/test/data/pa3/sample/list_get_element_oob_1.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b0e490d20e53bb31d28ff1f0b765b307b8c9234
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_1.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x = [1, 2, 3]
+print(x[-1])
diff --git a/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..c5e92549d7eb9aa8a59fd527c110f2b73449f8fb
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed
@@ -0,0 +1,156 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 13 ],
+  "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" : "<None>"
+      }
+    }
+  } ],
+  "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, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 4, 7, 4, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "UnaryExpr",
+          "location" : [ 4, 9, 4, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "operator" : "-",
+          "operand" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 4, 10, 4, 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/pa3/sample/list_get_element_oob_1.py.ast.typed.s.result b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/list_get_element_oob_2.py b/src/test/data/pa3/sample/list_get_element_oob_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba070b2d266d0cf4a0d3a786f6c20c9eb42a865b
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_2.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x = [1, 2, 3]
+print(x[3])
diff --git a/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..070d13ba28aac8ab8b3ec4ec282b94e6984e73db
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed
@@ -0,0 +1,147 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 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" : "<None>"
+      }
+    }
+  } ],
+  "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, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 4, 7, 4, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 9, 4, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s.result b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/list_get_element_oob_3.py b/src/test/data/pa3/sample/list_get_element_oob_3.py
new file mode 100644
index 0000000000000000000000000000000000000000..827aae5cfb257b722009084fcdc82d1efd26e382
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_3.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x = []
+print(x[0])
diff --git a/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..aaeb34f240068733759cdf1a3e62df576314b849
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed
@@ -0,0 +1,120 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 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" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 6 ],
+    "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, 6 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<Empty>"
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 4, 7, 4, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 9, 4, 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/pa3/sample/list_get_element_oob_3.py.ast.typed.s.result b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/list_len.py b/src/test/data/pa3/sample/list_len.py
new file mode 100644
index 0000000000000000000000000000000000000000..95ba341e3eb4d591a62bddc7e47bb636492dea36
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x = [1, 2, 3]
+print(len(x))
diff --git a/src/test/data/pa3/sample/list_len.py.ast.typed b/src/test/data/pa3/sample/list_len.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..5a34893e3e7ca7373c725b2061059bac2d2a9434
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len.py.ast.typed
@@ -0,0 +1,154 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 14 ],
+  "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" : "<None>"
+      }
+    }
+  } ],
+  "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, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 4, 7, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 11, 4, 11 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "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/pa3/sample/list_len.py.ast.typed.s.result b/src/test/data/pa3/sample/list_len.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..00750edc07d6415dcc07ae0351e9397b0222b7ba
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len.py.ast.typed.s.result
@@ -0,0 +1 @@
+3
diff --git a/src/test/data/pa3/sample/list_len_empty.py b/src/test/data/pa3/sample/list_len_empty.py
new file mode 100644
index 0000000000000000000000000000000000000000..52bd178413001a0cb4dbea1c7ba23a99dda183b4
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len_empty.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x = []
+print(len(x))
diff --git a/src/test/data/pa3/sample/list_len_empty.py.ast.typed b/src/test/data/pa3/sample/list_len_empty.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4b70475db3e2f98ed964008f84d3e125d3e4e8a0
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len_empty.py.ast.typed
@@ -0,0 +1,127 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 14 ],
+  "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" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 6 ],
+    "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, 6 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<Empty>"
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 4, 7, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 11, 4, 11 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "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/pa3/sample/list_len_empty.py.ast.typed.s.result b/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s.result
@@ -0,0 +1 @@
+0
diff --git a/src/test/data/pa3/sample/list_set_element.py b/src/test/data/pa3/sample/list_set_element.py
new file mode 100644
index 0000000000000000000000000000000000000000..c678fe97f6c227a88bad8e1bb8563701b15a364a
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element.py
@@ -0,0 +1,9 @@
+x:[int] = None
+
+x = [1, 2, 3]
+x[0] = 4
+x[1] = 5
+x[2] = 6
+print(x[0])
+print(x[1])
+print(x[2])
diff --git a/src/test/data/pa3/sample/list_set_element.py.ast.typed b/src/test/data/pa3/sample/list_set_element.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..69649ee39a0ffb2a10091ecb259a497b71e6fcea
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element.py.ast.typed
@@ -0,0 +1,382 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 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" : "<None>"
+      }
+    }
+  } ],
+  "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" : "AssignStmt",
+    "location" : [ 4, 1, 4, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 4, 1, 4, 4 ],
+      "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" : "IntegerLiteral",
+        "location" : [ 4, 3, 4, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 8, 4, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 4
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 5, 1, 5, 4 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 3, 5, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 5, 8, 5, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 5
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 6, 1, 6, 4 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 3, 6, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 6, 8, 6, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 6
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 7, 7, 7, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 7, 7, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 9, 7, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 8, 7, 8, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 7, 8, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 9, 8, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 1, 9, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 9, 7, 9, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 7, 9, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 9, 9, 9, 9 ],
+          "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/pa3/sample/list_set_element.py.ast.typed.s.result b/src/test/data/pa3/sample/list_set_element.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..4578bc10fe1f051dd8fce8f07ed8bb587da52a18
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+4
+5
+6
diff --git a/src/test/data/pa3/sample/list_set_element_none.py b/src/test/data/pa3/sample/list_set_element_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..281c7b4916d365f439d478682dd290ee1dbe9d5d
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_none.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x[0] = 1
+
diff --git a/src/test/data/pa3/sample/list_set_element_none.py.ast.typed b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..fd16a97af21afb9b79c3f42877eddf52323159dd
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed
@@ -0,0 +1,81 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 3, 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" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 3, 1, 3, 4 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "list" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "x"
+      },
+      "index" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 3, 3, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 8, 3, 8 ],
+      "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/pa3/sample/list_set_element_none.py.ast.typed.s.result b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ae52477deb467a7ad909a282522c592e696c63b9
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/list_set_element_oob_1.py b/src/test/data/pa3/sample/list_set_element_oob_1.py
new file mode 100644
index 0000000000000000000000000000000000000000..efd92cad45021214bbe88d1737e9b34f60c9392b
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_1.py
@@ -0,0 +1,7 @@
+x:[int] = None
+
+x = [1, 2, 3]
+x[-1] = 4
+print(x[0])
+print(x[1])
+print(x[2])
diff --git a/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..ed84b2290f0869a90ab08d921ac712f10768b7a2
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed
@@ -0,0 +1,309 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 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" : "<None>"
+      }
+    }
+  } ],
+  "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" : "AssignStmt",
+    "location" : [ 4, 1, 4, 9 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 4, 1, 4, 5 ],
+      "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" : "UnaryExpr",
+        "location" : [ 4, 3, 4, 4 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "operator" : "-",
+        "operand" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 4, 4, 4 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 9, 4, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 4
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 5, 7, 5, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 7, 5, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 9, 5, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 6, 7, 6, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 7, 6, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 6, 9, 6, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 7, 7, 7, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 7, 7, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 9, 7, 9 ],
+          "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/pa3/sample/list_set_element_oob_1.py.ast.typed.s.result b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/list_set_element_oob_2.py b/src/test/data/pa3/sample/list_set_element_oob_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..301cea1cd62885f641bc8390bbcbbba5e76bdab8
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_2.py
@@ -0,0 +1,7 @@
+x:[int] = None
+
+x = [1, 2, 3]
+x[4] = 4
+print(x[0])
+print(x[1])
+print(x[2])
diff --git a/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..5c06dcafc5eb35604dd2efeeb328cd994be4b7e6
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed
@@ -0,0 +1,300 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 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" : "<None>"
+      }
+    }
+  } ],
+  "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" : "AssignStmt",
+    "location" : [ 4, 1, 4, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 4, 1, 4, 4 ],
+      "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" : "IntegerLiteral",
+        "location" : [ 4, 3, 4, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 4
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 8, 4, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 4
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 5, 7, 5, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 7, 5, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 9, 5, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 0
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 6, 7, 6, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 7, 6, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 6, 9, 6, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 7, 7, 7, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 7, 7, 7 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "x"
+        },
+        "index" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 9, 7, 9 ],
+          "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/pa3/sample/list_set_element_oob_2.py.ast.typed.s.result b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/list_set_element_oob_3.py b/src/test/data/pa3/sample/list_set_element_oob_3.py
new file mode 100644
index 0000000000000000000000000000000000000000..281c93cb4afb1325a8bb96ca8756032962c08207
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_3.py
@@ -0,0 +1,4 @@
+x:[int] = None
+
+x = []
+x[0] = 4
diff --git a/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..ec34032cf6a9848e6ec693a12698a8da76dd6f54
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed
@@ -0,0 +1,105 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 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" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 6 ],
+    "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, 6 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<Empty>"
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 4, 1, 4, 8 ],
+    "targets" : [ {
+      "kind" : "IndexExpr",
+      "location" : [ 4, 1, 4, 4 ],
+      "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" : "IntegerLiteral",
+        "location" : [ 4, 3, 4, 3 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 4, 8, 4, 8 ],
+      "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/pa3/sample/list_set_element_oob_3.py.ast.typed.s.result b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/literal_bool.py b/src/test/data/pa3/sample/literal_bool.py
new file mode 100644
index 0000000000000000000000000000000000000000..54b7f1f4439a3962ce615a9316864cc0d616c153
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_bool.py
@@ -0,0 +1,2 @@
+print(True)
+print(False)
diff --git a/src/test/data/pa3/sample/literal_bool.py.ast.typed b/src/test/data/pa3/sample/literal_bool.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..436e5f7b83596328c10f550ae68dd240807cee31
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_bool.py.ast.typed
@@ -0,0 +1,83 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 13 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 11 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 1, 7, 1, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 7, 2, 11 ],
+        "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/pa3/sample/literal_bool.py.ast.typed.s.result b/src/test/data/pa3/sample/literal_bool.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..1cc8b5e10d332579303311a121b2c33c1d9c9f9a
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_bool.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+True
+False
diff --git a/src/test/data/pa3/sample/literal_int.py b/src/test/data/pa3/sample/literal_int.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e78541eaaec33974e67d3ab71c9c8ae1f547db4
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_int.py
@@ -0,0 +1,2 @@
+print(42)
+print(65999)
diff --git a/src/test/data/pa3/sample/literal_int.py.ast.typed b/src/test/data/pa3/sample/literal_int.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..eed7bda513da4333b2a97901bfa60ca8fdadcf74
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_int.py.ast.typed
@@ -0,0 +1,83 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 13 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 9 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 1, 7, 1, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 7, 2, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 65999
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/literal_int.py.ast.typed.s.result b/src/test/data/pa3/sample/literal_int.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..454025ba0d8bd338b889032c968e6b6d9639ab77
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_int.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+42
+65999
diff --git a/src/test/data/pa3/sample/literal_str.py b/src/test/data/pa3/sample/literal_str.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad35e5ae34d7df6d469bfe65dbfcefe988e0169f
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_str.py
@@ -0,0 +1 @@
+print("Hello World")
diff --git a/src/test/data/pa3/sample/literal_str.py.ast.typed b/src/test/data/pa3/sample/literal_str.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..9b924a569affa7955dab3837df70e6498c052b00
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_str.py.ast.typed
@@ -0,0 +1,47 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 21 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 20 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 20 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 1, 7, 1, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Hello World"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/literal_str.py.ast.typed.s.result b/src/test/data/pa3/sample/literal_str.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..557db03de997c86a4a028e1ebd3a1ceb225be238
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_str.py.ast.typed.s.result
@@ -0,0 +1 @@
+Hello World
diff --git a/src/test/data/pa3/sample/nested.py b/src/test/data/pa3/sample/nested.py
new file mode 100644
index 0000000000000000000000000000000000000000..3faa85b9085986a45f595fdd7853eba5cd5ffbab
--- /dev/null
+++ b/src/test/data/pa3/sample/nested.py
@@ -0,0 +1,11 @@
+g: int = 1
+def foo(x: int) -> int:
+    y: int = 2
+    def bar() -> int:
+        z: int = 3
+        def baz() -> int:
+            return y
+        return baz()
+    return bar()
+    
+print(foo(g))
diff --git a/src/test/data/pa3/sample/nested.py.ast.typed b/src/test/data/pa3/sample/nested.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..ecdc57d18ceb4bd6e692b6d64f91fbe7b5da0773
--- /dev/null
+++ b/src/test/data/pa3/sample/nested.py.ast.typed
@@ -0,0 +1,272 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 11, 14 ],
+  "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" : "g"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 4, 1, 6 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 10, 1, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 2, 1, 9, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 5, 2, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 2, 9, 2, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 12, 2, 14 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 2, 20, 2, 22 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 14 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 8, 3, 10 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 14, 3, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 8, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 18, 4, 20 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "VarDef",
+        "location" : [ 5, 9, 5, 18 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 5, 9, 5, 14 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 9, 5, 9 ],
+            "name" : "z"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 5, 12, 5, 14 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 18, 5, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        }
+      }, {
+        "kind" : "FuncDef",
+        "location" : [ 6, 9, 7, 21 ],
+        "name" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 13, 6, 15 ],
+          "name" : "baz"
+        },
+        "params" : [ ],
+        "returnType" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 22, 6, 24 ],
+          "className" : "int"
+        },
+        "declarations" : [ ],
+        "statements" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 7, 13, 7, 20 ],
+          "value" : {
+            "kind" : "Identifier",
+            "location" : [ 7, 20, 7, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "y"
+          }
+        } ]
+      } ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 8, 9, 8, 20 ],
+        "value" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 16, 8, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 16, 8, 18 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "baz"
+          },
+          "args" : [ ]
+        }
+      } ]
+    } ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 9, 5, 9, 16 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 9, 12, 9, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 12, 9, 14 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 11, 7, 11, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 7, 11, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "foo"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 11, 11, 11, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "g"
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/nested.py.ast.typed.s.result b/src/test/data/pa3/sample/nested.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..0cfbf08886fca9a91cb753ec8734c84fcbe52c9f
--- /dev/null
+++ b/src/test/data/pa3/sample/nested.py.ast.typed.s.result
@@ -0,0 +1 @@
+2
diff --git a/src/test/data/pa3/sample/nested2.py b/src/test/data/pa3/sample/nested2.py
new file mode 100644
index 0000000000000000000000000000000000000000..abafcce7e6eace2c925fd23d1342317347e480df
--- /dev/null
+++ b/src/test/data/pa3/sample/nested2.py
@@ -0,0 +1,14 @@
+g: int = 1
+def foo(x: int) -> int:
+    y: int = 2
+    def bar() -> int:
+        z: int = 3
+        def baz() -> int:
+            return qux(y)
+        return baz()
+    def qux(p: int) -> int:
+        return p
+
+    return bar()
+    
+print(foo(g))
diff --git a/src/test/data/pa3/sample/nested2.py.ast.typed b/src/test/data/pa3/sample/nested2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..8955e9f52b1dd4ce538878d0045f840c2487ca36
--- /dev/null
+++ b/src/test/data/pa3/sample/nested2.py.ast.typed
@@ -0,0 +1,337 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 14, 14 ],
+  "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" : "g"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 4, 1, 6 ],
+        "className" : "int"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 1, 10, 1, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 2, 1, 12, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 5, 2, 7 ],
+      "name" : "foo"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 2, 9, 2, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 9, 2, 9 ],
+        "name" : "x"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 12, 2, 14 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 2, 20, 2, 22 ],
+      "className" : "int"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 14 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 5 ],
+          "name" : "y"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 8, 3, 10 ],
+          "className" : "int"
+        }
+      },
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 3, 14, 3, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 8, 21 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 9, 4, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 18, 4, 20 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "VarDef",
+        "location" : [ 5, 9, 5, 18 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 5, 9, 5, 14 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 9, 5, 9 ],
+            "name" : "z"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 5, 12, 5, 14 ],
+            "className" : "int"
+          }
+        },
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 5, 18, 5, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 3
+        }
+      }, {
+        "kind" : "FuncDef",
+        "location" : [ 6, 9, 7, 26 ],
+        "name" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 13, 6, 15 ],
+          "name" : "baz"
+        },
+        "params" : [ ],
+        "returnType" : {
+          "kind" : "ClassType",
+          "location" : [ 6, 22, 6, 24 ],
+          "className" : "int"
+        },
+        "declarations" : [ ],
+        "statements" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 7, 13, 7, 25 ],
+          "value" : {
+            "kind" : "CallExpr",
+            "location" : [ 7, 20, 7, 25 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 7, 20, 7, 22 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "name" : "qux"
+            },
+            "args" : [ {
+              "kind" : "Identifier",
+              "location" : [ 7, 24, 7, 24 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "y"
+            } ]
+          }
+        } ]
+      } ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 8, 9, 8, 20 ],
+        "value" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 16, 8, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 16, 8, 18 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "baz"
+          },
+          "args" : [ ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 9, 5, 10, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 9, 9, 11 ],
+        "name" : "qux"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 9, 13, 9, 18 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 13, 9, 13 ],
+          "name" : "p"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 9, 16, 9, 18 ],
+          "className" : "int"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 9, 24, 9, 26 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 10, 9, 10, 16 ],
+        "value" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 16, 10, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "p"
+        }
+      } ]
+    } ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 12, 5, 12, 16 ],
+      "value" : {
+        "kind" : "CallExpr",
+        "location" : [ 12, 12, 12, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 12, 12, 14 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "bar"
+        },
+        "args" : [ ]
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 14, 7, 14, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "foo"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 14, 11, 14, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "g"
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/nested2.py.ast.typed.s.result b/src/test/data/pa3/sample/nested2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..0cfbf08886fca9a91cb753ec8734c84fcbe52c9f
--- /dev/null
+++ b/src/test/data/pa3/sample/nested2.py.ast.typed.s.result
@@ -0,0 +1 @@
+2
diff --git a/src/test/data/pa3/sample/object_attr_get.py b/src/test/data/pa3/sample/object_attr_get.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6bed6706525c885770b1efba18ecbb4143ca62d
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get.py
@@ -0,0 +1,16 @@
+class A(object):
+    a:int = 42
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+a:A = None
+b:B = None
+
+a = b = B()
+print(a.a)
+print(b.a)
+print(b.b)
diff --git a/src/test/data/pa3/sample/object_attr_get.py.ast.typed b/src/test/data/pa3/sample/object_attr_get.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..f87f054d9a93790c563a31c3a325877c2ec97e45
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get.py.ast.typed
@@ -0,0 +1,387 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 16, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 10, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 14, 5, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 18, 7, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 23, 7, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 27, 7, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 8, 15, 8, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 10, 1, 10, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 10, 1, 10, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 3, 10, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 7, 10, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 11 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 13, 1, 13, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 13, 5, 13, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 9, 13, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 9 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 14, 7, 14, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 9, 14, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 15, 7, 15, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 7, 15, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 9, 15, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 16, 7, 16, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 9, 16, 9 ],
+          "name" : "b"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s.result b/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..79171bc0cae5b4daf75a35a2e225a613becc65be
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s.result
@@ -0,0 +1,4 @@
+B
+42
+42
+True
diff --git a/src/test/data/pa3/sample/object_attr_get_none.py b/src/test/data/pa3/sample/object_attr_get_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..270bb1698bdc3ff2dca47034598103aa98b35d09
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get_none.py
@@ -0,0 +1,16 @@
+class A(object):
+    a:int = 42
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+a:A = None
+b:B = None
+
+a = B()
+print(a.a)
+print(b.a)
+print(b.b)
diff --git a/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..2787984c6444c28ea7b4ea2e31583cd84974b887
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed
@@ -0,0 +1,379 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 16, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 10, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 14, 5, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 18, 7, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 23, 7, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 27, 7, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 8, 15, 8, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 10, 1, 10, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 10, 1, 10, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 3, 10, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 7, 10, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 13, 1, 13, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 5, 13, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 5, 13, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 14, 7, 14, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 9, 14, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 15, 7, 15, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 7, 15, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 9, 15, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 16, 7, 16, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 9, 16, 9 ],
+          "name" : "b"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s.result b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..80d81d156b821dda451d84e05e768e8bc21606bb
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s.result
@@ -0,0 +1,4 @@
+B
+42
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/object_attr_set.py b/src/test/data/pa3/sample/object_attr_set.py
new file mode 100644
index 0000000000000000000000000000000000000000..41839992d1b1a400fa8537ddc7e1aa7bf6a6796d
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set.py
@@ -0,0 +1,18 @@
+class A(object):
+    a:int = 42
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+a:A = None
+b:B = None
+
+a = b = B()
+b.a = 1
+b.b = False
+print(a.a)
+print(b.a)
+print(b.b)
diff --git a/src/test/data/pa3/sample/object_attr_set.py.ast.typed b/src/test/data/pa3/sample/object_attr_set.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4ea6427fecb222827797f3c22c739bf8ccc555d1
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set.py.ast.typed
@@ -0,0 +1,455 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 10, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 14, 5, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 18, 7, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 23, 7, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 27, 7, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 8, 15, 8, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 10, 1, 10, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 10, 1, 10, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 3, 10, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 7, 10, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 11 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 13, 1, 13, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 13, 5, 13, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 9, 13, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 9 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 14, 1, 14, 7 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 14, 1, 14, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 3, 14, 3 ],
+        "name" : "a"
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 14, 7, 14, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 11 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 15, 1, 15, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 3, 15, 3 ],
+        "name" : "b"
+      }
+    } ],
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 15, 7, 15, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : false
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 16, 7, 16, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 9, 16, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 17, 1, 17, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 1, 17, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 17, 7, 17, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 7, 17, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 9, 17, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 18, 7, 18, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 7, 18, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 9, 18, 9 ],
+          "name" : "b"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s.result b/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..abf1b1734b716e78d712ea5dc1059d84e10e63b9
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s.result
@@ -0,0 +1,4 @@
+B
+1
+1
+False
diff --git a/src/test/data/pa3/sample/object_attr_set_eval_order.py b/src/test/data/pa3/sample/object_attr_set_eval_order.py
new file mode 100644
index 0000000000000000000000000000000000000000..162559d17bbd4c8b6fa3d65037d9eb17eb300bcb
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_eval_order.py
@@ -0,0 +1,33 @@
+class A(object):
+    a:int = 42
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+a:A = None
+b:B = None
+
+def get_b() -> B:
+    print("Getting B")
+    return b
+
+def get_one() -> int:
+    print("Getting 1")
+    return 1
+
+def get_false() -> bool:
+    print("Getting False")
+    return False
+
+a = b = B()
+get_b().a = get_one()
+print("Assigned B.a")
+get_b().b = get_false()
+print("Assigned B.b")
+
+print(a.a)
+print(b.a)
+print(b.b)
diff --git a/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..16ae2443fe754d5e6cf709e2ec3ed6ad158eb82d
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed
@@ -0,0 +1,771 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 33, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 10, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 14, 5, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 18, 7, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 23, 7, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 27, 7, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 8, 15, 8, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 10, 1, 10, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 10, 1, 10, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 3, 10, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 7, 10, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 13, 1, 15, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 13, 5, 13, 9 ],
+      "name" : "get_b"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 13, 16, 13, 16 ],
+      "className" : "B"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 14, 5, 14, 22 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 14, 5, 14, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 5, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 14, 11, 14, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "Getting B"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 15, 5, 15, 12 ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 12, 15, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 17, 1, 19, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 17, 5, 17, 11 ],
+      "name" : "get_one"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 17, 18, 17, 20 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 18, 5, 18, 22 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 18, 5, 18, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 5, 18, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 18, 11, 18, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "Getting 1"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 19, 5, 19, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 19, 12, 19, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 21, 1, 23, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 21, 5, 21, 13 ],
+      "name" : "get_false"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 21, 20, 21, 23 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 22, 5, 22, 26 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 22, 5, 22, 26 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 22, 5, 22, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 22, 11, 22, 25 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "Getting False"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 23, 5, 23, 16 ],
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 23, 12, 23, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 25, 1, 25, 11 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 25, 1, 25, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 25, 5, 25, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 25, 9, 25, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 25, 9, 25, 9 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 26, 1, 26, 21 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 26, 1, 26, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "CallExpr",
+        "location" : [ 26, 1, 26, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 26, 1, 26, 5 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            }
+          },
+          "name" : "get_b"
+        },
+        "args" : [ ]
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 26, 9, 26, 9 ],
+        "name" : "a"
+      }
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 26, 13, 26, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 26, 13, 26, 19 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "get_one"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 27, 1, 27, 21 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 27, 1, 27, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 27, 1, 27, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 27, 7, 27, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Assigned B.a"
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 28, 1, 28, 23 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 28, 1, 28, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "object" : {
+        "kind" : "CallExpr",
+        "location" : [ 28, 1, 28, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 28, 1, 28, 5 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            }
+          },
+          "name" : "get_b"
+        },
+        "args" : [ ]
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 28, 9, 28, 9 ],
+        "name" : "b"
+      }
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 28, 13, 28, 23 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 28, 13, 28, 21 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          }
+        },
+        "name" : "get_false"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 29, 1, 29, 21 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 29, 1, 29, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 29, 1, 29, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "StringLiteral",
+        "location" : [ 29, 7, 29, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "Assigned B.b"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 31, 1, 31, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 31, 1, 31, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 31, 1, 31, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 31, 7, 31, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 31, 7, 31, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 31, 9, 31, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 32, 1, 32, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 32, 1, 32, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 32, 1, 32, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 32, 7, 32, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 32, 7, 32, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 32, 9, 32, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 33, 1, 33, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 33, 1, 33, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 33, 1, 33, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 33, 7, 33, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 33, 7, 33, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 33, 9, 33, 9 ],
+          "name" : "b"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s.result b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..3f82dace32ea694e9d65dc5831cf1aea3180afb9
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s.result
@@ -0,0 +1,10 @@
+B
+Getting 1
+Getting B
+Assigned B.a
+Getting False
+Getting B
+Assigned B.b
+1
+1
+False
diff --git a/src/test/data/pa3/sample/object_attr_set_none.py b/src/test/data/pa3/sample/object_attr_set_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfd318482573adcb5671e80344076d7152a3bd57
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_none.py
@@ -0,0 +1,19 @@
+class A(object):
+    a:int = 42
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+a:A = None
+b:B = None
+
+a = B()
+print(a.a)
+
+b.a = 1
+b.b = False
+print(b.a)
+print(b.b)
diff --git a/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e6f56950a8274d73be161d7196cab76a5fb493cc
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed
@@ -0,0 +1,447 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 19, 11 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 10, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 14, 5, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 18, 7, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 23, 7, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 27, 7, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 8, 15, 8, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 10, 1, 10, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 10, 1, 10, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 1, 10, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 3, 10, 3 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 10, 7, 10, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 11, 1, 11, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 11, 1, 11, 3 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 11, 3, 11, 3 ],
+        "className" : "B"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 11, 7, 11, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 13, 1, 13, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 5, 13, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 5, 13, 5 ],
+        "name" : "B"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 14, 7, 14, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 9, 14, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 16, 1, 16, 7 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 16, 1, 16, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 3, 16, 3 ],
+        "name" : "a"
+      }
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 16, 7, 16, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 17, 1, 17, 11 ],
+    "targets" : [ {
+      "kind" : "MemberExpr",
+      "location" : [ 17, 1, 17, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "object" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 1 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "B"
+        },
+        "name" : "b"
+      },
+      "member" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 3, 17, 3 ],
+        "name" : "b"
+      }
+    } ],
+    "value" : {
+      "kind" : "BooleanLiteral",
+      "location" : [ 17, 7, 17, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "value" : false
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 18, 7, 18, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 7, 18, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 9, 18, 9 ],
+          "name" : "a"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 19, 1, 19, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 19, 1, 19, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MemberExpr",
+        "location" : [ 19, 7, 19, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "object" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 7, 19, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "B"
+          },
+          "name" : "b"
+        },
+        "member" : {
+          "kind" : "Identifier",
+          "location" : [ 19, 9, 19, 9 ],
+          "name" : "b"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s.result b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..80d81d156b821dda451d84e05e768e8bc21606bb
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s.result
@@ -0,0 +1,4 @@
+B
+42
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/object_init.py b/src/test/data/pa3/sample/object_init.py
new file mode 100644
index 0000000000000000000000000000000000000000..e48a5cd8a9c28fff34e1ca7c4f234a38b9a8258a
--- /dev/null
+++ b/src/test/data/pa3/sample/object_init.py
@@ -0,0 +1,11 @@
+class A(object):
+    a:int = 42
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+
+B()
diff --git a/src/test/data/pa3/sample/object_init.py.ast.typed b/src/test/data/pa3/sample/object_init.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..1ed066e0a0a5f12286a00942b179db512661627b
--- /dev/null
+++ b/src/test/data/pa3/sample/object_init.py.ast.typed
@@ -0,0 +1,173 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 11, 4 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 4, 1, 11, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 7, 4, 7 ],
+      "name" : "B"
+    },
+    "superClass" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 9, 4, 9 ],
+      "name" : "A"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 5, 5, 5, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 5, 5, 5, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 5, 7, 5, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 5, 14, 5, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 7, 5, 8, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 7, 18, 7, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 7, 23, 7, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 27, 7, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 8, 15, 8, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 3 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 3 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "B"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 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/pa3/sample/object_init.py.ast.typed.s.result b/src/test/data/pa3/sample/object_init.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..223b7836fb19fdf64ba2d3cd6173c6a283141f78
--- /dev/null
+++ b/src/test/data/pa3/sample/object_init.py.ast.typed.s.result
@@ -0,0 +1 @@
+B
diff --git a/src/test/data/pa3/sample/object_method.py b/src/test/data/pa3/sample/object_method.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b71299c9f110e57f98b9b98178e50334adb4fcb
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method.py
@@ -0,0 +1,16 @@
+class A(object):
+    a:int = 42
+
+    def foo(self:"A", ignore:object) -> int:
+        return self.a
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+    def bar(self:"B") -> int:
+        return self.foo(self.b)
+
+print(B().bar())
diff --git a/src/test/data/pa3/sample/object_method.py.ast.typed b/src/test/data/pa3/sample/object_method.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..955c83bb1aa2f0fbf2df96399686db2ef0a23375
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method.py.ast.typed
@@ -0,0 +1,387 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 16, 17 ],
+  "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "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"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 23, 4, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 23, 4, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 41, 4, 43 ],
+        "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" : "a"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 16, 0 ],
+    "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, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 14, 8, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 18, 10, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 18, 10, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 23, 10, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 27, 10, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 9, 11, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 9, 11, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 15, 11, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 14, 32 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 13, 13, 13, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 18, 13, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 26, 13, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 14, 9, 14, 31 ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 14, 16, 14, 31 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 14, 16, 14, 23 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "A"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 16, 14, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 21, 14, 23 ],
+              "name" : "foo"
+            }
+          },
+          "args" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 14, 25, 14, 30 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 25, 14, 28 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 30, 14, 30 ],
+              "name" : "b"
+            }
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 16 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 16, 7, 16, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 16, 7, 16, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 16, 7, 16, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 16, 7, 16, 7 ],
+              "name" : "B"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 16, 11, 16, 13 ],
+            "name" : "bar"
+          }
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_method.py.ast.typed.s.result b/src/test/data/pa3/sample/object_method.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..418c69bdef90108ecd796674adc6b90eae6dedb6
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+B
+42
diff --git a/src/test/data/pa3/sample/object_method_complex_call.py b/src/test/data/pa3/sample/object_method_complex_call.py
new file mode 100644
index 0000000000000000000000000000000000000000..d82ec1b682cdef5ec991a41f9894fa9be9d64888
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_complex_call.py
@@ -0,0 +1,19 @@
+class A(object):
+    a:int = 42
+
+    def foo(self:"A", ignore:object) -> int:
+        return self.a
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+    def bar(self:"B") -> int:
+        return self.foo(self.foo(print("...")))
+
+    def foo(self:"B", ignore:object) -> int:
+        return 1
+
+print(B().bar())
diff --git a/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..270f6342f74ed86c4a0736e629ccb3ad88ef3c0b
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed
@@ -0,0 +1,492 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 19, 17 ],
+  "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "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"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 23, 4, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 23, 4, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 41, 4, 43 ],
+        "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" : "a"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 19, 0 ],
+    "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, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 14, 8, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 18, 10, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 18, 10, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 23, 10, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 27, 10, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 9, 11, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 9, 11, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 15, 11, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 14, 48 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 13, 13, 13, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 18, 13, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 26, 13, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 14, 9, 14, 47 ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 14, 16, 14, 47 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 14, 16, 14, 23 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 16, 14, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 21, 14, 23 ],
+              "name" : "foo"
+            }
+          },
+          "args" : [ {
+            "kind" : "MethodCallExpr",
+            "location" : [ 14, 25, 14, 46 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 14, 25, 14, 32 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "B"
+                }, {
+                  "kind" : "ClassValueType",
+                  "className" : "object"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 14, 25, 14, 28 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "B"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 14, 30, 14, 32 ],
+                "name" : "foo"
+              }
+            },
+            "args" : [ {
+              "kind" : "CallExpr",
+              "location" : [ 14, 34, 14, 45 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              },
+              "function" : {
+                "kind" : "Identifier",
+                "location" : [ 14, 34, 14, 38 ],
+                "inferredType" : {
+                  "kind" : "FuncType",
+                  "parameters" : [ {
+                    "kind" : "ClassValueType",
+                    "className" : "object"
+                  } ],
+                  "returnType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "<None>"
+                  }
+                },
+                "name" : "print"
+              },
+              "args" : [ {
+                "kind" : "StringLiteral",
+                "location" : [ 14, 40, 14, 44 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "str"
+                },
+                "value" : "..."
+              } ]
+            } ]
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 16, 5, 17, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 9, 16, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 16, 13, 16, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 13, 16, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 16, 18, 16, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 16, 23, 16, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 23, 16, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 16, 30, 16, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 41, 16, 43 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 17, 9, 17, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 17, 16, 17, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 19, 1, 19, 16 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 19, 1, 19, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 19, 7, 19, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 19, 7, 19, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 19, 7, 19, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 19, 7, 19, 7 ],
+              "name" : "B"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 19, 11, 19, 13 ],
+            "name" : "bar"
+          }
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s.result b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..f83c3f1a9077b7e666c8e7c367c8fb7c8ba2bf77
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+B
+...
+1
diff --git a/src/test/data/pa3/sample/object_method_nested.py b/src/test/data/pa3/sample/object_method_nested.py
new file mode 100644
index 0000000000000000000000000000000000000000..b193ecd384f6077c9d0be4ebc9fadef631b139cf
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_nested.py
@@ -0,0 +1,18 @@
+class A(object):
+    a:int = 42
+
+    def foo(self:"A", ignore:object) -> int:
+        return self.a
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+    def bar(self:"B") -> int:
+        def qux(p: bool) -> int:
+            return self.foo(p)
+        return qux(True)
+
+print(B().bar())
diff --git a/src/test/data/pa3/sample/object_method_nested.py.ast.typed b/src/test/data/pa3/sample/object_method_nested.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..5480892d283de0e76ec094ed74fc1fec33ca6f59
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_nested.py.ast.typed
@@ -0,0 +1,439 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 18, 17 ],
+  "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "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"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 23, 4, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 23, 4, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 41, 4, 43 ],
+        "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" : "a"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 18, 0 ],
+    "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, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 14, 8, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 18, 10, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 18, 10, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 23, 10, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 27, 10, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 9, 11, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 9, 11, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 15, 11, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 16, 25 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 13, 13, 13, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 18, 13, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 26, 13, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "FuncDef",
+        "location" : [ 14, 9, 15, 31 ],
+        "name" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 13, 14, 15 ],
+          "name" : "qux"
+        },
+        "params" : [ {
+          "kind" : "TypedVar",
+          "location" : [ 14, 17, 14, 23 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 14, 17, 14, 17 ],
+            "name" : "p"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 14, 20, 14, 23 ],
+            "className" : "bool"
+          }
+        } ],
+        "returnType" : {
+          "kind" : "ClassType",
+          "location" : [ 14, 29, 14, 31 ],
+          "className" : "int"
+        },
+        "declarations" : [ ],
+        "statements" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 15, 13, 15, 30 ],
+          "value" : {
+            "kind" : "MethodCallExpr",
+            "location" : [ 15, 20, 15, 30 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "method" : {
+              "kind" : "MemberExpr",
+              "location" : [ 15, 20, 15, 27 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "A"
+                }, {
+                  "kind" : "ClassValueType",
+                  "className" : "object"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "int"
+                }
+              },
+              "object" : {
+                "kind" : "Identifier",
+                "location" : [ 15, 20, 15, 23 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "B"
+                },
+                "name" : "self"
+              },
+              "member" : {
+                "kind" : "Identifier",
+                "location" : [ 15, 25, 15, 27 ],
+                "name" : "foo"
+              }
+            },
+            "args" : [ {
+              "kind" : "Identifier",
+              "location" : [ 15, 29, 15, 29 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "name" : "p"
+            } ]
+          }
+        } ]
+      } ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 16, 9, 16, 24 ],
+        "value" : {
+          "kind" : "CallExpr",
+          "location" : [ 16, 16, 16, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 16, 16, 16, 18 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "name" : "qux"
+          },
+          "args" : [ {
+            "kind" : "BooleanLiteral",
+            "location" : [ 16, 20, 16, 23 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "value" : true
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 16 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 18, 7, 18, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 18, 7, 18, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 18, 7, 18, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 18, 7, 18, 7 ],
+              "name" : "B"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 18, 11, 18, 13 ],
+            "name" : "bar"
+          }
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s.result b/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..418c69bdef90108ecd796674adc6b90eae6dedb6
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+B
+42
diff --git a/src/test/data/pa3/sample/object_method_none.py b/src/test/data/pa3/sample/object_method_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd5066607a8f39ba190b9a4cde779185fb4c81ea
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_none.py
@@ -0,0 +1,17 @@
+class A(object):
+    a:int = 42
+
+    def foo(self:"A", ignore:object) -> int:
+        return self.a
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+    def bar(self:"B") -> int:
+        a:A = None
+        return a.foo(self.b)
+
+print(B().bar())
diff --git a/src/test/data/pa3/sample/object_method_none.py.ast.typed b/src/test/data/pa3/sample/object_method_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..db92330116d574abaa0e45c0f14a401dbe95679e
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_none.py.ast.typed
@@ -0,0 +1,412 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 17, 17 ],
+  "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "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"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 23, 4, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 23, 4, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 41, 4, 43 ],
+        "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" : "a"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 17, 0 ],
+    "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, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 14, 8, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 18, 10, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 18, 10, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 23, 10, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 27, 10, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 9, 11, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 9, 11, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 15, 11, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 15, 29 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 13, 13, 13, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 18, 13, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 26, 13, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ {
+        "kind" : "VarDef",
+        "location" : [ 14, 9, 14, 18 ],
+        "var" : {
+          "kind" : "TypedVar",
+          "location" : [ 14, 9, 14, 11 ],
+          "identifier" : {
+            "kind" : "Identifier",
+            "location" : [ 14, 9, 14, 9 ],
+            "name" : "a"
+          },
+          "type" : {
+            "kind" : "ClassType",
+            "location" : [ 14, 11, 14, 11 ],
+            "className" : "A"
+          }
+        },
+        "value" : {
+          "kind" : "NoneLiteral",
+          "location" : [ 14, 15, 14, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        }
+      } ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 15, 9, 15, 28 ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 15, 16, 15, 28 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 15, 16, 15, 20 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "A"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 15, 16, 15, 16 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "A"
+              },
+              "name" : "a"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 15, 18, 15, 20 ],
+              "name" : "foo"
+            }
+          },
+          "args" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 15, 22, 15, 27 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 15, 22, 15, 25 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 15, 27, 15, 27 ],
+              "name" : "b"
+            }
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 17, 1, 17, 16 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 1, 17, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 17, 7, 17, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 17, 7, 17, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 17, 7, 17, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 17, 7, 17, 7 ],
+              "name" : "B"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 17, 11, 17, 13 ],
+            "name" : "bar"
+          }
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_method_none.py.ast.typed.s.result b/src/test/data/pa3/sample/object_method_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..d9d147ec6f48ddb9bfd171843d29524b5e975424
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_none.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+B
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/object_method_override.py b/src/test/data/pa3/sample/object_method_override.py
new file mode 100644
index 0000000000000000000000000000000000000000..879b2ba72c3eec19c9861cd0cdfee5479520373a
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_override.py
@@ -0,0 +1,19 @@
+class A(object):
+    a:int = 42
+
+    def foo(self:"A", ignore:object) -> int:
+        return self.a
+
+class B(A):
+    b:bool = True
+
+    def __init__(self:"B"):
+        print("B")
+
+    def bar(self:"B") -> int:
+        return self.foo(self.b)
+
+    def foo(self:"B", ignore:object) -> int:
+        return 1
+
+print(B().bar())
diff --git a/src/test/data/pa3/sample/object_method_override.py.ast.typed b/src/test/data/pa3/sample/object_method_override.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..5684f7d29f29a85b18c2ea765ce1e6d05b539fc9
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_override.py.ast.typed
@@ -0,0 +1,441 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 19, 17 ],
+  "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 4, 5, 5, 22 ],
+      "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"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 4, 23, 4, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 23, 4, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 30, 4, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 41, 4, 43 ],
+        "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" : "a"
+          }
+        }
+      } ]
+    } ]
+  }, {
+    "kind" : "ClassDef",
+    "location" : [ 7, 1, 19, 0 ],
+    "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, 17 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 8, 5, 8, 10 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 5 ],
+          "name" : "b"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 8, 7, 8, 10 ],
+          "className" : "bool"
+        }
+      },
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 8, 14, 8, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 10, 5, 11, 19 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 16 ],
+        "name" : "__init__"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 10, 18, 10, 25 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 18, 10, 21 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 10, 23, 10, 25 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 27, 10, 27 ],
+        "className" : "<None>"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 9, 11, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 9, 11, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 15, 11, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "B"
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 13, 5, 14, 32 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 9, 13, 11 ],
+        "name" : "bar"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 13, 13, 13, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 13, 18, 13, 20 ],
+          "className" : "B"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 13, 26, 13, 28 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 14, 9, 14, 31 ],
+        "value" : {
+          "kind" : "MethodCallExpr",
+          "location" : [ 14, 16, 14, 31 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "method" : {
+            "kind" : "MemberExpr",
+            "location" : [ 14, 16, 14, 23 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 16, 14, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 21, 14, 23 ],
+              "name" : "foo"
+            }
+          },
+          "args" : [ {
+            "kind" : "MemberExpr",
+            "location" : [ 14, 25, 14, 30 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "object" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 25, 14, 28 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "B"
+              },
+              "name" : "self"
+            },
+            "member" : {
+              "kind" : "Identifier",
+              "location" : [ 14, 30, 14, 30 ],
+              "name" : "b"
+            }
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 16, 5, 17, 17 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 9, 16, 11 ],
+        "name" : "foo"
+      },
+      "params" : [ {
+        "kind" : "TypedVar",
+        "location" : [ 16, 13, 16, 20 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 13, 16, 16 ],
+          "name" : "self"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 16, 18, 16, 20 ],
+          "className" : "B"
+        }
+      }, {
+        "kind" : "TypedVar",
+        "location" : [ 16, 23, 16, 35 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 23, 16, 28 ],
+          "name" : "ignore"
+        },
+        "type" : {
+          "kind" : "ClassType",
+          "location" : [ 16, 30, 16, 35 ],
+          "className" : "object"
+        }
+      } ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 16, 41, 16, 43 ],
+        "className" : "int"
+      },
+      "declarations" : [ ],
+      "statements" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 17, 9, 17, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 17, 16, 17, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 19, 1, 19, 16 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 19, 1, 19, 16 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "MethodCallExpr",
+        "location" : [ 19, 7, 19, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "method" : {
+          "kind" : "MemberExpr",
+          "location" : [ 19, 7, 19, 13 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "object" : {
+            "kind" : "CallExpr",
+            "location" : [ 19, 7, 19, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "B"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 19, 7, 19, 7 ],
+              "name" : "B"
+            },
+            "args" : [ ]
+          },
+          "member" : {
+            "kind" : "Identifier",
+            "location" : [ 19, 11, 19, 13 ],
+            "name" : "bar"
+          }
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/object_method_override.py.ast.typed.s.result b/src/test/data/pa3/sample/object_method_override.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..9a6e55a6360c5a500c9379bf078108614d09257b
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_override.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+B
+1
diff --git a/src/test/data/pa3/sample/op_add.py b/src/test/data/pa3/sample/op_add.py
new file mode 100644
index 0000000000000000000000000000000000000000..95e89ae0131f936867608917fc76e1851f01e801
--- /dev/null
+++ b/src/test/data/pa3/sample/op_add.py
@@ -0,0 +1 @@
+print(1 + 100)
diff --git a/src/test/data/pa3/sample/op_add.py.ast.typed b/src/test/data/pa3/sample/op_add.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..a0a2d9b457f26764c7f724b14ec768a9b08ba250
--- /dev/null
+++ b/src/test/data/pa3/sample/op_add.py.ast.typed
@@ -0,0 +1,65 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 15 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 7, 1, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 11, 1, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 100
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/op_add.py.ast.typed.s.result b/src/test/data/pa3/sample/op_add.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..398050c62c882fa5ebc8d8aaa2e730e70790beeb
--- /dev/null
+++ b/src/test/data/pa3/sample/op_add.py.ast.typed.s.result
@@ -0,0 +1 @@
+101
diff --git a/src/test/data/pa3/sample/op_cmp_bool.py b/src/test/data/pa3/sample/op_cmp_bool.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f8d4b524b4674fb36a8a5da790b53b14249de6c
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_bool.py
@@ -0,0 +1,8 @@
+print(True == True)
+print(True == False)
+print(False == True)
+print(False == False)
+print(True != True)
+print(True != False)
+print(False != True)
+print(False != False)
diff --git a/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4c25364b8d1b83e591abca989022ab8bace4a425
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed
@@ -0,0 +1,443 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 22 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 19 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 1, 7, 1, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 1, 15, 1, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 20 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 20 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 2, 7, 2, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 2, 7, 2, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 2, 15, 2, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 20 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 3, 1, 3, 20 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 3, 7, 3, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 3, 7, 3, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 3, 16, 3, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 21 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 7, 4, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 4, 7, 4, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 4, 16, 4, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 19 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 5, 7, 5, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 5, 7, 5, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 5, 15, 5, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 20 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 20 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 6, 7, 6, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 6, 7, 6, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 6, 15, 6, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 20 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 20 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 7, 7, 7, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 7, 7, 7, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 7, 16, 7, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 21 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 8, 7, 8, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 8, 7, 8, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : false
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "BooleanLiteral",
+          "location" : [ 8, 16, 8, 20 ],
+          "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/pa3/sample/op_cmp_bool.py.ast.typed.s.result b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..12ea2d4bdf74a2b6ec75be94c824432334e3c35c
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s.result
@@ -0,0 +1,8 @@
+True
+False
+False
+True
+False
+True
+True
+False
diff --git a/src/test/data/pa3/sample/op_cmp_int.py b/src/test/data/pa3/sample/op_cmp_int.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd70a0950f899da386b6cc0e5ae131e9242f18b1
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_int.py
@@ -0,0 +1,16 @@
+x:int = 42
+y:int = 7
+
+print(x == y)
+print(x != y)
+print(x < y)
+print(x <= y)
+print(x > y)
+print(x >= y)
+
+print(x == x)
+print(x != x)
+print(x < x)
+print(x <= x)
+print(x > x)
+print(x >= x)
diff --git a/src/test/data/pa3/sample/op_cmp_int.py.ast.typed b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4b3633f3367bf3c1aff78572ca0193ba7280dc71
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed
@@ -0,0 +1,711 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 16, 14 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  }, {
+    "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" : 7
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 7, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 12, 4, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 5, 7, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 7, 5, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 12, 5, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 6, 7, 6, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 7, 6, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "<",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 11, 6, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 7, 1, 7, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 1, 7, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 7, 7, 7, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 7, 7, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "<=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 12, 7, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 8, 7, 8, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 7, 8, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 11, 8, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 9, 1, 9, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 1, 9, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 1, 9, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 9, 7, 9, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 7, 9, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : ">=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 12, 9, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 11, 7, 11, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 7, 11, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 12, 11, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 12, 7, 12, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 7, 12, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 12, 12, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 13, 7, 13, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 7, 13, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "<",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 11, 13, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 14, 7, 14, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "<=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 12, 14, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 15, 7, 15, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 7, 15, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : ">",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 11, 15, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 16, 7, 16, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : ">=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 12, 16, 12 ],
+          "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/pa3/sample/op_cmp_int.py.ast.typed.s.result b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..4386d2a3d8a9e8260add47981ecd90815dd9dcb0
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s.result
@@ -0,0 +1,12 @@
+False
+True
+False
+False
+True
+True
+True
+False
+False
+True
+False
+True
diff --git a/src/test/data/pa3/sample/op_div_mod.py b/src/test/data/pa3/sample/op_div_mod.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e41a788412c7a81c9655ceef75e353ac1e86a7d
--- /dev/null
+++ b/src/test/data/pa3/sample/op_div_mod.py
@@ -0,0 +1,5 @@
+x:int = 42
+y:int = 9
+
+print(x // y)
+print(x % y)
diff --git a/src/test/data/pa3/sample/op_div_mod.py.ast.typed b/src/test/data/pa3/sample/op_div_mod.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..eded4a3ba5d78c82a835ad4e9643ee58765147b3
--- /dev/null
+++ b/src/test/data/pa3/sample/op_div_mod.py.ast.typed
@@ -0,0 +1,171 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 13 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  }, {
+    "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" : 9
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 7, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "//",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 12, 4, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 5, 1, 5, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 5, 1, 5, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 5, 7, 5, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 7, 5, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "%",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 11, 5, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "y"
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s.result b/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..cfbeb15fac5256c14238255de929074ca952a96e
--- /dev/null
+++ b/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+4
+6
diff --git a/src/test/data/pa3/sample/op_is.py b/src/test/data/pa3/sample/op_is.py
new file mode 100644
index 0000000000000000000000000000000000000000..4207f29fb089abeae05b0b50240a093eff953b2a
--- /dev/null
+++ b/src/test/data/pa3/sample/op_is.py
@@ -0,0 +1,19 @@
+class A(object):
+    a:int = 42
+
+a1:A = None
+a2:A = None
+a3:A = None
+a4:A = None
+
+a1 = A()
+a2 = a1
+a3 = A()
+
+print(a1 is a1)
+print(a1 is a2)
+print(a1 is a3)
+print(a1 is a4)
+print(a1 is None)
+print(a4 is None)
+print(None is None)
diff --git a/src/test/data/pa3/sample/op_is.py.ast.typed b/src/test/data/pa3/sample/op_is.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..962be5e735cacb0d2437454674d87d7cde074b80
--- /dev/null
+++ b/src/test/data/pa3/sample/op_is.py.ast.typed
@@ -0,0 +1,598 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 19, 20 ],
+  "declarations" : [ {
+    "kind" : "ClassDef",
+    "location" : [ 1, 1, 2, 15 ],
+    "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, 14 ],
+      "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, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 42
+      }
+    } ]
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 11 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 4 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 2 ],
+        "name" : "a1"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 4, 4, 4 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 8, 4, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 11 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 4 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 2 ],
+        "name" : "a2"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 4, 5, 4 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 5, 8, 5, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 6, 1, 6, 11 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 6, 1, 6, 4 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 2 ],
+        "name" : "a3"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 4, 6, 4 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 6, 8, 6, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 7, 1, 7, 11 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 7, 1, 7, 4 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 1, 7, 2 ],
+        "name" : "a4"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 4, 7, 4 ],
+        "className" : "A"
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 7, 8, 7, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 2 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a1"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 6, 9, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 6, 9, 6 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 7 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 10, 1, 10, 2 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a2"
+    } ],
+    "value" : {
+      "kind" : "Identifier",
+      "location" : [ 10, 6, 10, 7 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a1"
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 8 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 11, 1, 11, 2 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "name" : "a3"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 6, 11, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "A"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 6, 11, 6 ],
+        "name" : "A"
+      },
+      "args" : [ ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 13, 7, 13, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 7, 13, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a1"
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a1"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 14, 7, 14, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a1"
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 13, 14, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a2"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 15, 7, 15, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 7, 15, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a1"
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 13, 15, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a3"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 16, 7, 16, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a1"
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 13, 16, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a4"
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 17, 1, 17, 17 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 1, 17, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 17, 7, 17, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 17, 7, 17, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a1"
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "NoneLiteral",
+          "location" : [ 17, 13, 17, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 17 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 18, 7, 18, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 18, 7, 18, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "A"
+          },
+          "name" : "a4"
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "NoneLiteral",
+          "location" : [ 18, 13, 18, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 19, 1, 19, 19 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 19, 1, 19, 19 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 19, 7, 19, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "NoneLiteral",
+          "location" : [ 19, 7, 19, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "NoneLiteral",
+          "location" : [ 19, 15, 19, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/op_is.py.ast.typed.s.result b/src/test/data/pa3/sample/op_is.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..0ac4f5b7a6d758b783f5342299f0e1a744807e41
--- /dev/null
+++ b/src/test/data/pa3/sample/op_is.py.ast.typed.s.result
@@ -0,0 +1,7 @@
+True
+True
+False
+False
+False
+True
+True
diff --git a/src/test/data/pa3/sample/op_logical.py b/src/test/data/pa3/sample/op_logical.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b55262a26463dce42d5b098140d699a14a04254
--- /dev/null
+++ b/src/test/data/pa3/sample/op_logical.py
@@ -0,0 +1,13 @@
+def f() -> bool:
+  print("f called")
+  return True
+
+def g() -> bool:
+  print("g called")
+  return False
+
+if f() or g():      # Short-circuit
+  if g() and f():   # Short-circuit
+    print("Never")
+  else:
+    print(not (f() and (g() or f())))
diff --git a/src/test/data/pa3/sample/op_logical.py.ast.typed b/src/test/data/pa3/sample/op_logical.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4aa1544c3b1982dda554cd0249850246b7d6b4ba
--- /dev/null
+++ b/src/test/data/pa3/sample/op_logical.py.ast.typed
@@ -0,0 +1,411 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 14, 2 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 3, 14 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 5 ],
+      "name" : "f"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 12, 1, 15 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 2, 3, 2, 19 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 3, 2, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 3, 2, 7 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 2, 9, 2, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "f called"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 3, 3, 3, 13 ],
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 3, 10, 3, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 7, 15 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "name" : "g"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 12, 5, 15 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 6, 3, 6, 19 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 6, 3, 6, 19 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 3, 6, 7 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 6, 9, 6, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "g called"
+        } ]
+      }
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 7, 3, 7, 14 ],
+      "value" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 7, 10, 7, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : false
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "IfStmt",
+    "location" : [ 9, 1, 14, 2 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 9, 4, 9, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "CallExpr",
+        "location" : [ 9, 4, 9, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 4, 9, 4 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "f"
+        },
+        "args" : [ ]
+      },
+      "operator" : "or",
+      "right" : {
+        "kind" : "CallExpr",
+        "location" : [ 9, 11, 9, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 11, 9, 11 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "g"
+        },
+        "args" : [ ]
+      }
+    },
+    "thenBody" : [ {
+      "kind" : "IfStmt",
+      "location" : [ 10, 3, 14, 1 ],
+      "condition" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 10, 6, 10, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "CallExpr",
+          "location" : [ 10, 6, 10, 8 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 10, 6, 10, 6 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              }
+            },
+            "name" : "g"
+          },
+          "args" : [ ]
+        },
+        "operator" : "and",
+        "right" : {
+          "kind" : "CallExpr",
+          "location" : [ 10, 14, 10, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 10, 14, 10, 14 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              }
+            },
+            "name" : "f"
+          },
+          "args" : [ ]
+        }
+      },
+      "thenBody" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 5, 11, 18 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 5, 11, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 5, 11, 9 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 11, 11, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "Never"
+          } ]
+        }
+      } ],
+      "elseBody" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 13, 5, 13, 37 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 13, 5, 13, 37 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 13, 5, 13, 9 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "UnaryExpr",
+            "location" : [ 13, 11, 13, 36 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            },
+            "operator" : "not",
+            "operand" : {
+              "kind" : "BinaryExpr",
+              "location" : [ 13, 16, 13, 35 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "bool"
+              },
+              "left" : {
+                "kind" : "CallExpr",
+                "location" : [ 13, 16, 13, 18 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "function" : {
+                  "kind" : "Identifier",
+                  "location" : [ 13, 16, 13, 16 ],
+                  "inferredType" : {
+                    "kind" : "FuncType",
+                    "parameters" : [ ],
+                    "returnType" : {
+                      "kind" : "ClassValueType",
+                      "className" : "bool"
+                    }
+                  },
+                  "name" : "f"
+                },
+                "args" : [ ]
+              },
+              "operator" : "and",
+              "right" : {
+                "kind" : "BinaryExpr",
+                "location" : [ 13, 25, 13, 34 ],
+                "inferredType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "bool"
+                },
+                "left" : {
+                  "kind" : "CallExpr",
+                  "location" : [ 13, 25, 13, 27 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bool"
+                  },
+                  "function" : {
+                    "kind" : "Identifier",
+                    "location" : [ 13, 25, 13, 25 ],
+                    "inferredType" : {
+                      "kind" : "FuncType",
+                      "parameters" : [ ],
+                      "returnType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "bool"
+                      }
+                    },
+                    "name" : "g"
+                  },
+                  "args" : [ ]
+                },
+                "operator" : "or",
+                "right" : {
+                  "kind" : "CallExpr",
+                  "location" : [ 13, 32, 13, 34 ],
+                  "inferredType" : {
+                    "kind" : "ClassValueType",
+                    "className" : "bool"
+                  },
+                  "function" : {
+                    "kind" : "Identifier",
+                    "location" : [ 13, 32, 13, 32 ],
+                    "inferredType" : {
+                      "kind" : "FuncType",
+                      "parameters" : [ ],
+                      "returnType" : {
+                        "kind" : "ClassValueType",
+                        "className" : "bool"
+                      }
+                    },
+                    "name" : "f"
+                  },
+                  "args" : [ ]
+                }
+              }
+            }
+          } ]
+        }
+      } ]
+    } ],
+    "elseBody" : [ ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/op_logical.py.ast.typed.s.result b/src/test/data/pa3/sample/op_logical.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..82c1ab26168a1ee67f83270e36376980a606f4fe
--- /dev/null
+++ b/src/test/data/pa3/sample/op_logical.py.ast.typed.s.result
@@ -0,0 +1,6 @@
+f called
+g called
+f called
+g called
+f called
+False
diff --git a/src/test/data/pa3/sample/op_mul.py b/src/test/data/pa3/sample/op_mul.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf6201d9de408d23c8d4dd9c38a46dd586f77634
--- /dev/null
+++ b/src/test/data/pa3/sample/op_mul.py
@@ -0,0 +1 @@
+print(6*9*2)
diff --git a/src/test/data/pa3/sample/op_mul.py.ast.typed b/src/test/data/pa3/sample/op_mul.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..6ed26ccfb588558e52ed1b40e3ffc222cf92f887
--- /dev/null
+++ b/src/test/data/pa3/sample/op_mul.py.ast.typed
@@ -0,0 +1,83 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 13 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 1, 7, 1, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "left" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 7, 1, 7 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 6
+          },
+          "operator" : "*",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 1, 9, 1, 9 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 9
+          }
+        },
+        "operator" : "*",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 11, 1, 11 ],
+          "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/pa3/sample/op_mul.py.ast.typed.s.result b/src/test/data/pa3/sample/op_mul.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..3b20426c05051ed8bd8c8cc632573c194e57809c
--- /dev/null
+++ b/src/test/data/pa3/sample/op_mul.py.ast.typed.s.result
@@ -0,0 +1 @@
+108
diff --git a/src/test/data/pa3/sample/op_negate.py b/src/test/data/pa3/sample/op_negate.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f3b2bed33ddac3e5c9db599593949f293bc3089
--- /dev/null
+++ b/src/test/data/pa3/sample/op_negate.py
@@ -0,0 +1,2 @@
+x:int = 42
+print(-x)
diff --git a/src/test/data/pa3/sample/op_negate.py.ast.typed b/src/test/data/pa3/sample/op_negate.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4268b3b58108fe5a92fc70ad1ca74e16f6e22d06
--- /dev/null
+++ b/src/test/data/pa3/sample/op_negate.py.ast.typed
@@ -0,0 +1,82 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 2, 10 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 9 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 9 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "UnaryExpr",
+        "location" : [ 2, 7, 2, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "operator" : "-",
+        "operand" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 8, 2, 8 ],
+          "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/pa3/sample/op_negate.py.ast.typed.s.result b/src/test/data/pa3/sample/op_negate.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..6a0e60d48b173a5049079e37e284315a97918b76
--- /dev/null
+++ b/src/test/data/pa3/sample/op_negate.py.ast.typed.s.result
@@ -0,0 +1 @@
+-42
diff --git a/src/test/data/pa3/sample/op_sub.py b/src/test/data/pa3/sample/op_sub.py
new file mode 100644
index 0000000000000000000000000000000000000000..48aa45be84a04d885c21b935beb01883de6028d1
--- /dev/null
+++ b/src/test/data/pa3/sample/op_sub.py
@@ -0,0 +1 @@
+print(1 - 100)
diff --git a/src/test/data/pa3/sample/op_sub.py.ast.typed b/src/test/data/pa3/sample/op_sub.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..2c927e805a989cd5b8ffd060ccb7d593fdc5c5e2
--- /dev/null
+++ b/src/test/data/pa3/sample/op_sub.py.ast.typed
@@ -0,0 +1,65 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 15 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 7, 1, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        },
+        "operator" : "-",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 1, 11, 1, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 100
+        }
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/op_sub.py.ast.typed.s.result b/src/test/data/pa3/sample/op_sub.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..d3a0ef5a4aee82dc28a0402adeb191e53e57dfce
--- /dev/null
+++ b/src/test/data/pa3/sample/op_sub.py.ast.typed.s.result
@@ -0,0 +1 @@
+-99
diff --git a/src/test/data/pa3/sample/pass.py b/src/test/data/pa3/sample/pass.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ae28399f5fda2dfb1b04405f4a3b4895f5fac1e
--- /dev/null
+++ b/src/test/data/pa3/sample/pass.py
@@ -0,0 +1 @@
+pass
diff --git a/src/test/data/pa3/sample/pass.py.ast.typed b/src/test/data/pa3/sample/pass.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..ceb0bbd7d4ee28516d8ff200c4760c8abaefbc33
--- /dev/null
+++ b/src/test/data/pa3/sample/pass.py.ast.typed
@@ -0,0 +1,11 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 5 ],
+  "declarations" : [ ],
+  "statements" : [ ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/pass.py.ast.typed.s.result b/src/test/data/pa3/sample/pass.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/data/pa3/sample/predef_constructors.py b/src/test/data/pa3/sample/predef_constructors.py
new file mode 100644
index 0000000000000000000000000000000000000000..0086564a7da0f2d8d36a0b6225d806164bb11002
--- /dev/null
+++ b/src/test/data/pa3/sample/predef_constructors.py
@@ -0,0 +1,4 @@
+print(object() is None)
+print(int())
+print(str())
+print(bool())
diff --git a/src/test/data/pa3/sample/predef_constructors.py.ast.typed b/src/test/data/pa3/sample/predef_constructors.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..3644f24f8693de5fb51164cd27fd9ecf48cdc2e4
--- /dev/null
+++ b/src/test/data/pa3/sample/predef_constructors.py.ast.typed
@@ -0,0 +1,192 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 14 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 23 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 23 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "BinaryExpr",
+        "location" : [ 1, 7, 1, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "CallExpr",
+          "location" : [ 1, 7, 1, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 1, 7, 1, 12 ],
+            "name" : "object"
+          },
+          "args" : [ ]
+        },
+        "operator" : "is",
+        "right" : {
+          "kind" : "NoneLiteral",
+          "location" : [ 1, 19, 1, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 2, 1, 2, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 2, 1, 2, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 2, 7, 2, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 7, 2, 9 ],
+          "name" : "int"
+        },
+        "args" : [ ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 3, 1, 3, 12 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 3, 1, 3, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 3, 7, 3, 11 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 7, 3, 9 ],
+          "name" : "str"
+        },
+        "args" : [ ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 4, 7, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 7, 4, 10 ],
+          "name" : "bool"
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s.result b/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..8add9b0e380ac952f710358a5e7743581b795fd0
--- /dev/null
+++ b/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s.result
@@ -0,0 +1,4 @@
+False
+0
+
+False
diff --git a/src/test/data/pa3/sample/stmt_for_list.py b/src/test/data/pa3/sample/stmt_for_list.py
new file mode 100644
index 0000000000000000000000000000000000000000..78c5c00d47bf506c79fa094dd6e28fe38cb9e2da
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list.py
@@ -0,0 +1,7 @@
+x:int = 0
+z:[int] = None
+
+z = [1, 2, 3]
+
+for x in z:
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_list.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..53d683409f223d159f959f3008c1062f5341f5d6
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed
@@ -0,0 +1,178 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 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
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 11, 2, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "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" : "z"
+    } ],
+    "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" : "ForStmt",
+    "location" : [ 6, 1, 8, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 5, 6, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 10, 6, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 7, 5, 7, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 7, 5, 7, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 7, 11, 7, 11 ],
+          "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/pa3/sample/stmt_for_list.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+1
+2
+3
diff --git a/src/test/data/pa3/sample/stmt_for_list_empty.py b/src/test/data/pa3/sample/stmt_for_list_empty.py
new file mode 100644
index 0000000000000000000000000000000000000000..23fba4aad8e3ca5db3768cee3aa96921676f4ec6
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_empty.py
@@ -0,0 +1,12 @@
+x:int = 0
+y:int = 0
+z:[int] = None
+e:[int] = None
+
+z = [1,2,3]
+e = []
+
+for x in z:
+    for y in e:
+        print("Never")
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..ca4160cf0fdcbbaac88364b86b792a8b7d58614b
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed
@@ -0,0 +1,318 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 13, 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
+    }
+  }, {
+    "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, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 11, 3, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "e"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 4, 3, 4, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 4, 4, 4, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 4, 11, 4, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 6, 1, 6, 11 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 6, 1, 6, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 6, 5, 6, 11 ],
+      "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, 8, 6, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 6, 10, 6, 10 ],
+        "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" : "e"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 7, 5, 7, 6 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<Empty>"
+      },
+      "elements" : [ ]
+    }
+  }, {
+    "kind" : "ForStmt",
+    "location" : [ 9, 1, 13, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 9, 5, 9, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 9, 10, 9, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ForStmt",
+      "location" : [ 10, 5, 12, 4 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 9, 10, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "y"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 14, 10, 14 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "e"
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 11, 9, 11, 22 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 11, 9, 11, 22 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 9, 11, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 11, 15, 11, 21 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : "Never"
+          } ]
+        }
+      } ]
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 12, 5, 12, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 12, 5, 12, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 5, 12, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 12, 11, 12, 11 ],
+          "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/pa3/sample/stmt_for_list_empty.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+1
+2
+3
diff --git a/src/test/data/pa3/sample/stmt_for_list_eval.py b/src/test/data/pa3/sample/stmt_for_list_eval.py
new file mode 100644
index 0000000000000000000000000000000000000000..a77b1718093670329a9e20ed571273eb75cbd63f
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_eval.py
@@ -0,0 +1,8 @@
+x:int = 0
+z:[int] = None
+
+z = [1, 2, 3]
+
+for x in z:
+    z = []
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..c86d71817762e34114ba80f727af57bd2cc30408
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed
@@ -0,0 +1,202 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 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
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 11, 2, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "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" : "z"
+    } ],
+    "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" : "ForStmt",
+    "location" : [ 6, 1, 9, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 5, 6, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 10, 6, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 7, 5, 7, 10 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 5 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "z"
+      } ],
+      "value" : {
+        "kind" : "ListExpr",
+        "location" : [ 7, 9, 7, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<Empty>"
+        },
+        "elements" : [ ]
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 8, 5, 8, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 8, 5, 8, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 8, 11, 8, 11 ],
+          "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/pa3/sample/stmt_for_list_eval.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+1
+2
+3
diff --git a/src/test/data/pa3/sample/stmt_for_list_modify.py b/src/test/data/pa3/sample/stmt_for_list_modify.py
new file mode 100644
index 0000000000000000000000000000000000000000..3006cd200a9696b0ef8f1b9d8a0f73667480dc78
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_modify.py
@@ -0,0 +1,8 @@
+x:int = 0
+z:[int] = None
+
+z = [1, 2, 1]
+
+for x in z:
+    z[x] = x
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..fa19b607be9fcbd83179fe62941bdc58dc68847e
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed
@@ -0,0 +1,219 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 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
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 11, 2, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "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" : "z"
+    } ],
+    "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" : 1
+      } ]
+    }
+  }, {
+    "kind" : "ForStmt",
+    "location" : [ 6, 1, 9, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 5, 6, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 10, 6, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 7, 5, 7, 12 ],
+      "targets" : [ {
+        "kind" : "IndexExpr",
+        "location" : [ 7, 5, 7, 8 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 5, 7, 5 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "z"
+        },
+        "index" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 7, 7, 7 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        }
+      } ],
+      "value" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 12, 7, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 8, 5, 8, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 8, 5, 8, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 5, 8, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 8, 11, 8, 11 ],
+          "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/pa3/sample/stmt_for_list_modify.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..e8183f05f5db68b3934e93f4bf6bed2bb664e0b5
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+1
+1
+1
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested.py b/src/test/data/pa3/sample/stmt_for_list_nested.py
new file mode 100644
index 0000000000000000000000000000000000000000..b69f3f00588fbc965bb7413cb4567fa6f131f2f5
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested.py
@@ -0,0 +1,9 @@
+x:int = 0
+y:int = 0
+z:[int] = None
+
+z = [1, 2, 3]
+
+for x in z:
+    for y in z:
+        print(x * y)
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..0521e4ad6bd20265cdcd17eb2248b6da9cd6e5f0
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed
@@ -0,0 +1,247 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 2 ],
+  "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, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 11, 3, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 5, 5, 5, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 6, 5, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 9, 5, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ForStmt",
+    "location" : [ 7, 1, 10, 2 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 10, 7, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ForStmt",
+      "location" : [ 8, 5, 10, 1 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "y"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 14, 8, 14 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "z"
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 9, 9, 9, 20 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 9, 9, 9, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 9, 9, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "BinaryExpr",
+            "location" : [ 9, 15, 9, 19 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "left" : {
+              "kind" : "Identifier",
+              "location" : [ 9, 15, 9, 15 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "x"
+            },
+            "operator" : "*",
+            "right" : {
+              "kind" : "Identifier",
+              "location" : [ 9, 19, 9, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              },
+              "name" : "y"
+            }
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..0d1fb9e54a9d0d99ab7953f1053440f6151c40cc
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s.result
@@ -0,0 +1,9 @@
+1
+2
+3
+2
+4
+6
+3
+6
+9
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py
new file mode 100644
index 0000000000000000000000000000000000000000..00571644e66bc65ab8c113786ef67bcfe9386b42
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py
@@ -0,0 +1,9 @@
+x:int = 0
+y:int = 0
+z:[int] = None
+
+z = [1, 2, 3]
+
+for x in z:
+    for x in z:
+        print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..2feac514b89a7475b531d9be534c87f89f486295
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed
@@ -0,0 +1,229 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 10, 2 ],
+  "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, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 3, 3, 3, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 3, 4, 3, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 3, 11, 3, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 5, 1, 5, 13 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 5, 1, 5, 1 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    } ],
+    "value" : {
+      "kind" : "ListExpr",
+      "location" : [ 5, 5, 5, 13 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "elements" : [ {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 6, 5, 6 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 9, 5, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 5, 12, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ForStmt",
+    "location" : [ 7, 1, 10, 2 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 10, 7, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ForStmt",
+      "location" : [ 8, 5, 10, 1 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 14, 8, 14 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "z"
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 9, 9, 9, 16 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 9, 9, 9, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 9, 9, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 9, 15, 9, 15 ],
+            "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/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..a8401b1cae8f6eb0ce8b17f9b3c7e14cb363b0a6
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s.result
@@ -0,0 +1,9 @@
+1
+2
+3
+1
+2
+3
+1
+2
+3
diff --git a/src/test/data/pa3/sample/stmt_for_list_none.py b/src/test/data/pa3/sample/stmt_for_list_none.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd511fa341cbebd38f7336fb1db568f8908ca4f4
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_none.py
@@ -0,0 +1,5 @@
+x:int = 0
+z:[int] = None
+
+for x in z:
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..00acc087319388451e4f7d18d792e221e05b5202
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed
@@ -0,0 +1,127 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 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
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 14 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 7 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 3, 2, 7 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 2, 4, 2, 6 ],
+          "className" : "int"
+        }
+      }
+    },
+    "value" : {
+      "kind" : "NoneLiteral",
+      "location" : [ 2, 11, 2, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      }
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 4, 1, 6, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 10, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ListValueType",
+        "elementType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        }
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 5, 5, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 5, 11, 5, 11 ],
+          "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/pa3/sample/stmt_for_list_none.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..ae52477deb467a7ad909a282522c592e696c63b9
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Operation on None
+Exited with error code 4
diff --git a/src/test/data/pa3/sample/stmt_for_list_nonlocal.py b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9b54a2c7fb1f4f422b51b8b24d54facaf3067f7
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py
@@ -0,0 +1,15 @@
+x:int = 0
+def crunch(zz:[[int]]) -> object:
+    z:[int] = None
+    global x
+    def make_z() -> object:
+        nonlocal z
+        for z in zz:
+            pass # Set z to last element in zz
+
+    make_z()
+    for x in z:
+        pass # Set x to last element in z
+
+crunch([[1,2],[2,3],[4,5],[6,7]])
+print(x) 
diff --git a/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..2c686f8a39a24235629a540b16faf98ae1490531
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed
@@ -0,0 +1,408 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 15, 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" : "FuncDef",
+    "location" : [ 2, 1, 14, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 2, 5, 2, 10 ],
+      "name" : "crunch"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 2, 12, 2, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 12, 2, 13 ],
+        "name" : "zz"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 2, 15, 2, 21 ],
+        "elementType" : {
+          "kind" : "ListType",
+          "location" : [ 2, 16, 2, 20 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 2, 17, 2, 19 ],
+            "className" : "int"
+          }
+        }
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 2, 27, 2, 32 ],
+      "className" : "object"
+    },
+    "declarations" : [ {
+      "kind" : "VarDef",
+      "location" : [ 3, 5, 3, 18 ],
+      "var" : {
+        "kind" : "TypedVar",
+        "location" : [ 3, 5, 3, 11 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 5 ],
+          "name" : "z"
+        },
+        "type" : {
+          "kind" : "ListType",
+          "location" : [ 3, 7, 3, 11 ],
+          "elementType" : {
+            "kind" : "ClassType",
+            "location" : [ 3, 8, 3, 10 ],
+            "className" : "int"
+          }
+        }
+      },
+      "value" : {
+        "kind" : "NoneLiteral",
+        "location" : [ 3, 15, 3, 18 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        }
+      }
+    }, {
+      "kind" : "GlobalDecl",
+      "location" : [ 4, 5, 4, 12 ],
+      "variable" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 12, 4, 12 ],
+        "name" : "x"
+      }
+    }, {
+      "kind" : "FuncDef",
+      "location" : [ 5, 5, 10, 4 ],
+      "name" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 9, 5, 14 ],
+        "name" : "make_z"
+      },
+      "params" : [ ],
+      "returnType" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 21, 5, 26 ],
+        "className" : "object"
+      },
+      "declarations" : [ {
+        "kind" : "NonLocalDecl",
+        "location" : [ 6, 9, 6, 18 ],
+        "variable" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 18, 6, 18 ],
+          "name" : "z"
+        }
+      } ],
+      "statements" : [ {
+        "kind" : "ForStmt",
+        "location" : [ 7, 9, 10, 4 ],
+        "identifier" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 13, 7, 13 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "z"
+        },
+        "iterable" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 18, 7, 19 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            }
+          },
+          "name" : "zz"
+        },
+        "body" : [ ]
+      } ]
+    } ],
+    "statements" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 10, 5, 10, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 10, 5, 10, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "object"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 10, 5, 10, 10 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            }
+          },
+          "name" : "make_z"
+        },
+        "args" : [ ]
+      }
+    }, {
+      "kind" : "ForStmt",
+      "location" : [ 11, 5, 14, 0 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 9, 11, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 14, 11, 14 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "z"
+      },
+      "body" : [ ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 33 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 33 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 6 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ListValueType",
+              "elementType" : {
+                "kind" : "ClassValueType",
+                "className" : "int"
+              }
+            }
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "name" : "crunch"
+      },
+      "args" : [ {
+        "kind" : "ListExpr",
+        "location" : [ 14, 8, 14, 32 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          }
+        },
+        "elements" : [ {
+          "kind" : "ListExpr",
+          "location" : [ 14, 9, 14, 13 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 10, 14, 10 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 1
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 12, 14, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 2
+          } ]
+        }, {
+          "kind" : "ListExpr",
+          "location" : [ 14, 15, 14, 19 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 16, 14, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 2
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 18, 14, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 3
+          } ]
+        }, {
+          "kind" : "ListExpr",
+          "location" : [ 14, 21, 14, 25 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 22, 14, 22 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 4
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 24, 14, 24 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 5
+          } ]
+        }, {
+          "kind" : "ListExpr",
+          "location" : [ 14, 27, 14, 31 ],
+          "inferredType" : {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "elements" : [ {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 28, 14, 28 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 6
+          }, {
+            "kind" : "IntegerLiteral",
+            "location" : [ 14, 30, 14, 30 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 7
+          } ]
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 15, 7, 15, 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/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..7f8f011eb73d6043d2e6db9d2c101195ae2801f2
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s.result
@@ -0,0 +1 @@
+7
diff --git a/src/test/data/pa3/sample/stmt_for_list_return.py b/src/test/data/pa3/sample/stmt_for_list_return.py
new file mode 100644
index 0000000000000000000000000000000000000000..35716dd6e9a5dab7fd1eb164f1ff5dbc61adf438
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_return.py
@@ -0,0 +1,8 @@
+def print_list(z:[int]) -> object:
+    x:int = 0
+    for x in z:
+        print(x)
+        if x >= 30:
+            return
+
+print_list([10,20,30,40])
diff --git a/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4fca85f0983336a6ddcd8fc996e0ba9fc9a33fba
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed
@@ -0,0 +1,241 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 26 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 8, 0 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 14 ],
+      "name" : "print_list"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 1, 16, 1, 22 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 16, 1, 16 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ListType",
+        "location" : [ 1, 18, 1, 22 ],
+        "elementType" : {
+          "kind" : "ClassType",
+          "location" : [ 1, 19, 1, 21 ],
+          "className" : "int"
+        }
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 28, 1, 33 ],
+      "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" : "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" : 0
+      }
+    } ],
+    "statements" : [ {
+      "kind" : "ForStmt",
+      "location" : [ 3, 5, 8, 0 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 9, 3, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 14, 3, 14 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "name" : "z"
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 4, 9, 4, 16 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 4, 9, 4, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 4, 9, 4, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 4, 15, 4, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "x"
+          } ]
+        }
+      }, {
+        "kind" : "IfStmt",
+        "location" : [ 5, 9, 8, 0 ],
+        "condition" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 5, 12, 5, 18 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 5, 12, 5, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "name" : "x"
+          },
+          "operator" : ">=",
+          "right" : {
+            "kind" : "IntegerLiteral",
+            "location" : [ 5, 17, 5, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            },
+            "value" : 30
+          }
+        },
+        "thenBody" : [ {
+          "kind" : "ReturnStmt",
+          "location" : [ 6, 13, 6, 18 ],
+          "value" : null
+        } ],
+        "elseBody" : [ ]
+      } ]
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 25 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 25 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 10 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ListValueType",
+            "elementType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          }
+        },
+        "name" : "print_list"
+      },
+      "args" : [ {
+        "kind" : "ListExpr",
+        "location" : [ 8, 12, 8, 24 ],
+        "inferredType" : {
+          "kind" : "ListValueType",
+          "elementType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          }
+        },
+        "elements" : [ {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 13, 8, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 10
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 16, 8, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 20
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 19, 8, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 30
+        }, {
+          "kind" : "IntegerLiteral",
+          "location" : [ 8, 22, 8, 23 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 40
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..300ed6fcd17373e06dd6ecdf001f55e0e9cd765f
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+10
+20
+30
diff --git a/src/test/data/pa3/sample/stmt_for_str.py b/src/test/data/pa3/sample/stmt_for_str.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3ab74fc66ae5c36f9548a4eed9f58721ce2e495
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str.py
@@ -0,0 +1,5 @@
+x:str = ""
+z:str = "abc"
+
+for x in z:
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_str.py.ast.typed b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4b0e5837fbbbc70a30d4c3ea071ca5c681cb6d4e
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed
@@ -0,0 +1,121 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 4, 1, 6, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 10, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 5, 5, 5, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 5, 5, 5, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 5, 5, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 5, 11, 5, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "x"
+        } ]
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..de980441c3ab03a8c07dda1ad27b8a11f39deb1e
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+a
+b
+c
diff --git a/src/test/data/pa3/sample/stmt_for_str_empty.py b/src/test/data/pa3/sample/stmt_for_str_empty.py
new file mode 100644
index 0000000000000000000000000000000000000000..9dc60e71c6e038cb334128235735e8bb46049e51
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_empty.py
@@ -0,0 +1,8 @@
+x:str = ""
+y:str = "123"
+z:str = "abc"
+
+for x in z:
+    print(x)
+    for x in "":
+        print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..9be591fc8f8489b190d9d1467716c90f25fbfcf8
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed
@@ -0,0 +1,205 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 2 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "123"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 5, 1, 9, 2 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 10, 5, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 6, 5, 6, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 6, 5, 6, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 6, 11, 6, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "x"
+        } ]
+      }
+    }, {
+      "kind" : "ForStmt",
+      "location" : [ 7, 5, 9, 1 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "iterable" : {
+        "kind" : "StringLiteral",
+        "location" : [ 7, 14, 7, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : ""
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 16 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 8, 15, 8, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "x"
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..de980441c3ab03a8c07dda1ad27b8a11f39deb1e
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+a
+b
+c
diff --git a/src/test/data/pa3/sample/stmt_for_str_eval.py b/src/test/data/pa3/sample/stmt_for_str_eval.py
new file mode 100644
index 0000000000000000000000000000000000000000..69c2ea954d262b874accb6d303474fa0a49b2298
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_eval.py
@@ -0,0 +1,6 @@
+x:str = ""
+z:str = "abc"
+
+for x in z:
+    z = "doesn't matter"
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..1e64270779b941915773f94836419bd7d71f7212
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed
@@ -0,0 +1,142 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 7, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 13 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "z"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 4, 1, 7, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 10, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "AssignStmt",
+      "location" : [ 5, 5, 5, 24 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 5, 5, 5, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "z"
+      } ],
+      "value" : {
+        "kind" : "StringLiteral",
+        "location" : [ 5, 9, 5, 24 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "value" : "doesn't matter"
+      }
+    }, {
+      "kind" : "ExprStmt",
+      "location" : [ 6, 5, 6, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 6, 5, 6, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 6, 11, 6, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "x"
+        } ]
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..de980441c3ab03a8c07dda1ad27b8a11f39deb1e
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+a
+b
+c
diff --git a/src/test/data/pa3/sample/stmt_for_str_nested.py b/src/test/data/pa3/sample/stmt_for_str_nested.py
new file mode 100644
index 0000000000000000000000000000000000000000..81f0f46011739ad678d6f8a97206966bb2e10150
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_nested.py
@@ -0,0 +1,8 @@
+x:str = ""
+y:str = "123"
+z:str = "abc"
+
+for x in z:
+    print(x)
+    for x in y:
+        print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..5260c3b5a1491d629899cfad7af9e2e487a8c102
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed
@@ -0,0 +1,205 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 9, 2 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "123"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 5, 1, 9, 2 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 10, 5, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "z"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 6, 5, 6, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 6, 5, 6, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 5, 6, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 6, 11, 6, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "x"
+        } ]
+      }
+    }, {
+      "kind" : "ForStmt",
+      "location" : [ 7, 5, 9, 1 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 9, 7, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      },
+      "iterable" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 14, 7, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "y"
+      },
+      "body" : [ {
+        "kind" : "ExprStmt",
+        "location" : [ 8, 9, 8, 16 ],
+        "expr" : {
+          "kind" : "CallExpr",
+          "location" : [ 8, 9, 8, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 8, 9, 8, 13 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "object"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "<None>"
+              }
+            },
+            "name" : "print"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 8, 15, 8, 15 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "x"
+          } ]
+        }
+      } ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..c2cb64d90b8a907ec51d1efaf0a9119e115f3edf
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s.result
@@ -0,0 +1,12 @@
+a
+1
+2
+3
+b
+1
+2
+3
+c
+1
+2
+3
diff --git a/src/test/data/pa3/sample/stmt_for_str_same_var.py b/src/test/data/pa3/sample/stmt_for_str_same_var.py
new file mode 100644
index 0000000000000000000000000000000000000000..438c74e613fa5dc108133923e1be4f8a6cf6aa31
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_same_var.py
@@ -0,0 +1,4 @@
+x:str = "xXx"
+
+for x in x:
+    print(x)
diff --git a/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e3870ecaa3c60ac1076798eb755afcd73820273a
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed
@@ -0,0 +1,95 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 5, 1 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "xXx"
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "ForStmt",
+    "location" : [ 3, 1, 5, 1 ],
+    "identifier" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "x"
+    },
+    "iterable" : {
+      "kind" : "Identifier",
+      "location" : [ 3, 10, 3, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "x"
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 4, 5, 4, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 4, 5, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 5, 4, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 4, 11, 4, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "x"
+        } ]
+      }
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..723425ffbbf55ff784aa34f91eb016fc39fb59fe
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+x
+X
+x
diff --git a/src/test/data/pa3/sample/stmt_if.py b/src/test/data/pa3/sample/stmt_if.py
new file mode 100644
index 0000000000000000000000000000000000000000..61bc6054b9e9095b4fb177934a1e5e6fb3286dae
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_if.py
@@ -0,0 +1,7 @@
+if False:
+    print("No")
+elif True:
+    if True:
+        print("Yes")
+else:
+    pass
diff --git a/src/test/data/pa3/sample/stmt_if.py.ast.typed b/src/test/data/pa3/sample/stmt_if.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..0b671242ee63e8d16f763737fe9a65206cc14131
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_if.py.ast.typed
@@ -0,0 +1,125 @@
+{
+  "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" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 2, 5, 2, 15 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 2, 5, 2, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 2, 5, 2, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 2, 11, 2, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "No"
+        } ]
+      }
+    } ],
+    "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" : "BooleanLiteral",
+          "location" : [ 4, 8, 4, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "bool"
+          },
+          "value" : true
+        },
+        "thenBody" : [ {
+          "kind" : "ExprStmt",
+          "location" : [ 5, 9, 5, 20 ],
+          "expr" : {
+            "kind" : "CallExpr",
+            "location" : [ 5, 9, 5, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            },
+            "function" : {
+              "kind" : "Identifier",
+              "location" : [ 5, 9, 5, 13 ],
+              "inferredType" : {
+                "kind" : "FuncType",
+                "parameters" : [ {
+                  "kind" : "ClassValueType",
+                  "className" : "object"
+                } ],
+                "returnType" : {
+                  "kind" : "ClassValueType",
+                  "className" : "<None>"
+                }
+              },
+              "name" : "print"
+            },
+            "args" : [ {
+              "kind" : "StringLiteral",
+              "location" : [ 5, 15, 5, 19 ],
+              "inferredType" : {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              },
+              "value" : "Yes"
+            } ]
+          }
+        } ],
+        "elseBody" : [ ]
+      } ],
+      "elseBody" : [ ]
+    } ]
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_if.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_if.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..dcd7a5d6d55bef30b5619e90266d7af48a1c239f
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_if.py.ast.typed.s.result
@@ -0,0 +1 @@
+Yes
diff --git a/src/test/data/pa3/sample/stmt_return_early.py b/src/test/data/pa3/sample/stmt_return_early.py
new file mode 100644
index 0000000000000000000000000000000000000000..267eab769554229dbcf9fe2d1a63b046f04cfab8
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_return_early.py
@@ -0,0 +1,6 @@
+def f() -> int:
+    while True:
+        return 1
+    return 0
+
+print(f())
diff --git a/src/test/data/pa3/sample/stmt_return_early.py.ast.typed b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..456834974fbadfb2a467a354b222053d3d7e4607
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed
@@ -0,0 +1,113 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 6, 11 ],
+  "declarations" : [ {
+    "kind" : "FuncDef",
+    "location" : [ 1, 1, 4, 13 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 1, 5, 1, 5 ],
+      "name" : "f"
+    },
+    "params" : [ ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 1, 12, 1, 14 ],
+      "className" : "int"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "WhileStmt",
+      "location" : [ 2, 5, 4, 4 ],
+      "condition" : {
+        "kind" : "BooleanLiteral",
+        "location" : [ 2, 11, 2, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "value" : true
+      },
+      "body" : [ {
+        "kind" : "ReturnStmt",
+        "location" : [ 3, 9, 3, 16 ],
+        "value" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 3, 16, 3, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    }, {
+      "kind" : "ReturnStmt",
+      "location" : [ 4, 5, 4, 12 ],
+      "value" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 4, 12, 4, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 6, 1, 6, 10 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 6, 1, 6, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 1, 6, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 6, 7, 6, 9 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 7, 6, 7 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "f"
+        },
+        "args" : [ ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s.result
@@ -0,0 +1 @@
+1
diff --git a/src/test/data/pa3/sample/stmt_while.py b/src/test/data/pa3/sample/stmt_while.py
new file mode 100644
index 0000000000000000000000000000000000000000..acb4d7ac0a0d8a460119a1b9c3e958b7235f0f1a
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_while.py
@@ -0,0 +1,4 @@
+x:int = 1
+while x < 10:
+    print(x)
+    x = x + 1
diff --git a/src/test/data/pa3/sample/stmt_while.py.ast.typed b/src/test/data/pa3/sample/stmt_while.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..3802a75089a9992ef2c1c913a8eac0c8b2588195
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_while.py.ast.typed
@@ -0,0 +1,143 @@
+{
+  "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" : 1
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "WhileStmt",
+    "location" : [ 2, 1, 5, 1 ],
+    "condition" : {
+      "kind" : "BinaryExpr",
+      "location" : [ 2, 7, 2, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "bool"
+      },
+      "left" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 7, 2, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      },
+      "operator" : "<",
+      "right" : {
+        "kind" : "IntegerLiteral",
+        "location" : [ 2, 11, 2, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 10
+      }
+    },
+    "body" : [ {
+      "kind" : "ExprStmt",
+      "location" : [ 3, 5, 3, 12 ],
+      "expr" : {
+        "kind" : "CallExpr",
+        "location" : [ 3, 5, 3, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "<None>"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 3, 5, 3, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "<None>"
+            }
+          },
+          "name" : "print"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 3, 11, 3, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        } ]
+      }
+    }, {
+      "kind" : "AssignStmt",
+      "location" : [ 4, 5, 4, 13 ],
+      "targets" : [ {
+        "kind" : "Identifier",
+        "location" : [ 4, 5, 4, 5 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "name" : "x"
+      } ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 4, 9, 4, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 4, 9, 4, 9 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "x"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 4, 13, 4, 13 ],
+          "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/pa3/sample/stmt_while.py.ast.typed.s.result b/src/test/data/pa3/sample/stmt_while.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..07193989308c972f8a2d0f1b3a15c29ea4ac565b
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_while.py.ast.typed.s.result
@@ -0,0 +1,9 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
diff --git a/src/test/data/pa3/sample/str_cat.py b/src/test/data/pa3/sample/str_cat.py
new file mode 100644
index 0000000000000000000000000000000000000000..f28db5e56ad0a5c5d5ed18ccd5936e48e01aa464
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat.py
@@ -0,0 +1,17 @@
+a:str = "Hello"
+b:str = "World"
+c:str = "ChocoPy"
+
+def cat2(a:str, b:str) -> str:
+    return a + b
+
+def cat3(a:str, b:str, c:str) -> str:
+    return a + b + c
+
+print(cat2(a, b))
+print(cat2("", c))
+print(cat3(a, " ", c))
+print(len(a))
+print(len(cat2(a,a)))
+print(len(cat2("","")))
+
diff --git a/src/test/data/pa3/sample/str_cat.py.ast.typed b/src/test/data/pa3/sample/str_cat.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..1db5a86568671b3d62a1181bbc67e6c9511db138
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat.py.ast.typed
@@ -0,0 +1,738 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 16, 24 ],
+  "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" : "a"
+      },
+      "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" : "b"
+      },
+      "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, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 3, 9, 3, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "ChocoPy"
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 6, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 8 ],
+      "name" : "cat2"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 5, 10, 5, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 10, 5, 10 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 12, 5, 14 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 5, 17, 5, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 17, 5, 17 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 19, 5, 21 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 27, 5, 29 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 6, 5, 6, 16 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 6, 12, 6, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 12, 6, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 16, 6, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        }
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 8, 1, 9, 21 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 8 ],
+      "name" : "cat3"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 8, 10, 8, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 10, 8, 10 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 12, 8, 14 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 8, 17, 8, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 17, 8, 17 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 19, 8, 21 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 8, 24, 8, 28 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 24, 8, 24 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 26, 8, 28 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 8, 34, 8, 36 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 9, 5, 9, 20 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 9, 12, 9, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 9, 12, 9, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 12, 9, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "a"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "Identifier",
+            "location" : [ 9, 16, 9, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "b"
+          }
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 20, 9, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "c"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 17 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 11, 7, 11, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 7, 11, 10 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }
+          },
+          "name" : "cat2"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 11, 12, 11, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 11, 15, 11, 15 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 18 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 18 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 12, 7, 12, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 7, 12, 10 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }
+          },
+          "name" : "cat2"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 12, 12, 12, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : ""
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 12, 16, 12, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "c"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 22 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 22 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 13, 7, 13, 21 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 7, 13, 10 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }
+          },
+          "name" : "cat3"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 13, 12, 13, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        }, {
+          "kind" : "StringLiteral",
+          "location" : [ 13, 15, 13, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : " "
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 13, 20, 13, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "c"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 13 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 14, 7, 14, 12 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 14, 11, 14, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 21 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 15, 7, 15, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 7, 15, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "CallExpr",
+          "location" : [ 15, 11, 15, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 15, 11, 15, 14 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              }
+            },
+            "name" : "cat2"
+          },
+          "args" : [ {
+            "kind" : "Identifier",
+            "location" : [ 15, 16, 15, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "a"
+          }, {
+            "kind" : "Identifier",
+            "location" : [ 15, 18, 15, 18 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "a"
+          } ]
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 23 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 23 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 16, 7, 16, 22 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "CallExpr",
+          "location" : [ 16, 11, 16, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "function" : {
+            "kind" : "Identifier",
+            "location" : [ 16, 11, 16, 14 ],
+            "inferredType" : {
+              "kind" : "FuncType",
+              "parameters" : [ {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              }, {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              } ],
+              "returnType" : {
+                "kind" : "ClassValueType",
+                "className" : "str"
+              }
+            },
+            "name" : "cat2"
+          },
+          "args" : [ {
+            "kind" : "StringLiteral",
+            "location" : [ 16, 16, 16, 17 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : ""
+          }, {
+            "kind" : "StringLiteral",
+            "location" : [ 16, 19, 16, 20 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "value" : ""
+          } ]
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_cat.py.ast.typed.s.result b/src/test/data/pa3/sample/str_cat.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..b2e262a1b2899914249f33347808bca50dcb2daf
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat.py.ast.typed.s.result
@@ -0,0 +1,6 @@
+HelloWorld
+ChocoPy
+Hello ChocoPy
+5
+10
+0
diff --git a/src/test/data/pa3/sample/str_cat_2.py b/src/test/data/pa3/sample/str_cat_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8367c0feb571575c6cab1dccc36e131239af33a
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat_2.py
@@ -0,0 +1,19 @@
+a:str = "no"
+b:str = "o"
+c:str = ""
+d:str = ""
+e:str = ""
+
+def cat2(a:str, b:str) -> str:
+    return a + b
+
+def cat3(a:str, b:str, c:str) -> str:
+    return a + b + c
+
+c = cat2(b, a)
+d = cat2(a, a)
+e = cat3(a, b, cat2(b, b))
+
+print(c)
+print(d)
+print(e)
diff --git a/src/test/data/pa3/sample/str_cat_2.py.ast.typed b/src/test/data/pa3/sample/str_cat_2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..543fa96f4cd348edeaf26edf379857889590fc76
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat_2.py.ast.typed
@@ -0,0 +1,638 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 19, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 12 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 1, 1, 1, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 1, 3, 1, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 1, 9, 1, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "no"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 11 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 11 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "o"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 3, 9, 3, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "d"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 4, 9, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 5, 1, 5, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 5, 1, 5, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 1, 5, 1 ],
+        "name" : "e"
+      },
+      "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" : "FuncDef",
+    "location" : [ 7, 1, 8, 17 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 7, 5, 7, 8 ],
+      "name" : "cat2"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 7, 10, 7, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 10, 7, 10 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 12, 7, 14 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 7, 17, 7, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 17, 7, 17 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 7, 19, 7, 21 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 7, 27, 7, 29 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 8, 5, 8, 16 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 8, 12, 8, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 12, 8, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 8, 16, 8, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        }
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 10, 1, 11, 21 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 10, 5, 10, 8 ],
+      "name" : "cat3"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 10, 10, 10, 14 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 10, 10, 10 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 12, 10, 14 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 10, 17, 10, 21 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 17, 10, 17 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 19, 10, 21 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 10, 24, 10, 28 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 24, 10, 24 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 10, 26, 10, 28 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 10, 34, 10, 36 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 11, 5, 11, 20 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 11, 12, 11, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "left" : {
+          "kind" : "BinaryExpr",
+          "location" : [ 11, 12, 11, 16 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "left" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 12, 11, 12 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "a"
+          },
+          "operator" : "+",
+          "right" : {
+            "kind" : "Identifier",
+            "location" : [ 11, 16, 11, 16 ],
+            "inferredType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            },
+            "name" : "b"
+          }
+        },
+        "operator" : "+",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 20, 11, 20 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "c"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 13, 1, 13, 14 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 13, 1, 13, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 5, 13, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 5, 13, 8 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "cat2"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 13, 10, 13, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "b"
+      }, {
+        "kind" : "Identifier",
+        "location" : [ 13, 13, 13, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 14, 1, 14, 14 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 14, 1, 14, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "d"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 5, 14, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 5, 14, 8 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "cat2"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 14, 10, 14, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      }, {
+        "kind" : "Identifier",
+        "location" : [ 14, 13, 14, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 15, 1, 15, 26 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 15, 1, 15, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "e"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 5, 15, 26 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 5, 15, 8 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "cat3"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 15, 10, 15, 10 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      }, {
+        "kind" : "Identifier",
+        "location" : [ 15, 13, 15, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "b"
+      }, {
+        "kind" : "CallExpr",
+        "location" : [ 15, 16, 15, 25 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 16, 15, 19 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }
+          },
+          "name" : "cat2"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 15, 21, 15, 21 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 15, 24, 15, 24 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 17, 1, 17, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 17, 1, 17, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 17, 1, 17, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 17, 7, 17, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "c"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 18, 1, 18, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 18, 1, 18, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 18, 1, 18, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 18, 7, 18, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "d"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 19, 1, 19, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 19, 1, 19, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 19, 1, 19, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 19, 7, 19, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "e"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s.result b/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..2f6ff88bb671a7fc4539d98a70fc8d7ff35c2c91
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+ono
+nono
+noooo
diff --git a/src/test/data/pa3/sample/str_cmp.py b/src/test/data/pa3/sample/str_cmp.py
new file mode 100644
index 0000000000000000000000000000000000000000..9258cd96cfee2593f12b6129be488987622156ea
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cmp.py
@@ -0,0 +1,17 @@
+a:str = "Hello"
+b:str = "World"
+c:str = "ChocoPy"
+
+def eq(a:str, b:str) -> bool:
+    return a == b
+
+def neq(a:str, b:str) -> bool:
+    return a != b
+
+print(eq(a,a))
+print(eq(a,b))
+print(neq(a,b))
+print(neq(b,b))
+print(eq(c,a))
+print(neq(c,b))
+
diff --git a/src/test/data/pa3/sample/str_cmp.py.ast.typed b/src/test/data/pa3/sample/str_cmp.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..b185ac1346fdbaccb7b929b47aec3da1de608d00
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cmp.py.ast.typed
@@ -0,0 +1,659 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 16, 16 ],
+  "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" : "a"
+      },
+      "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" : "b"
+      },
+      "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, 17 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 3, 9, 3, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "ChocoPy"
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 5, 1, 6, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 5, 5, 5, 6 ],
+      "name" : "eq"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 5, 8, 5, 12 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 8, 5, 8 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 10, 5, 12 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 5, 15, 5, 19 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 5, 15, 5, 15 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 5, 17, 5, 19 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 5, 25, 5, 28 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 6, 5, 6, 17 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 6, 12, 6, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 12, 6, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        },
+        "operator" : "==",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 6, 17, 6, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        }
+      }
+    } ]
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 8, 1, 9, 18 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 8, 5, 8, 7 ],
+      "name" : "neq"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 8, 9, 8, 13 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 9, 8, 9 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 11, 8, 13 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 8, 16, 8, 20 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 16, 8, 16 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 8, 18, 8, 20 ],
+        "className" : "str"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 8, 26, 8, 29 ],
+      "className" : "bool"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 9, 5, 9, 17 ],
+      "value" : {
+        "kind" : "BinaryExpr",
+        "location" : [ 9, 12, 9, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "left" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 12, 9, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        },
+        "operator" : "!=",
+        "right" : {
+          "kind" : "Identifier",
+          "location" : [ 9, 17, 9, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 11, 1, 11, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 1, 11, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 1, 11, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 11, 7, 11, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 11, 7, 11, 8 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "eq"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 11, 10, 11, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 11, 12, 11, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 12, 7, 12, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 12, 7, 12, 8 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "eq"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 12, 10, 12, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 12, 12, 12, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 13, 7, 13, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 13, 7, 13, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "neq"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 13, 11, 13, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 13, 13, 13, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 14, 7, 14, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 14, 7, 14, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "neq"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 14, 11, 14, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 14, 13, 14, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 15, 1, 15, 14 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 15, 1, 15, 14 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 15, 1, 15, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 15, 7, 15, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 15, 7, 15, 8 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "eq"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 15, 10, 15, 10 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "c"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 15, 12, 15, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "a"
+        } ]
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 16, 1, 16, 15 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 16, 1, 16, 15 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 16, 1, 16, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 16, 7, 16, 14 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "bool"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 16, 7, 16, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            }, {
+              "kind" : "ClassValueType",
+              "className" : "str"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "bool"
+            }
+          },
+          "name" : "neq"
+        },
+        "args" : [ {
+          "kind" : "Identifier",
+          "location" : [ 16, 11, 16, 11 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "c"
+        }, {
+          "kind" : "Identifier",
+          "location" : [ 16, 13, 16, 13 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "b"
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_cmp.py.ast.typed.s.result b/src/test/data/pa3/sample/str_cmp.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..72232fd5b4a45826894c933b20e6f08441479a86
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cmp.py.ast.typed.s.result
@@ -0,0 +1,6 @@
+True
+False
+True
+False
+False
+True
diff --git a/src/test/data/pa3/sample/str_get_element.py b/src/test/data/pa3/sample/str_get_element.py
new file mode 100644
index 0000000000000000000000000000000000000000..8681a05aef28589e51fafb0983e7d077fdba48c9
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element.py
@@ -0,0 +1,14 @@
+x:str = "abc"
+a:str = ""
+b:str = ""
+c:str = ""
+
+def str_get(s:str, i:int) -> str:
+    return s[i]
+
+a = str_get(x, 0)
+b = str_get(x, 1)
+c = str_get(x, 2)
+print(a)
+print(b)
+print(c)
diff --git a/src/test/data/pa3/sample/str_get_element.py.ast.typed b/src/test/data/pa3/sample/str_get_element.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..ff9c44929348e7ba07a9cc5e1450f9552aef860c
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element.py.ast.typed
@@ -0,0 +1,462 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 14, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 3, 1, 3, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 3, 1, 3, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 3, 1, 3, 1 ],
+        "name" : "b"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 3, 3, 3, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 3, 9, 3, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 4, 1, 4, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 4, 1, 4, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 1 ],
+        "name" : "c"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 3, 4, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 4, 9, 4, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 6, 1, 7, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 6, 5, 6, 11 ],
+      "name" : "str_get"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 6, 13, 6, 17 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 13, 6, 13 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 15, 6, 17 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 6, 20, 6, 24 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 6, 20, 6, 20 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 6, 22, 6, 24 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 6, 30, 6, 32 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 7, 5, 7, 15 ],
+      "value" : {
+        "kind" : "IndexExpr",
+        "location" : [ 7, 12, 7, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 12, 7, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        },
+        "index" : {
+          "kind" : "Identifier",
+          "location" : [ 7, 14, 7, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 9, 1, 9, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 9, 1, 9, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 9, 5, 9, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 9, 5, 9, 11 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "str_get"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 9, 13, 9, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 9, 16, 9, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 10, 1, 10, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 10, 1, 10, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "b"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 10, 5, 10, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 10, 5, 10, 11 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "str_get"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 10, 13, 10, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 10, 16, 10, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 1
+      } ]
+    }
+  }, {
+    "kind" : "AssignStmt",
+    "location" : [ 11, 1, 11, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 11, 1, 11, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "c"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 11, 5, 11, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 11, 5, 11, 11 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "str_get"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 11, 13, 11, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 11, 16, 11, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 2
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 12, 1, 12, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 12, 1, 12, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 12, 1, 12, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 12, 7, 12, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 13, 1, 13, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 13, 1, 13, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 13, 1, 13, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 13, 7, 13, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "b"
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 14, 1, 14, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 14, 1, 14, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 14, 1, 14, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 14, 7, 14, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "c"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_get_element.py.ast.typed.s.result b/src/test/data/pa3/sample/str_get_element.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..de980441c3ab03a8c07dda1ad27b8a11f39deb1e
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element.py.ast.typed.s.result
@@ -0,0 +1,3 @@
+a
+b
+c
diff --git a/src/test/data/pa3/sample/str_get_element_oob_1.py b/src/test/data/pa3/sample/str_get_element_oob_1.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6613d11bafa4a4e93971e02293286404c0cfb81
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_1.py
@@ -0,0 +1,8 @@
+x:str = "abc"
+a:str = ""
+
+def str_get(s:str, i:int) -> str:
+    return s[i]
+
+a = str_get(x, -1)
+print(a)
diff --git a/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..4ce273300481f549e1ba74c1415f06ecd48d7a3d
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed
@@ -0,0 +1,235 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 11 ],
+      "name" : "str_get"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 4, 13, 4, 17 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 13, 4, 13 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 15, 4, 17 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 4, 20, 4, 24 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 20, 4, 20 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 22, 4, 24 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 30, 4, 32 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 15 ],
+      "value" : {
+        "kind" : "IndexExpr",
+        "location" : [ 5, 12, 5, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 12, 5, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        },
+        "index" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 14, 5, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 18 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 5, 7, 18 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 11 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "str_get"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 7, 13, 7, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }, {
+        "kind" : "UnaryExpr",
+        "location" : [ 7, 16, 7, 17 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "operator" : "-",
+        "operand" : {
+          "kind" : "IntegerLiteral",
+          "location" : [ 7, 17, 7, 17 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "value" : 1
+        }
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 8, 7, 8, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s.result b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/str_get_element_oob_2.py b/src/test/data/pa3/sample/str_get_element_oob_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c4e0e05a74200a28fb0a52db0d54ec1abb626b4
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_2.py
@@ -0,0 +1,8 @@
+x:str = "abc"
+a:str = ""
+
+def str_get(s:str, i:int) -> str:
+    return s[i]
+
+a = str_get(x, 3)
+print(a)
diff --git a/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..3a10e59b42c1caae67da1903ddce4377c19e6965
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed
@@ -0,0 +1,226 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 13 ],
+    "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, 13 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : "abc"
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 11 ],
+      "name" : "str_get"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 4, 13, 4, 17 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 13, 4, 13 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 15, 4, 17 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 4, 20, 4, 24 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 20, 4, 20 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 22, 4, 24 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 30, 4, 32 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 15 ],
+      "value" : {
+        "kind" : "IndexExpr",
+        "location" : [ 5, 12, 5, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 12, 5, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        },
+        "index" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 14, 5, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 5, 7, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 11 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "str_get"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 7, 13, 7, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 16, 7, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 3
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 8, 7, 8, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s.result b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/str_get_element_oob_3.py b/src/test/data/pa3/sample/str_get_element_oob_3.py
new file mode 100644
index 0000000000000000000000000000000000000000..28e545a6ab7b45cbba2f3c28ac73c21d0a86e84f
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_3.py
@@ -0,0 +1,8 @@
+x:str = ""
+a:str = ""
+
+def str_get(s:str, i:int) -> str:
+    return s[i]
+
+a = str_get(x, 0)
+print(a)
diff --git a/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..bac1f1899b1753162d757cc38d1ea80e27a91886
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed
@@ -0,0 +1,226 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 8, 9 ],
+  "declarations" : [ {
+    "kind" : "VarDef",
+    "location" : [ 1, 1, 1, 10 ],
+    "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, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 10 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 5 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "a"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 5 ],
+        "className" : "str"
+      }
+    },
+    "value" : {
+      "kind" : "StringLiteral",
+      "location" : [ 2, 9, 2, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "value" : ""
+    }
+  }, {
+    "kind" : "FuncDef",
+    "location" : [ 4, 1, 5, 16 ],
+    "name" : {
+      "kind" : "Identifier",
+      "location" : [ 4, 5, 4, 11 ],
+      "name" : "str_get"
+    },
+    "params" : [ {
+      "kind" : "TypedVar",
+      "location" : [ 4, 13, 4, 17 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 13, 4, 13 ],
+        "name" : "s"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 15, 4, 17 ],
+        "className" : "str"
+      }
+    }, {
+      "kind" : "TypedVar",
+      "location" : [ 4, 20, 4, 24 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 20, 4, 20 ],
+        "name" : "i"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 4, 22, 4, 24 ],
+        "className" : "int"
+      }
+    } ],
+    "returnType" : {
+      "kind" : "ClassType",
+      "location" : [ 4, 30, 4, 32 ],
+      "className" : "str"
+    },
+    "declarations" : [ ],
+    "statements" : [ {
+      "kind" : "ReturnStmt",
+      "location" : [ 5, 5, 5, 15 ],
+      "value" : {
+        "kind" : "IndexExpr",
+        "location" : [ 5, 12, 5, 15 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "list" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 12, 5, 12 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "name" : "s"
+        },
+        "index" : {
+          "kind" : "Identifier",
+          "location" : [ 5, 14, 5, 14 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          },
+          "name" : "i"
+        }
+      }
+    } ]
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 7, 1, 7, 17 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 7, 1, 7, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "name" : "a"
+    } ],
+    "value" : {
+      "kind" : "CallExpr",
+      "location" : [ 7, 5, 7, 17 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "str"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 7, 5, 7, 11 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }, {
+            "kind" : "ClassValueType",
+            "className" : "int"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          }
+        },
+        "name" : "str_get"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 7, 13, 7, 13 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "x"
+      }, {
+        "kind" : "IntegerLiteral",
+        "location" : [ 7, 16, 7, 16 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "value" : 0
+      } ]
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 8, 1, 8, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 8, 1, 8, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 8, 1, 8, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 8, 7, 8, 7 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "str"
+        },
+        "name" : "a"
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s.result b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..144d019705a74e0945ce4f9331bb596525d6ff80
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s.result
@@ -0,0 +1,2 @@
+Index out of bounds
+Exited with error code 3
diff --git a/src/test/data/pa3/sample/str_len.py b/src/test/data/pa3/sample/str_len.py
new file mode 100644
index 0000000000000000000000000000000000000000..829f00b1c6dc55126cc59f1b7699c5e37234011b
--- /dev/null
+++ b/src/test/data/pa3/sample/str_len.py
@@ -0,0 +1 @@
+print(len("ChocoPy"))
diff --git a/src/test/data/pa3/sample/str_len.py.ast.typed b/src/test/data/pa3/sample/str_len.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..d76359c4c65d76e940a930e8517ded5ac8e1101d
--- /dev/null
+++ b/src/test/data/pa3/sample/str_len.py.ast.typed
@@ -0,0 +1,71 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 1, 22 ],
+  "declarations" : [ ],
+  "statements" : [ {
+    "kind" : "ExprStmt",
+    "location" : [ 1, 1, 1, 21 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 1, 1, 1, 21 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 1, 1, 1, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "CallExpr",
+        "location" : [ 1, 7, 1, 20 ],
+        "inferredType" : {
+          "kind" : "ClassValueType",
+          "className" : "int"
+        },
+        "function" : {
+          "kind" : "Identifier",
+          "location" : [ 1, 7, 1, 9 ],
+          "inferredType" : {
+            "kind" : "FuncType",
+            "parameters" : [ {
+              "kind" : "ClassValueType",
+              "className" : "object"
+            } ],
+            "returnType" : {
+              "kind" : "ClassValueType",
+              "className" : "int"
+            }
+          },
+          "name" : "len"
+        },
+        "args" : [ {
+          "kind" : "StringLiteral",
+          "location" : [ 1, 11, 1, 19 ],
+          "inferredType" : {
+            "kind" : "ClassValueType",
+            "className" : "str"
+          },
+          "value" : "ChocoPy"
+        } ]
+      } ]
+    }
+  } ],
+  "errors" : {
+    "errors" : [ ],
+    "kind" : "Errors",
+    "location" : [ 0, 0, 0, 0 ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/data/pa3/sample/str_len.py.ast.typed.s.result b/src/test/data/pa3/sample/str_len.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..7f8f011eb73d6043d2e6db9d2c101195ae2801f2
--- /dev/null
+++ b/src/test/data/pa3/sample/str_len.py.ast.typed.s.result
@@ -0,0 +1 @@
+7
diff --git a/src/test/data/pa3/sample/var_assign.py b/src/test/data/pa3/sample/var_assign.py
new file mode 100644
index 0000000000000000000000000000000000000000..c56b7ca34e8a3c4e3c8308a2cf5505563569ddb3
--- /dev/null
+++ b/src/test/data/pa3/sample/var_assign.py
@@ -0,0 +1,4 @@
+x:int = 0
+y:object = 1
+x = y = 42
+print(x)
diff --git a/src/test/data/pa3/sample/var_assign.py.ast.typed b/src/test/data/pa3/sample/var_assign.py.ast.typed
new file mode 100644
index 0000000000000000000000000000000000000000..83fb4c48f40541811a858478a059b01abfe486d9
--- /dev/null
+++ b/src/test/data/pa3/sample/var_assign.py.ast.typed
@@ -0,0 +1,128 @@
+{
+  "kind" : "Program",
+  "location" : [ 1, 1, 4, 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
+    }
+  }, {
+    "kind" : "VarDef",
+    "location" : [ 2, 1, 2, 12 ],
+    "var" : {
+      "kind" : "TypedVar",
+      "location" : [ 2, 1, 2, 8 ],
+      "identifier" : {
+        "kind" : "Identifier",
+        "location" : [ 2, 1, 2, 1 ],
+        "name" : "y"
+      },
+      "type" : {
+        "kind" : "ClassType",
+        "location" : [ 2, 3, 2, 8 ],
+        "className" : "object"
+      }
+    },
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 2, 12, 2, 12 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 1
+    }
+  } ],
+  "statements" : [ {
+    "kind" : "AssignStmt",
+    "location" : [ 3, 1, 3, 10 ],
+    "targets" : [ {
+      "kind" : "Identifier",
+      "location" : [ 3, 1, 3, 1 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "name" : "x"
+    }, {
+      "kind" : "Identifier",
+      "location" : [ 3, 5, 3, 5 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "object"
+      },
+      "name" : "y"
+    } ],
+    "value" : {
+      "kind" : "IntegerLiteral",
+      "location" : [ 3, 9, 3, 10 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "int"
+      },
+      "value" : 42
+    }
+  }, {
+    "kind" : "ExprStmt",
+    "location" : [ 4, 1, 4, 8 ],
+    "expr" : {
+      "kind" : "CallExpr",
+      "location" : [ 4, 1, 4, 8 ],
+      "inferredType" : {
+        "kind" : "ClassValueType",
+        "className" : "<None>"
+      },
+      "function" : {
+        "kind" : "Identifier",
+        "location" : [ 4, 1, 4, 5 ],
+        "inferredType" : {
+          "kind" : "FuncType",
+          "parameters" : [ {
+            "kind" : "ClassValueType",
+            "className" : "object"
+          } ],
+          "returnType" : {
+            "kind" : "ClassValueType",
+            "className" : "<None>"
+          }
+        },
+        "name" : "print"
+      },
+      "args" : [ {
+        "kind" : "Identifier",
+        "location" : [ 4, 7, 4, 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/pa3/sample/var_assign.py.ast.typed.s.result b/src/test/data/pa3/sample/var_assign.py.ast.typed.s.result
new file mode 100644
index 0000000000000000000000000000000000000000..d81cc0710eb6cf9efd5b920a8453e1e07157b6cd
--- /dev/null
+++ b/src/test/data/pa3/sample/var_assign.py.ast.typed.s.result
@@ -0,0 +1 @@
+42