From 75f93cc0be5bbd554f08c59b57c166d3f1e6a80c Mon Sep 17 00:00:00 2001
From: Peter Matta <mattapet@fit.cvut.cz>
Date: Wed, 23 May 2018 20:54:08 +0200
Subject: [PATCH] Added constat expression solving

---
 examples/globExpr.dusk              |   5 +-
 include/dusk/AST/ASTNode.h          |   2 +-
 include/dusk/AST/ASTVisitor.h       | 140 ++------
 include/dusk/AST/Decl.h             |   9 +-
 include/dusk/AST/DiagnosticsParse.h |  12 +
 include/dusk/AST/Expr.h             |  21 +-
 include/dusk/AST/Pattern.h          |  15 +-
 include/dusk/AST/Scope.h            |  22 ++
 include/dusk/AST/Stmt.h             |  27 +-
 include/dusk/AST/Type.h             |  25 +-
 include/dusk/AST/TypeRepr.h         |  35 +-
 lib/AST/ASTContext.cpp              |   3 +-
 lib/AST/ASTNode.cpp                 |   2 +-
 lib/AST/ASTPrinter.cpp              |  88 ++---
 lib/AST/ASTWalker.cpp               | 429 ++++--------------------
 lib/AST/Decl.cpp                    |  20 ++
 lib/AST/Expr.cpp                    |  42 ++-
 lib/AST/Pattern.cpp                 |  10 +
 lib/AST/Scope.cpp                   |  18 +
 lib/AST/Stmt.cpp                    |  50 +++
 lib/AST/Type.cpp                    |   8 +
 lib/AST/TypeRepr.cpp                |  10 +
 lib/IRGen/GenFunc.cpp               |  81 +++--
 lib/Parser/ParseType.cpp            |  82 ++---
 lib/Sema/CMakeLists.txt             |   1 +
 lib/Sema/Sema.cpp                   |   4 +-
 lib/Sema/TypeCheckDecl.cpp          | 273 ++++++++++-----
 lib/Sema/TypeCheckExpr.cpp          | 501 +++++++++++++++++++++++-----
 lib/Sema/TypeCheckPattern.cpp       |  98 ++++--
 lib/Sema/TypeCheckStmt.cpp          | 346 ++++++++++++-------
 lib/Sema/TypeCheckType.cpp          |  86 +++++
 lib/Sema/TypeChecker.cpp            | 238 ++++++-------
 lib/Sema/TypeChecker.h              | 138 ++++----
 lib/Sema/TypeResolver.cpp           |  18 +-
 tools/duskc/main.cpp                |   4 +-
 35 files changed, 1721 insertions(+), 1142 deletions(-)
 create mode 100644 lib/Sema/TypeCheckType.cpp

