Browse Source

Fix anonymous procedures and their dependencies

Ginger Bill 8 years ago
parent
commit
923b039cf6
11 changed files with 387 additions and 374 deletions
  1. 8 15
      code/demo.odin
  2. 1 1
      core/_preload.odin
  3. 156 156
      core/_soft_numbers.odin
  4. 1 2
      core/os_windows.odin
  5. 8 6
      core/utf8.odin
  6. 3 1
      src/checker/checker.c
  7. 64 64
      src/checker/expr.c
  8. 2 0
      src/checker/stmt.c
  9. 18 9
      src/main.c
  10. 116 88
      src/parser.c
  11. 10 32
      src/ssa.c

+ 8 - 15
code/demo.odin

@@ -10,22 +10,15 @@ import (
 	"utf8.odin";
 )
 
-type Byte_Size f64;
-const (
-	_            = iota; // ignore first value by assigning to blank identifier
-	KB Byte_Size = 1 << (10 * iota);
-	// Because there is no type or expression, the previous one is used but
-	// with `iota` incremented by one
-	MB;
-	GB;
-	TB;
-	PB;
-	EB;
-)
-
-
 proc main() {
-	fmt.println("Here");
+	var x = proc() -> int {
+		proc print_here() {
+			fmt.println("Here");
+		}
 
+		print_here();
+		return 1;
+	};
+	fmt.println(x());
 }
 

+ 1 - 1
core/_preload.odin

@@ -112,7 +112,7 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
 
