diff --git a/use-based-refs/interpreter/README.md b/use-based-refs/interpreter/README.md
index 60f7666b51511fbd33e00113ed82d6727e19b20b..a27c017300420dbbf68049659a20706adf84d55d 100644
--- a/use-based-refs/interpreter/README.md
+++ b/use-based-refs/interpreter/README.md
@@ -31,6 +31,7 @@ Right now, the interpreter only executes a program hardcoded in `main`. Change t
     - [x] Dereference -- read
     - [x] Dereference -- write
     - [ ] Builtins
+    - [ ] "Parallel" execution with `||` (needs Pratt parsing (?) and product types for joining)
     - [ ] `NoAlias` specification
     - [ ] Alias checking, of course 
 - [ ] Add tests for typechecking functions/function calls
diff --git a/use-based-refs/interpreter/src/aliascheck.rs b/use-based-refs/interpreter/src/aliascheck.rs
new file mode 100644
index 0000000000000000000000000000000000000000..098cf97737c857205b84154c97f8ed26bf0bad1e
--- /dev/null
+++ b/use-based-refs/interpreter/src/aliascheck.rs
@@ -0,0 +1,113 @@
+use std::collections::HashMap;
+
+use crate::{Error, Node, Result};
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+pub struct Context {
+    counter: i32, // Region Id counter
+    idents: HashMap<String, Provenance>,
+}
+
+impl Context {
+    /// Create a new empty context.
+    fn new() -> Self {
+        Self {
+            idents: HashMap::new(),
+            counter: 0,
+        }
+    }
+
+    /// Add a fresh reference to the context.
+    ///
+    /// A reference is fresh if it doesn't alias with any existing reference,
+    /// that is, it points directly to a value.
+    fn fresh(&mut self, ident: String) {
+        self.idents
+            .insert(ident, Region::Concrete(self.counter).into());
+        self.counter += 1;
+    }
+}
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+struct Provenance(Vec<Region>);
+
+impl From<Region> for Provenance {
+    fn from(value: Region) -> Self {
+        Self(vec![value])
+    }
+}
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+pub enum Region {
+    Concrete(i32),
+    Abstract(i32),
+}
+
+fn aliascheck_ctx(ast: &Node, ctx: &mut Context) -> Result<()> {
+    match ast {
+        // No references are created or used, therefore automatic pass
+        Node::Num(_) | Node::Unit | Node::Ident(_) => (),
+        // Check sequences ... sequentially
+        Node::Seq(nodes) => {
+            for node in nodes {
+                aliascheck_ctx(node, ctx)?;
+            }
+        }
+        // A `let` is okay if its expr is okay; also we need to store `ident`
+        // in the context if it is a reference.
+        Node::Let { ident, expr, ty } => todo!(),
+        // We take a reference. If it is a value
+        Node::Ref(_) => todo!(),
+        Node::DerefRead(_) => todo!(),
+        Node::DerefWrite { reference, expr } => todo!(),
+        Node::Func {
+            ident,
+            args,
+            ty,
+            body,
+        } => todo!(),
+        Node::Call { ident, args } => todo!(),
+    };
+    Ok(())
+}
+
+/// Aliascheck given AST using a fresh context
+///
+/// # Errors
+///
+/// Returns error if aliaschecking fails.
+pub fn aliascheck(ast: Node) -> Result<Node> {
+    aliascheck_ctx(&ast, &mut Context::new()).and(Ok(ast))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::parser::ast;
+
+    fn test(input: &str) {
+        aliascheck(ast(input).expect("Parse in test unsuccessful"))
+            .expect("Aliascheck in test unsuccessful");
+    }
+
+    #[test]
+    fn num() {
+        test("4")
+    }
+
+    #[test]
+    fn unit() {
+        test("{}")
+    }
+
+    // #[test]
+    // fn no_refs() {
+    //     test("let x = 4; x")
+    // }
+
+    // #[test]
+    // fn no_refs_fn() {
+    //     // If there are no references, there shouldn't be a problem
+    //     test("fn foo(x: Num) -> Num = x; foo(3)");
+    // }
+}
diff --git a/use-based-refs/interpreter/src/eval.rs b/use-based-refs/interpreter/src/eval.rs
index e44715a70077bb7d811c69b70f4cdced31ad7888..9dc21e0e5a33da3fa65afbfdf28a31f039db044e 100644
--- a/use-based-refs/interpreter/src/eval.rs
+++ b/use-based-refs/interpreter/src/eval.rs
@@ -159,7 +159,7 @@ fn eval_ctx(ast: Node, ctx: &mut Context) -> Result<Value> {
             // Eager evaluation of the arguments
             let mut evals = Vec::with_capacity(args.len());
             for arg in args {
-                evals.push(eval_ctx(arg, ctx)?)
+                evals.push(eval_ctx(arg, ctx)?);
             }
 
             // Look up function
diff --git a/use-based-refs/interpreter/src/grammar.pest b/use-based-refs/interpreter/src/grammar.pest
index 7f6fb51725b57746c39b248546c1871ef9c71b6f..f21ac572c35a42c2fbd45e1922db8c8f629d7f5f 100644
--- a/use-based-refs/interpreter/src/grammar.pest
+++ b/use-based-refs/interpreter/src/grammar.pest
@@ -20,7 +20,7 @@ Seq = { (Expr ~ ";")* ~ Expr }
 // I must put DerefWrite first because of shenanigans;
 // I don't know the reason, but it fails to parse otherwise.
 Expr = _{ DerefWrite | Value | TypedLet | Let
-        | Func | Call | Ident | Block | DerefRead  }
+        | Func | Call | Ident | Block | DerefRead }
 
 Value = _{ Unit | Num | Ref }
 