diff --git a/examples/globExpr.dusk b/examples/globExpr.dusk
index 6510eb5..4ad8c89 100644
--- a/examples/globExpr.dusk
+++ b/examples/globExpr.dusk
@@ -1,4 +1,7 @@
-var a: Int;
+let a = 4;
+var arr: Int[a];
+
+// var a: Int;
 
 func main() {
     println(a = 14);
diff --git a/include/dusk/AST/ASTNode.h b/include/dusk/AST/ASTNode.h
index ca4bd08..480230e 100644
--- a/include/dusk/AST/ASTNode.h
+++ b/include/dusk/AST/ASTNode.h
@@ -45,7 +45,7 @@ public:
   ///
   /// \return \c true if the node was walked properly and may continue
   ///  traversing the AST, \c false if should terminate.
-  virtual bool walk(ASTWalker &Walker);
+  bool walk(ASTWalker &Walker);
   
 public:
   /// Only allow allocation using \c ASTContext
diff --git a/include/dusk/AST/ASTVisitor.h b/include/dusk/AST/ASTVisitor.h
index 7d28973..ea1172d 100644
--- a/include/dusk/AST/ASTVisitor.h
+++ b/include/dusk/AST/ASTVisitor.h
@@ -34,110 +34,19 @@ namespace dusk {
 /// traversal. \c true indicates valid traversal of given node/subtree and
 /// visitor may continue traversing. \c false means failure, upon which visitor
 /// must immedietly terminate traversal of the AST.
-template <typename Derived> class ASTVisitor {
+template <typename Derived,
+          typename DeclRetTy = void,
+          typename ExprRetTy = void,
+          typename StmtRetTy = void,
+          typename PatternRetTy = void,
+          typename TypeReprRetTy = void>
+class ASTVisitor {
 public:
   /// Returns a reference to the derived class.
   Derived &getDerived() { return *static_cast<Derived *>(this); }
 
-  bool visit_(ASTNode *N) {
-    if (auto *D = dynamic_cast<Decl *>(N))
-      return visit_(D);
-    if (auto *E = dynamic_cast<Expr *>(N))
-      return visit_(E);
-    if (auto *S = dynamic_cast<Stmt *>(N))
-      return visit_(S);
-
-    llvm_unreachable("Unexpected node");
-  }
-
-  /// Visit a concrete declaration node.
-  bool visit_(Decl *D) {
-    switch (D->getKind()) {
-    case DeclKind::Let:
-      return getDerived().visit(static_cast<LetDecl *>(D));
-    case DeclKind::Func:
-      return getDerived().visit(static_cast<FuncDecl *>(D));
-    case DeclKind::Module:
-      return getDerived().visit(static_cast<ModuleDecl *>(D));
-    case DeclKind::Param:
-      return getDerived().visit(static_cast<ParamDecl *>(D));
-    case DeclKind::Var:
-      return getDerived().visit(static_cast<VarDecl *>(D));
-    }
-  }
-
-  /// Visit a conrete expression node.
-  bool visit_(Expr *E) {
-    switch (E->getKind()) {
-    case ExprKind::NumberLiteral:
-      return getDerived().visit(static_cast<NumberLiteralExpr *>(E));
-    case ExprKind::ArrayLiteral:
-      return getDerived().visit(static_cast<ArrayLiteralExpr *>(E));
-    case ExprKind::Identifier:
-      return getDerived().visit(static_cast<IdentifierExpr *>(E));
-    case ExprKind::Paren:
-      return getDerived().visit(static_cast<ParenExpr *>(E));
-    case ExprKind::Assign:
-      return getDerived().visit(static_cast<AssignExpr *>(E));
-    case ExprKind::Infix:
-      return getDerived().visit(static_cast<InfixExpr *>(E));
-    case ExprKind::Prefix:
-      return getDerived().visit(static_cast<PrefixExpr *>(E));
-    case ExprKind::Call:
-      return getDerived().visit(static_cast<CallExpr *>(E));
-    case ExprKind::Subscript:
-      return getDerived().visit(static_cast<SubscriptExpr *>(E));
-    }
-  }
-
-  /// Visit a concrete statement node.
-  bool visit_(Stmt *S) {
-    switch (S->getKind()) {
-    case StmtKind::Break:
-      return getDerived().visit(static_cast<BreakStmt *>(S));
-    case StmtKind::Return:
-      return getDerived().visit(static_cast<ReturnStmt *>(S));
-    case StmtKind::Range:
-      return getDerived().visit(static_cast<RangeStmt *>(S));
-    case StmtKind::Subscript:
-      return getDerived().visit(static_cast<SubscriptStmt *>(S));
-    case StmtKind::Block:
-      return getDerived().visit(static_cast<BlockStmt *>(S));
-    case StmtKind::Extern:
-      return getDerived().visit(static_cast<ExternStmt *>(S));
-    case StmtKind::For:
-      return getDerived().visit(static_cast<ForStmt *>(S));
-    case StmtKind::Func:
-      return getDerived().visit(static_cast<FuncStmt *>(S));
-    case StmtKind::If:
-      return getDerived().visit(static_cast<IfStmt *>(S));
-    case StmtKind::While:
-      return getDerived().visit(static_cast<WhileStmt *>(S));
-    }
-  }
-
-  /// Visit a concrete pattern node.
-  bool visit_(Pattern *P) {
-    switch (P->getKind()) {
-    case PatternKind::Expr:
-      return getDerived().visit(static_cast<ExprPattern *>(P));
-    case PatternKind::Variable:
-      return getDerived().visit(static_cast<VarPattern *>(P));
-    }
-  }
-  
-  /// Visits concrete TypeRepr
-  bool visit_(TypeRepr *T) {
-    switch (T->getKind()) {
-    case TypeReprKind::Ident:
-      return getDerived().visit(static_cast<IdentTypeRepr *>(T));
-    case TypeReprKind::Array:
-      return getDerived().visit(static_cast<ArrayTypeRepr *>(T));
-    }
-  }
-  
   /// Visit a concrete declaration node.
-  bool visit(Decl *D) {
+  DeclRetTy visit(Decl *D) {
     switch (D->getKind()) {
     case DeclKind::Let:
       return getDerived().visitLetDecl(static_cast<LetDecl *>(D));
@@ -151,9 +60,9 @@ public:
       return getDerived().visitParamDecl(static_cast<ParamDecl *>(D));
     }
   }
-  
+
   /// Visit a concrete expression node.
-  Expr *visit(Expr *E) {
+  ExprRetTy visit(Expr *E) {
     switch (E->getKind()) {
     case ExprKind::NumberLiteral:
       return getDerived().visitNumberLiteralExpr(
@@ -177,9 +86,9 @@ public:
       return getDerived().visitSubscriptExpr(static_cast<SubscriptExpr *>(E));
     }
   }
-  
+
   /// Visit a concrete statement node.
-  bool visit(Stmt *S) {
+  StmtRetTy visit(Stmt *S) {
     switch (S->getKind()) {
     case StmtKind::Break:
       return getDerived().visitBreakStmt(static_cast<BreakStmt *>(S));
@@ -203,9 +112,9 @@ public:
       return getDerived().visitWhileStmt(static_cast<WhileStmt *>(S));
     }
   }
-  
+
   /// Visit a concrete pattern node.
-  bool visit(Pattern *P) {
+  PatternRetTy visit(Pattern *P) {
     switch (P->getKind()) {
     case PatternKind::Expr:
       return getDerived().visitExprPattern(static_cast<ExprPattern *>(P));
@@ -213,9 +122,9 @@ public:
       return getDerived().visitVarPattern(static_cast<VarPattern *>(P));
     }
   }
-  
+
   /// Visits concrete TypeRepr
-  bool visit(TypeRepr *T) {
+  TypeReprRetTy visit(TypeRepr *T) {
     switch (T->getKind()) {
     case TypeReprKind::Ident:
       return getDerived().visitIdentTypeRepr(static_cast<IdentTypeRepr *>(T));
@@ -225,6 +134,23 @@ public:
   }
 };
 
+template <typename Derived, typename DeclRetTy = void>
+using DeclVisitor = ASTVisitor<Derived, DeclRetTy, void, void, void, void>;
+
+template <typename Derived, typename ExprRetTy = void>
+using ExprVisitor = ASTVisitor<Derived, void, ExprRetTy, void, void, void>;
+
+template <typename Derived, typename StmtRetTy = void>
+using StmtVisitor = ASTVisitor<Derived, void, void, StmtRetTy, void, void>;
+
+template <typename Derived, typename PatternRetTy = void>
+using PatternVisitor =
+    ASTVisitor<Derived, void, void, void, PatternRetTy, void>;
+
+template <typename Derived, typename TypeReprRetTy = void>
+using TypeReprVisitor =
+    ASTVisitor<Derived, void, void, void, void, TypeReprRetTy>;
+
 } // namespace dusk
 
 #endif /* DUSK_AST_VISITOR_H */
diff --git a/include/dusk/AST/Decl.h b/include/dusk/AST/Decl.h
index 85226d6..41f0b9c 100644
--- a/include/dusk/AST/Decl.h
+++ b/include/dusk/AST/Decl.h
@@ -87,7 +87,12 @@ public:
 
   SMRange getSourceRange() const override;
   
-  bool walk(ASTWalker &Walker) override;
+  bool walk(ASTWalker &Walker);
+
+  VarDecl *getVarDecl();
+  LetDecl *getLetDecl();
+  ParamDecl *getParamDecl();
+  FuncDecl *getFuncDecl();
 };
 
 /// Declaration of value-holdable node
@@ -106,6 +111,8 @@ public:
   bool hasValue() const { return Value != nullptr; }
   Expr *getValue() const { return Value; }
   void setValue(Expr *V) { Value = V; }
+  
+  bool isLet() const { return isKind(DeclKind::Let); }
 };
 
 /// Declaration of a variable
diff --git a/include/dusk/AST/DiagnosticsParse.h b/include/dusk/AST/DiagnosticsParse.h
index c6e86d6..a6fe376 100644
--- a/include/dusk/AST/DiagnosticsParse.h
+++ b/include/dusk/AST/DiagnosticsParse.h
@@ -44,11 +44,13 @@ enum DiagID : unsigned {
   
   // Semantic diagnostics
   
+  unexpected_expresssion,
   unexpected_break_stmt,
   unexpected_return_stmt,
   expression_not_assignable,
   redefinition_of_identifier,
   return_missing_value,
+  array_index_out_of_bounds,
   
   // Types
   expected_type_annotation,
@@ -59,6 +61,8 @@ enum DiagID : unsigned {
   subscripted_value_not_array,
   invalid_array_size,
   expected_array_size,
+  variable_array_size,
+  invalid_operand_type,
   
   ambigous_types,
   type_missmatch,
@@ -112,6 +116,8 @@ static StringRef getTextForID(DiagID ID) {
   case DiagID::expected_func_kw:
     return "Expected 'func' keyword to at start of function delaration.";
       
+  case DiagID::unexpected_expresssion:
+    return "Unexpected expression outside of a function scope.";
   case DiagID::unexpected_break_stmt:
       return "Unexpected 'break' statement.";
   case DiagID::unexpected_return_stmt:
@@ -120,6 +126,8 @@ static StringRef getTextForID(DiagID ID) {
     return "Expression is not assignable.";
   case DiagID::return_missing_value:
     return "Non-void function must return a value.";
+  case DiagID::array_index_out_of_bounds:
+    return "Indexing array out of array bounds.";
       
   case DiagID::expected_type_annotation:
     return "Expected type annocation ': Type'.";
@@ -139,6 +147,10 @@ static StringRef getTextForID(DiagID ID) {
     return "Array size must be specified as a number literal.";
   case DiagID::expected_array_size:
     return "Every array type must define size of the array.";
+  case DiagID::invalid_operand_type:
+    return "Invalid operand type.";
+  case DiagID::variable_array_size:
+    return "Size of the array must be specified as a constant expression.";
       
   case DiagID::ambigous_types:
     return "Ambigous type resolution.";
diff --git a/include/dusk/AST/Expr.h b/include/dusk/AST/Expr.h
index 0b5c9c9..745ccbc 100644
--- a/include/dusk/AST/Expr.h
+++ b/include/dusk/AST/Expr.h
@@ -53,6 +53,9 @@ class Expr : public ASTNode {
 
   /// Type of declaration
   Type *Ty;
+  
+  /// Bool indicating if the expression was solved.
+  bool Solved;
 
 public:
   Expr(ExprKind K);
@@ -66,7 +69,22 @@ public:
   /// Sets declaration type
   void setType(Type *T) { Ty = T; }
 
-  bool walk(ASTWalker &Walker) override;
+  /// Return \c true if the expression was solved, \c false otherwise.
+  bool getSolved() const { return Solved; }
+  
+  /// Sets the \c Solved state of the expression.
+  void setSolved(bool S) { Solved = S; }
+  
+  virtual Expr *walk(ASTWalker &Walker);
+
+  NumberLiteralExpr *getNumberLiteralExpr();
+  ArrayLiteralExpr *getArrayLiteralExpr();
+  IdentifierExpr *getIdentifierExpr();
+  ParenExpr *getParenExpr();
+  InfixExpr *getInfixExpr();
+  PrefixExpr *getPrefixExpr();
+  CallExpr *getCallExpr();
+  SubscriptExpr *getSubscriptExpr();
 };
 
 /// Number literal expression encalsulation.
@@ -80,6 +98,7 @@ public:
 
   SMRange getValLoc() const { return ValueLoc; }
   int64_t getValue() const { return Value; }
+  void setValue(int64_t Val) { Value = Val; }
 
   SMRange getSourceRange() const override;
 };
diff --git a/include/dusk/AST/Pattern.h b/include/dusk/AST/Pattern.h
index e433ef2..7ae4166 100644
--- a/include/dusk/AST/Pattern.h
+++ b/include/dusk/AST/Pattern.h
@@ -22,6 +22,8 @@ class Expr;
 class Stmt;
 class Type;
 class ParamDecl;
+class ExprPattern;
+class VarPattern;
 class ASTWalker;
 
 /// Pattern description.
@@ -30,25 +32,28 @@ enum struct PatternKind { Expr, Variable };
 class Pattern {
   /// Pattern type.
   PatternKind Kind;
-  
+
   /// Pattern type
   Type *Ty;
 
 public:
   Pattern(PatternKind K);
   PatternKind getKind() const { return Kind; }
-  
+
   virtual size_t count() const = 0;
   virtual SMRange getSourceRange() const = 0;
-  
+
   void setType(Type *T) { Ty = T; }
   Type *getType() const { return Ty; }
-  
+
   SMLoc getLocStart() { return getSourceRange().Start; }
   SMLoc getLocEnd() { return getSourceRange().End; }
-  
+
   bool walk(ASTWalker &Walker);
   
+  ExprPattern *getExprPattern();
+  VarPattern *getVarPattern();
+
 public:
   /// Only allow allocation using \c ASTContext
   void *operator new(size_t Bytes, ASTContext &Context);
diff --git a/include/dusk/AST/Scope.h b/include/dusk/AST/Scope.h
index 6abc5ab..3fa83b2 100644
--- a/include/dusk/AST/Scope.h
+++ b/include/dusk/AST/Scope.h
@@ -100,6 +100,28 @@ public:
   /// Returns statement owning the current scope.
   Stmt *getStmt() const { return S; }
 };
+  
+/// A RAII class representing a push scope change.
+class PushScopeRAII {
+  bool Popped;
+  
+public:
+  /// Previous parent scope.
+  Scope Parent;
+  
+  /// Current scope reference.
+  Scope &Self;
+  
+  PushScopeRAII(Scope &Scp, unsigned Flags, Stmt *S = nullptr);
+  
+  ~PushScopeRAII();
+  
+  /// Returns \c true if scope change has not been popped, \c false otherwise.
+  bool isValid() const { return !Popped; }
+  
+  /// Explicitely pop the scope change.
+  void pop();
+};
 
 } // namespace dusk
 
diff --git a/include/dusk/AST/Stmt.h b/include/dusk/AST/Stmt.h
index 692afee..ed04535 100644
--- a/include/dusk/AST/Stmt.h
+++ b/include/dusk/AST/Stmt.h
@@ -22,6 +22,16 @@ namespace dusk {
 class Decl;
 class Expr;
 class Stmt;
+class BreakStmt;
+class ReturnStmt;
+class SubscriptStmt;
+class RangeStmt;
+class ExternStmt;
+class BlockStmt;
+class FuncStmt;
+class ForStmt;
+class WhileStmt;
+class IfStmt;
 class IdentifierExpr;
 class ASTWalker;
 class ASTContext;
@@ -30,14 +40,14 @@ class ASTContext;
 enum struct StmtKind {
   Break,
   Return,
+  Subscript,
   Range,
   Extern,
   Block,
   Func,
   For,
   While,
-  If,
-  Subscript
+  If
 };
 
 class Stmt : public ASTNode {
@@ -49,7 +59,18 @@ public:
 
   StmtKind getKind() const { return Kind; }
   
-  bool walk(ASTWalker &Walker) override;
+  bool walk(ASTWalker &Walker);
+  
+  BreakStmt *getBreakStmt();
+  ReturnStmt *getReturnStmt();
+  SubscriptStmt *getSubscripStmt();
+  RangeStmt *getRangeStmt();
+  ExternStmt *getExternStmt();
+  BlockStmt *getBlockStmt();
+  FuncStmt *getFuncStmt();
+  ForStmt *getForStmt();
+  WhileStmt *getWhileStmt();
+  IfStmt *getIfStmt();
 };
 
 /// Represents a \c break statement in a loop.
diff --git a/include/dusk/AST/Type.h b/include/dusk/AST/Type.h
index ec4c237..fb731df 100644
--- a/include/dusk/AST/Type.h
+++ b/include/dusk/AST/Type.h
@@ -26,7 +26,7 @@ class FunctionType;
 class PatternType;
 class ArrayType;
 class ASTContext;
-  
+
 enum struct TypeKind;
 
 enum struct TypeKind { Void, Int, Value, Pattern, Array, Function };
@@ -43,16 +43,17 @@ public:
   virtual bool isValueType() const { return false; }
   virtual bool isVoidType() const { return false; }
   virtual bool isClassOf(const Type *T) const { return this == T; }
-  
+
   VoidType *getVoidType();
   IntType *getIntType();
+  PatternType *getPatternType();
   FunctionType *getFuncType();
   ArrayType *getArrayType();
-  
+
 private:
   void *operator new(size_t Bytes) throw() = delete;
   void operator delete(void *Data) throw() = delete;
-  
+
 public:
   /// Only allow allocation using \c ASTContext
   void *operator new(size_t Bytes, ASTContext &Context);
@@ -87,18 +88,18 @@ public:
     return T->getKind() == TypeKind::Int;
   }
 };
-  
+
 /// Representing array type
 class ArrayType : public ValueType {
   Type *BaseTy;
   size_t Size;
-  
+
 public:
   ArrayType(Type *Ty, size_t S);
-  
+
   Type *getBaseType() const { return BaseTy; }
   size_t getSize() const { return Size; }
-  
+
   bool isClassOf(const Type *T) const  override {
     if (Type::isClassOf(T))
       return true;
@@ -106,7 +107,7 @@ public:
       return isClassOf(Ty);
     return false;
   }
-  
+
   bool isClassOf(const ArrayType *T) const;
 };
 
@@ -119,7 +120,7 @@ public:
   FunctionType(Type *AT, Type *RT);
   Type *getArgsType() const { return ArgsTy; }
   Type *getRetType() const { return RetTy; }
-  
+
   bool isClassOf(const Type *T) const override {
     if (Type::isClassOf(T))
       return true;
@@ -127,7 +128,7 @@ public:
       return isClassOf(Ty);
     return false;
   }
-  
+
   bool isClassOf(const FunctionType *T) const;
 };
 
@@ -138,7 +139,7 @@ public:
   PatternType(SmallVector<Type *, 128> &&I);
 
   ArrayRef<Type *> getItems() const { return Items; }
-  
+
   bool isClassOf(const Type *T) const override {
     if (Type::isClassOf(T))
       return true;
diff --git a/include/dusk/AST/TypeRepr.h b/include/dusk/AST/TypeRepr.h
index 9529f34..a365632 100644
--- a/include/dusk/AST/TypeRepr.h
+++ b/include/dusk/AST/TypeRepr.h
@@ -19,6 +19,8 @@ namespace dusk {
 class Expr;
 class Stmt;
 class Type;
+class IdentTypeRepr;
+class ArrayTypeRepr;
 class ASTWalker;
 class ASTContext;
 
@@ -26,25 +28,28 @@ enum struct TypeReprKind {
   Ident,
   Array
 };
-  
+
 class TypeRepr {
   TypeReprKind Kind;
-  
+
   Type *Ty;
-  
+
 public:
   TypeRepr(TypeReprKind K);
-  
+
   TypeReprKind getKind() const { return Kind; }
   SMLoc getLocStart() const { return getSourceRange().Start; }
   SMLoc getLocEnd() const { return getSourceRange().End; }
   virtual SMRange getSourceRange() const = 0;
-  
+
   Type *getType() const { return Ty; }
   void setType(Type *T) { Ty = T; }
-  
+
   bool walk(ASTWalker &Walker);
-  
+
+  IdentTypeRepr *getIdentTypeRepr();
+  ArrayTypeRepr *getArrayTypeRepr();
+
 public:
   /// Only allow allocation using \c ASTContext
   void *operator new(size_t Bytes, ASTContext &Context);
@@ -55,12 +60,12 @@ public:
 class IdentTypeRepr : public TypeRepr {
   /// Type identifier
   StringRef Ident;
-  
+
 public:
   IdentTypeRepr(StringRef ID);
-  
+
   StringRef getIdent() const { return Ident; }
-  
+
   SMRange getSourceRange() const override;
 };
 
@@ -68,19 +73,19 @@ public:
 class ArrayTypeRepr : public TypeRepr {
   /// Base type of array.
   TypeRepr *BaseTyRepr;
-  
+
   /// Array size specifier.
   Stmt *Size;
-  
+
 public:
   ArrayTypeRepr(TypeRepr *B, Stmt *S);
-  
+
   TypeRepr *getBaseTyRepr() const { return BaseTyRepr; }
   Stmt *getSize() const { return Size; }
-  
+
   SMRange getSourceRange() const override;
 };
-  
+
 } // namespace dusk
 
 #endif /* DUSK_TYPE_REPR_H */
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7ada432..e46062a 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1,4 +1,3 @@
-
 //===--- ASTContext.cpp ---------------------------------------------------===//
 //
 //                                 dusk-lang
@@ -26,7 +25,7 @@ void *ASTContext::Allocate(size_t Bytes) {
   if (Bytes == 0)
     return nullptr;
 
-  auto Res = new size_t[Bytes];
+  auto Res = new uint8_t[Bytes];
   Cleanups.push_back([Res] { delete[] Res; });
 
   return static_cast<void *>(Res);
diff --git a/lib/AST/ASTNode.cpp b/lib/AST/ASTNode.cpp
index 2c3174a..65db039 100644
--- a/lib/AST/ASTNode.cpp
+++ b/lib/AST/ASTNode.cpp
@@ -26,7 +26,7 @@ bool ASTNode::walk(ASTWalker &Walker) {
     return D->walk(Walker);
   
   else if (auto E = dynamic_cast<Expr *>(this))
-    return E->walk(Walker);
+    return E->walk(Walker) != nullptr;
   
   else if (auto S = dynamic_cast<Stmt *>(this))
     return S->walk(Walker);
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 99a4793..23180da 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -38,7 +38,7 @@ public:
 
   // MARK: - Declaration nodes
 
-  bool visitModuleDecl(ModuleDecl *D) {
+  void visitModuleDecl(ModuleDecl *D) {
     Printer.printText(D->getName());
     Printer.printNewline();
 
@@ -60,10 +60,9 @@ public:
         Printer.printText(";");
     }
     Printer.printNewline();
-    return true;
   }
 
-  bool visitLetDecl(LetDecl *D) {
+  void visitLetDecl(LetDecl *D) {
     Printer.printDeclPre(D);
     Printer << D->getName();
     
@@ -77,10 +76,9 @@ public:
       super::visit(D->getValue());
     }
     Printer.printDeclPost(D);
-    return true;
   }
 
-  bool visitVarDecl(VarDecl *D) {
+  void visitVarDecl(VarDecl *D) {
     Printer.printDeclPre(D);
     Printer << D->getName();
     
@@ -94,10 +92,9 @@ public:
       super::visit(D->getValue());
     }
     Printer.printDeclPost(D);
-    return true;
   }
 
-  bool visitFuncDecl(FuncDecl *D) {
+  void visitFuncDecl(FuncDecl *D) {
     Printer.printDeclPre(D);
     Printer << D->getName() << "(";
     super::visit(D->getArgs());
@@ -109,108 +106,94 @@ public:
     }
     
     Printer.printDeclPost(D);
-    return true;
   }
 
-  bool visitParamDecl(ParamDecl *D) {
+  void visitParamDecl(ParamDecl *D) {
     Printer.printDeclPost(D);
     Printer << D->getName() << ": ";
     if (D->hasTypeRepr())
       super::visit(D->getTypeRepr());
     Printer.printDeclPost(D);
-    return true;
   }
 
   // MARK: - Expression nodes
 
-  Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) {
+  void visitNumberLiteralExpr(NumberLiteralExpr *E) {
     auto St = E->getLocStart().getPointer();
     auto En = E->getLocEnd().getPointer();
     StringRef Str = {St, (size_t)(En - St)};
     Printer << Str;
-    return E;
   }
   
-  Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) {
+  void visitArrayLiteralExpr(ArrayLiteralExpr *E) {
     Printer << "[";
     super::visit(E->getValues());
     Printer << "]";
-    return E;
   }
   
-  Expr *visitIdentifierExpr(IdentifierExpr *E) {
+  void visitIdentifierExpr(IdentifierExpr *E) {
     Printer << E->getName();
-    return E;
   }
 
-  Expr *visitParenExpr(ParenExpr *E) {
+  void visitParenExpr(ParenExpr *E) {
     Printer << "(";
     super::visit(E->getExpr());
     Printer << ")";
-    return E;
   }
 
-  Expr *visitAssignExpr(AssignExpr *E) {
+  void visitAssignExpr(AssignExpr *E) {
     super::visit(E->getDest());
     Printer << " " << tok::assign << " ";
     super::visit(E->getSource());
-    return E;
   }
 
-  Expr *visitCallExpr(CallExpr *E) {
+  void visitCallExpr(CallExpr *E) {
     super::visit(E->getCallee());
     Printer << "(";
     super::visit(E->getArgs());
     Printer << ")";
-    return E;
   }
 
-  Expr *visitInfixExpr(InfixExpr *E) {
+  void visitInfixExpr(InfixExpr *E) {
     super::visit(E->getLHS());
     Printer << " " << E->getOp().getKind() << " ";
     super::visit(E->getRHS());
-    return E;
   }
 
-  Expr *visitPrefixExpr(PrefixExpr *E) {
+  void visitPrefixExpr(PrefixExpr *E) {
     Printer << E->getOp().getKind();
     super::visit(E->getDest());
-    return E;
   }
 
-  Expr *visitSubscriptExpr(SubscriptExpr *E) {
+  void visitSubscriptExpr(SubscriptExpr *E) {
     super::visit(E->getBase());
     super::visit(E->getSubscript());
-    return E;
   }
 
   // MARK: - Statement nodes
 
-  bool visitBreakStmt(BreakStmt *S) {
+  void visitBreakStmt(BreakStmt *S) {
     Printer.printStmtPre(S);
     Printer << tok::kwBreak;
     Printer.printStmtPost(S);
-    return true;
   }
 
-  bool visitReturnStmt(ReturnStmt *S) {
+  void visitReturnStmt(ReturnStmt *S) {
     Printer.printStmtPre(S);
 
     Printer << tok::kwReturn << " ";
     super::visit(S->getValue());
 
     Printer.printStmtPost(S);
-    return true;
   }
 
-  bool visitSubscriptStmt(SubscriptStmt *S) {
+  void visitSubscriptStmt(SubscriptStmt *S) {
     Printer.printStmtPre(S);
     super::visit(S->getValue());
     Printer.printStmtPost(S);
-    return true;
   }
 
-  bool visitRangeStmt(RangeStmt *S) {
+  void visitRangeStmt(RangeStmt *S) {
     Printer.printStmtPre(S);
     super::visit(S->getStart());
 
@@ -218,10 +201,9 @@ public:
     
     super::visit(S->getEnd());
     Printer.printStmtPost(S);
-    return true;
   }
 
-  bool visitBlockStmt(BlockStmt *S) {
+  void visitBlockStmt(BlockStmt *S) {
     Printer.printStmtPre(S);
     bool IsFirst = true;
     for (auto N : S->getNodes()) {
@@ -245,53 +227,48 @@ public:
         Printer.printText(";");
     }
     Printer.printStmtPost(S);
-    return true;
   }
 
-  bool visitExternStmt(ExternStmt *S) {
+  void visitExternStmt(ExternStmt *S) {
     Printer.printStmtPre(S);
     Printer << tok::kwExtern << " ";
     super::visit(S->getPrototype());
     Printer.printStmtPost(S);
-    return true;
   }
   
-  bool visitFuncStmt(FuncStmt *S) {
+  void visitFuncStmt(FuncStmt *S) {
     Printer.printStmtPre(S);
     super::visit(S->getPrototype());
     Printer << " ";
     super::visit(S->getBody());
     Printer.printStmtPost(S);
-    return true;
   }
   
-  bool visitForStmt(ForStmt *S) {
+  void visitForStmt(ForStmt *S) {
     Printer.printStmtPre(S);
 
     Printer << tok::kwFor << " ";
     super::visit(S->getIter());
     Printer << " " << tok::kwIn << " ";
-    super::visit_(S->getRange());
+    super::visit(S->getRange());
     Printer << " ";
     super::visit(S->getBody());
 
     Printer.printStmtPost(S);
-    return true;
   }
 
-  bool visitWhileStmt(WhileStmt *S) {
+  void visitWhileStmt(WhileStmt *S) {
     Printer.printStmtPre(S);
     Printer << tok::kwWhile << " ";
     
-    super::visit_(S->getCond());
+    super::visit(S->getCond());
     Printer << " ";
     super::visit(S->getBody());
     
     Printer.printStmtPost(S);
-    return true;
   }
   
-  bool visitIfStmt(IfStmt *S) {
+  void visitIfStmt(IfStmt *S) {
     Printer.printStmtPre(S);
     Printer << tok::kwIf << " ";
 
@@ -305,40 +282,35 @@ public:
     }
 
     Printer.printStmtPost(S);
-    return true;
   }
 
   // MARK: - Pattern nodes
 
-  bool visitExprPattern(ExprPattern *P) {
+  void visitExprPattern(ExprPattern *P) {
     bool isFirst = true;
     for (auto V : P->getValues()) {
       Printer.printSeparator(isFirst, ", ");
       super::visit(V);
     }
-    return true;
   }
 
-  bool visitVarPattern(VarPattern *P) {
+  void visitVarPattern(VarPattern *P) {
     bool isFirst = true;
     for (auto V : P->getVars()) {
       Printer.printSeparator(isFirst, ", ");
       super::visit(V);
     }
-    return true;
   }
   
   // MARK: - Type representations
   
-  bool visitIdentTypeRepr(IdentTypeRepr *T) {
+  void visitIdentTypeRepr(IdentTypeRepr *T) {
     Printer << T->getIdent();
-    return true;
   }
   
-  bool visitArrayTypeRepr(ArrayTypeRepr *T) {
+  void visitArrayTypeRepr(ArrayTypeRepr *T) {
     super::visit(T->getBaseTyRepr());
     super::visit(T->getSize());
-    return true;
   }
 };
 
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index c5b3686..3b1ba47 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -34,22 +34,27 @@ namespace {
 /// This class implements recursive AST node traversal. It uses user-provided
 /// instance of \c ASTWalker of any class derived from it to actually walk
 /// each and every node of the AST.
-class Traversal : public ASTVisitor<Traversal> {
+class Traversal : public ASTVisitor<Traversal,
+                                    /* Decl */ bool,
+                                    /* Expr */ Expr *,
+                                    /* Stmt */ bool,
+                                    /* Pattern */ bool,
+                                    /* TypeRepr */ bool> {
   /// Walker to be used to walk the tree.
   ASTWalker &Walker;
 
   /// Convenience type alias.
   typedef ASTVisitor super;
-  
+
   friend super;
-  
+
   // MARK: - Declarations
-  
+
   bool visitLetDecl(LetDecl *D) {
     if (D->hasTypeRepr())
       if (!traverse(D->getTypeRepr()))
         return false;
-    
+
     if (D->hasValue()) {
       auto E = traverse(D->getValue());
       if (!E)
@@ -58,12 +63,12 @@ class Traversal : public ASTVisitor<Traversal> {
     }
     return true;
   }
-  
+
   bool visitVarDecl(VarDecl *D) {
     if (D->hasTypeRepr())
       if (!traverse(D->getTypeRepr()))
         return false;
-    
+
     if (D->hasValue()) {
       auto E = traverse(D->getValue());
       if (!E)
@@ -72,51 +77,47 @@ class Traversal : public ASTVisitor<Traversal> {
     }
     return true;
   }
-  
+
   bool visitParamDecl(ParamDecl *D) {
     return !D->hasTypeRepr() || traverse(D->getTypeRepr());
   }
-  
+
   bool visitFuncDecl(FuncDecl *D) {
     if (!traverse(D->getArgs()))
       return false;
     return !D->hasTypeRepr() || traverse(D->getTypeRepr());
   }
-  
+
   bool visitModuleDecl(ModuleDecl *D) {
     for (auto &N : D->getContents()) {
       if (auto D = dynamic_cast<Decl *>(N))
         if (!traverse(D))
           return false;
-      
+
       if (auto E = dynamic_cast<Expr *>(N))
         if ((N = traverse(E)) == nullptr)
           return false;
-      
+
       if (auto S = dynamic_cast<Stmt *>(N))
         if (!traverse(S))
           return false;
     }
     return true;
   }
-  
+
   // MARK: - Expressions
-  
-  Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) {
-    return E;
-  }
-  
+
+  Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) { return E; }
+
   Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) {
     if (E->getValues())
       return E;
     else
       return nullptr;
   }
-  
-  Expr *visitIdentifierExpr(IdentifierExpr *E) {
-    return E;
-  }
-  
+
+  Expr *visitIdentifierExpr(IdentifierExpr *E) { return E; }
+
   Expr *visitParenExpr(ParenExpr *E) {
     if (auto Ex = traverse(E->getExpr()))
       E->setExpr(Ex);
@@ -124,7 +125,7 @@ class Traversal : public ASTVisitor<Traversal> {
       return nullptr;
     return E;
   }
-  
+
   Expr *visitInfixExpr(InfixExpr *E) {
     auto Ex = traverse(E->getLHS());
     if (!Ex)
@@ -136,7 +137,7 @@ class Traversal : public ASTVisitor<Traversal> {
     E->setRHS(Ex);
     return E;
   }
-  
+
   Expr *visitAssignExpr(AssignExpr *E) {
     auto Ex = traverse(E->getDest());
     if (!Ex)
@@ -148,7 +149,7 @@ class Traversal : public ASTVisitor<Traversal> {
     E->setSource(Ex);
     return E;
   }
-  
+
   Expr *visitPrefixExpr(PrefixExpr *E) {
     if (auto Ex = traverse(E->getDest()))
       E->setDest(Ex);
@@ -156,35 +157,33 @@ class Traversal : public ASTVisitor<Traversal> {
       return nullptr;
     return E;
   }
-  
+
   Expr *visitCallExpr(CallExpr *E) {
     if (auto Ex = traverse(E->getCallee()))
       E->setCallee(Ex);
     else
       return nullptr;
-    
+
     if (!traverse(E->getArgs()))
       return nullptr;
     return E;
   }
-  
+
   Expr *visitSubscriptExpr(SubscriptExpr *E) {
     if (auto Ex = traverse(E->getBase()))
       E->setBase(Ex);
     else
       return nullptr;
-    
+
     if (!traverse(E->getSubscript()))
       return nullptr;
     return E;
   }
-  
+
   // MAKR: - Statements
-  
-  bool visitBreakStmt(BreakStmt *S) {
-    return true;
-  }
-  
+
+  bool visitBreakStmt(BreakStmt *S) { return true; }
+
   bool visitReturnStmt(ReturnStmt *S) {
     if (S->hasValue()) {
       if (auto Val = traverse(S->getValue()))
@@ -194,7 +193,7 @@ class Traversal : public ASTVisitor<Traversal> {
     }
     return true;
   }
-  
+
   bool visitSubscriptStmt(SubscriptStmt *S) {
     if (auto Val = traverse(S->getValue()))
       S->setValue(Val);
@@ -202,51 +201,49 @@ class Traversal : public ASTVisitor<Traversal> {
       return false;
     return true;
   }
-  
+
   bool visitRangeStmt(RangeStmt *S) {
     auto Val = traverse(S->getStart());
     if (!Val)
       return false;
     S->setStart(Val);
-    
+
     Val = traverse(S->getEnd());
     if (!Val)
       return false;
     S->setEnd(Val);
     return true;
   }
-  
+
   bool visitBlockStmt(BlockStmt *S) {
     for (auto &N : S->getNodes()) {
       if (auto D = dynamic_cast<Decl *>(N)) {
         if (!traverse(D))
           return false;
-      
+
       } else if (auto E = dynamic_cast<Expr *>(N)) {
         if ((N = traverse(E)) == nullptr)
           return false;
-      
+
       } else if (auto S = dynamic_cast<Stmt *>(N)) {
         if (!traverse(S))
           return false;
-        
+
       } else {
         llvm_unreachable("Unexpected AST node.");
       }
     }
     return true;
   }
-  
-  bool visitExternStmt(ExternStmt *S) {
-    return traverse(S->getPrototype());
-  }
-  
+
+  bool visitExternStmt(ExternStmt *S) { return traverse(S->getPrototype()); }
+
   bool visitFuncStmt(FuncStmt *S) {
     if (!traverse(S->getPrototype()))
       return false;
     return traverse(S->getBody());
   }
-  
+
   bool visitForStmt(ForStmt *S) {
     if (!traverse(S->getIter()))
       return false;
@@ -254,7 +251,7 @@ class Traversal : public ASTVisitor<Traversal> {
       return false;
     return traverse(S->getBody());
   }
-  
+
   bool visitWhileStmt(WhileStmt *S) {
     if (auto C = traverse(S->getCond()))
       S->setCond(C);
@@ -262,7 +259,7 @@ class Traversal : public ASTVisitor<Traversal> {
       return false;
     return traverse(S->getBody());
   }
-  
+
   bool visitIfStmt(IfStmt *S) {
     if (auto C = traverse(S->getCond()))
       S->setCond(C);
@@ -272,9 +269,9 @@ class Traversal : public ASTVisitor<Traversal> {
       return false;
     return !S->hasElseBlock() || traverse(S->getElse());
   }
-  
+
   // MARK: - Patterns
-  
+
   bool visitExprPattern(ExprPattern *P) {
     for (auto &E : P->getValues()) {
       if (auto Val = traverse(E))
@@ -284,63 +281,61 @@ class Traversal : public ASTVisitor<Traversal> {
     }
     return true;
   }
-  
+
   bool visitVarPattern(VarPattern *P) {
     for (auto Var : P->getVars())
       if (!traverse(Var))
         return false;
     return false;
   }
-  
+
   // MARK: - Type representations
-  
-  bool visitIdentTypeRepr(IdentTypeRepr *TR) {
-    return true;
-  }
-  
+
+  bool visitIdentTypeRepr(IdentTypeRepr *TR) { return true; }
+
   bool visitArrayTypeRepr(ArrayTypeRepr *TR) {
     if (!traverse(TR->getBaseTyRepr()))
       return false;
     return traverse(TR->getSize());
   }
-  
+
 public:
   /// Constructs a basic traversal object.
   Traversal(ASTWalker &W) : Walker(W) {}
-  
+
   bool traverse(Decl *D) {
     // Skip current subtree
     if (!Walker.preWalkDecl(D))
       return true;
     if (!super::visit(D))
       return false;
-    
+
     return Walker.postWalkDecl(D);
   }
-  
+
   Expr *traverse(Expr *E) {
     auto Pre = Walker.preWalkExpr(E);
     // Skip current subtree
     if (!Pre.first || !Pre.second)
       return Pre.second;
-    
+
     E = super::visit(E);
-    
+
     if (E)
       E = Walker.postWalkExpr(E);
     return E;
   }
-  
+
   bool traverse(Stmt *S) {
     // Skip current subtree
     if (!Walker.preWalkStmt(S))
       return true;
     if (!super::visit(S))
       return false;
-    
+
     return Walker.postWalkStmt(S);
   }
-  
+
   bool traverse(Pattern *P) {
     // Skip current subtree
     if (!Walker.preWalkPattern(P))
@@ -349,295 +344,15 @@ public:
       return false;
     return Walker.postWalkPattern(P);
   }
-  
+
   bool traverse(TypeRepr *TR) {
     // Skip current subtree
     if (!Walker.preWalkTypeRepr(TR))
       return true;
     if (!super::visit(TR))
       return false;
-    
-    return Walker.postWalkTypeRepr(TR);
-  }
-  
-  // MARK: - Declaration nodes
-
-  bool visit(LetDecl *D) {
-    // Skip current subtree
-    if (!Walker.preWalk(D))
-      return true;
-
-    if (!super::visit_(D->getValue()))
-      return false;
-    return Walker.postWalk(D);
-  }
-
-  bool visit(FuncDecl *D) {
-    // Skip subtree
-    if (!Walker.preWalk(D))
-      return true;
-
-    if (!super::visit_(D->getArgs()))
-      return false;
-    return Walker.postWalk(D);
-  }
-
-  bool visit(ModuleDecl *D) {
-    if (!Walker.preWalk(D))
-      return true;
-
-    for (auto C : D->getContents())
-      if (!super::visit_(C))
-        return false;
-    return Walker.postWalk(D);
-  }
-
-  bool visit(ParamDecl *D) {
-    // Skip subtree
-    if (!Walker.preWalk(D))
-      return true;
-
-    return Walker.postWalk(D);
-  }
-
-  bool visit(VarDecl *D) {
-    // Skip subtree
-    if (!Walker.preWalk(D))
-      return true;
-    
-    if (D->hasValue() && !super::visit_(D->getValue()))
-      return false;
-    return Walker.postWalk(D);
-  }
-
-  // MARK: - Expression nodes
-
-  bool visit(NumberLiteralExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-    return Walker.postWalk(E);
-  }
-
-  bool visit(ArrayLiteralExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-    if (!super::visit_(E->getValues()))
-      return false;
-    return Walker.postWalk(E);
-  }
-  
-  bool visit(IdentifierExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    return Walker.postWalk(E);
-  }
-
-  bool visit(ParenExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    if (!super::visit_(E->getExpr()))
-      return false;
-    return Walker.postWalk(E);
-  }
-
-  bool visit(AssignExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    if (!super::visit_(E->getDest()))
-      return false;
-    if (!super::visit_(E->getSource()))
-      return false;
-    return Walker.postWalk(E);
-  }
-
-  bool visit(InfixExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    if (!super::visit_(E->getLHS()))
-      return false;
-    if (!super::visit_(E->getRHS()))
-      return false;
-    return Walker.postWalk(E);
-  }
-
-  bool visit(PrefixExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    if (!super::visit_(E->getDest()))
-      return false;
-    return Walker.postWalk(E);
-  }
-
-  bool visit(CallExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    if (!super::visit_(E->getCallee()))
-      return false;
-    if (!super::visit_(E->getArgs()))
-      return false;
-    return Walker.postWalk(E);
-  }
 
-  bool visit(SubscriptExpr *E) {
-    // Skip subtree
-    if (!Walker.preWalk(E))
-      return true;
-
-    if (!super::visit_(E->getBase()))
-      return false;
-    if (!super::visit_(E->getSubscript()))
-      return false;
-    return Walker.postWalk(E);
-  }
-
-  // MARK: - Statement nodes
-
-  bool visit(BreakStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-    return Walker.postWalk(S);
-  }
-
-  bool visit(ReturnStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-
-    if (S->hasValue() && !super::visit_(S->getValue()))
-      return false;
-    return Walker.postWalk(S);
-  }
-
-  bool visit(RangeStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return false;
-
-    if (!super::visit_(S->getStart()))
-      return false;
-    if (!super::visit_(S->getEnd()))
-      return false;
-    return Walker.postWalk(S);
-  }
-  
-  bool visit(SubscriptStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-    
-    if (!super::visit_(S->getValue()))
-      return false;
-    return Walker.postWalk(S);
-  }
-
-  bool visit(BlockStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-
-    for (auto N : S->getNodes())
-      if (!super::visit_(N))
-        return false;
-    return Walker.postWalk(S);
-  }
-
-  bool visit(ExternStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-    
-    if (!super::visit_(S->getPrototype()))
-      return false;
-    return Walker.postWalk(S);
-  }
-  
-  bool visit(FuncStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-    
-    if (!super::visit_(S->getPrototype()))
-      return false;
-    if (!super::visit_(S->getBody()))
-      return false;
-    return Walker.postWalk(S);
-  }
-  
-  bool visit(ForStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return false;
-
-    if (!super::visit_(S->getRange()))
-      return false;
-    if (!super::visit_(S->getBody()))
-      return false;
-    return Walker.postWalk(S);
-  }
-
-  bool visit(IfStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-
-    if (!super::visit_(S->getCond()))
-      return false;
-    if (!super::visit_(S->getThen()))
-      return false;
-    if (S->hasElseBlock() && !super::visit_(S->getElse()))
-      return false;
-    return Walker.postWalk(S);
-  }
-
-  bool visit(WhileStmt *S) {
-    // Skip subtree
-    if (!Walker.preWalk(S))
-      return true;
-
-    if (!super::visit_(S->getCond()))
-      return false;
-    if (!super::visit_(S->getBody()))
-      return false;
-    return Walker.postWalk(S);
-  }
-
-  // MARK: - Patterns
-
-  bool visit(ExprPattern *P) {
-    // Skip subtree
-    if (!Walker.preWalk(P))
-      return true;
-
-    for (auto V : P->getValues())
-      if (!super::visit_(V))
-        return false;
-    return Walker.postWalk(P);
-  }
-
-  bool visit(VarPattern *P) {
-    // Skip subtree
-    if (!Walker.preWalk(P))
-      return true;
-
-    for (auto V : P->getVars())
-      if (!super::visit_(V))
-        return false;
-    return Walker.postWalk(P);
+    return Walker.postWalkTypeRepr(TR);
   }
 };
 
@@ -645,17 +360,13 @@ public:
 
 // MARK: - Basic ASTNodes implementations
 
-bool Decl::walk(ASTWalker &Walker) {
-  return Traversal(Walker).traverse(this);
-}
+bool Decl::walk(ASTWalker &Walker) { return Traversal(Walker).traverse(this); }
 
-bool Expr::walk(ASTWalker &Walker) {
-    return Traversal(Walker).traverse(this) != nullptr;
+Expr *Expr::walk(ASTWalker &Walker) {
+  return Traversal(Walker).traverse(this);
 }
 
-bool Stmt::walk(ASTWalker &Walker) {
-    return Traversal(Walker).traverse(this);
-}
+bool Stmt::walk(ASTWalker &Walker) { return Traversal(Walker).traverse(this); }
 
 bool Pattern::walk(ASTWalker &Walker) {
   return Traversal(Walker).traverse(this);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 7c68718..60a1854 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -20,6 +20,26 @@ using namespace dusk;
 Decl::Decl(DeclKind K, StringRef N, SMLoc NL)
     : Kind(K), Name(N), NameLoc(NL), Ty(nullptr), TyRepr(nullptr) {}
 
+VarDecl *Decl::getVarDecl() {
+  assert(Kind == DeclKind::Var && "Invalid Decl convertion");
+  return static_cast<VarDecl *>(this);
+}
+
+LetDecl *Decl::getLetDecl() {
+  assert(Kind == DeclKind::Let && "Invalid Decl convertion");
+  return static_cast<LetDecl *>(this);
+}
+
+ParamDecl *Decl::getParamDecl() {
+  assert(Kind == DeclKind::Param && "Invalid Decl convertion");
+  return static_cast<ParamDecl *>(this);
+}
+
+FuncDecl *Decl::getFuncDecl() {
+  assert(Kind == DeclKind::Func && "Invalid Decl convertion");
+  return static_cast<FuncDecl *>(this);
+}
+
 Decl::Decl(DeclKind K, StringRef N, SMLoc NL, TypeRepr *TR) : Decl(K, N, NL) {
   TyRepr = TR;
 }
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 1fd4432..24b06f8 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -16,7 +16,47 @@
 
 using namespace dusk;
 
-Expr::Expr(ExprKind K) : Kind(K), Ty(nullptr) {}
+Expr::Expr(ExprKind K) : Kind(K), Ty(nullptr), Solved(false) {}
+
+NumberLiteralExpr *Expr::getNumberLiteralExpr() {
+  assert(Kind == ExprKind::NumberLiteral && "Invalid Expr convertion");
+  return static_cast<NumberLiteralExpr *>(this);
+}
+
+ArrayLiteralExpr *Expr::getArrayLiteralExpr() {
+  assert(Kind == ExprKind::ArrayLiteral && "Invalid Expr convertion");
+  return static_cast<ArrayLiteralExpr *>(this);
+}
+
+IdentifierExpr *Expr::getIdentifierExpr() {
+  assert(Kind == ExprKind::Identifier && "Invalid Expr convertion");
+  return static_cast<IdentifierExpr *>(this);
+}
+
+ParenExpr *Expr::getParenExpr() {
+  assert(Kind == ExprKind::Paren && "Invalid Expr convertion");
+  return static_cast<ParenExpr *>(this);
+}
+
+InfixExpr *Expr::getInfixExpr() {
+  assert(Kind == ExprKind::Infix && "Invalid Expr convertion");
+  return static_cast<InfixExpr *>(this);
+}
+
+PrefixExpr *Expr::getPrefixExpr() {
+  assert(Kind == ExprKind::Prefix && "Invalid Expr convertion");
+  return static_cast<PrefixExpr *>(this);
+}
+
+CallExpr *Expr::getCallExpr() {
+  assert(Kind == ExprKind::Call && "Invalid Expr convertion");
+  return static_cast<CallExpr *>(this);
+}
+
+SubscriptExpr *Expr::getSubscriptExpr() {
+  assert(Kind == ExprKind::Subscript && "Invalid Expr convertion");
+  return static_cast<SubscriptExpr *>(this);
+}
 
 // MARK: - Number literal expresssion
 
diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp
index 8f230a1..d7e68c0 100644
--- a/lib/AST/Pattern.cpp
+++ b/lib/AST/Pattern.cpp
@@ -18,6 +18,16 @@ using namespace dusk;
 
 Pattern::Pattern(PatternKind K) : Kind(K), Ty(nullptr) {}
 
+ExprPattern *Pattern::getExprPattern() {
+  assert(Kind == PatternKind::Expr && "Invalid Pattern convertion");
+  return static_cast<ExprPattern *>(this);
+}
+
+VarPattern *Pattern::getVarPattern() {
+  assert(Kind == PatternKind::Variable && "Invalid Pattern convertion");
+  return static_cast<VarPattern *>(this);
+}
+
 void *Pattern::operator new(size_t Bytes, ASTContext &Context) {
   return Context.Allocate(Bytes);
 }
diff --git a/lib/AST/Scope.cpp b/lib/AST/Scope.cpp
index 74b420e..c7ad2d5 100644
--- a/lib/AST/Scope.cpp
+++ b/lib/AST/Scope.cpp
@@ -24,3 +24,21 @@ Scope::Scope(Scope *P, unsigned SF, Stmt *S)
   ControlParent =
       Parent->isControlScope() ? Parent : Parent->getControlParent();
 }
+
+// MARK: - Scope change
+
+PushScopeRAII::PushScopeRAII(Scope &Scp, unsigned Flags, Stmt *S)
+    : Popped(false), Parent(Scp), Self(Scp) {
+  Self = Scope(&Parent, Flags, S);
+}
+
+PushScopeRAII::~PushScopeRAII() {
+  if (!Popped)
+    Self = Parent;
+}
+
+void PushScopeRAII::pop() {
+  assert(isValid() && "Popping already popped scope.");
+  Self = Parent;
+  Popped = true;
+}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index d0e8562..93a5f47 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -16,6 +16,56 @@ using namespace dusk;
 
 Stmt::Stmt(StmtKind K) : Kind(K) {}
 
+BreakStmt *Stmt::getBreakStmt() {
+  assert(Kind == StmtKind::Break && "Invalid Stmt conversion");
+  return static_cast<BreakStmt *>(this);
+}
+
+ReturnStmt *Stmt::getReturnStmt() {
+  assert(Kind == StmtKind::Return && "Invalid Stmt conversion");
+  return static_cast<ReturnStmt *>(this);
+}
+
+SubscriptStmt *Stmt::getSubscripStmt() {
+  assert(Kind == StmtKind::Subscript && "Invalid Stmt conversion");
+  return static_cast<SubscriptStmt *>(this);
+}
+
+RangeStmt *Stmt::getRangeStmt() {
+  assert(Kind == StmtKind::Range && "Invalid Stmt conversion");
+  return static_cast<RangeStmt *>(this);
+}
+
+ExternStmt *Stmt::getExternStmt() {
+  assert(Kind == StmtKind::Extern && "Invalid Stmt conversion");
+  return static_cast<ExternStmt *>(this);
+}
+
+BlockStmt *Stmt::getBlockStmt() {
+  assert(Kind == StmtKind::Block && "Invalid Stmt conversion");
+  return static_cast<BlockStmt *>(this);
+}
+
+FuncStmt *Stmt::getFuncStmt() {
+  assert(Kind == StmtKind::Func && "Invalid Stmt conversion");
+  return static_cast<FuncStmt *>(this);
+}
+
+ForStmt *Stmt::getForStmt() {
+  assert(Kind == StmtKind::For && "Invalid Stmt conversion");
+  return static_cast<ForStmt *>(this);
+}
+
+WhileStmt *Stmt::getWhileStmt() {
+  assert(Kind == StmtKind::While && "Invalid Stmt conversion");
+  return static_cast<WhileStmt *>(this);
+}
+
+IfStmt *Stmt::getIfStmt() {
+  assert(Kind == StmtKind::If && "Invalid Stmt conversion");
+  return static_cast<IfStmt *>(this);
+}
+
 // MARK: - Break statement
 
 BreakStmt::BreakStmt(SMRange BL) : Stmt(StmtKind::Break), BreakLoc(BL) {}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index fe382a6..a5a6274 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -22,14 +22,22 @@ VoidType *Type::getVoidType() {
   assert(Kind == TypeKind::Void && "Accessing invalid type.");
   return static_cast<VoidType *>(this);
 }
+
 IntType *Type::getIntType() {
   assert(Kind == TypeKind::Int && "Accessing invalid type.");
   return static_cast<IntType *>(this);
 }
+
+PatternType *Type::getPatternType() {
+  assert(Kind == TypeKind::Pattern && "Accessing invalid type.");
+  return static_cast<PatternType *>(this);
+}
+
 FunctionType *Type::getFuncType() {
   assert(Kind == TypeKind::Function && "Accessing invalid type.");
   return static_cast<FunctionType *>(this);
 }
+
 ArrayType *Type::getArrayType() {
   assert(Kind == TypeKind::Array && "Accessing invalid type.");
   return static_cast<ArrayType *>(this);
diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp
index df2af22..e14eda2 100644
--- a/lib/AST/TypeRepr.cpp
+++ b/lib/AST/TypeRepr.cpp
@@ -15,6 +15,16 @@ using namespace dusk;
 
 TypeRepr::TypeRepr(TypeReprKind K) : Kind(K) {}
 
+IdentTypeRepr *TypeRepr::getIdentTypeRepr() {
+  assert(Kind == TypeReprKind::Ident && "Invalid TypeRepr convertion");
+  return static_cast<IdentTypeRepr *>(this);
+}
+
+ArrayTypeRepr *TypeRepr::getArrayTypeRepr() {
+  assert(Kind == TypeReprKind::Array && "Invalid TypeRepr convertion");
+  return static_cast<ArrayTypeRepr *>(this);
+}
+
 void *TypeRepr::operator new(size_t Bytes, ASTContext &Context) {
   return Context.Allocate(Bytes);
 }
diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp
index 71f4e5e..545a042 100644
--- a/lib/IRGen/GenFunc.cpp
+++ b/lib/IRGen/GenFunc.cpp
@@ -36,7 +36,12 @@ static llvm::Value *emitCond(IRGenFunc &IRGF, Expr *E) {
 
 namespace {
 
-class GenFunc: public ASTVisitor<GenFunc> {
+  class GenFunc: public ASTVisitor<GenFunc,
+                                  /* Decl */ bool,
+                                  /* Expr */ bool,
+                                  /* Stmt */ bool,
+                                  /* Pattern */ bool,
+                                  /* TypeRepr */ bool> {
   typedef ASTVisitor super;
 
   IRGenFunc &IRGF;
@@ -44,24 +49,38 @@ class GenFunc: public ASTVisitor<GenFunc> {
 public:
   GenFunc(IRGenFunc &IRGF) : IRGF(IRGF) {}
 
-  bool visit(ValDecl *D) {
+  bool visitLetDecl(ValDecl *D) {
+    return IRGF.declare(D).isValid();
+  }
+  
+  bool visitVarDecl(ValDecl *D) {
     return IRGF.declare(D).isValid();
   }
 
-  bool visit(BlockStmt *S) {
+  bool visitBlockStmt(BlockStmt *S) {
     for (auto N : S->getNodes())
-      if (!super::visit_(N))
-        return false;
+      if (auto D = dynamic_cast<Decl *>(N)) {
+        if (!super::visit(D))
+          return false;
+      } else if (auto E = dynamic_cast<Expr *>(N)) {
+        if (!super::visit(E))
+          return false;
+      } else if (auto S = dynamic_cast<Stmt *>(N)) {
+        if (!super::visit(S))
+          return false;
+      } else {
+        llvm_unreachable("Unexpected node.");
+      }
     return true;
   }
 
-  bool visit(BreakStmt *S) {
+  bool visitBreakStmt(BreakStmt *S) {
     // Get end block of top level loop
     auto EndBB = IRGF.LoopStack.getInfo().getEndBlock();
     return IRGF.Builder.CreateBr(EndBB) != nullptr;
   }
 
-  bool visit(ReturnStmt *S) {
+  bool visitReturnStmt(ReturnStmt *S) {
     if (!IRGF.Fn->getReturnType()->isVoidTy()) {
       auto RetVal = codegenExpr(IRGF.IRGM, S->getValue());
       IRGF.setRetVal(RetVal);
@@ -70,7 +89,7 @@ public:
     return true;
   }
 
-  bool visit(IfStmt *S) {
+  bool visitIfStmt(IfStmt *S) {
     // Create basic blocks
     auto ThenBB =
         llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "if.then", IRGF.Fn);
@@ -90,7 +109,7 @@ public:
     // Emit Then branch
     IRGF.Builder.SetInsertPoint(ThenBB);
     IRGF.IRGM.Lookup.push();
-    if (!super::visit_(S->getThen()))
+    if (!super::visit(S->getThen()))
       return false;
     IRGF.IRGM.Lookup.pop();
     if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
@@ -100,7 +119,7 @@ public:
     if (S->hasElseBlock()) {
       IRGF.Builder.SetInsertPoint(ElseBB);
       IRGF.IRGM.Lookup.push();
-      if (!super::visit_(S->getElse()))
+      if (!super::visit(S->getElse()))
         return false;
       IRGF.IRGM.Lookup.pop();
       if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
@@ -114,7 +133,7 @@ public:
     return true;
   }
 
-  bool visit(WhileStmt *S) {
+  bool visitWhileStmt(WhileStmt *S) {
     // Create loop blocks
     auto HeaderBlock =
         llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn);
@@ -136,7 +155,7 @@ public:
 
     // Emit loop body
     IRGF.Builder.SetInsertPoint(BodyBlock);
-    if (!super::visit_(S->getBody()))
+    if (!super::visit(S->getBody()))
       return false;
     // Jump back to the condition
     if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr)
@@ -148,7 +167,7 @@ public:
     return true;
   }
 
-  bool visit(ForStmt *S) {
+  bool visitForStmt(ForStmt *S) {
     // Create loop blocks
     auto HeaderBlock =
         llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn);
@@ -178,7 +197,7 @@ public:
     
     // Emit loop body
     IRGF.Builder.SetInsertPoint(BodyBlock);
-    if (!super::visit_(S->getBody()))
+    if (!super::visit(S->getBody()))
       return false;
     // Jump back to the condition
     auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext);
@@ -195,38 +214,38 @@ public:
   }
   
   
-  bool visit(FuncStmt *S) { return true; }
-  bool visit(RangeStmt *S) { return true; }
-  bool visit(SubscriptStmt *S) { return true; }
-  bool visit(ExternStmt *S) { return true; }
-  bool visit(FuncDecl *S) { return true; }
-  bool visit(ModuleDecl *D) { return true; }
-  bool visit(ParamDecl *D) { return true; }
-  bool visit(NumberLiteralExpr *E) {
+  bool visitFuncStmt(FuncStmt *S) { return true; }
+  bool visitRangeStmt(RangeStmt *S) { return true; }
+  bool visitSubscriptStmt(SubscriptStmt *S) { return true; }
+  bool visitExternStmt(ExternStmt *S) { return true; }
+  bool visitFuncDecl(FuncDecl *S) { return true; }
+  bool visitModuleDecl(ModuleDecl *D) { return true; }
+  bool visitParamDecl(ParamDecl *D) { return true; }
+  bool visitNumberLiteralExpr(NumberLiteralExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(ArrayLiteralExpr *E) {
+  bool visitArrayLiteralExpr(ArrayLiteralExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(IdentifierExpr *E) {
+  bool visitIdentifierExpr(IdentifierExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(ParenExpr *E) {
+  bool visitParenExpr(ParenExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(AssignExpr *E) {
+  bool visitAssignExpr(AssignExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(InfixExpr *E) {
+  bool visitInfixExpr(InfixExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(PrefixExpr *E) {
+  bool visitPrefixExpr(PrefixExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(CallExpr *E) {
+  bool visitCallExpr(CallExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
-  bool visit(SubscriptExpr *E) {
+  bool visitSubscriptExpr(SubscriptExpr *E) {
     return codegenExpr(IRGF.IRGM, E) != nullptr;
   }
 };
@@ -235,6 +254,6 @@ public:
 
 bool irgen::genFunc(IRGenFunc &IRGF, FuncStmt *F) {
   GenFunc GF(IRGF);
-  return GF.ASTVisitor::visit_(F->getBody());
+  return GF.ASTVisitor::visit(F->getBody());
 }
 
diff --git a/lib/Parser/ParseType.cpp b/lib/Parser/ParseType.cpp
index 752dd95..852b527 100644
--- a/lib/Parser/ParseType.cpp
+++ b/lib/Parser/ParseType.cpp
@@ -12,36 +12,34 @@
 
 using namespace dusk;
 
-
 /// TypeRepr ::=
 ///     IdentTypeRepr
 ///     ArrayTypeRepr
 TypeRepr *Parser::parseTypeRepr() {
   switch (Tok.getKind()) {
-    case tok::kwInt:
-    case tok::kwVoid:
-      return parseIdentType();
-      
-    default:
-      // Unexpected token
-      diagnose(Tok.getLoc());
-      return nullptr;
+  case tok::kwInt:
+  case tok::kwVoid:
+    return parseIdentType();
+
+  default:
+    // Unexpected token
+    diagnose(Tok.getLoc());
+    return nullptr;
   }
 }
 
-
 /// IdentType ::=
 ///     ':' identifier
 TypeRepr *Parser::parseIdentType() {
   auto Ty = Tok;
   switch (Tok.getKind()) {
-    case tok::kwInt:
-    case tok::kwVoid:
-      consumeToken();
-      return parseArrayType(new(Context) IdentTypeRepr(Ty.getText()));
-      
-    default:
-      llvm_unreachable("Invalid parse method");
+  case tok::kwInt:
+  case tok::kwVoid:
+    consumeToken();
+    return parseArrayType(new (Context) IdentTypeRepr(Ty.getText()));
+
+  default:
+    llvm_unreachable("Invalid parse method");
   }
 }
 
@@ -50,38 +48,26 @@ TypeRepr *Parser::parseIdentType() {
 ///    '[' Expr ']' ArrayType
 TypeRepr *Parser::parseArrayType(TypeRepr *Base) {
   switch (Tok.getKind()) {
-    case tok::comma:
-    case tok::assign:
-    case tok::r_paren:
-    case tok::semicolon:
-      return Base;
-      
-    case tok::l_bracket: {
-      auto L = consumeToken();
-      Expr *E = nullptr;
-      if (Tok.isNot(tok::number_literal)) {
-        if (Tok.is(tok::r_bracket)) {
-          diagnose(Tok.getLoc(), diag::invalid_array_size);
-          consumeToken();
-        } else {
-          diagnose(Tok.getLoc(), diag::expected_array_size);
-        }
-        
-      } else {
-        E = parseNumberLiteralExpr();
-      }
-      
-      if (!consumeIf(tok::r_bracket)) {
-        diagnose(Tok.getLoc(), diag::expected_r_bracket)
-          .fixIt("]", Tok.getLoc());
-        return nullptr;
-      }
-      auto S = new(Context) SubscriptStmt(E, L, PreviousLoc);
-      return parseArrayType(new(Context) ArrayTypeRepr(Base, S));
+  case tok::comma:
+  case tok::assign:
+  case tok::r_paren:
+  case tok::semicolon:
+    return Base;
+
+  case tok::l_bracket: {
+    auto L = consumeToken();
+    Expr *E = parseExpr();
+
+    if (!consumeIf(tok::r_bracket)) {
+      diagnose(Tok.getLoc(), diag::expected_r_bracket).fixIt("]", Tok.getLoc());
+      return nullptr;
     }
-      
-    default:
-      llvm_unreachable("Unexpected token.");
+    auto S = new (Context) SubscriptStmt(E, L, PreviousLoc);
+    return parseArrayType(new (Context) ArrayTypeRepr(Base, S));
+  }
+
+  default:
+    llvm_unreachable("Unexpected token.");
   }
 }
 
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 6604f16..3272d7b 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -6,6 +6,7 @@ set(SOURCE
     ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckExpr.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckPattern.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckStmt.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/TypeCheckType.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/TypeResolver.cpp
     ${SOURCE}
     PARENT_SCOPE
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 69c741c..cc7e7f5 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -17,6 +17,7 @@
 #include "dusk/AST/TypeRepr.h"
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/NameLookup.h"
+#include "dusk/Runtime/RuntimeFuncs.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/SmallVector.h"
 
@@ -85,8 +86,7 @@ void Sema::declareFuncs() {
 }
 
 void Sema::typeCheck() {
-  TypeChecker TC(*this, DeclCtx, Ctx, Diag);
-  Ctx.getRootModule()->walk(TC);
+  TypeChecker(*this, DeclCtx, Ctx, Diag).typeCheckDecl(Ctx.getRootModule());
 }
 
 static Type *typeReprResolve(Sema &S, ASTContext &C, IdentTypeRepr *TyRepr) {
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index ada8459..c6a54e6 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -12,107 +12,206 @@
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
 #include "dusk/AST/NameLookup.h"
+#include "dusk/AST/ASTVisitor.h"
 #include "dusk/Sema/Sema.h"
+#include "dusk/Sema/TypeResolver.h"
 
 using namespace dusk;
 using namespace sema;
 
-bool TypeChecker::preWalkLetDecl(LetDecl *D) {
-  // Check for initialization value
-  if (!D->hasValue()) {
-    diagnose(D->getLocStart(), diag::expected_default_initialization);
-    return false;
-  }
-
-  if (D->hasTypeRepr())
-    D->setType(S.typeReprResolve(D->getTypeRepr()));
-  return true;
-}
+namespace {
 
-bool TypeChecker::preWalkVarDecl(VarDecl *D) {
-  if (!D->hasValue() && !D->hasTypeRepr()) {
-    diagnose(D->getLocEnd(), diag::expected_type_specifier);
-    return false;
+class DeclChecker : public DeclVisitor<DeclChecker> {
+  TypeChecker &TC;
+  
+  typedef ASTVisitor super;
+  
+  friend super;
+  
+public:
+  DeclChecker(TypeChecker &TC) : TC(TC) {}
+  
+private:
+  
+  void visitLetDecl(LetDecl *D) {
+    TC.Lookup.declareLet(D);
+    if (!D->hasValue()) {
+      TC.diagnose(D->getLocEnd(), diag::expected_default_initialization);
+      return;
+    }
+    
+    if (D->hasTypeRepr())
+      TC.typeCheckType(D->getTypeRepr());
+    
+    auto Val = TC.typeCheckExpr(D->getValue());
+    
+    if (D->hasTypeRepr())
+      TC.typeCheckEquals(D->getTypeRepr()->getType(), Val->getType());
+    D->setValue(Val);
+    D->setType(Val->getType());
   }
-
-  if (D->hasTypeRepr())
-    D->setType(S.typeReprResolve(D->getTypeRepr()));
-  return true;
-}
-
-bool TypeChecker::preWalkParamDecl(ParamDecl *D) {
-  if (D->hasTypeRepr())
-    D->setType(S.typeReprResolve(D->getTypeRepr()));
-  return false;
-}
-
-bool TypeChecker::preWalkFuncDecl(FuncDecl *D) {
-  D->setType(S.typeReprResolve(D));
-  return true;
-}
-
-bool TypeChecker::preWalkModuleDecl(ModuleDecl *D) { return true; }
-
-bool TypeChecker::postWalkLetDecl(LetDecl *D) {
-  // Infer type
-  if (!D->getType())
-    D->setType(D->getValue()->getType());
-
-  // Check if resolved both types
-  if (!D->getType() || !D->getValue()->getType())
-    return false;
-
-  if (!D->getType()->isValueType()) {
-    diagnose(D->getValue()->getLocStart(),
-             diag::expected_value_type_expression);
-    return false;
+  
+  void visitVarDecl(VarDecl *D) {
+    TC.Lookup.declareVar(D);
+    if (D->hasTypeRepr())
+      TC.typeCheckType(D->getTypeRepr());
+    
+    if (!D->hasValue()) {
+      if (!D->hasTypeRepr())
+        TC.diagnose(D->getLocEnd(), diag::expected_type_annotation);
+      else
+        D->setType(D->getTypeRepr()->getType());
+      return;
+    }
+    
+    auto Val = TC.typeCheckExpr(D->getValue());
+    if (D->hasTypeRepr())
+      TC.typeCheckEquals(D->getTypeRepr()->getType(), Val->getType());
+    
+    D->setValue(Val);
+    D->setType(Val->getType());
   }
   
-  // Validate types
-  if (D->getType()->isClassOf(D->getValue()->getType())) {
-    // If types match, declare
-    if (DeclCtx.declareLet(D)) {
-      return true;
-    } else {
-      diagnose(D->getLocStart(), diag::redefinition_of_identifier);
-      return false;
+  void visitParamDecl(ParamDecl *D) {
+    if (D->hasTypeRepr()) {
+      TC.typeCheckType(D->getTypeRepr());
+      D->setType(D->getTypeRepr()->getType());
+      return;
     }
   }
-
-  diagnose(D->getValue()->getLocStart(), diag::type_missmatch);
-  return false;
-}
-
-bool TypeChecker::postWalkVarDecl(VarDecl *D) {
-  // Infer type
-  if (!D->getType() && D->hasValue())
-    D->setType(D->getValue()->getType());
-
-  // Check if resolved both types
-  if (!D->getType() || (D->hasValue() && !D->getValue()->getType()))
-    return false;
-
-  if (!D->getType()->isValueType()) {
-    diagnose(D->getValue()->getLocStart(),
-             diag::expected_value_type_expression);
-    return false;
+  
+  void visitFuncDecl(FuncDecl *D) {
+    PushScopeRAII Push(TC.ASTScope, Scope::FnProtoScope);
+    TC.Lookup.declareFunc(D);
+    TC.typeCheckPattern(D->getArgs());
+    if (D->hasTypeRepr())
+      TC.typeCheckType(D->getTypeRepr());
   }
   
-  // Validate types
-  if (!D->hasValue() || D->getType()->isClassOf(D->getValue()->getType()))
-    // If types match, declare
-    return DeclCtx.declareVar(D);
-
-  diagnose(D->getValue()->getLocStart(), diag::type_missmatch);
-  return false;
-}
+  void visitModuleDecl(ModuleDecl *D) {
+    for (auto N : D->getContents()) {
+      if (auto D = dynamic_cast<Decl *>(N))
+        typeCheckDecl(D);
+      else if (auto E = dynamic_cast<Expr *>(N))
+        TC.diagnose(E->getLocStart(), diag::unexpected_expresssion);
+      else if (auto S = dynamic_cast<Stmt *>(N))
+        TC.typeCheckStmt(S);
+      else
+        llvm_unreachable("Unexpected node type.");
+    }
+  }
+  
+public:
+  void typeCheckDecl(Decl *D) {
+    if (TC.Lookup.contains(D->getName()))
+      TC.diagnose(D->getLocStart(), diag::redefinition_of_identifier);
+    
+    super::visit(D);
+  }
+};
 
-bool TypeChecker::postWalkParamDecl(ParamDecl *D) {
-  return D->getType() != nullptr;
-}
+} // anonymous namespace 
 
-bool TypeChecker::postWalkFuncDecl(FuncDecl *D) {
-  return (D->getType()) != nullptr;
+void TypeChecker::typeCheckDecl(Decl *D) {
+  DeclChecker(*this).typeCheckDecl(D);
 }
 
-bool TypeChecker::postWalkModuleDecl(ModuleDecl *D) { return true; }
+//bool TypeChecker::preWalkLetDecl(LetDecl *D) {
+//  // Check for initialization value
+//  if (!D->hasValue()) {
+//    diagnose(D->getLocStart(), diag::expected_default_initialization);
+//    return false;
+//  }
+//
+//  if (D->hasTypeRepr())
+//    D->setType(S.typeReprResolve(D->getTypeRepr()));
+//  return true;
+//}
+//
+//bool TypeChecker::preWalkVarDecl(VarDecl *D) {
+//  if (!D->hasValue() && !D->hasTypeRepr()) {
+//    diagnose(D->getLocEnd(), diag::expected_type_specifier);
+//    return false;
+//  }
+//
+//  if (D->hasTypeRepr())
+//    D->setType(S.typeReprResolve(D->getTypeRepr()));
+//  return true;
+//}
+//
+//bool TypeChecker::preWalkParamDecl(ParamDecl *D) {
+//  if (D->hasTypeRepr())
+//    D->setType(S.typeReprResolve(D->getTypeRepr()));
+//  return false;
+//}
+//
+//bool TypeChecker::preWalkFuncDecl(FuncDecl *D) {
+//  D->setType(S.typeReprResolve(D));
+//  return true;
+//}
+//
+//bool TypeChecker::preWalkModuleDecl(ModuleDecl *D) { return true; }
+//
+//bool TypeChecker::postWalkLetDecl(LetDecl *D) {
+//  // Infer type
+//  if (!D->getType())
+//    D->setType(D->getValue()->getType());
+//
+//  // Check if resolved both types
+//  if (!D->getType() || !D->getValue()->getType())
+//    return false;
+//
+//  if (!D->getType()->isValueType()) {
+//    diagnose(D->getValue()->getLocStart(),
+//             diag::expected_value_type_expression);
+//    return false;
+//  }
+//
+//  // Validate types
+//  if (D->getType()->isClassOf(D->getValue()->getType())) {
+//    // If types match, declare
+//    if (Lookup.declareLet(D)) {
+//      return true;
+//    } else {
+//      diagnose(D->getLocStart(), diag::redefinition_of_identifier);
+//      return false;
+//    }
+//  }
+//
+//  diagnose(D->getValue()->getLocStart(), diag::type_missmatch);
+//  return false;
+//}
+//
+//bool TypeChecker::postWalkVarDecl(VarDecl *D) {
+//  // Infer type
+//  if (!D->getType() && D->hasValue())
+//    D->setType(D->getValue()->getType());
+//
+//  // Check if resolved both types
+//  if (!D->getType() || (D->hasValue() && !D->getValue()->getType()))
+//    return false;
+//
+//  if (!D->getType()->isValueType()) {
+//    diagnose(D->getValue()->getLocStart(),
+//             diag::expected_value_type_expression);
+//    return false;
+//  }
+//
+//  // Validate types
+//  if (!D->hasValue() || D->getType()->isClassOf(D->getValue()->getType()))
+//    // If types match, declare
+//    return Lookup.declareVar(D);
+//
+//  diagnose(D->getValue()->getLocStart(), diag::type_missmatch);
+//  return false;
+//}
+//
+//bool TypeChecker::postWalkParamDecl(ParamDecl *D) {
+//  return D->getType() != nullptr;
+//}
+//
+//bool TypeChecker::postWalkFuncDecl(FuncDecl *D) {
+//  return (D->getType()) != nullptr;
+//}
+//
+//bool TypeChecker::postWalkModuleDecl(ModuleDecl *D) { return true; }
diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp
index 7f5f8f8..b78c326 100644
--- a/lib/Sema/TypeCheckExpr.cpp
+++ b/lib/Sema/TypeCheckExpr.cpp
@@ -12,104 +12,451 @@
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/NameLookup.h"
 #include "dusk/Sema/Sema.h"
+#include "dusk/AST/ASTVisitor.h"
+#include "dusk/AST/ASTWalker.h"
+#include "dusk/AST/NameLookup.h"
+#include "dusk/AST/ASTWalker.h"
 
 using namespace dusk;
 using namespace sema;
 
-bool TypeChecker::postWalkNumberLiteralExpr(NumberLiteralExpr *E) {
-  return true;
-}
+namespace {
 
-bool TypeChecker::postWalkArrayLiteralExpr(ArrayLiteralExpr *E) {
-  E->setType(S.typeReprResolve(E));
-  return true;
-}
-
-bool TypeChecker::postWalkIdentifierExpr(IdentifierExpr *E) {
-  // Check if it's a value type
-  if (auto D = DeclCtx.getVal(E->getName())) {
-    E->setType(D->getType());
-    return true;
+/// Perform expression solution.
+///
+/// Operates on a single expression tree and tries to simplify is as much
+/// as it can. Most of simplification operations include value substitutions
+/// (e.g. substitute indexed element in array with the element itself) and/or
+/// an identifier with a value it refers to.
+///
+/// \note Only constants can be substituted.
+class ExprSolver : public ASTWalker {
+  TypeChecker &TC;
+  
+public:
+  ExprSolver(TypeChecker &TC) : TC(TC) {}
+  
+  std::pair<bool, Expr *> preWalkExpr(Expr *E) {
+    // Skip all solved expressions
+    return {!E->getSolved(), E};
   }
-  // Check if it's a function reference
-  if (auto Fn = DeclCtx.getFunc(E->getName())) {
-    E->setType(Fn->getType());
-    return true;
+  
+  Expr *postWalkExpr(Expr *E) {
+    switch (E->getKind()) {
+    // Literals can't be solved anymore
+    case ExprKind::NumberLiteral:
+    case ExprKind::ArrayLiteral:
+        
+    // Assignements and calls must be executed during runtime
+    case ExprKind::Assign:
+    case ExprKind::Call:
+      break;
+      
+    case ExprKind::Identifier:
+      E = solveIdentifierExpr(static_cast<IdentifierExpr *>(E));
+      break;
+      
+    case ExprKind::Paren:
+      // Simply extract paranthesized expression.
+      E = static_cast<ParenExpr *>(E)->getExpr();
+      break;
+      
+    case ExprKind::Infix:
+      E = solveInfixExpr(static_cast<InfixExpr *>(E));
+      break;
+      
+    case ExprKind::Prefix:
+      E = solvePrefixExpr(static_cast<PrefixExpr *>(E));
+      break;
+      
+    case ExprKind::Subscript:
+      E = solveSubscriptExpr(static_cast<SubscriptExpr *>(E));
+      break;
+    }
+    // Set each expression to solved at the end of traversal.
+    E->setSolved(true);
+    return E;
+  }
+  
+private:
+  
+  // MARK: - Solvers
+  
+  Expr *solveIdentifierExpr(IdentifierExpr *E) {
+    // Check if we have a variable with the name.
+    if (auto D = dynamic_cast<ValDecl *>(TC.Lookup.getVal(E->getName()))) {
+      // We can only substitute immutable values.
+      if (!D->isLet())
+        return E;
+      
+      else if (auto Val = dynamic_cast<NumberLiteralExpr *>(D->getValue()))
+        return Val;
+      else if (auto Val = dynamic_cast<ArrayLiteralExpr *>(D->getValue()))
+        return Val;
+    }
+    return E;
+  }
+  
+  Expr *solveInfixExpr(InfixExpr *E) {
+    auto L = dynamic_cast<NumberLiteralExpr *>(E);
+    auto R = dynamic_cast<NumberLiteralExpr *>(E);
+    // Check if both sides are number literals
+    //
+    // NOTE: we can perform arithmetics only with a signle type being integer.
+    // In future this resolution will need fix for other types, that might
+    // also be applied to these operands.
+    if (!L || !R)
+      return E;
+    
+    int64_t Value = 0;
+    switch (E->getOp().getKind()) {
+    case tok::land:
+      Value = L->getValue() && R->getValue();
+      break;
+      
+    case tok::lor:
+      Value = L->getValue() || R->getValue();
+      break;
+    
+    case tok::plus:
+      Value = L->getValue() + R->getValue();
+      break;
+    
+    case tok::minus:
+      Value = L->getValue() - R->getValue();
+      break;
+      
+    case tok::multipy:
+      Value = L->getValue() * R->getValue();
+      break;
+      
+    case tok::divide:
+      Value = L->getValue() / R->getValue();
+      break;
+      
+    case tok::mod:
+      Value = L->getValue() % R->getValue();
+      break;
+      
+    default:
+      llvm_unreachable("Unexpected infix operator.");
+    }
+    return new (TC.Ctx) NumberLiteralExpr(Value, SMRange{});
+  }
+  
+  Expr *solvePrefixExpr(PrefixExpr *E) {
+    // Check if destination value is number literal
+    //
+    // NOTE: we can perform arithmetics only with a signle type being integer.
+    // In future this resolution will need fix for other types, that might
+    // also be applied to these operands.
+    auto Dest = dynamic_cast<NumberLiteralExpr *>(E);
+    if (!Dest)
+      return E;
+    
+    int64_t Value = 0;
+    switch (E->getOp().getKind()) {
+    case tok::lnot:
+      Value = !Dest->getValue();
+      break;
+      
+    case tok::minus:
+      Value = -Dest->getValue();
+      break;
+      
+    default:
+      llvm_unreachable("Unexpectd prefixoperator.");
+    }
+    return new (TC.Ctx) NumberLiteralExpr(Value, SMRange{});
+  }
+  
+  Expr *solveSubscriptExpr(SubscriptExpr *E) {
+    // Check if both destination is an array and index a number literal.
+    //
+    // NOTE: we can perform subscript only with a arrays. In future this will
+    // need update to support subscript operand on other types as well.
+    auto Arr = dynamic_cast<ArrayLiteralExpr *>(E->getBase());
+    auto Idx = dynamic_cast<NumberLiteralExpr *>(
+        E->getSubscript()->getSubscripStmt()->getValue());
+    if (!Arr || !Idx)
+      return E;
+    
+    auto Values = Arr->getValues()->getExprPattern();
+    if (Values->count() < Idx->getValue() || Idx->getValue() < 0) {
+      TC.diagnose(Idx->getLocStart(), diag::array_index_out_of_bounds);
+      return E;
+    }
+    
+    return Values->getValues()[Idx->getValue()];
+  }
+};
+  
+/// Performs type checking and resolution of expressions.
+class ExprChecker : public ExprVisitor<ExprChecker, Expr *> {
+  TypeChecker &TC;
+  
+  typedef ASTVisitor super;
+  
+  friend super;
+  
+public:
+  ExprChecker(TypeChecker &TC) : TC(TC) {}
+  
+private:
+  
+  // MARK: - Visitors
+  
+  Expr *visitNumberLiteralExpr(NumberLiteralExpr *E) {
+    // Number literal is always an integer type.
+    E->setType(TC.Ctx.getIntType());
+    return E;
   }
-  diagnose(E->getLocStart(), diag::undefined_identifier);
-  return false;
-}
 
-bool TypeChecker::postWalkParenExpr(ParenExpr *E) {
-  E->setType(E->getExpr()->getType());
-  return true;
-}
+  Expr *visitArrayLiteralExpr(ArrayLiteralExpr *E) {
+    if (!E->getValues()->count()) {
+      TC.diagnose(E->getLocStart(), diag::invalid_array_size);
+      return E;
+    }
+    
+    TC.typeCheckPattern(E->getValues());
+    auto Ty = E->getValues()->getType()->getPatternType();
+    if (!Ty)
+      return E;
+    
+    auto BaseTy = Ty->getItems().front();
+    // All items al the array must be of the same type
+    for (auto T : Ty->getItems())
+      if (!TC.typeCheckEquals(BaseTy, T))
+        return E;
 
-bool TypeChecker::postWalkAssignExpr(AssignExpr *E) {
-  auto Ident = dynamic_cast<IdentifierExpr *>(E->getDest());
-  // Check if its an assignable expression
-  if (!Ident || DeclCtx.getFunc(Ident->getName())) {
-    diagnose(E->getDest()->getLocStart(), diag::expression_not_assignable);
-    return false;
+    auto ArrTy = new (TC.Ctx) ArrayType(BaseTy, E->getValues()->count());
+    E->setType(ArrTy);
+    return E;
   }
-  // Check if it is a variable
-  if (DeclCtx.getVal(Ident->getName()) && !DeclCtx.getVar(Ident->getName())) {
-    diagnose(E->getDest()->getLocStart(), diag::cannot_reassign_let_value);
+  
+  Expr *visitIdentifierExpr(IdentifierExpr *E) {
+    if (auto D = TC.Lookup.getVal(E->getName())) {
+      if (D->getType())
+        E->setType(D->getType());
+    
+    } else if (auto Fn = TC.Lookup.getFunc(E->getName())) {
+      if (Fn->getType())
+        E->setType(Fn->getType());
+    
+    } else {
+      TC.diagnose(E->getLocStart(), diag::undefined_identifier);
+    }
+    
+    return E;
   }
 
-  // Check type match.
-  if (E->getDest()->getType()->isClassOf(E->getSource()->getType())) {
-    E->setType(E->getDest()->getType());
-    return true;
+  Expr *visitParenExpr(ParenExpr *E) {
+    // Simplt extract paranthesizes expression.
+    return E->getExpr();
   }
-  diagnose(E->getDest()->getLocEnd(), diag::type_missmatch);
-  return false;
-}
-
-bool TypeChecker::postWalkInfixExpr(InfixExpr *E) {
-  if (!E->getLHS()->getType() || !E->getRHS()->getType())
-    return false;
 
-  // Check type match.
-  if (E->getLHS()->getType()->isClassOf(E->getRHS()->getType())) {
-    E->setType(E->getLHS()->getType());
-    return true;
+  Expr *visitAssignExpr(AssignExpr *E) {
+    E->setDest(typeCheckExpr(E->getDest(), /* Solve */false));
+    E->setSource(typeCheckExpr(E->getSource()));
+    
+    auto DTy = E->getDest()->getType();
+    auto STy = E->getSource()->getType();
+    if (!DTy || !STy)
+      return E;
+    
+    // Check if we have valid destination node.
+    if (auto Dest = dynamic_cast<IdentifierExpr *>(E->getDest())) {
+      if (auto D = dynamic_cast<ValDecl *>(TC.Lookup.getVal(Dest->getName())))
+        if (D->isLet()) {
+          TC.diagnose(E->getLocStart(), diag::cannot_reassign_let_value);
+          return E;
+        }
+    } else if (dynamic_cast<SubscriptExpr *>(E->getDest()) == nullptr) {
+      TC.diagnose(E->getLocStart(), diag::unexpected_expresssion);
+      return E;
+    }
+    
+    if (!TC.typeCheckEquals(DTy, STy)) {
+      TC.diagnose(E->getLocStart(), diag::type_missmatch);
+      return E;
+    }
+    
+    E->setType(DTy);
+    return E;
   }
-  diagnose(E->getOp().getLoc(), diag::type_missmatch);
-  return false;
-}
 
-bool TypeChecker::postWalkPrefixExpr(PrefixExpr *E) {
-  E->setType(E->getDest()->getType());
-  return true;
-}
+  Expr *visitInfixExpr(InfixExpr *E) {
+    E->setLHS(typeCheckExpr(E->getLHS()));
+    E->setRHS(typeCheckExpr(E->getRHS()));
+    
+    auto LTy = E->getLHS()->getType();
+    auto RTy = E->getRHS()->getType();
+    if (!LTy || !RTy)
+      return E;
 
-bool TypeChecker::postWalkCallExpr(CallExpr *E) {
-  auto FTy = dynamic_cast<FunctionType *>(E->getCallee()->getType());
+    // We only support arithmetics with integer types
+    if (!LTy->isClassOf(TC.Ctx.getIntType()) ||
+        !RTy->isClassOf(TC.Ctx.getIntType())) {
+      TC.diagnose(E->getLocStart(), diag::invalid_operand_type);
+      return E;
+    }
+    
+    E->setType(LTy);
+    return E;
+  }
 
-  // Check if references a function
-  if (!FTy) {
-    diagnose(E->getCallee()->getLocStart(), diag::func_call_non_func_type);
-    return false;
+  Expr *visitPrefixExpr(PrefixExpr *E) {
+    E->setDest(typeCheckExpr(E->getDest()));
+    // We only support integer types with any and all prefix operations.
+    if (auto Ty = dynamic_cast<IntType *>(E->getDest()->getType()))
+      E->setType(Ty);
+    return E;
   }
 
-  // Check is arguments are the same as in proto
-  if (E->getArgs()->getType()->isClassOf(FTy->getArgsType())) {
-    E->setType(FTy->getRetType());
-    return true;
-  } else {
-    diagnose(E->getArgs()->getLocStart(), diag::arguments_mismatch);
-    return false;
+  Expr *visitCallExpr(CallExpr *E) {
+    E->setCallee(typeCheckExpr(E->getCallee()));
+    TC.typeCheckPattern(E->getArgs());
+    
+    // Calle must be function type.
+    auto FnTy = dynamic_cast<FunctionType *>(E->getCallee()->getType());
+    auto ArgsTy = E->getArgs()->getType();
+    if (!FnTy || !ArgsTy)
+      return E;
+    
+    if (!TC.typeCheckEquals(FnTy->getFuncType()->getArgsType(), ArgsTy))
+      return E;
+    
+    E->setType(FnTy->getFuncType()->getRetType());
+    return E;
   }
-}
 
-bool TypeChecker::postWalkSubscriptExpr(SubscriptExpr *E) {
-  if (E->getBase()->getType()->getKind() != TypeKind::Array) {
-    diagnose(E->getBase()->getLocStart(), diag::subscripted_value_not_array);
-    return false;
-  } else {
-    auto ArrTy = static_cast<ArrayType *>(E->getBase()->getType());
-    E->setType(ArrTy->getBaseType());
-    return true;
+  Expr *visitSubscriptExpr(SubscriptExpr *E) {
+    E->setBase(TC.typeCheckExpr(E->getBase()));
+    TC.typeCheckStmt(E->getSubscript());
+    
+    // Destination must be array type.
+    auto ArrTy = dynamic_cast<ArrayType *>(E->getBase()->getType());
+    if (!ArrTy)
+      return E;
+    
+    E->setType(ArrTy->getArrayType()->getBaseType());
+    return E;
   }
+  
+public:
+  Expr *typeCheckExpr(Expr *E, bool Solve = true) {
+    E = super::visit(E);
+
+    // Solve expression if type resolution succeeded.
+    if (E->getType() && Solve) {
+      ExprSolver Solver(TC);
+      E = E->walk(Solver);
+    }
+    
+    return E;
+  }
+};
+  
+} // anonymous namesapce
+
+Expr *TypeChecker::typeCheckExpr(Expr *E) {
+  return ExprChecker(*this).typeCheckExpr(E);
 }
+
+//bool TypeChecker::postWalkNumberLiteralExpr(NumberLiteralExpr *E) {
+//  return true;
+//}
+//
+//bool TypeChecker::postWalkArrayLiteralExpr(ArrayLiteralExpr *E) {
+//  E->setType(S.typeReprResolve(E));
+//  return true;
+//}
+//
+//bool TypeChecker::postWalkIdentifierExpr(IdentifierExpr *E) {
+//  // Check if it's a value type
+//  if (auto D = Lookup.getVal(E->getName())) {
+//    E->setType(D->getType());
+//    return true;
+//  }
+//  // Check if it's a function reference
+//  if (auto Fn = Lookup.getFunc(E->getName())) {
+//    E->setType(Fn->getType());
+//    return true;
+//  }
+//  diagnose(E->getLocStart(), diag::undefined_identifier);
+//  return false;
+//}
+//
+//bool TypeChecker::postWalkParenExpr(ParenExpr *E) {
+//  E->setType(E->getExpr()->getType());
+//  return true;
+//}
+//
+//bool TypeChecker::postWalkAssignExpr(AssignExpr *E) {
+//  auto Ident = dynamic_cast<IdentifierExpr *>(E->getDest());
+//  // Check if its an assignable expression
+//  if (!Ident || Lookup.getFunc(Ident->getName())) {
+//    diagnose(E->getDest()->getLocStart(), diag::expression_not_assignable);
+//    return false;
+//  }
+//  // Check if it is a variable
+//  if (Lookup.getVal(Ident->getName()) && !Lookup.getVar(Ident->getName())) {
+//    diagnose(E->getDest()->getLocStart(), diag::cannot_reassign_let_value);
+//  }
+//
+//  // Check type match.
+//  if (E->getDest()->getType()->isClassOf(E->getSource()->getType())) {
+//    E->setType(E->getDest()->getType());
+//    return true;
+//  }
+//  diagnose(E->getDest()->getLocEnd(), diag::type_missmatch);
+//  return false;
+//}
+//
+//bool TypeChecker::postWalkInfixExpr(InfixExpr *E) {
+//  if (!E->getLHS()->getType() || !E->getRHS()->getType())
+//    return false;
+//
+//  // Check type match.
+//  if (E->getLHS()->getType()->isClassOf(E->getRHS()->getType())) {
+//    E->setType(E->getLHS()->getType());
+//    return true;
+//  }
+//  diagnose(E->getOp().getLoc(), diag::type_missmatch);
+//  return false;
+//}
+//
+//bool TypeChecker::postWalkPrefixExpr(PrefixExpr *E) {
+//  E->setType(E->getDest()->getType());
+//  return true;
+//}
+//
+//bool TypeChecker::postWalkCallExpr(CallExpr *E) {
+//  auto FTy = dynamic_cast<FunctionType *>(E->getCallee()->getType());
+//
+//  // Check if references a function
+//  if (!FTy) {
+//    diagnose(E->getCallee()->getLocStart(), diag::func_call_non_func_type);
+//    return false;
+//  }
+//
+//  // Check is arguments are the same as in proto
+//  if (E->getArgs()->getType()->isClassOf(FTy->getArgsType())) {
+//    E->setType(FTy->getRetType());
+//    return true;
+//  } else {
+//    diagnose(E->getArgs()->getLocStart(), diag::arguments_mismatch);
+//    return false;
+//  }
+//}
+//
+//bool TypeChecker::postWalkSubscriptExpr(SubscriptExpr *E) {
+//  if (E->getBase()->getType()->getKind() != TypeKind::Array) {
+//    diagnose(E->getBase()->getLocStart(), diag::subscripted_value_not_array);
+//    return false;
+//  } else {
+//    auto ArrTy = static_cast<ArrayType *>(E->getBase()->getType());
+//    E->setType(ArrTy->getBaseType());
+//    return true;
+//  }
+//}
diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp
index 58a1106..3b9d88a 100644
--- a/lib/Sema/TypeCheckPattern.cpp
+++ b/lib/Sema/TypeCheckPattern.cpp
@@ -12,6 +12,7 @@
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
 #include "dusk/AST/NameLookup.h"
+#include "dusk/AST/ASTVisitor.h"
 #include "dusk/Sema/Sema.h"
 #include "llvm/ADT/SmallVector.h"
 #include <memory>
@@ -19,35 +20,82 @@
 using namespace dusk;
 using namespace sema;
 
-bool TypeChecker::preWalkVarPattern(VarPattern *P) {
-  return P->getType() == nullptr;
-}
+namespace {
 
-bool TypeChecker::preWalkExprPattern(ExprPattern *P) {
-  return P->getType() == nullptr;
-}
+/// Pattern type checker.
+class PatternChecker : public PatternVisitor<PatternChecker> {
+  TypeChecker &TC;
+
+  typedef ASTVisitor super;
+
+  friend super;
 
-bool TypeChecker::postWalkVarPattern(VarPattern *P) {
-  llvm::SmallVector<Type *, 128> Ty;
-  for (auto V : P->getVars()) {
-    if (!V->getType())
-      return false;
-    Ty.push_back(V->getType());
+public:
+  PatternChecker(TypeChecker &TC) : TC(TC) {}
+
+private:
+  void visitExprPattern(ExprPattern *P) {
+    llvm::SmallVector<Type *, 128> Tys;
+    for (auto &E : P->getValues()) {
+      E = TC.typeCheckExpr(E);
+      Tys.push_back(E->getType());
+      if (!Tys.back())
+        return;
+    }
+    P->setType(new (TC.Ctx) PatternType(std::move(Tys)));
   }
-  
-  P->setType(new(Ctx) PatternType(std::move(Ty)));
-  return true;
-}
 
-bool TypeChecker::postWalkExprPattern(ExprPattern *P) {
-  llvm::SmallVector<Type *, 128> Ty;
-  for (auto V : P->getValues()) {
-    if (!V->getType())
-      return false;
-    Ty.push_back(V->getType());
+  void visitVarPattern(VarPattern *P) {
+    llvm::SmallVector<Type *, 128> Tys;
+    for (auto D : P->getVars()) {
+      TC.typeCheckDecl(D);
+      Tys.push_back(D->getType());
+      if (!Tys.back())
+        return;
+    }
+    P->setType(new (TC.Ctx) PatternType(std::move(Tys)));
   }
-  
-  P->setType(new(Ctx) PatternType(std::move(Ty)));
-  return true;
+
+public:
+  void typeCheckPattern(Pattern *P) { super::visit(P); }
+};
+
+} // anonymous namespace
+
+void TypeChecker::typeCheckPattern(Pattern *P) {
+  PatternChecker(*this).typeCheckPattern(P);
 }
 
+// bool TypeChecker::preWalkVarPattern(VarPattern *P) {
+//  return P->getType() == nullptr;
+//}
+//
+// bool TypeChecker::preWalkExprPattern(ExprPattern *P) {
+//  return P->getType() == nullptr;
+//}
+//
+// bool TypeChecker::postWalkVarPattern(VarPattern *P) {
+//  llvm::SmallVector<Type *, 128> Ty;
+//  for (auto V : P->getVars()) {
+//    if (!V->getType())
+//      return false;
+//    Ty.push_back(V->getType());
+//  }
+//
+//  P->setType(new(Ctx) PatternType(std::move(Ty)));
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkExprPattern(ExprPattern *P) {
+//  llvm::SmallVector<Type *, 128> Ty;
+//  for (auto V : P->getValues()) {
+//    if (!V->getType())
+//      return false;
+//    Ty.push_back(V->getType());
+//  }
+//
+//  P->setType(new(Ctx) PatternType(std::move(Ty)));
+//  return true;
+//}
+//
+
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index 82a7b51..8b1322d 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -12,143 +12,265 @@
 #include "dusk/AST/Diagnostics.h"
 #include "dusk/AST/Scope.h"
 #include "dusk/AST/NameLookup.h"
+#include "dusk/AST/ASTVisitor.h"
+
+#include "TypeChecker.h"
 
 using namespace dusk;
 using namespace sema;
 
-bool TypeChecker::preWalkBlockStmt(BlockStmt *S) {
-  DeclCtx.push();
-  if (auto Fn = dynamic_cast<FuncStmt *>(Scp.top().getStmt())) {
-    auto Proto = static_cast<FuncDecl *>(Fn->getPrototype());
-    auto Args = static_cast<VarPattern *>(Proto->getArgs());
-    for (auto Arg : Args->getVars())
-      if (!DeclCtx.declareVar(Arg)) {
-        diagnose(Args->getLocStart(), diag::redefinition_of_identifier);
-        return false;
-      }
-  }
+class StmtChecker : public StmtVisitor<StmtChecker> {
+  typedef ASTVisitor super;
+  friend super;
 
-  if (auto For = dynamic_cast<ForStmt *>(Scp.top().getStmt())) {
-    if (!For->getRange()->walk(*this))
-      return false;
-    auto Rng = static_cast<RangeStmt *>(For->getRange());
-    auto Iter = static_cast<ParamDecl *>(For->getIter());
-    Iter->setType(Rng->getStart()->getType());
-    DeclCtx.declareLet(Iter);
-  }
-  Scp.push(Scope(&Scp.top(), Scope::BlockScope, S));
-  return true;
-}
+  TypeChecker &TC;
 
-bool TypeChecker::preWalkExternStmt(ExternStmt *S) {
-  Scp.push(Scope(&Scp.top(), Scope::FnScope, S));
-  DeclCtx.push();
-  return true;
-}
+public:
+  StmtChecker(TypeChecker &TC) : TC(TC) {}
 
-bool TypeChecker::preWalkForStmt(ForStmt *S) {
-  Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S));
-  return true;
-}
-
-bool TypeChecker::preWalkFuncStmt(FuncStmt *S) {
-  Scp.push(Scope(&Scp.top(), Scope::FnScope, S));
-  return true;
-}
+private:
+  void visitBreakStmt(BreakStmt *S) {
+    if (!TC.ASTScope.isBreakScope())
+      TC.diagnose(S->getLocStart(), diag::unexpected_break_stmt);
+  }
 
-bool TypeChecker::preWalkIfStmt(IfStmt *S) {
-  Scp.push(Scope(&Scp.top(), Scope::ControlScope, S));
-  return true;
-}
+  void visitReturnStmt(ReturnStmt *S) {
+    // Return cannot occur outside of function scope
+    if (!TC.ASTScope.isFnScope())
+      TC.diagnose(S->getLocStart(), diag::unexpected_return_stmt);
 
-bool TypeChecker::preWalkWhileStmt(WhileStmt *S) {
-  Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S));
-  return true;
-}
+    // Extract function type
+    auto Fn = TC.ASTScope.getFnParent()->getStmt()->getFuncStmt();
+    auto FnTy = Fn->getPrototype()->getType()->getFuncType();
 
-bool TypeChecker::postWalkBreakStmt(BreakStmt *S) {
-  if (Scp.top().isBreakScope() || Scp.top().getBreakParent() != nullptr)
-    return true;
-  diagnose(S->getLocStart(), diag::unexpected_break_stmt);
-  return false;
-}
+    // Check if valid void type
+    if (!S->hasValue()) {
+      if (!FnTy->getRetType()->isVoidType())
+        TC.diagnose(S->getLocStart(), diag::return_missing_value);
+      return;
+    }
 
-bool TypeChecker::postWalkReturnStmt(ReturnStmt *S) {
-  if (!Scp.top().isFnScope() && Scp.top().getFnParent() == nullptr) {
-    diagnose(S->getLocStart(), diag::unexpected_return_stmt);
-    return false;
+    // Resolve return value and type
+    auto E = TC.typeCheckExpr(S->getValue());
+    TC.typeCheckEquals(FnTy->getRetType(), E->getType());
+    S->setValue(E);
   }
-  auto &FnScp = Scp.top().isFnScope() ? Scp.top() : *Scp.top().getFnParent();
 
-  auto F = static_cast<FuncStmt *>(FnScp.getStmt());
-  auto FD = static_cast<FuncDecl *>(F->getPrototype());
-  auto FTy = static_cast<FunctionType *>(FD->getType());
+  void visitSubscriptStmt(SubscriptStmt *S) {
+    auto Val = TC.typeCheckExpr(S->getValue());
+    S->setValue(Val);
+  }
 
-  if (!S->hasValue()) {
-    if (FTy->getRetType()->isVoidType())
-      return true;
-    diagnose(S->getLocStart(), diag::return_missing_value);
-    return false;
+  void visitRangeStmt(RangeStmt *S) {
+    auto Start = TC.typeCheckExpr(S->getStart());
+    auto End = TC.typeCheckExpr(S->getStart());
+    
+    // Both range value must be of same type
+    TC.typeCheckEquals(Start->getType(), End->getType());
+    S->setStart(Start);
+    S->setEnd(End);
   }
 
-  if (FTy->getRetType()->isClassOf(S->getValue()->getType()))
-    return true;
+  void visitBlockStmt(BlockStmt *S) {
+    PushScopeRAII Push(TC.ASTScope, Scope::BlockScope, S);
+    for (auto &N : S->getNodes()) {
+      if (auto D = dynamic_cast<Decl *>(N))
+        TC.typeCheckDecl(D);
 
-  diagnose(S->getLocStart(), diag::type_missmatch);
-  return false;
-}
+      else if (auto E = dynamic_cast<Expr *>(N))
+        N = TC.typeCheckExpr(E);
+
+      else if (auto S = dynamic_cast<Stmt *>(N))
+        typeCheckStmt(S);
 
-bool TypeChecker::postWalkRangeStmt(RangeStmt *S) {
-  if (!S->getStart()->getType()->isValueType()) {
-    diagnose(S->getStart()->getLocStart(),
-             diag::expected_value_type_expression);
-    return false;
+      else
+        llvm_unreachable("Unexpected node type.");
+    }
   }
-  if (!S->getEnd()->getType()->isValueType()) {
-    diagnose(S->getEnd()->getLocStart(), diag::expected_value_type_expression);
-    return false;
+
+  void visitExternStmt(ExternStmt *S) {
+    PushScopeRAII Push(TC.ASTScope, Scope::FnScope, S);
+    TC.typeCheckDecl(S->getPrototype());
   }
-  return true;
-}
 
-bool TypeChecker::postWalkSubscriptStmt(SubscriptStmt *S) {
-  return S->getValue()->getType()->isValueType();
-}
+  void visitFuncStmt(FuncStmt *S) {
+    PushScopeRAII Push(TC.ASTScope, Scope::FnScope, S);
+    TC.typeCheckDecl(S->getPrototype());
+    typeCheckStmt(S->getBody());
+  }
 
-bool TypeChecker::postWalkBlockStmt(BlockStmt *S) {
-  DeclCtx.pop();
-  Scp.pop();
-  return true;
-}
+  void visitForStmt(ForStmt *S) {
+    PushScopeRAII Push(TC.ASTScope, Scope::BreakScope | Scope::ControlScope, S);
+    TC.typeCheckDecl(S->getIter());
+    typeCheckStmt(S->getRange());
+    
+    // Set iterator type BEFORE type checking the body.
+    auto Ty = S->getRange()->getRangeStmt()->getStart()->getType();
+    S->getIter()->setType(Ty);
+    
+    typeCheckStmt(S->getBody());
+  }
 
-bool TypeChecker::postWalkExternStmt(ExternStmt *S) {
-  DeclCtx.pop();
-  Scp.pop();
-  return true;
-}
+  void visitWhileStmt(WhileStmt *S) {
+    PushScopeRAII Push(TC.ASTScope, Scope::BreakScope | Scope::ControlScope, S);
+    auto Cond = TC.typeCheckExpr(S->getCond());
+    TC.typeCheckStmt(S->getBody());
+    S->setCond(Cond);
+  }
 
-bool TypeChecker::postWalkForStmt(ForStmt *S) {
-  Scp.pop();
-  return true;
-}
+  void visitIfStmt(IfStmt *S) {
+    PushScopeRAII Push(TC.ASTScope, Scope::ControlScope, S);
+    auto Cond = TC.typeCheckExpr(S->getCond());
+    typeCheckStmt(S->getThen());
+    if (S->hasElseBlock())
+      typeCheckStmt(S->getElse());
+    S->setCond(Cond);
+  }
 
-bool TypeChecker::postWalkFuncStmt(FuncStmt *S) {
-  Scp.pop();
-  return true;
-}
+public:
+  void typeCheckStmt(Stmt *S) {
+    super::visit(S);
+  }
+};
 
-bool TypeChecker::postWalkIfStmt(IfStmt *S) {
-  Scp.pop();
-  if (S->getCond()->getType()->isValueType())
-    return true;
-  diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression);
-  return false;
+void TypeChecker::typeCheckStmt(Stmt *S) {
+  StmtChecker(*this).typeCheckStmt(S);
 }
 
-bool TypeChecker::postWalkWhileStmt(WhileStmt *S) {
-  Scp.pop();
-  if (S->getCond()->getType()->isValueType())
-    return true;
-  diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression);
-  return false;
-}
+// bool TypeChecker::preWalkBlockStmt(BlockStmt *S) {
+//  Lookup.push();
+//  if (auto Fn = dynamic_cast<FuncStmt *>(Scp.top().getStmt())) {
+//    auto Proto = static_cast<FuncDecl *>(Fn->getPrototype());
+//    auto Args = static_cast<VarPattern *>(Proto->getArgs());
+//    for (auto Arg : Args->getVars())
+//      if (!Lookup.declareVar(Arg)) {
+//        diagnose(Args->getLocStart(), diag::redefinition_of_identifier);
+//        return false;
+//      }
+//  }
+//
+//  if (auto For = dynamic_cast<ForStmt *>(Scp.top().getStmt())) {
+//    if (!For->getRange()->walk(*this))
+//      return false;
+//    auto Rng = static_cast<RangeStmt *>(For->getRange());
+//    auto Iter = static_cast<ParamDecl *>(For->getIter());
+//    Iter->setType(Rng->getStart()->getType());
+//    Lookup.declareLet(Iter);
+//  }
+//  Scp.push(Scope(&Scp.top(), Scope::BlockScope, S));
+//  return true;
+//}
+//
+// bool TypeChecker::preWalkExternStmt(ExternStmt *S) {
+//  Scp.push(Scope(&Scp.top(), Scope::FnScope, S));
+//  Lookup.push();
+//  return true;
+//}
+//
+// bool TypeChecker::preWalkForStmt(ForStmt *S) {
+//  Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S));
+//  return true;
+//}
+//
+// bool TypeChecker::preWalkFuncStmt(FuncStmt *S) {
+//  Scp.push(Scope(&Scp.top(), Scope::FnScope, S));
+//  return true;
+//}
+//
+// bool TypeChecker::preWalkIfStmt(IfStmt *S) {
+//  Scp.push(Scope(&Scp.top(), Scope::ControlScope, S));
+//  return true;
+//}
+//
+// bool TypeChecker::preWalkWhileStmt(WhileStmt *S) {
+//  Scp.push(Scope(&Scp.top(), Scope::ControlScope | Scope::BreakScope, S));
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkBreakStmt(BreakStmt *S) {
+//  if (Scp.top().isBreakScope() || Scp.top().getBreakParent() != nullptr)
+//    return true;
+//  diagnose(S->getLocStart(), diag::unexpected_break_stmt);
+//  return false;
+//}
+//
+// bool TypeChecker::postWalkReturnStmt(ReturnStmt *S) {
+//  if (!Scp.top().isFnScope() && Scp.top().getFnParent() == nullptr) {
+//    diagnose(S->getLocStart(), diag::unexpected_return_stmt);
+//    return false;
+//  }
+//  auto &FnScp = Scp.top().isFnScope() ? Scp.top() : *Scp.top().getFnParent();
+//
+//  auto F = static_cast<FuncStmt *>(FnScp.getStmt());
+//  auto FD = static_cast<FuncDecl *>(F->getPrototype());
+//  auto FTy = static_cast<FunctionType *>(FD->getType());
+//
+//  if (!S->hasValue()) {
+//    if (FTy->getRetType()->isVoidType())
+//      return true;
+//    diagnose(S->getLocStart(), diag::return_missing_value);
+//    return false;
+//  }
+//
+//  if (FTy->getRetType()->isClassOf(S->getValue()->getType()))
+//    return true;
+//
+//  diagnose(S->getLocStart(), diag::type_missmatch);
+//  return false;
+//}
+//
+// bool TypeChecker::postWalkRangeStmt(RangeStmt *S) {
+//  if (!S->getStart()->getType()->isValueType()) {
+//    diagnose(S->getStart()->getLocStart(),
+//             diag::expected_value_type_expression);
+//    return false;
+//  }
+//  if (!S->getEnd()->getType()->isValueType()) {
+//    diagnose(S->getEnd()->getLocStart(),
+//    diag::expected_value_type_expression);
+//    return false;
+//  }
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkSubscriptStmt(SubscriptStmt *S) {
+//  return S->getValue()->getType()->isValueType();
+//}
+//
+// bool TypeChecker::postWalkBlockStmt(BlockStmt *S) {
+//  Lookup.pop();
+//  Scp.pop();
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkExternStmt(ExternStmt *S) {
+//  Lookup.pop();
+//  Scp.pop();
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkForStmt(ForStmt *S) {
+//  Scp.pop();
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkFuncStmt(FuncStmt *S) {
+//  Scp.pop();
+//  return true;
+//}
+//
+// bool TypeChecker::postWalkIfStmt(IfStmt *S) {
+//  Scp.pop();
+//  if (S->getCond()->getType()->isValueType())
+//    return true;
+//  diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression);
+//  return false;
+//}
+//
+// bool TypeChecker::postWalkWhileStmt(WhileStmt *S) {
+//  Scp.pop();
+//  if (S->getCond()->getType()->isValueType())
+//    return true;
+//  diagnose(S->getCond()->getLocStart(), diag::expected_value_type_expression);
+//  return false;
+//}
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
new file mode 100644
index 0000000..4ded976
--- /dev/null
+++ b/lib/Sema/TypeCheckType.cpp
@@ -0,0 +1,86 @@
+//===--- TypeCheckStmt.cpp ------------------------------------------------===//
+//
+//                                 dusk-lang
+// This source file is part of a dusk-lang project, which is a semestral
+// assignement for BI-PJP course at Czech Technical University in Prague.
+// The software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeChecker.h"
+
+#include "dusk/AST/Diagnostics.h"
+#include "dusk/AST/Scope.h"
+#include "dusk/AST/NameLookup.h"
+#include "dusk/AST/ASTVisitor.h"
+#include "dusk/Sema/Sema.h"
+#include "dusk/Sema/TypeResolver.h"
+#include "dusk/AST/ASTWalker.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace dusk;
+using namespace sema;
+
+namespace {
+  
+class TypeReprChecker : public TypeReprVisitor<TypeReprChecker> {
+  TypeChecker &TC;
+  
+  typedef ASTVisitor super;
+  
+  friend super;
+  
+public:
+  TypeReprChecker(TypeChecker &TC) : TC(TC) {}
+  
+private:
+  
+  void visitIdentTypeRepr(IdentTypeRepr *TR) {
+    auto Ty = llvm::StringSwitch<Type *>(TR->getIdent())
+    .Case("Int", TC.Ctx.getIntType())
+    .Case("Void", TC.Ctx.getVoidType())
+    .Default(nullptr);
+    
+    if (Ty)
+      TR->setType(Ty);
+    else
+      TC.diagnose(TR->getLocStart(), diag::unknown_type);
+  }
+  
+  void visitArrayTypeRepr(ArrayTypeRepr *TR) {
+    typeCheckType(TR->getBaseTyRepr());
+    TC.typeCheckStmt(TR->getSize());
+    
+    auto BaseTy = TR->getBaseTyRepr()->getType();
+    auto Size = dynamic_cast<NumberLiteralExpr *>(
+        TR->getSize()->getSubscripStmt()->getValue());
+    
+    if (!BaseTy)
+      return;
+    
+    // Array must not be of null type
+    if (BaseTy->isVoidType()) {
+      TC.diagnose(TR->getLocStart(), diag::type_missmatch);
+      return;
+    }
+    
+    // Array size must be known at compile time
+    if (!Size) {
+      TC.diagnose(TR->getSize()->getLocStart(), diag::variable_array_size);
+      return;
+    }
+    auto Ty = new (TC.Ctx) ArrayType(BaseTy, Size->getValue());
+    TR->setType(Ty);
+  }
+  
+public:
+  void typeCheckType(TypeRepr *TR) {
+    super::visit(TR);
+  }
+};
+  
+} // anonymous namespace
+
+void TypeChecker::typeCheckType(TypeRepr *TR) {
+  TypeReprChecker(*this).typeCheckType(TR);
+}
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index 8006e9c..34f62c0 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -19,7 +19,7 @@ using namespace sema;
 
 TypeChecker::TypeChecker(Sema &S, NameLookup &C, ASTContext &Ctx,
                          DiagnosticEngine &D)
-    : S(S), DeclCtx(C), Ctx(Ctx), Diag(D) {
+    : S(S), Lookup(C), Ctx(Ctx), Diag(D) {
   Scp.push(Scope());
 }
 
@@ -28,123 +28,123 @@ void TypeChecker::diagnose(SMLoc Loc, diag::DiagID ID) {
   Ctx.setError();
 }
 
-bool TypeChecker::preWalk(Decl *D) {
-  switch (D->getKind()) {
-  case DeclKind::Let:
-    return preWalkLetDecl(static_cast<LetDecl *>(D));
-  case DeclKind::Func:
-    return preWalkFuncDecl(static_cast<FuncDecl *>(D));
-  case DeclKind::Module:
-    return preWalkModuleDecl(static_cast<ModuleDecl *>(D));
-  case DeclKind::Param:
-    return preWalkParamDecl(static_cast<ParamDecl *>(D));
-  case DeclKind::Var:
-    return preWalkVarDecl(static_cast<VarDecl *>(D));
-  }
-}
-
-bool TypeChecker::postWalk(Decl *D) {
-  switch (D->getKind()) {
-  case DeclKind::Let:
-    return postWalkLetDecl(static_cast<LetDecl *>(D));
-  case DeclKind::Func:
-    return postWalkFuncDecl(static_cast<FuncDecl *>(D));
-  case DeclKind::Module:
-    return postWalkModuleDecl(static_cast<ModuleDecl *>(D));
-  case DeclKind::Param:
-    return postWalkParamDecl(static_cast<ParamDecl *>(D));
-  case DeclKind::Var:
-    return postWalkVarDecl(static_cast<VarDecl *>(D));
-  }
-}
-
-bool TypeChecker::preWalk(Expr *E) {
-  // Skip expression type validation tree if the root expression has a type.
-  return E->getType() == nullptr;
-}
-
-bool TypeChecker::postWalk(Expr *E) {
-  switch (E->getKind()) {
-  case ExprKind::NumberLiteral:
-    return postWalkNumberLiteralExpr(static_cast<NumberLiteralExpr *>(E));
-  case ExprKind::ArrayLiteral:
-    return postWalkArrayLiteralExpr(static_cast<ArrayLiteralExpr *>(E));
-  case ExprKind::Identifier:
-    return postWalkIdentifierExpr(static_cast<IdentifierExpr *>(E));
-  case ExprKind::Paren:
-    return postWalkParenExpr(static_cast<ParenExpr *>(E));
-  case ExprKind::Assign:
-    return postWalkAssignExpr(static_cast<AssignExpr *>(E));
-  case ExprKind::Infix:
-    return postWalkInfixExpr(static_cast<InfixExpr *>(E));
-  case ExprKind::Prefix:
-    return postWalkPrefixExpr(static_cast<PrefixExpr *>(E));
-  case ExprKind::Call:
-    return postWalkCallExpr(static_cast<CallExpr *>(E));
-  case ExprKind::Subscript:
-    return postWalkSubscriptExpr(static_cast<SubscriptExpr *>(E));
-  }
-}
-
-bool TypeChecker::preWalk(Stmt *S) {
-  switch (S->getKind()) {
-  case StmtKind::Block:
-    return preWalkBlockStmt(static_cast<BlockStmt *>(S));
-  case StmtKind::Extern:
-    return preWalkExternStmt(static_cast<ExternStmt *>(S));
-  case StmtKind::For:
-    return preWalkForStmt(static_cast<ForStmt *>(S));
-  case StmtKind::Func:
-    return preWalkFuncStmt(static_cast<FuncStmt *>(S));
-  case StmtKind::If:
-    return preWalkIfStmt(static_cast<IfStmt *>(S));
-  case StmtKind::While:
-    return preWalkWhileStmt(static_cast<WhileStmt *>(S));
-  default: return true;
-  }
-}
-
-bool TypeChecker::postWalk(Stmt *S) {
-  switch (S->getKind()) {
-  case StmtKind::Break:
-    return postWalkBreakStmt(static_cast<BreakStmt *>(S));
-  case StmtKind::Return:
-    return postWalkReturnStmt(static_cast<ReturnStmt *>(S));
-  case StmtKind::Range:
-    return postWalkRangeStmt(static_cast<RangeStmt *>(S));
-  case StmtKind::Subscript:
-    return postWalkSubscriptStmt(static_cast<SubscriptStmt *>(S));
-  case StmtKind::Block:
-    return postWalkBlockStmt(static_cast<BlockStmt *>(S));
-  case StmtKind::Extern:
-    return postWalkExternStmt(static_cast<ExternStmt *>(S));
-  case StmtKind::For:
-    return postWalkForStmt(static_cast<ForStmt *>(S));
-  case StmtKind::Func:
-    return postWalkFuncStmt(static_cast<FuncStmt *>(S));
-  case StmtKind::If:
-    return postWalkIfStmt(static_cast<IfStmt *>(S));
-  case StmtKind::While:
-    return postWalkWhileStmt(static_cast<WhileStmt *>(S));
-  }
-}
-
-bool TypeChecker::preWalk(Pattern *P) {
-  switch (P->getKind()) {
-  case PatternKind::Variable:
-    return preWalkVarPattern(static_cast<VarPattern *>(P));
-  case PatternKind::Expr:
-    return preWalkExprPattern(static_cast<ExprPattern *>(P));
-  }
-}
-
-bool TypeChecker::postWalk(Pattern *P) {
-  switch (P->getKind()) {
-    case PatternKind::Variable:
-      return postWalkVarPattern(static_cast<VarPattern *>(P));
-    case PatternKind::Expr:
-      return postWalkExprPattern(static_cast<ExprPattern *>(P));
-  }
-}
+//bool TypeChecker::preWalk(Decl *D) {
+//  switch (D->getKind()) {
+//  case DeclKind::Let:
+//    return preWalkLetDecl(static_cast<LetDecl *>(D));
+//  case DeclKind::Func:
+//    return preWalkFuncDecl(static_cast<FuncDecl *>(D));
+//  case DeclKind::Module:
+//    return preWalkModuleDecl(static_cast<ModuleDecl *>(D));
+//  case DeclKind::Param:
+//    return preWalkParamDecl(static_cast<ParamDecl *>(D));
+//  case DeclKind::Var:
+//    return preWalkVarDecl(static_cast<VarDecl *>(D));
+//  }
+//}
+//
+//bool TypeChecker::postWalk(Decl *D) {
+//  switch (D->getKind()) {
+//  case DeclKind::Let:
+//    return postWalkLetDecl(static_cast<LetDecl *>(D));
+//  case DeclKind::Func:
+//    return postWalkFuncDecl(static_cast<FuncDecl *>(D));
+//  case DeclKind::Module:
+//    return postWalkModuleDecl(static_cast<ModuleDecl *>(D));
+//  case DeclKind::Param:
+//    return postWalkParamDecl(static_cast<ParamDecl *>(D));
+//  case DeclKind::Var:
+//    return postWalkVarDecl(static_cast<VarDecl *>(D));
+//  }
+//}
+//
+//bool TypeChecker::preWalk(Expr *E) {
+//  // Skip expression type validation tree if the root expression has a type.
+//  return E->getType() == nullptr;
+//}
+//
+//bool TypeChecker::postWalk(Expr *E) {
+//  switch (E->getKind()) {
+//  case ExprKind::NumberLiteral:
+//    return postWalkNumberLiteralExpr(static_cast<NumberLiteralExpr *>(E));
+//  case ExprKind::ArrayLiteral:
+//    return postWalkArrayLiteralExpr(static_cast<ArrayLiteralExpr *>(E));
+//  case ExprKind::Identifier:
+//    return postWalkIdentifierExpr(static_cast<IdentifierExpr *>(E));
+//  case ExprKind::Paren:
+//    return postWalkParenExpr(static_cast<ParenExpr *>(E));
+//  case ExprKind::Assign:
+//    return postWalkAssignExpr(static_cast<AssignExpr *>(E));
+//  case ExprKind::Infix:
+//    return postWalkInfixExpr(static_cast<InfixExpr *>(E));
+//  case ExprKind::Prefix:
+//    return postWalkPrefixExpr(static_cast<PrefixExpr *>(E));
+//  case ExprKind::Call:
+//    return postWalkCallExpr(static_cast<CallExpr *>(E));
+//  case ExprKind::Subscript:
+//    return postWalkSubscriptExpr(static_cast<SubscriptExpr *>(E));
+//  }
+//}
+//
+//bool TypeChecker::preWalk(Stmt *S) {
+//  switch (S->getKind()) {
+//  case StmtKind::Block:
+//    return preWalkBlockStmt(static_cast<BlockStmt *>(S));
+//  case StmtKind::Extern:
+//    return preWalkExternStmt(static_cast<ExternStmt *>(S));
+//  case StmtKind::For:
+//    return preWalkForStmt(static_cast<ForStmt *>(S));
+//  case StmtKind::Func:
+//    return preWalkFuncStmt(static_cast<FuncStmt *>(S));
+//  case StmtKind::If:
+//    return preWalkIfStmt(static_cast<IfStmt *>(S));
+//  case StmtKind::While:
+//    return preWalkWhileStmt(static_cast<WhileStmt *>(S));
+//  default: return true;
+//  }
+//}
+//
+//bool TypeChecker::postWalk(Stmt *S) {
+//  switch (S->getKind()) {
+//  case StmtKind::Break:
+//    return postWalkBreakStmt(static_cast<BreakStmt *>(S));
+//  case StmtKind::Return:
+//    return postWalkReturnStmt(static_cast<ReturnStmt *>(S));
+//  case StmtKind::Range:
+//    return postWalkRangeStmt(static_cast<RangeStmt *>(S));
+//  case StmtKind::Subscript:
+//    return postWalkSubscriptStmt(static_cast<SubscriptStmt *>(S));
+//  case StmtKind::Block:
+//    return postWalkBlockStmt(static_cast<BlockStmt *>(S));
+//  case StmtKind::Extern:
+//    return postWalkExternStmt(static_cast<ExternStmt *>(S));
+//  case StmtKind::For:
+//    return postWalkForStmt(static_cast<ForStmt *>(S));
+//  case StmtKind::Func:
+//    return postWalkFuncStmt(static_cast<FuncStmt *>(S));
+//  case StmtKind::If:
+//    return postWalkIfStmt(static_cast<IfStmt *>(S));
+//  case StmtKind::While:
+//    return postWalkWhileStmt(static_cast<WhileStmt *>(S));
+//  }
+//}
+//
+//bool TypeChecker::preWalk(Pattern *P) {
+//  switch (P->getKind()) {
+//  case PatternKind::Variable:
+//    return preWalkVarPattern(static_cast<VarPattern *>(P));
+//  case PatternKind::Expr:
+//    return preWalkExprPattern(static_cast<ExprPattern *>(P));
+//  }
+//}
+//
+//bool TypeChecker::postWalk(Pattern *P) {
+//  switch (P->getKind()) {
+//    case PatternKind::Variable:
+//      return postWalkVarPattern(static_cast<VarPattern *>(P));
+//    case PatternKind::Expr:
+//      return postWalkExprPattern(static_cast<ExprPattern *>(P));
+//  }
+//}
 
 
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index 0d72af1..e240f76 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -37,80 +37,92 @@ class Sema;
 ///
 /// This class takes an AST as an input and resolves types of all it's nodes,
 /// while validating them.
-class TypeChecker : public ASTWalker {
+class TypeChecker /*: public ASTWalker*/ {
   Sema &S;
-  NameLookup &DeclCtx;
+  
+public:
+  NameLookup &Lookup;
   ASTContext &Ctx;
   std::stack<Scope> Scp;
+  Scope ASTScope;
   DiagnosticEngine &Diag;
-
-public:
+  
   TypeChecker(Sema &S, NameLookup &DC, ASTContext &Ctx, DiagnosticEngine &Diag);
 
-  virtual bool preWalk(Decl *D) override;
-  virtual bool postWalk(Decl *D) override;
-
-  virtual bool preWalk(Expr *E) override;
-  virtual bool postWalk(Expr *E) override;
-
-  virtual bool preWalk(Stmt *S) override;
-  virtual bool postWalk(Stmt *S) override;
-  
-  virtual bool preWalk(Pattern *P) override;
-  virtual bool postWalk(Pattern *P) override;
+//  virtual bool preWalk(Decl *D) override;
+//  virtual bool postWalk(Decl *D) override;
+//
+//  virtual bool preWalk(Expr *E) override;
+//  virtual bool postWalk(Expr *E) override;
+//
+//  virtual bool preWalk(Stmt *S) override;
+//  virtual bool postWalk(Stmt *S) override;
+//
+//  virtual bool preWalk(Pattern *P) override;
+//  virtual bool postWalk(Pattern *P) override;
 
-private:
   void diagnose(SMLoc Loc, diag::DiagID ID);
   
-  // MARK: - Declarations
-  bool preWalkLetDecl(LetDecl *D);
-  bool preWalkFuncDecl(FuncDecl *D);
-  bool preWalkModuleDecl(ModuleDecl *D);
-  bool preWalkParamDecl(ParamDecl *D);
-  bool preWalkVarDecl(VarDecl *D);
-
-  bool postWalkLetDecl(LetDecl *D);
-  bool postWalkFuncDecl(FuncDecl *D);
-  bool postWalkModuleDecl(ModuleDecl *D);
-  bool postWalkParamDecl(ParamDecl *D);
-  bool postWalkVarDecl(VarDecl *D);
-
-  // MARK: - Expressions
-  bool postWalkNumberLiteralExpr(NumberLiteralExpr *E);
-  bool postWalkArrayLiteralExpr(ArrayLiteralExpr *E);
-  bool postWalkIdentifierExpr(IdentifierExpr *E);
-  bool postWalkParenExpr(ParenExpr *E);
-  bool postWalkAssignExpr(AssignExpr *E);
-  bool postWalkInfixExpr(InfixExpr *E);
-  bool postWalkPrefixExpr(PrefixExpr *E);
-  bool postWalkCallExpr(CallExpr *E);
-  bool postWalkSubscriptExpr(SubscriptExpr *E);
-
-  // MARK: - Statements
-  bool preWalkBlockStmt(BlockStmt *S);
-  bool preWalkExternStmt(ExternStmt *S);
-  bool preWalkForStmt(ForStmt *S);
-  bool preWalkFuncStmt(FuncStmt *S);
-  bool preWalkIfStmt(IfStmt *S);
-  bool preWalkWhileStmt(WhileStmt *S);
-
-  bool postWalkBreakStmt(BreakStmt *S);
-  bool postWalkReturnStmt(ReturnStmt *S);
-  bool postWalkRangeStmt(RangeStmt *S);
-  bool postWalkSubscriptStmt(SubscriptStmt *S);
-  bool postWalkBlockStmt(BlockStmt *S);
-  bool postWalkExternStmt(ExternStmt *S);
-  bool postWalkForStmt(ForStmt *S);
-  bool postWalkFuncStmt(FuncStmt *S);
-  bool postWalkIfStmt(IfStmt *S);
-  bool postWalkWhileStmt(WhileStmt *S);
+  bool typeCheckEquals(Type *LHS, Type *RHS) {
+    return LHS->isClassOf(RHS);
+  }
   
-  // MARK: - Patterns
-  bool preWalkVarPattern(VarPattern *P);
-  bool preWalkExprPattern(ExprPattern *P);
+  void typeCheckDecl(Decl *D);
+  Expr *typeCheckExpr(Expr *E);
+  void typeCheckStmt(Stmt *S);
+  void typeCheckPattern(Pattern *P);
+  void typeCheckType(TypeRepr *TR);
   
-  bool postWalkVarPattern(VarPattern *P);
-  bool postWalkExprPattern(ExprPattern *P);
+//private:
+//  // MARK: - Declarations
+//  bool preWalkLetDecl(LetDecl *D);
+//  bool preWalkFuncDecl(FuncDecl *D);
+//  bool preWalkModuleDecl(ModuleDecl *D);
+//  bool preWalkParamDecl(ParamDecl *D);
+//  bool preWalkVarDecl(VarDecl *D);
+//
+//  bool postWalkLetDecl(LetDecl *D);
+//  bool postWalkFuncDecl(FuncDecl *D);
+//  bool postWalkModuleDecl(ModuleDecl *D);
+//  bool postWalkParamDecl(ParamDecl *D);
+//  bool postWalkVarDecl(VarDecl *D);
+//
+//  // MARK: - Expressions
+//  bool postWalkNumberLiteralExpr(NumberLiteralExpr *E);
+//  bool postWalkArrayLiteralExpr(ArrayLiteralExpr *E);
+//  bool postWalkIdentifierExpr(IdentifierExpr *E);
+//  bool postWalkParenExpr(ParenExpr *E);
+//  bool postWalkAssignExpr(AssignExpr *E);
+//  bool postWalkInfixExpr(InfixExpr *E);
+//  bool postWalkPrefixExpr(PrefixExpr *E);
+//  bool postWalkCallExpr(CallExpr *E);
+//  bool postWalkSubscriptExpr(SubscriptExpr *E);
+//
+//  // MARK: - Statements
+//  bool preWalkBlockStmt(BlockStmt *S);
+//  bool preWalkExternStmt(ExternStmt *S);
+//  bool preWalkForStmt(ForStmt *S);
+//  bool preWalkFuncStmt(FuncStmt *S);
+//  bool preWalkIfStmt(IfStmt *S);
+//  bool preWalkWhileStmt(WhileStmt *S);
+//
+//  bool postWalkBreakStmt(BreakStmt *S);
+//  bool postWalkReturnStmt(ReturnStmt *S);
+//  bool postWalkRangeStmt(RangeStmt *S);
+//  bool postWalkSubscriptStmt(SubscriptStmt *S);
+//  bool postWalkBlockStmt(BlockStmt *S);
+//  bool postWalkExternStmt(ExternStmt *S);
+//  bool postWalkForStmt(ForStmt *S);
+//  bool postWalkFuncStmt(FuncStmt *S);
+//  bool postWalkIfStmt(IfStmt *S);
+//  bool postWalkWhileStmt(WhileStmt *S);
+//
+//  // MARK: - Patterns
+//  bool preWalkVarPattern(VarPattern *P);
+//  bool preWalkExprPattern(ExprPattern *P);
+//
+//  bool postWalkVarPattern(VarPattern *P);
+//  bool postWalkExprPattern(ExprPattern *P);
 };
 
 } // namespace sema
diff --git a/lib/Sema/TypeResolver.cpp b/lib/Sema/TypeResolver.cpp
index 57e3f6e..2572c68 100644
--- a/lib/Sema/TypeResolver.cpp
+++ b/lib/Sema/TypeResolver.cpp
@@ -115,16 +115,14 @@ bool TypeResolver::resolveFuncDecl(FuncDecl *D) {
   if (D->hasTypeRepr()) {
     RT = D->getTypeRepr()->getType();
   } else {
-    RT = new(Context) VoidType();
+    RT = new (Context) VoidType();
   }
 
-  D->setType(new(Context) FunctionType(AT, RT));
+  D->setType(new (Context) FunctionType(AT, RT));
   return true;
 }
 
-bool TypeResolver::resolveModuleDecl(ModuleDecl *D) {
-  return true;
-}
+bool TypeResolver::resolveModuleDecl(ModuleDecl *D) { return true; }
 
 bool TypeResolver::resolveParamDecl(ParamDecl *D) {
   if (D->hasTypeRepr())
@@ -143,7 +141,7 @@ Expr *TypeResolver::resolveArrayLiteralExpr(ArrayLiteralExpr *E) {
   auto Size = E->getValues()->count();
   auto Vals = static_cast<ExprPattern *>(E->getValues());
   auto BaseTy = Vals->getValues().front()->getType();
-  E->setType(new(Context) ArrayType(BaseTy, Size));
+  E->setType(new (Context) ArrayType(BaseTy, Size));
   return E;
 }
 
@@ -217,12 +215,12 @@ bool TypeResolver::typeResolveIdentTypeRepr(IdentTypeRepr *TR) {
   if (TR->getIdent() == "Void") {
     TR->setType(Context.getVoidType());
     return true;
-    
+
   } else if (TR->getIdent() == "Int") {
     TR->setType(Context.getVoidType());
     return true;
   }
-  
+
   Diag.diagnose(TR->getLocStart(), diag::unknown_type);
   return true;
 }
@@ -230,7 +228,7 @@ bool TypeResolver::typeResolveIdentTypeRepr(IdentTypeRepr *TR) {
 bool TypeResolver::typeResolveArrayTypeRepr(ArrayTypeRepr *TR) {
   auto BaseTy = TR->getBaseTyRepr()->getType();
   auto Size = 0; // TODO: perform exctraction. TR->getSize();
-  
-  TR->setType(new(Context) ArrayType(BaseTy, Size));
+
+  TR->setType(new (Context) ArrayType(BaseTy, Size));
   return true;
 }
diff --git a/tools/duskc/main.cpp b/tools/duskc/main.cpp
index b9cf9a0..c69dee6 100644
--- a/tools/duskc/main.cpp
+++ b/tools/duskc/main.cpp
@@ -7,6 +7,8 @@
 #include <iostream>
 #include <string>
 
+#include "dusk/AST/Scope.h"
+
 using namespace dusk;
 using namespace llvm;
 
@@ -29,7 +31,7 @@ int main(int argc, const char *argv[]) {
   cl::ParseCommandLineOptions(argc, argv);
   CompilerInstance Compiler;
   initCompilerInstance(Compiler);
-  
+
   Compiler.performParseOnly();
   if (Compiler.hasASTContext() && !Compiler.getContext().isError()) {
     Formatter F(Compiler.getContext(), llvm::errs());
-- 
GitLab