-type Allocator_Mode int;
+type Allocator_Mode u8;
 const (
 	ALLOCATOR_ALLOC Allocator_Mode = iota;
 	ALLOCATOR_FREE;

+ 156 - 156
core/_soft_numbers.odin

@@ -1,158 +1,158 @@
 #shared_global_scope;
 
-/*
-#import "fmt.odin"
-
-__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" {
-	_, r := __u128_quo_mod(a, b)
-	return r
-}
-
-__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" {
-	n, _ := __u128_quo_mod(a, b)
-	return n
-}
-
-__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" {
-	_, r := __i128_quo_mod(a, b)
-	return r
-}
-
-__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" {
-	n, _ := __i128_quo_mod(a, b)
-	return n
-}
-
-__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
-	s := b >> 127
-	b = (b ~ s) - s
-	s = a >> 127
-	a = (a ~ s) - s
-
-	n, r := __u128_quo_mod(a as u128, b as u128)
-	return (n as i128 ~ s) - s, (r as i128 ~ s) - s
-}
-
-
-__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
-	clz :: proc(x: u64) -> u64 {
-		clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
-		return clz_u64(x, false)
-	}
-	ctz :: proc(x: u64) -> u64 {
-		ctz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
-		return ctz_u64(x, false)
-	}
-
-
-	u128_lo_hi :: raw_union {
-		all: u128
-		using _lohi: struct {lo, hi: u64;}
-	}
-
-	n, d, q, r: u128_lo_hi
-	sr: u64
-
-	n.all = a
-	d.all = b
-
-	if n.hi == 0 {
-		if d.hi == 0 {
-			return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
-		}
-		return 0, n.lo as u128
-	}
-	if d.lo == 0 {
-		if d.hi == 0 {
-			return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
-		}
-		if n.lo == 0 {
-			r.hi = n.hi % d.hi
-			r.lo = 0
-			return (n.hi / d.hi) as u128, r.all
-		}
-		if (d.hi & (d.hi-1)) == 0 {
-			r.lo = n.lo
-			r.hi = n.hi & (d.hi-1)
-			return (n.hi >> ctz(d.hi)) as u128, r.all
-		}
-
-		sr = clz(d.hi) - clz(n.hi)
-		if sr > 64 - 2 {
-			return 0, n.all
-		}
-		sr++
-		q.lo = 0
-		q.hi = n.lo << (64-sr)
-		r.hi = n.hi >> sr
-		r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-	} else {
-		if d.hi == 0 {
-			if (d.lo & (d.lo - 1)) == 0 {
-				rem := (n.lo % (d.lo - 1)) as u128
-				if d.lo == 1 {
-					return n.all, rem
-				}
-				sr = ctz(d.lo)
-				q.hi = n.hi >> sr
-				q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-				return q.all, rem
-			}
-
-			sr = 1 + 64 + clz(d.lo) - clz(n.hi)
-
-			q.all = n.all << (128-sr)
-			r.all = n.all >> sr
-			if sr == 64 {
-				q.lo = 0
-				q.hi = n.lo
-				r.hi = 0
-				r.lo = n.hi
-			} else if sr < 64 {
-				q.lo = 0
-				q.hi = n.lo << (64-sr)
-				r.hi = n.hi >> sr
-				r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-			} else {
-				q.lo = n.lo << (128-sr)
-				q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
-				r.hi = 0
-				r.lo = n.hi >> (sr-64)
-			}
-		} else {
-			sr = clz(d.hi) - clz(n.hi)
-			if sr > 64-1 {
-				return 0, n.all
-			}
-			sr++
-			q.lo = 0
-			q.hi = n.lo << (64-sr)
-			r.all = n.all >> sr
-			if sr < 64 {
-				r.hi = n.hi >> sr
-				r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-			} else {
-				r.hi = 0
-				r.lo = n.hi
-			}
-		}
-	}
-
-	carry: u64
-	for ; sr > 0; sr-- {
-		r.hi = (r.hi << 1) | (r.lo >> (64-1))
-		r.lo = (r.lo << 1) | (r.hi >> (64-1))
-		q.hi = (q.hi << 1) | (q.lo >> (64-1))
-		q.lo = (q.lo << 1) | carry
-
-		carry = 0
-		if r.all >= d.all {
-			r.all -= d.all
-			carry = 1
-		}
-	}
-
-	q.all = (q.all << 1) | (carry as u128)
-	return q.all, r.all
-}
-*/
+
+// import "fmt.odin";
+
+// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" {
+// 	var _, r := __u128_quo_mod(a, b)
+// 	return r
+// }
+
+// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" {
+// 	var n, _ := __u128_quo_mod(a, b)
+// 	return n
+// }
+
+// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" {
+// 	var _, r := __i128_quo_mod(a, b)
+// 	return r
+// }
+
+// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" {
+// 	var n, _ := __i128_quo_mod(a, b)
+// 	return n
+// }
+
+// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
+// 	var s := b >> 127
+// 	b = (b ~ s) - s
+// 	s = a >> 127
+// 	a = (a ~ s) - s
+
+// 	var n, r := __u128_quo_mod(a as u128, b as u128)
+// 	return (n as i128 ~ s) - s, (r as i128 ~ s) - s
+// }
+
+
+// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
+// 	proc clz(x: u64) -> u64 {
+// 		proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
+// 		return clz_u64(x, false)
+// 	}
+// 	proc ctz(x: u64) -> u64 {
+// 		proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
+// 		return ctz_u64(x, false)
+// 	}
+
+
+// 	u128_lo_hi :: raw_union {
+// 		all: u128
+// 		using _lohi: struct {lo, hi: u64;}
+// 	}
+
+// 	n, d, q, r: u128_lo_hi
+// 	sr: u64
+
+// 	n.all = a
+// 	d.all = b
+
+// 	if n.hi == 0 {
+// 		if d.hi == 0 {
+// 			return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
+// 		}
+// 		return 0, n.lo as u128
+// 	}
+// 	if d.lo == 0 {
+// 		if d.hi == 0 {
+// 			return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
+// 		}
+// 		if n.lo == 0 {
+// 			r.hi = n.hi % d.hi
+// 			r.lo = 0
+// 			return (n.hi / d.hi) as u128, r.all
+// 		}
+// 		if (d.hi & (d.hi-1)) == 0 {
+// 			r.lo = n.lo
+// 			r.hi = n.hi & (d.hi-1)
+// 			return (n.hi >> ctz(d.hi)) as u128, r.all
+// 		}
+
+// 		sr = clz(d.hi) - clz(n.hi)
+// 		if sr > 64 - 2 {
+// 			return 0, n.all
+// 		}
+// 		sr++
+// 		q.lo = 0
+// 		q.hi = n.lo << (64-sr)
+// 		r.hi = n.hi >> sr
+// 		r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
+// 	} else {
+// 		if d.hi == 0 {
+// 			if (d.lo & (d.lo - 1)) == 0 {
+// 				var rem := (n.lo % (d.lo - 1)) as u128
+// 				if d.lo == 1 {
+// 					return n.all, rem
+// 				}
+// 				sr = ctz(d.lo)
+// 				q.hi = n.hi >> sr
+// 				q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
+// 				return q.all, rem
+// 			}
+
+// 			sr = 1 + 64 + clz(d.lo) - clz(n.hi)
+
+// 			q.all = n.all << (128-sr)
+// 			r.all = n.all >> sr
+// 			if sr == 64 {
+// 				q.lo = 0
+// 				q.hi = n.lo
+// 				r.hi = 0
+// 				r.lo = n.hi
+// 			} else if sr < 64 {
+// 				q.lo = 0
+// 				q.hi = n.lo << (64-sr)
+// 				r.hi = n.hi >> sr
+// 				r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
+// 			} else {
+// 				q.lo = n.lo << (128-sr)
+// 				q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
+// 				r.hi = 0
+// 				r.lo = n.hi >> (sr-64)
+// 			}
+// 		} else {
+// 			sr = clz(d.hi) - clz(n.hi)
+// 			if sr > 64-1 {
+// 				return 0, n.all
+// 			}
+// 			sr++
+// 			q.lo = 0
+// 			q.hi = n.lo << (64-sr)
+// 			r.all = n.all >> sr
+// 			if sr < 64 {
+// 				r.hi = n.hi >> sr
+// 				r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
+// 			} else {
+// 				r.hi = 0
+// 				r.lo = n.hi
+// 			}
+// 		}
+// 	}
+
+// 	carry: u64
+// 	for ; sr > 0; sr-- {
+// 		r.hi = (r.hi << 1) | (r.lo >> (64-1))
+// 		r.lo = (r.lo << 1) | (r.hi >> (64-1))
+// 		q.hi = (q.hi << 1) | (q.lo >> (64-1))
+// 		q.lo = (q.lo << 1) | carry
+
+// 		carry = 0
+// 		if r.all >= d.all {
+// 			r.all -= d.all
+// 			carry = 1
+// 		}
+// 	}
+
+// 	q.all = (q.all << 1) | (carry as u128)
+// 	return q.all, r.all
+// }
+

+ 1 - 2
core/os_windows.odin

@@ -93,8 +93,7 @@ const (
 	FILE_STANDARD_ERROR;
 
 	FILE_STANDARD_COUNT;
-);
-
+)
 // NOTE(bill): Uses startup to initialize it
 var (
 	__std_files = [FILE_STANDARD_COUNT]File{

+ 8 - 6
core/utf8.odin

@@ -8,11 +8,11 @@ const (
 
 	SURROGATE_MIN = 0xd800;
 	SURROGATE_MAX = 0xdfff;
-);
+)
 
 type Accept_Range struct {
 	lo, hi u8;
-};
+}
 
 var (
 	accept_ranges = [5]Accept_Range{
@@ -99,10 +99,12 @@ proc decode_rune(s string) -> (rune, int) {
 		return RUNE_ERROR, 1;
 	}
 
-	const MASK_X = 0b00111111;
-	const MASK_2 = 0b00011111;
-	const MASK_3 = 0b00001111;
-	const MASK_4 = 0b00000111;
+	const (
+		MASK_X = 0b00111111;
+		MASK_2 = 0b00011111;
+		MASK_3 = 0b00001111;
+		MASK_4 = 0b00000111;
+	)
 
 	if size == 2 {
 		return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;

+ 3 - 1
src/checker/checker.c

@@ -1142,6 +1142,8 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 			for_array(iota, gd->specs) {
 				AstNode *spec = gd->specs.e[iota];
 				switch (spec->kind) {
+				case_ast_node(bd, BadDecl, decl);
+				case_end;
 				case_ast_node(is, ImportSpec, spec);
 					if (!parent_scope->is_file) {
 						// NOTE(bill): _Should_ be caught by the parser
@@ -1347,7 +1349,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
 				}
 				// NOTE(bill): Do not add other imported entities
 				add_entity(c, parent_scope, NULL, e);
-				if (!id->is_load) { // `#import`ed entities don't get exported
+				if (id->keyword == Token_import) { // `#import`ed entities don't get exported
 					HashKey key = hash_string(e->token.string);
 					map_entity_set(&parent_scope->implicit, key, e);
 				}

+ 64 - 64
src/checker/expr.c

@@ -87,6 +87,8 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
 			for_array(iota, gd->specs) {
 				AstNode *spec = gd->specs.e[iota];
 				switch (spec->kind) {
+				case_ast_node(bd, BadDecl, spec);
+				case_end;
 				case_ast_node(vs, ValueSpec, spec);
 					switch (vs->keyword) {
 					case Token_var:
@@ -453,15 +455,15 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 		fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL);
 		for_array(decl_index, decls) {
 			AstNode *decl = decls.e[decl_index];
-			if (decl->kind != AstNode_Parameter) {
+			if (decl->kind != AstNode_Field) {
 				continue;
 			}
 
-			ast_node(p, Parameter, decl);
-			Type *base_type = check_type_extra(c, p->type, NULL);
+			ast_node(f, Field, decl);
+			Type *base_type = check_type_extra(c, f->type, NULL);
 
-			for_array(name_index, p->names) {
-				AstNode *name = p->names.e[name_index];
+			for_array(name_index, f->names) {
+				AstNode *name = f->names.e[name_index];
 				if (!ast_node_expect(name, AstNode_Ident)) {
 					continue;
 				}
@@ -493,28 +495,28 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 		isize field_index = 0;
 		for_array(decl_index, decls) {
 			AstNode *decl = decls.e[decl_index];
-			if (decl->kind != AstNode_Parameter) {
+			if (decl->kind != AstNode_Field) {
 				continue;
 			}
-			ast_node(param, Parameter, decl);
+			ast_node(f, Field, decl);
 
-			Type *type = check_type_extra(c, param->type, NULL);
+			Type *type = check_type_extra(c, f->type, NULL);
 
-			if (param->is_using) {
-				if (param->names.count > 1) {
-					error_node(param->names.e[0], "Cannot apply `using` to more than one of the same type");
+			if (f->is_using) {
+				if (f->names.count > 1) {
+					error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type");
 				}
 			}
 
-			for_array(name_index, param->names) {
-				AstNode *name = param->names.e[name_index];
+			for_array(name_index, f->names) {
+				AstNode *name = f->names.e[name_index];
 				if (!ast_node_expect(name, AstNode_Ident)) {
 					continue;
 				}
 
 				Token name_token = name->Ident;
 
-				Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, param->is_using, cast(i32)field_index);
+				Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->is_using, cast(i32)field_index);
 				e->identifier = name;
 				if (str_eq(name_token.string, str_lit("_"))) {
 					fields[field_index++] = e;
@@ -533,19 +535,19 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 			}
 
 
-			if (param->is_using) {
+			if (f->is_using) {
 				Type *t = base_type(type_deref(type));
 				if (!is_type_struct(t) && !is_type_raw_union(t) &&
-				    param->names.count >= 1 &&
-				    param->names.e[0]->kind == AstNode_Ident) {
-					Token name_token = param->names.e[0]->Ident;
+				    f->names.count >= 1 &&
+				    f->names.e[0]->kind == AstNode_Ident) {
+					Token name_token = f->names.e[0]->Ident;
 					if (is_type_indexable(t)) {
 						bool ok = true;
 						for_array(emi, entity_map.entries) {
 							Entity *e = entity_map.entries.e[emi].value;
 							if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
 								if (is_type_indexable(e->type)) {
-									if (e->identifier != param->names.e[0]) {
+									if (e->identifier != f->names.e[0]) {
 										ok = false;
 										using_index_expr = e;
 										break;
@@ -613,8 +615,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
 	for_array(field_index, st->fields) {
 		AstNode *field = st->fields.e[field_index];
 		switch (field->kind) {
-		case_ast_node(p, Parameter, field);
-			field_count += p->names.count;
+		case_ast_node(f, Field, field);
+			field_count += f->names.count;
 		case_end;
 		}
 	}
@@ -662,8 +664,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
 	for_array(field_index, ut->fields) {
 		AstNode *field = ut->fields.e[field_index];
 		switch (field->kind) {
-		case_ast_node(p, Parameter, field);
-			field_count += p->names.count;
+		case_ast_node(f, Field, field);
+			field_count += f->names.count;
 		case_end;
 		}
 	}
@@ -685,8 +687,8 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
 	for_array(field_index, ut->fields) {
 		AstNode *field = ut->fields.e[field_index];
 		switch (field->kind) {
-		case_ast_node(p, Parameter, field);
-			field_count += p->names.count;
+		case_ast_node(f, Field, field);
+			field_count += f->names.count;
 		case_end;
 		}
 	}
@@ -699,51 +701,47 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
 	union_type->Record.field_count = field_count;
 }
 
-GB_COMPARE_PROC(cmp_enum_order) {
-	// Rule:
-	// Biggest to smallest alignment
-	// if same alignment: biggest to smallest size
-	// if same size: order by source order
-	Entity *x = *(Entity **)a;
-	Entity *y = *(Entity **)b;
-	GB_ASSERT(x != NULL);
-	GB_ASSERT(y != NULL);
-	GB_ASSERT(x->kind == Entity_Constant);
-	GB_ASSERT(y->kind == Entity_Constant);
-	GB_ASSERT(x->Constant.value.kind == ExactValue_Integer);
-	GB_ASSERT(y->Constant.value.kind == ExactValue_Integer);
-	i64 i = x->Constant.value.value_integer;
-	i64 j = y->Constant.value.value_integer;
-
-	return i < j ? -1 : i > j;
-}
+// GB_COMPARE_PROC(cmp_enum_order) {
+// 	// Rule:
+// 	// Biggest to smallest alignment
+// 	// if same alignment: biggest to smallest size
+// 	// if same size: order by source order
+// 	Entity *x = *(Entity **)a;
+// 	Entity *y = *(Entity **)b;
+// 	GB_ASSERT(x != NULL);
+// 	GB_ASSERT(y != NULL);
+// 	GB_ASSERT(x->kind == Entity_Constant);
+// 	GB_ASSERT(y->kind == Entity_Constant);
+// 	GB_ASSERT(x->Constant.value.kind == ExactValue_Integer);
+// 	GB_ASSERT(y->Constant.value.kind == ExactValue_Integer);
+// 	i64 i = x->Constant.value.value_integer;
+// 	i64 j = y->Constant.value.value_integer;
+
+// 	return i < j ? -1 : i > j;
+// }
 
 Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
 	if (params.count == 0) {
 		return NULL;
 	}
 
-	bool is_variadic = false;
-
-	Type *tuple = make_type_tuple(c->allocator);
-
 	isize variable_count = 0;
 	for_array(i, params) {
 		AstNode *field = params.e[i];
-		if (!ast_node_expect(field, AstNode_Parameter)) {
-			continue;
+		if (ast_node_expect(field, AstNode_Field)) {
+			ast_node(f, Field, field);
+			variable_count += f->names.count;
 		}
-		ast_node(p, Parameter, field);
-		variable_count += p->names.count;
 	}
 
+	bool is_variadic = false;
 	Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
 	isize variable_index = 0;
 	for_array(i, params) {
-		if (params.e[i]->kind != AstNode_Parameter) {
+		if (params.e[i]->kind != AstNode_Field) {
 			continue;
 		}
-		ast_node(p, Parameter, params.e[i]);
+		ast_node(p, Field, params.e[i]);
 		AstNode *type_expr = p->type;
 		if (type_expr) {
 			if (type_expr->kind == AstNode_Ellipsis) {
@@ -777,6 +775,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 		end->type = make_type_slice(c->allocator, end->type);
 	}
 
+	Type *tuple = make_type_tuple(c->allocator);
 	tuple->Tuple.variables = variables;
 	tuple->Tuple.variable_count = variable_count;
 
@@ -3687,21 +3686,21 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 	case_end;
 
 	case_ast_node(pl, ProcLit, node);
-		check_open_scope(c, pl->type);
-		c->context.decl = make_declaration_info(c->allocator, c->context.scope);
 		Type *proc_type = check_type(c, pl->type);
-		if (proc_type != NULL) {
-			check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);
-			o->mode = Addressing_Value;
-			o->type = proc_type;
-			check_close_scope(c);
-		} else {
+		if (proc_type == NULL) {
 			gbString str = expr_to_string(node);
 			error_node(node, "Invalid procedure literal `%s`", str);
 			gb_string_free(str);
 			check_close_scope(c);
 			goto error;
 		}
+		check_open_scope(c, pl->type);
+		check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);
+		check_close_scope(c);
+
+		o->mode = Addressing_Value;
+		o->type = proc_type;
+
 	case_end;
 
 	case_ast_node(cl, CompoundLit, node);
@@ -4240,7 +4239,7 @@ gbString write_expr_to_string(gbString str, AstNode *node);
 
 gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
 	for_array(i, params) {
-		ast_node(p, Parameter, params.e[i]);
+		ast_node(p, Field, params.e[i]);
 		if (i > 0) {
 			str = gb_string_appendc(str, sep);
 		}
@@ -4390,14 +4389,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = write_expr_to_string(str, vt->elem);
 	case_end;
 
-	case_ast_node(p, Parameter, node);
+	case_ast_node(p, Field, node);
 		if (p->is_using) {
 			str = gb_string_appendc(str, "using ");
 		}
 		for_array(i, p->names) {
 			AstNode *name = p->names.e[i];
-			if (i > 0)
+			if (i > 0) {
 				str = gb_string_appendc(str, ", ");
+			}
 			str = write_expr_to_string(str, name);
 		}
 

+ 2 - 0
src/checker/stmt.c

@@ -1088,6 +1088,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		for_array(spec_index, gd->specs) {
 			AstNode *spec = gd->specs.e[spec_index];
 			switch (spec->kind) {
+			case_ast_node(bd, BadDecl, spec);
+			case_end;
 			case_ast_node(vs, ValueSpec, spec);
 				switch (vs->keyword) {
 				case Token_let:

+ 18 - 9
src/main.c

@@ -59,17 +59,26 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 	return exit_code;
 }
 
+void print_usage_line(i32 indent, char *fmt, ...) {
+	while (indent --> 0) {
+		gb_printf_err("\t");
+	}
+	va_list va;
+	va_start(va, fmt);
+	gb_printf_err_va(fmt, va);
+	va_end(va);
+	gb_printf_err("\n");
+}
 
 void usage(char *argv0) {
-	gb_printf_err("%s is a tool for managing Odin source code\n", argv0);
-	gb_printf_err("Usage:");
-	gb_printf_err("\n\t%s command [arguments]\n", argv0);
-	gb_printf_err("Commands:");
-	gb_printf_err("\n\tbuild     compile .odin file");
-	gb_printf_err("\n\tbuild_dll compile .odin file as dll");
-	gb_printf_err("\n\trun       compile and run .odin file");
-	gb_printf_err("\n\tversion   print Odin version");
-	gb_printf_err("\n\n");
+	print_usage_line(0, "%s is a tool for managing Odin source code", argv0);
+	print_usage_line(0, "Usage:");
+	print_usage_line(1, "%s command [arguments]", argv0);
+	print_usage_line(0, "Commands:");
+	print_usage_line(1, "build        compile .odin file as executable");
+	print_usage_line(1, "build_dll    compile .odin file as dll");
+	print_usage_line(1, "run          compile and run .odin file");
+	print_usage_line(1, "version      print version");
 }
 
 int main(int argc, char **argv) {

+ 116 - 88
src/parser.c

@@ -57,6 +57,7 @@ typedef struct Parser {
 	Array(ImportedFile) imports;
 	gbAtomic32          import_index;
 	isize               total_token_count;
+	isize               total_line_count;
 	gbMutex             mutex;
 } Parser;
 
@@ -176,52 +177,56 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
 		AstNodeArray results; \
 	}) \
 	AST_NODE_KIND(ForStmt, "for statement", struct { \
-		Token token; \
-		AstNode *init, *cond, *post; \
+		Token    token; \
+		AstNode *init; \
+		AstNode *cond; \
+		AstNode *post; \
 		AstNode *body; \
 	}) \
 	AST_NODE_KIND(CaseClause, "case clause", struct { \
-		Token token; \
-		AstNodeArray list, stmts; \
+		Token token;        \
+		AstNodeArray list;  \
+		AstNodeArray stmts; \
 	}) \
 	AST_NODE_KIND(MatchStmt, "match statement", struct { \
-		Token token; \
-		AstNode *init, *tag; \
+		Token token;   \
+		AstNode *init; \
+		AstNode *tag;  \
 		AstNode *body; \
 	}) \
 	AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
-		Token token; \
-		AstNode *tag, *var; \
-		AstNode *body; \
+		Token    token; \
+		AstNode *tag;   \
+ 		AstNode *var;   \
+		AstNode *body;  \
 	}) \
 	AST_NODE_KIND(DeferStmt,  "defer statement",  struct { Token token; AstNode *stmt; }) \
 	AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
 	AST_NODE_KIND(UsingStmt,  "using statement",  struct { Token token; AstNode *node; }) \
 	AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
-		Token string; \
+		Token string;     \
 		AstNode *operand; \
 	}) \
 	AST_NODE_KIND(AsmStmt,    "assembly statement", struct { \
-		Token token; \
-		bool is_volatile; \
-		Token open, close; \
-		Token code_string; \
-		AstNode *output_list; \
-		AstNode *input_list; \
+		Token token;           \
+		bool is_volatile;      \
+		Token open, close;     \
+		Token code_string;     \
+		AstNode *output_list;  \
+		AstNode *input_list;   \
 		AstNode *clobber_list; \
 		isize output_count, input_count, clobber_count; \
 	}) \
 	AST_NODE_KIND(PushAllocator, "push_allocator statement", struct { \
-		Token token; \
+		Token token;   \
 		AstNode *expr; \
 		AstNode *body; \
 	}) \
 	AST_NODE_KIND(PushContext, "push_context statement", struct { \
-		Token token; \
+		Token token;   \
 		AstNode *expr; \
 		AstNode *body; \
 	}) \
-\
 AST_NODE_KIND(_ComplexStmtEnd, "", i32) \
 AST_NODE_KIND(_StmtEnd,        "", i32) \
 AST_NODE_KIND(_SpecBegin, "", i32) \
@@ -237,12 +242,12 @@ AST_NODE_KIND(_SpecBegin, "", i32) \
 		AstNode *note; \
 	}) \
 	AST_NODE_KIND(ImportSpec, "import specification", struct { \
-		Token   relpath;      \
-		String  fullpath;     \
-		Token   import_name;  \
-		bool    is_load;      \
-		AstNode *cond;        \
-		AstNode *note;        \
+		TokenKind keyword;      \
+		Token     relpath;      \
+		String    fullpath;     \
+		Token     import_name;  \
+		AstNode   *cond;        \
+		AstNode   *note;        \
 	}) \
 AST_NODE_KIND(_SpecEnd,   "", i32) \
 AST_NODE_KIND(_DeclBegin,      "", i32) \
@@ -270,12 +275,12 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		bool is_system;        \
 	}) \
 AST_NODE_KIND(_DeclEnd,   "", i32) \
-AST_NODE_KIND(_TypeBegin, "", i32) \
-	AST_NODE_KIND(Parameter, "parameter", struct { \
-		AstNodeArray names; \
-		AstNode *type; \
-		bool is_using; \
+	AST_NODE_KIND(Field, "field", struct { \
+		AstNodeArray names;    \
+		AstNode *    type;     \
+		bool         is_using; \
 	}) \
+AST_NODE_KIND(_TypeBegin, "", i32) \
 	AST_NODE_KIND(ProcType, "procedure type", struct { \
 		Token token;          \
 		AstNodeArray params;  \
@@ -477,11 +482,11 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_ImportSpec:
 		return node->ImportSpec.relpath;
 
-	case AstNode_Parameter: {
-		if (node->Parameter.names.count > 0) {
-			return ast_node_token(node->Parameter.names.e[0]);
+	case AstNode_Field: {
+		if (node->Field.names.count > 0) {
+			return ast_node_token(node->Field.names.e[0]);
 		} else {
-			return ast_node_token(node->Parameter.type);
+			return ast_node_token(node->Field.type);
 		}
 	}
 	case AstNode_ProcType:
@@ -898,11 +903,11 @@ AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
 	return result;
 }
 
-AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) {
-	AstNode *result = make_node(f, AstNode_Parameter);
-	result->Parameter.names = names;
-	result->Parameter.type = type;
-	result->Parameter.is_using = is_using;
+AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) {
+	AstNode *result = make_node(f, AstNode_Field);
+	result->Field.names = names;
+	result->Field.type = type;
+	result->Field.is_using = is_using;
 	return result;
 }
 
@@ -1030,12 +1035,12 @@ AstNode *make_type_spec(AstFile *f, AstNode *name, AstNode *type) {
 }
 
 
-AstNode *make_import_spec(AstFile *f, Token relpath, Token import_name, AstNode *cond, bool is_load) {
+AstNode *make_import_spec(AstFile *f, TokenKind keyword, Token relpath, Token import_name, AstNode *cond) {
 	AstNode *result = make_node(f, AstNode_ImportSpec);
+	result->ImportSpec.keyword = keyword;
 	result->ImportSpec.relpath = relpath;
 	result->ImportSpec.import_name = import_name;
 	result->ImportSpec.cond = cond;
-	result->ImportSpec.is_load = is_load;
 	return result;
 }
 
@@ -1057,6 +1062,21 @@ bool next_token(AstFile *f) {
 	return false;
 }
 
+TokenKind look_ahead_token_kind(AstFile *f, isize amount) {
+	GB_ASSERT(amount > 0);
+
+	TokenKind kind = Token_Invalid;
+	isize index = f->curr_token_index;
+	while (amount > 0) {
+		index++;
+		kind = f->tokens.e[index].kind;
+		if (kind != Token_Comment) {
+			amount--;
+		}
+	}
+	return kind;
+}
+
 Token expect_token(AstFile *f, TokenKind kind) {
 	Token prev = f->curr_token;
 	if (prev.kind != kind) {
@@ -1859,17 +1879,17 @@ AstNodeArray parse_identfier_list(AstFile *f) {
 }
 
 void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) {
-	// for_array(i, names) {
-	// 	AstNode *name = names.e[i];
-	// 	if (name->kind == AstNode_Ident) {
-	// 		String n = name->Ident.string;
-	// 		// NOTE(bill): Check for reserved identifiers
-	// 		if (str_eq(n, str_lit("context"))) {
-	// 			syntax_error_node(name, "`context` is a reserved identifier");
-	// 			break;
-	// 		}
-	// 	}
-	// }
+	for_array(i, names) {
+		AstNode *name = names.e[i];
+		if (name->kind == AstNode_Ident) {
+			String n = name->Ident.string;
+			// NOTE(bill): Check for reserved identifiers
+			if (str_eq(n, str_lit("context"))) {
+				syntax_error_node(name, "`context` is a reserved identifier");
+				break;
+			}
+		}
+	}
 }
 
 AstNode *parse_type_attempt(AstFile *f) {
@@ -1998,7 +2018,7 @@ PARSE_SPEC_PROC(parse_import_spec) {
 		syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope");
 		spec = make_bad_decl(f, import_name, file_path);
 	} else {
-		spec = make_import_spec(f, file_path, import_name, cond, false);
+		spec = make_import_spec(f, Token_import, file_path, import_name, cond);
 	}
 	return spec;
 }
@@ -2017,7 +2037,7 @@ PARSE_SPEC_PROC(parse_include_spec) {
 		syntax_error(import_name, "You cannot use `include` within a procedure. This must be done at the file scope");
 		spec = make_bad_decl(f, import_name, file_path);
 	} else {
-		spec = make_import_spec(f, file_path, import_name, cond, true);
+		spec = make_import_spec(f, Token_include, file_path, import_name, cond);
 	}
 	return spec;
 }
@@ -2060,11 +2080,7 @@ AstNode *parse_simple_stmt(AstFile *f) {
 		return parse_decl(f);
 	}
 
-	isize lhs_count = 0, rhs_count = 0;
 	AstNodeArray lhs = parse_lhs_expr_list(f);
-
-
-	AstNode *statement = NULL;
 	Token token = f->curr_token;
 	switch (token.kind) {
 	case Token_Eq:
@@ -2096,7 +2112,7 @@ AstNode *parse_simple_stmt(AstFile *f) {
 	} break;
 	}
 
-	if (lhs_count > 1) {
+	if (lhs.count > 1) {
 		syntax_error(token, "Expected 1 expression");
 		return make_bad_stmt(f, token, f->curr_token);
 	}
@@ -2109,9 +2125,9 @@ AstNode *parse_simple_stmt(AstFile *f) {
 			syntax_error(f->curr_token, "You cannot use a simple statement in the file scope");
 			return make_bad_stmt(f, f->curr_token, f->curr_token);
 		}
-		statement = make_inc_dec_stmt(f, token, lhs.e[0]);
+		AstNode *stmt = make_inc_dec_stmt(f, token, lhs.e[0]);
 		next_token(f);
-		return statement;
+		return stmt;
 	}
 
 	return make_expr_stmt(f, lhs.e[0]);
@@ -2155,7 +2171,7 @@ AstNode *parse_proc_type(AstFile *f) {
 }
 
 
-AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) {
+AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) {
 	AstNodeArray params = make_ast_node_array(f);
 	isize name_count = 0;
 
@@ -2210,10 +2226,9 @@ AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_usi
 			syntax_error(f->curr_token, "Expected a type for this parameter declaration");
 		}
 
-		AstNode *param = make_parameter(f, names, type, is_using);
+		AstNode *param = make_field(f, names, type, is_using);
 		array_add(&params, param);
 
-
 		if (separator == Token_Semicolon) {
 			expect_semicolon(f, param);
 		} else {
@@ -2229,8 +2244,8 @@ AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_usi
 }
 
 
-AstNodeArray parse_record_params(AstFile *f, isize *field_count_, bool allow_using, String context) {
-	return parse_parameter_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace);
+AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, bool allow_using, String context) {
+	return parse_field_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace);
 }
 
 AstNode *parse_identifier_or_type(AstFile *f) {
@@ -2295,7 +2310,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		bool is_packed = false;
 		bool is_ordered = false;
 		while (allow_token(f, Token_Hash)) {
-			Token tag = expect_token_after(f, Token_Ident, "`#`");
+			Token tag = expect_token_after(f, Token_Ident, "#");
 			if (str_eq(tag.string, str_lit("packed"))) {
 				if (is_packed) {
 					syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
@@ -2315,9 +2330,9 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 			syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
 		}
 
-		Token open = expect_token_after(f, Token_OpenBrace, "`struct`");
+		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("struct"));
+		AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("struct"));
 		Token close = expect_token(f, Token_CloseBrace);
 
 		return make_struct_type(f, token, decls, decl_count, is_packed, is_ordered);
@@ -2325,9 +2340,9 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 
 	case Token_union: {
 		Token token = expect_token(f, Token_union);
-		Token open = expect_token_after(f, Token_OpenBrace, "`union`");
+		Token open = expect_token_after(f, Token_OpenBrace, "union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_params(f, &decl_count, false, str_lit("union"));
+		AstNodeArray decls = parse_record_fields(f, &decl_count, false, str_lit("union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
 		return make_union_type(f, token, decls, decl_count);
@@ -2335,9 +2350,9 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 
 	case Token_raw_union: {
 		Token token = expect_token(f, Token_raw_union);
-		Token open = expect_token_after(f, Token_OpenBrace, "`raw_union`");
+		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("raw_union"));
+		AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("raw_union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
 		return make_raw_union_type(f, token, decls, decl_count);
@@ -2391,7 +2406,7 @@ void parse_proc_signature(AstFile *f,
                           AstNodeArray *params,
                           AstNodeArray *results) {
 	expect_token(f, Token_OpenParen);
-	*params = parse_parameter_list(f, NULL, true, Token_Comma, Token_CloseParen);
+	*params = parse_field_list(f, NULL, true, Token_Comma, Token_CloseParen);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	*results = parse_results(f);
 }
@@ -2409,8 +2424,14 @@ AstNode *parse_body(AstFile *f) {
 
 
 AstNode *parse_proc_decl(AstFile *f) {
-	Token proc_token = expect_token(f, Token_proc);
+	if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
+		// NOTE(bill): It's an anonymous procedure
+		// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
+		// but is that a problem in practice?
+		return make_expr_stmt(f, parse_expr(f, true));
+	}
 
+	Token proc_token = expect_token(f, Token_proc);
 	AstNode *name = parse_identifier(f);
 
 	AstNodeArray params = {0};
@@ -2426,19 +2447,18 @@ AstNode *parse_proc_decl(AstFile *f) {
 
 	parse_proc_tags(f, &tags, &foreign_name, &link_name);
 
-	AstNode *curr_proc = f->curr_proc;
-	f->curr_proc = proc_type;
-
 	if (f->curr_token.kind == Token_OpenBrace) {
 		if ((tags & ProcTag_foreign) != 0) {
-			syntax_error_node(name, "A procedure tagged as `#foreign` cannot have a body");
+			syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
 		}
+		AstNode *curr_proc = f->curr_proc;
+		f->curr_proc = proc_type;
 		body = parse_body(f);
+		f->curr_proc = curr_proc;
 	} else if ((tags & ProcTag_foreign) == 0) {
-		syntax_error_node(name, "Only a procedure tagged as `#foreign` cannot have a body");
+		syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
 	}
 
-	f->curr_proc = curr_proc;
 	return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
 }
 
@@ -2958,6 +2978,11 @@ AstNodeArray parse_stmt_list(AstFile *f) {
 		AstNode *stmt = parse_stmt(f);
 		if (stmt && stmt->kind != AstNode_EmptyStmt) {
 			array_add(&list, stmt);
+			if (stmt->kind == AstNode_ExprStmt &&
+			    stmt->ExprStmt.expr != NULL &&
+			    stmt->ExprStmt.expr->kind == AstNode_ProcLit) {
+				syntax_error_node(stmt, "Procedure literal evaluated but not used");
+			}
 		}
 	}
 
@@ -3031,7 +3056,7 @@ void destroy_parser(Parser *p) {
 	for_array(i, p->files) {
 		destroy_ast_file(&p->files.e[i]);
 	}
-#if 1
+#if 0
 	for_array(i, p->imports) {
 		// gb_free(heap_allocator(), p->imports[i].text);
 	}
@@ -3093,21 +3118,23 @@ bool is_import_path_valid(String path) {
 		u8 *start = path.text;
 		u8 *end = path.text + path.len;
 		u8 *curr = start;
-		Rune r = -1;
 		while (curr < end) {
 			isize width = 1;
-			r = curr[0];
+			Rune r = curr[0];
 			if (r >= 0x80) {
 				width = gb_utf8_decode(curr, end-curr, &r);
-				if (r == GB_RUNE_INVALID && width == 1)
+				if (r == GB_RUNE_INVALID && width == 1) {
 					return false;
-				else if (r == GB_RUNE_BOM && curr-start > 0)
+				}
+				else if (r == GB_RUNE_BOM && curr-start > 0) {
 					return false;
+				}
 			}
 
 			for (isize i = 0; i < gb_count_of(illegal_import_runes); i++) {
-				if (r == illegal_import_runes[i])
+				if (r == illegal_import_runes[i]) {
 					return false;
+				}
 			}
 
 			curr += width;
@@ -3135,7 +3162,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray
 					String file_str = is->relpath.string;
 
 					if (!is_import_path_valid(file_str)) {
-						if (is->is_load) {
+						if (is->keyword == Token_include) {
 							syntax_error_node(node, "Invalid #include path: `%.*s`", LIT(file_str));
 						} else {
 							syntax_error_node(node, "Invalid #import path: `%.*s`", LIT(file_str));
@@ -3266,6 +3293,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
 			gb_mutex_lock(&p->mutex);
 			file.id = p->files.count;
 			array_add(&p->files, file);
+			p->total_line_count += file.tokenizer.line_count;
 			gb_mutex_unlock(&p->mutex);
 		}
 	}

+ 10 - 32
src/ssa.c

@@ -2607,6 +2607,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		} else if (e != NULL && e->kind == Entity_Variable) {
 			return ssa_addr_load(proc, ssa_build_addr(proc, expr));
 		}
+		GB_PANIC("nil value for expression from identifier: %.*s", LIT(i->string));
 		return NULL;
 	case_end;
 
@@ -2714,9 +2715,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 		                                           proc->module, NULL, type, pl->type, pl->body, name);
 
 		value->Proc.tags = pl->tags;
+		value->Proc.parent = proc;
 
 		array_add(&proc->children, &value->Proc);
-		ssa_build_proc(value, proc);
+		array_add(&proc->module->procs_to_generate, value);
 
 		return value;
 	case_end;
@@ -2971,32 +2973,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 				} break;
 
-#if 0
-				case BuiltinProc_ptr_offset: {
-					ssa_emit_comment(proc, str_lit("ptr_offset"));
-					ssaValue *ptr = ssa_build_expr(proc, ce->args.e[0]);
-					ssaValue *offset = ssa_build_expr(proc, ce->args.e[1]);
-					return ssa_emit_ptr_offset(proc, ptr, offset);
-				} break;
-
-				case BuiltinProc_ptr_sub: {
-					ssa_emit_comment(proc, str_lit("ptr_sub"));
-					ssaValue *ptr_a = ssa_build_expr(proc, ce->args.e[0]);
-					ssaValue *ptr_b = ssa_build_expr(proc, ce->args.e[1]);
-					Type *ptr_type = base_type(ssa_type(ptr_a));
-					GB_ASSERT(ptr_type->kind == Type_Pointer);
-					isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem);
-
-					ssaValue *v = ssa_emit_arith(proc, Token_Sub, ptr_a, ptr_b, t_int);
-					if (elem_size > 1) {
-						ssaValue *ez = ssa_make_const_int(proc->module->allocator, elem_size);
-						v = ssa_emit_arith(proc, Token_Quo, v, ez, t_int);
-					}
-
-					return v;
-				} break;
-#endif
-
 				case BuiltinProc_slice_ptr: {
 					ssa_emit_comment(proc, str_lit("slice_ptr"));
 					ssaValue *ptr = ssa_build_expr(proc, ce->args.e[0]);
@@ -3095,9 +3071,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			}
 		}
 
-
 		// NOTE(bill): Regular call
 		ssaValue *value = ssa_build_expr(proc, ce->proc);
+		GB_ASSERT(value != NULL);
 		Type *proc_type_ = base_type(ssa_type(value));
 		GB_ASSERT(proc_type_->kind == Type_Proc);
 		TypeProc *type = &proc_type_->Proc;
@@ -3269,7 +3245,7 @@ ssaAddr ssa_build_addr_from_entity(ssaProcedure *proc, Entity *e, AstNode *expr)
 	}
 
 	if (v == NULL) {
-		GB_PANIC("Unknown value: %s, entity: %p %.*s\n", expr_to_string(expr), e, LIT(entity_strings[e->kind]));
+		GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
 	}
 
 	return ssa_make_addr(v, expr);
@@ -3293,7 +3269,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 	case_ast_node(se, SelectorExpr, expr);
 		ssa_emit_comment(proc, str_lit("SelectorExpr"));
-		String selector = unparen_expr(se->selector)->Ident.string;
+		AstNode *sel = unparen_expr(se->selector);
+		GB_ASSERT(sel->kind == AstNode_Ident);
+		String selector = sel->Ident.string;
 		Type *type = base_type(type_of_expr(proc->module->info, se->expr));
 
 		if (type == t_invalid) {
@@ -4958,7 +4936,7 @@ void ssa_gen_tree(ssaGen *s) {
 				array_add(&global_variables, var);
 			}
 
-			map_ssa_value_set(&m->values,  hash_pointer(e), g);
+			ssa_module_add_value(m, e, g);
 			map_ssa_value_set(&m->members, hash_string(name), g);
 		} break;
 
@@ -4978,7 +4956,7 @@ void ssa_gen_tree(ssaGen *s) {
 			ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
 			p->Proc.tags = pd->tags;
 
-			map_ssa_value_set(&m->values, hash_pointer(e), p);
+			ssa_module_add_value(m, e, p);
 			HashKey hash_name = hash_string(name);
 			if (map_ssa_value_get(&m->members, hash_name) == NULL) {
 				map_ssa_value_set(&m->members, hash_name, p);