diff --git a/use-based-refs/interpreter/src/lib.rs b/use-based-refs/interpreter/src/lib.rs
index 917c2c9e050cf4a7bcfba4555f1d0ddea6e619a1..8b92fa37a8990b6482ea4ebc5daaab27bb036c90 100644
--- a/use-based-refs/interpreter/src/lib.rs
+++ b/use-based-refs/interpreter/src/lib.rs
@@ -4,10 +4,12 @@
 
 use thiserror::Error;
 
+mod aliascheck;
 mod eval;
 mod parser;
 mod typecheck;
 
+pub use aliascheck::aliascheck;
 pub use eval::eval;
 pub use parser::ast;
 pub use typecheck::typecheck;
@@ -56,6 +58,8 @@ pub enum Error {
     General(String),
     #[error("Name error: {0}")]
     Name(String),
+    #[error("Alias error: {0}")]
+    Alias(String),
 }
 
 pub type Result<T> = std::result::Result<T, Error>;
diff --git a/use-based-refs/interpreter/src/main.rs b/use-based-refs/interpreter/src/main.rs
index 0a109b5ea89f0ba2366ac9cb25389d5bc65971c7..0c62240012b01c143f7643c07485a2bb766ad664 100644
--- a/use-based-refs/interpreter/src/main.rs
+++ b/use-based-refs/interpreter/src/main.rs
@@ -1,11 +1,20 @@
 #![warn(clippy::pedantic)]
 
-use interpreter::{ast, eval, typecheck};
+use interpreter::{aliascheck, ast, eval, typecheck};
+
+// This should fail since `x` and `y` may alias and mutate at the same time.
+// "fn danger(x: &Num, y: &Num) -> {} = {x := 1 | y := 2; x}"
+// This, on the other hand, is fine since x and y are marked as not aliasing.
+// "fn fine[x ^ y](x: &Num, y: &Num) -> {} = {x := 1 | y := 2}"
 
 fn main() {
-    let program = "fn infinite() -> Num = {infinite()}; infinite()";
+    let program = "let x = 3; let y = &x; y := 4; *y";
 
-    match ast(program).and_then(typecheck).and_then(eval) {
+    match ast(program)
+        .and_then(typecheck)
+        // .and_then(aliascheck)
+        .and_then(eval)
+    {
         Ok(val) => println!("{val}"),
         Err(err) => eprintln!("{err}"),
     }