Parcourir la source

Bug fix: comparisons with shifts

Ginger Bill il y a 8 ans
Parent
commit
6fe25badf0
9 fichiers modifiés avec 770 ajouts et 409 suppressions
  1. 5 6
      code/demo.odin
  2. 12 3
      core/_preload.odin
  3. 350 34
      core/fmt.odin
  4. 100 224
      src/check_expr.c
  5. 7 8
      src/check_stmt.c
  6. 181 67
      src/checker.c
  7. 25 12
      src/ir.c
  8. 42 30
      src/parser.c
  9. 48 25
      src/types.c

+ 5 - 6
code/demo.odin

@@ -1,10 +1,9 @@
 #import "fmt.odin";
 
 main :: proc() {
-	Fruit :: enum f32 {
-		Apple = 123,
-		Pear = 321,
-		Tomato,
-	}
-	fmt.printf("%s = %f\n", Fruit.Apple, Fruit.Apple);
+	fmt.printf("%f\n", 0.0);
+	fmt.printf("%f\n", 1.0);
+	fmt.printf("%f\n", -0.5);
+	fmt.printf("%+f\n", 1334.67);
+	fmt.printf("%f\n", 789.789);
 }

+ 12 - 3
core/_preload.odin

@@ -30,6 +30,14 @@ Type_Info_Enum_Value :: raw_union {
 	i: i64;
 }
 
+// NOTE(bill): This much the same as the compiler's
+Calling_Convention :: enum {
+	ODIN = 0,
+	C    = 1,
+	STD  = 2,
+	FAST = 3,
+}
+
 Type_Info :: union {
 	Named: struct #ordered {
 		name: string;
@@ -52,9 +60,10 @@ Type_Info :: union {
 		elem: ^Type_Info;
 	};
 	Procedure: struct #ordered {
-		params:   ^Type_Info; // Type_Info.Tuple
-		results:  ^Type_Info; // Type_Info.Tuple
-		variadic: bool;
+		params:     ^Type_Info; // Type_Info.Tuple
+		results:    ^Type_Info; // Type_Info.Tuple
+		variadic:   bool;
+		convention: Calling_Convention;
 	};
 	Array: struct #ordered {
 		elem:      ^Type_Info;

+ 350 - 34
core/fmt.odin

@@ -421,8 +421,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
 }
 
 fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
-	u_i64 := u as i64;
-	negative := signed && u_i64 < 0;
+	negative := signed && u as i64 < 0;
 	if negative {
 		u = -u;
 	}
@@ -548,48 +547,365 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) {
 		fmt_bad_verb(fi, verb);
 	}
 }
-fmt_float :: proc(fi: ^Fmt_Info, v: f64, bits: int, verb: rune) {
-	// TODO(bill): Actually print a float correctly
-	// THIS IS FUCKING SHIT!
+
+__bot       := [23]f64{1e+000,1e+001,1e+002,1e+003,1e+004,1e+005,1e+006,1e+007,1e+008,1e+009,1e+010,1e+011,1e+012,1e+013,1e+014,1e+015,1e+016,1e+017,1e+018,1e+019,1e+020,1e+021,1e+022};
+__negbot    := [22]f64{1e-001,1e-002,1e-003,1e-004,1e-005,1e-006,1e-007,1e-008,1e-009,1e-010,1e-011,1e-012,1e-013,1e-014,1e-015,1e-016,1e-017,1e-018,1e-019,1e-020,1e-021,1e-022};
+__negboterr := [22]f64{-5.551115123125783e-018,-2.0816681711721684e-019,-2.0816681711721686e-020,-4.7921736023859299e-021,-8.1803053914031305e-022,4.5251888174113741e-023,4.5251888174113739e-024,-2.0922560830128471e-025,-6.2281591457779853e-026,-3.6432197315497743e-027,6.0503030718060191e-028,2.0113352370744385e-029,-3.0373745563400371e-030,1.1806906454401013e-032,-7.7705399876661076e-032,2.0902213275965398e-033,-7.1542424054621921e-034,-7.1542424054621926e-035,2.4754073164739869e-036,5.4846728545790429e-037,9.2462547772103625e-038,-4.8596774326570872e-039};
+__top       := [13]f64{1e+023,1e+046,1e+069,1e+092,1e+115,1e+138,1e+161,1e+184,1e+207,1e+230,1e+253,1e+276,1e+299};
+__negtop    := [13]f64{1e-023,1e-046,1e-069,1e-092,1e-115,1e-138,1e-161,1e-184,1e-207,1e-230,1e-253,1e-276,1e-299};
+__toperr    := [13]f64{8388608,6.8601809640529717e+028,-7.253143638152921e+052,-4.3377296974619174e+075,-1.5559416129466825e+098,-3.2841562489204913e+121,-3.7745893248228135e+144,-1.7356668416969134e+167,-3.8893577551088374e+190,-9.9566444326005119e+213,6.3641293062232429e+236,-5.2069140800249813e+259,-5.2504760255204387e+282};
+__negtoperr := [13]f64{3.9565301985100693e-040,-2.299904345391321e-063,3.6506201437945798e-086,1.1875228833981544e-109,-5.0644902316928607e-132,-6.7156837247865426e-155,-2.812077463003139e-178,-5.7778912386589953e-201,7.4997100559334532e-224,-4.6439668915134491e-247,-6.3691100762962136e-270,-9.436808465446358e-293,8.0970921678014997e-317};
+
+__digitpair := "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
+
+
+__powten := [20]u64{1,10,100,1000, 10000,100000,1000000,10000000, 100000000,1000000000,10000000000,100000000000,  1000000000000,10000000000000,100000000000000,1000000000000000,  10000000000000000,100000000000000000,1000000000000000000,10000000000000000000 };
+
+__TEN_TO_19TH :: 1000000000000000000;
+
+__ddmulthi :: proc(ol: f64, xh, yh: f64) -> f64 {
+	bt: i64;
+	oh := xh * yh;
+	bt = xh transmute i64;
+	bt &= (~(0 as u64)<<27) as i64;
+	ahi := bt transmute f64;
+	alo := xh-ahi;
+	bt = yh transmute i64;
+	bt &= (~(0 as u64)<<27) as i64;
+	bhi := bt transmute f64;
+	blo := yh-bhi;
+	return ((ahi*bhi-oh)+ahi*blo+alo*bhi)+alo*blo;
+}
+
+__ddtoi64 :: proc(xh, xl: f64) -> i64 {
+	ob := xh as i64;
+	vh := ob as f64;
+	ahi := xh-vh;
+	t := ahi-xh;
+	alo := (xh-(ahi-t)) - (vh+t);
+	ob += (ahi+alo+xl) as i64;
+	return ob;
+}
+
+__ddrenorm :: proc(oh, ol: f64) -> f64 {
+	s := oh + ol;
+	ol = ol - (s-oh);
+	return s;
+}
+
+__ddmultlo :: proc(oh, ol, xh, xl, yh, yl: f64) -> f64 {
+	return ol + (xh*yl + xl*yh);
+}
+
+__ddmutlos :: proc(oh, ol, xh, yl: f64) -> f64 {
+	return ol + (xh*yl);
+}
+
+__raise_to_power10 :: proc(ohi, olo: ^f64, d: f64, power: i32) { // power can be -323 to +350
+	ph, pl: f64;
+
+	if 0<=power&&power<=22 {
+		ph = __ddmulthi(pl, d, __bot[power]);
+	} else {
+		p2h, p2l: f64;
+
+		e := power; if power<0 { e = -e; }
+		et := (e*0x2c9)>>14;
+		if et>13 {
+			et = 13;
+		}
+		eb := e-(et*23);
+
+		ph = d;
+		pl = 0.0;
+		if power<0 {
+			if eb != 0 {
+				eb -= 1;
+				ph = __ddmulthi(pl, d, __negbot[eb]);
+				ph = __ddmutlos(ph, pl, d, __negboterr[eb]);
+			}
+			if et != 0 {
+				ph = __ddrenorm(ph, pl);
+				et -= 1;
+				p2h = __ddmulthi(p2l, ph, __negtop[et]);
+				p2h = __ddmultlo(p2h, p2l, ph, pl, __negtop[et], __negtoperr[et]);
+				ph = p2h;
+				pl = p2l;
+			}
+		} else {
+			if eb != 0 {
+				e = eb;
+				if eb > 22 {
+					eb = 22;
+				}
+				e -= eb;
+				ph = __ddmulthi(pl, d, __bot[eb]);
+				if e != 0 {
+					ph = __ddrenorm(ph, pl);
+					p2h = __ddmulthi(p2l, ph, __bot[e]);
+					p2h = __ddmutlos(p2h, p2l, __bot[e], pl);
+					ph = p2h;
+					pl = p2l;
+				}
+			}
+			if et != 0 {
+				ph = __ddrenorm(ph, pl);
+				et -= 1;
+				p2h = __ddmulthi(p2l, ph, __top[et]);
+				p2h = __ddmultlo(p2h, p2l, ph, pl, __top[et], __toperr[et]);
+				ph = p2h;
+				pl = p2l;
+			}
+		}
+	}
+
+	ph = __ddrenorm(ph, pl);
+	ohi^ = ph;
+	olo^ = pl;
+}
+
+__SPECIAL :: 0x7000;
+
+__real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f64, frac_digits: i32, verb: rune) -> bool {
+	e, tens: i32;
+	d: f64 = val;
+
+	bits := d transmute i64;
+	expo := (bits>>52 & 2047) as i32;
+	neg := (bits>>63) as i32 != 0;
+	if neg {
+		d = -d;
+	}
+
+	if expo == 2047 {
+		x: i64 = 1<<52-1;
+		if bits&x != 0 {
+			start^ = "NaN";
+		} else {
+			start^ = "Inf";
+		}
+		decimal_pos^ = __SPECIAL;
+		return neg;
+	}
+
+	if expo == 0 { // is zero or denormal
+		if bits<<1 == 0 {
+			decimal_pos^ = 1;
+			out[0] = '0';
+			start^ = out[:1] as string;
+			return neg;
+		}
+		// find the right expo for denormals
+		v: i64 = 1<<51;
+		while bits&v == 0 {
+			expo -=1;
+			v >>= 1;
+		}
+	}
+
+	// find the decimal exponent as well as the decimal bits of the value
+	{
+		// log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046
+		ph, pl: f64;
+		tens = expo-1023;
+		if tens < 0 {
+			tens = (tens*617)/2048;
+		} else {
+			tens = ((tens*1233)/4096) + 1;
+		}
+
+		// move the significant bits into position and stick them into an int
+		__raise_to_power10(^ph, ^pl, d, 18-tens);
+
+		// get full as much precision from double-double as possible
+		bits = __ddtoi64(ph, pl);
+
+		// check if we undershot
+		if bits as u64 >= __TEN_TO_19TH {
+			tens += 1;
+		}
+	}
+
+	// now do the rounding in integer land
 	match verb {
-	case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
-		break;
+	case 'e', 'E', 'g', 'G':
+		frac_digits += 1;
 	default:
-		fmt_bad_verb(fi, verb);
-		return;
+		frac_digits += tens;
+	}
+
+	if frac_digits < 24 {
+		skip := false;
+		dg: u32 = 1;
+		if bits as u64 >= __powten[9] {
+			dg = 10;
+		}
+		while bits as u64 >= __powten[dg] {
+			dg += 1;
+			if dg == 20 {
+				skip = true;
+				break;
+			}
+		}
+
+		if (!skip) {
+			r: u64;
+			// add 0.5 at the right position and round
+			e = dg as i32 - frac_digits;
+			if e as u32 < 24 {
+				r = __powten[e];
+				bits += (r/2) as i64;
+				if bits as u64 >= __powten[dg] {
+					tens += 1;
+				}
+				bits /= r as i64;
+			}
+		}
+	}
+
+	// kill long trailing runs of zeros
+	if bits != 0 {
+		skip := false;
+		while true {
+			if bits <= 0xffffffff {
+				break;
+			}
+			if bits%1000 != 0 {
+				skip = true;
+				break;
+			}
+			bits /= 1000;
+		}
+		if !skip {
+			n := bits as u32;
+			while n%1000 == 0 {
+				n /= 1000;
+			}
+			bits = n as i64;
+		}
 	}
 
-	f := v;
 
-	if f == 0 {
-		buffer_write_byte(fi.buf, '0');
-		return;
+	e = 0;
+	outp := ^out[64];
+	while true {
+		n: u32;
+		o := outp-8;
+		// do the conversion in chunks of u32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
+		if bits >= 100000000 {
+			n = (bits%100000000) as u32;
+			bits /= 100000000;
+		} else {
+			n = bits as u32;
+			bits = 0;
+		}
+		while n != 0 {
+			outp -= 2;
+			(outp as ^u16)^ = (^__digitpair[(n%100)*2] as ^u16)^;
+			n /= 100;
+			e += 2;
+		}
+		if bits == 0 {
+			if e != 0 && outp^ == '0' {
+				outp += 1;
+				e -= 1;
+			}
+			break;
+		}
+		while outp != o {
+			outp -= 1;
+			outp^ = '0';
+			e += 1;
+		}
 	}
 
-	if f < 0 {
-		buffer_write_byte(fi.buf, '-');
-		f = -f;
+	decimal_pos^ = tens;
+	start^ = slice_ptr(outp, e) as string;
+	return neg;
+}
+
+
+generic_ftoa :: proc(buf: []byte, val: f64, verb: rune, prec, bit_size: int) -> []byte {
+	Float_Info :: struct {
+		mantbits: uint;
+		expbits:  uint;
+		bias:     int;
+	};
+	f32info := Float_Info{23,  8,  -127};
+	f64info := Float_Info{52, 11, -1023};
+
+
+	bits: u64;
+	flt: ^Float_Info;
+	match bit_size {
+	case 32:
+		bits = ((val as f32) transmute u32) as u64;
+		flt = ^f32info;
+	case 64:
+		bits = val transmute u64;
+		flt = ^f64info;
+	default:
+		panic("illegal float bit_size");
 	}
-	i := f as u64;
-	fmt_int(fi, i, false, 'd');
-	f -= i as f64;
-	buffer_write_byte(fi.buf, '.');
 
-	decimal_places := 5;
-	match bits {
-	case 32: decimal_places = 7;
-	case 64: decimal_places = 15;
+	neg := bits>>(flt.expbits+flt.mantbits) != 0;
+	exp := (bits>>flt.mantbits) as int & (1<<flt.expbits - 1);
+	mant := bits & ((1 as u64)<<flt.mantbits - 1);
+
+	match exp {
+	case 1<<flt.expbits-1:
+		s: string;
+		match {
+		case mant!=0: s = "NaN";
+		case neg:     s = "-Inf";
+		default:      s = "+Inf";
+		}
+		copy(buf, s as []byte);
+		return buf[:s.count];
+
+	case 0: // denormalized
+		exp+=1;
+	default: // add implicit top bit
+		mant |= (1 as u64)<<flt.mantbits;
 	}
-	if fi.prec_set {
-		decimal_places = fi.prec;
+
+
+	i := 0;
+	match verb {
+	case 'e', 'E':
+
+	case 'v', 'f', 'F':
+		if neg {
+			buf[i] = '-'; i+=1;
+		}
+		buf[i] = '0'; i+=1;
+		if prec > 0 {
+			buf[i] = '.'; i+=1;
+			for j : 0..<prec {
+				ch: byte = '0';
+			}
+		}
+
+	case 'g', 'G':
+
 	}
 
-	while mult: f64 = 10.0; decimal_places >= 0 {
-		i = (f * mult) as u64;
-		fmt_int(fi, i, false, 'd');
-		f -= i as f64 / mult;
-		mult *= 10;
-		decimal_places -= 1;
+	return buf[:0];
+}
+
+fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
+	buf: [512]byte;
+
+	match verb {
+	// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
+	// case 'f', 'F', 'v':
+
+	case 'f', 'F', 'v':
+		b := generic_ftoa(buf[:], v, verb, fi.prec, bit_size);
+		buffer_write(fi.buf, b);
+	default:
+		fmt_bad_verb(fi, verb);
+		return;
 	}
 }
 fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
@@ -833,8 +1149,8 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 
 	if verb == 'T' {
 		ti := arg.type_info;
-		if ti == type_info(^Type_Info) {
-			ti = (arg.data as ^^Type_Info)^;
+		match type a : arg {
+		case ^Type_Info: ti = a;
 		}
 		buffer_write_type(fi.buf, ti);
 		return;

+ 100 - 224
src/check_expr.c

@@ -28,143 +28,11 @@ gb_inline Type *check_type(Checker *c, AstNode *expression) {
 
 
 
-typedef struct DelayedEntity {
-	AstNode *   ident;
-	Entity *    entity;
-	DeclInfo *  decl;
-} DelayedEntity;
-
-typedef struct DelayedOtherFields {
-	Entity **other_fields;
-	isize other_field_count;
-	isize other_field_index;
-
-	MapEntity *entity_map;
-} DelayedOtherFields;
-
-typedef Array(DelayedEntity) DelayedEntities;
-
-void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntities *delayed_entities, DelayedOtherFields *dof);
-
-void check_local_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, DelayedEntities *delayed_entities, DelayedOtherFields *dof) {
-	Operand operand = {Addressing_Invalid};
-	check_expr(c, &operand, ws->cond);
-	if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
-		error_node(ws->cond, "Non-boolean condition in `when` statement");
-	}
-	if (operand.mode != Addressing_Constant) {
-		error_node(ws->cond, "Non-constant condition in `when` statement");
-	}
-	if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
-		error_node(ws->cond, "Invalid body for `when` statement");
-	} else {
-		if (operand.value.kind == ExactValue_Bool &&
-		    operand.value.value_bool) {
-			check_local_collect_entities(c, ws->body->BlockStmt.stmts, delayed_entities, dof);
-		} else if (ws->else_stmt) {
-			switch (ws->else_stmt->kind) {
-			case AstNode_BlockStmt:
-				check_local_collect_entities(c, ws->else_stmt->BlockStmt.stmts, delayed_entities, dof);
-				break;
-			case AstNode_WhenStmt:
-				check_local_collect_entities_from_when_stmt(c, &ws->else_stmt->WhenStmt, delayed_entities, dof);
-				break;
-			default:
-				error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
-				break;
-			}
-		}
-	}
-}
-
-// NOTE(bill): The `dof` is for use within records
-void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntities *delayed_entities, DelayedOtherFields *dof) {
-	for_array(i, nodes) {
-		AstNode *node = nodes.e[i];
-		switch (node->kind) {
-		case_ast_node(ws, WhenStmt, node);
-			// Will be handled later
-		case_end;
-
-		case_ast_node(vd, ValueDecl, node);
-			if (vd->is_var) {
-				// NOTE(bill): Handled later
-			} else {
-				for_array(i, vd->names) {
-					AstNode *name = vd->names.e[i];
-					if (name->kind != AstNode_Ident) {
-						error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
-						continue;
-					}
-
-					AstNode *init = NULL;
-					if (i < vd->values.count) {
-						init = vd->values.e[i];
-					}
-
-					DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
-					Entity *e = NULL;
-
-					AstNode *up_init = unparen_expr(init);
-					if (init != NULL && is_ast_node_type(up_init)) {
-						e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
-						d->type_expr = init;
-						d->init_expr = init;
-					} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
-						e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
-						d->proc_lit = init;
-					} else {
-						e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0});
-						d->type_expr = vd->type;
-						d->init_expr = init;
-					}
-					GB_ASSERT(e != NULL);
-					e->identifier = name;
-
-					add_entity_and_decl_info(c, name, e, d);
-
-					DelayedEntity delay = {name, e, d};
-					array_add(delayed_entities, delay);
-				}
-
-				check_arity_match(c, vd);
-			}
-		case_end;
-#if 0
-		case_ast_node(pd, ProcDecl, node);
-			if (!ast_node_expect(pd->name, AstNode_Ident)) {
-				break;
-			}
-
-			Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL);
-			e->identifier = pd->name;
-
-			DeclInfo *d = make_declaration_info(c->allocator, e->scope);
-			d->proc_lit = node;
-
-			add_entity_and_decl_info(c, pd->name, e, d);
-			check_entity_decl(c, e, d, NULL, NULL);
-		case_end;
-#endif
-		}
-	}
-
-	// NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something
-	// declared after this stmt in source
-	for_array(i, nodes) {
-		AstNode *node = nodes.e[i];
-		switch (node->kind) {
-		case_ast_node(ws, WhenStmt, node);
-			check_local_collect_entities_from_when_stmt(c, ws, delayed_entities, dof);
-		case_end;
-		}
-	}
-}
-
-void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size, DelayedOtherFields *dof) {
+void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) {
+	GB_ASSERT(!c->context.scope->is_file);
 	DelayedEntities delayed_entities;
 	array_init_reserve(&delayed_entities, heap_allocator(), reserve_size);
-	check_local_collect_entities(c, nodes, &delayed_entities, dof);
+	check_collect_entities(c, nodes, NULL, &delayed_entities);
 
 	for_array(i, delayed_entities) {
 		DelayedEntity delayed = delayed_entities.e[i];
@@ -462,7 +330,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 
 			Type *type = check_type_extra(c, f->type, NULL);
 
-			if (f->is_using) {
+			if (f->flags&FieldFlag_using) {
 				if (f->names.count > 1) {
 					error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type");
 				}
@@ -476,7 +344,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 
 				Token name_token = name->Ident;
 
-				Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->is_using, cast(i32)field_index);
+				Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->flags&FieldFlag_using, cast(i32)field_index);
 				e->identifier = name;
 				if (str_eq(name_token.string, str_lit("_"))) {
 					fields[field_index++] = e;
@@ -495,7 +363,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 			}
 
 
-			if (f->is_using) {
+			if (f->flags&FieldFlag_using) {
 				Type *t = base_type(type_deref(type));
 				if (!is_type_struct(t) && !is_type_raw_union(t) &&
 				    f->names.count >= 1 &&
@@ -843,7 +711,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 			for_array(j, p->names) {
 				AstNode *name = p->names.e[j];
 				if (ast_node_expect(name, AstNode_Ident)) {
-					Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->is_using);
+					Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->flags&FieldFlag_using);
 					add_entity(c, scope, name, param);
 					variables[variable_index++] = param;
 				}
@@ -966,25 +834,15 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
 			o->type = t_invalid;
 			return;
 		}
-	#if 0
-		if (e->Variable.param) {
-			o->mode = Addressing_Value;
-		} else {
-			o->mode = Addressing_Variable;
-		}
-	#else
 		o->mode = Addressing_Variable;
 		if (e->Variable.is_immutable) {
 			o->mode = Addressing_Value;
 		}
-	#endif
 		break;
 
 	case Entity_TypeName: {
 		o->mode = Addressing_Type;
-#if 1
-	// TODO(bill): Fix cyclical dependancy checker
-#endif
+		// TODO(bill): Fix cyclical dependancy checker
 	} break;
 
 	case Entity_Procedure:
@@ -1028,7 +886,7 @@ i64 check_array_count(Checker *c, AstNode *e) {
 		}
 		return 0;
 	}
-	Type *type = base_type(base_enum_type(o.type));
+	Type *type = base_type(o.type);
 	if (is_type_untyped(type) || is_type_integer(type)) {
 		if (o.value.kind == ExactValue_Integer) {
 			i64 count = o.value.value_integer;
@@ -1252,7 +1110,7 @@ end:
 
 bool check_unary_op(Checker *c, Operand *o, Token op) {
 	// TODO(bill): Handle errors correctly
-	Type *type = base_type(base_enum_type(base_vector_type(o->type)));
+	Type *type = base_type(base_vector_type(o->type));
 	gbString str = NULL;
 	switch (op.kind) {
 	case Token_Add:
@@ -1288,7 +1146,7 @@ bool check_unary_op(Checker *c, Operand *o, Token op) {
 
 bool check_binary_op(Checker *c, Operand *o, Token op) {
 	// TODO(bill): Handle errors correctly
-	Type *type = base_type(base_enum_type(base_vector_type(o->type)));
+	Type *type = base_type(base_vector_type(o->type));
 	switch (op.kind) {
 	case Token_Sub:
 	case Token_SubEq:
@@ -1359,6 +1217,7 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
 	return true;
 
 }
+
 bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) {
 	if (in_value.kind == ExactValue_Invalid) {
 		// NOTE(bill): There's already been an error
@@ -1389,7 +1248,6 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
 		}
 		i64 imax = (1ll << (s-1ll));
 
-
 		switch (type->Basic.kind) {
 		case Basic_i8:
 		case Basic_i16:
@@ -1581,16 +1439,15 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
 	o->mode = Addressing_Value;
 }
 
-void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
-	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
-
+void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
 	gbString err_str = NULL;
 
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
 	if (check_is_assignable_to(c, x, y->type) ||
 	    check_is_assignable_to(c, y, x->type)) {
 		Type *err_type = x->type;
 		bool defined = false;
-		switch (op.kind) {
+		switch (op) {
 		case Token_CmpEq:
 		case Token_NotEq:
 			defined = is_type_comparable(x->type);
@@ -1615,7 +1472,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
 		if (!defined) {
 			gbString type_string = type_to_string(err_type);
 			err_str = gb_string_make(c->tmp_allocator,
-			                         gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(op.string), type_string));
+			                         gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(token_strings[op]), type_string));
 			gb_string_free(type_string);
 		}
 	} else {
@@ -1633,7 +1490,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
 	} else {
 		if (x->mode == Addressing_Constant &&
 		    y->mode == Addressing_Constant) {
-			x->value = make_exact_value_bool(compare_exact_values(op.kind, x->value, y->value));
+			x->value = make_exact_value_bool(compare_exact_values(op, x->value, y->value));
 		} else {
 			x->mode = Addressing_Value;
 
@@ -1650,8 +1507,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
 
 	if (err_str != NULL) {
 		gb_string_free(err_str);
-	};
-
+	}
 	gb_temp_arena_memory_end(tmp);
 }
 
@@ -1665,7 +1521,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 	}
 
 	bool x_is_untyped = is_type_untyped(x->type);
-	if (!(is_type_integer(base_enum_type(x->type)) || (x_is_untyped && x_val.kind == ExactValue_Integer))) {
+	if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) {
 		gbString err_str = expr_to_string(x->expr);
 		error_node(node, "Shifted operand `%s` must be an integer", err_str);
 		gb_string_free(err_str);
@@ -1673,7 +1529,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 		return;
 	}
 
-	if (is_type_unsigned(base_enum_type(y->type))) {
+	if (is_type_unsigned(y->type)) {
 
 	} else if (is_type_untyped(y->type)) {
 		convert_to_typed(c, y, t_untyped_integer, 0);
@@ -1702,7 +1558,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 			}
 
 			u64 amount = cast(u64)y_val.value_integer;
-			if (amount > 1074) {
+			if (amount > 64) {
 				gbString err_str = expr_to_string(y->expr);
 				error_node(node, "Shift amount too large: `%s`", err_str);
 				gb_string_free(err_str);
@@ -1710,7 +1566,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 				return;
 			}
 
-			if (!is_type_integer(base_enum_type(x->type))) {
+			if (!is_type_integer(x->type)) {
 				// NOTE(bill): It could be an untyped float but still representable
 				// as an integer
 				x->type = t_untyped_integer;
@@ -1719,17 +1575,19 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 			x->value = exact_value_shift(be->op.kind, x_val, make_exact_value_integer(amount));
 
 			if (is_type_typed(x->type)) {
-				check_is_expressible(c, x, base_type(base_enum_type(x->type)));
+				check_is_expressible(c, x, base_type(x->type));
 			}
 			return;
 		}
 
+		TokenPos pos = ast_node_token(x->expr).pos;
 		if (x_is_untyped) {
 			ExprInfo *info = map_expr_info_get(&c->info.untyped, hash_pointer(x->expr));
 			if (info != NULL) {
 				info->is_lhs = true;
 			}
 			x->mode = Addressing_Value;
+			// x->value = x_val;
 			return;
 		}
 	}
@@ -1740,6 +1598,14 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 		gb_string_free(err_str);
 	}
 
+	if (!is_type_integer(x->type)) {
+		gbString err_str = expr_to_string(y->expr);
+		error_node(node, "Shift operand `%s` must be an integer", err_str);
+		gb_string_free(err_str);
+		x->mode = Addressing_Invalid;
+		return;
+	}
+
 	x->mode = Addressing_Value;
 }
 
@@ -2129,10 +1995,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	}
 
 	if (op.kind == Token_Add || op.kind == Token_Sub) {
-		if (is_type_pointer(x->type) && is_type_integer(base_enum_type(y->type))) {
+		if (is_type_pointer(x->type) && is_type_integer(y->type)) {
 			*x = check_ptr_addition(c, op.kind, x, y, node);
 			return;
-		} else if (is_type_integer(base_enum_type(x->type)) && is_type_pointer(y->type)) {
+		} else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
 			if (op.kind == Token_Sub) {
 				gbString lhs = expr_to_string(x->expr);
 				gbString rhs = expr_to_string(y->expr);
@@ -2159,7 +2025,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 	}
 
 	if (token_is_comparison(op)) {
-		check_comparison(c, x, y, op);
+		check_comparison(c, x, y, op.kind);
 		return;
 	}
 
@@ -2259,48 +2125,58 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
 	if (found == NULL) {
 		return;
 	}
+	ExprInfo old = *found;
 
 	switch (e->kind) {
 	case_ast_node(ue, UnaryExpr, e);
-		if (found->value.kind != ExactValue_Invalid) {
+		if (old.value.kind != ExactValue_Invalid) {
+			// NOTE(bill): if `e` is constant, the operands will be constant too.
+			// They don't need to be updated as they will be updated later and
+			// checked at the end of general checking stage.
 			break;
 		}
 		update_expr_type(c, ue->expr, type, final);
 	case_end;
 
 	case_ast_node(be, BinaryExpr, e);
-		if (found->value.kind != ExactValue_Invalid) {
+		if (old.value.kind != ExactValue_Invalid) {
+			// See above note in UnaryExpr case
 			break;
 		}
-		if (!token_is_comparison(be->op)) {
-			if (token_is_shift(be->op)) {
-				update_expr_type(c, be->left,  type, final);
-			} else {
-				update_expr_type(c, be->left,  type, final);
-				update_expr_type(c, be->right, type, final);
-			}
+		if (token_is_comparison(be->op)) {
+		}
+		else if (token_is_shift(be->op)) {
+			update_expr_type(c, be->left,  type, final);
+		} else {
+			update_expr_type(c, be->left,  type, final);
+			update_expr_type(c, be->right, type, final);
 		}
 	case_end;
+
+	case_ast_node(pe, ParenExpr, e);
+		update_expr_type(c, pe->expr, type, final);
+	case_end;
 	}
 
 	if (!final && is_type_untyped(type)) {
-		found->type = base_type(type);
-		map_expr_info_set(&c->info.untyped, key, *found);
-	} else {
-		ExprInfo old = *found;
-		map_expr_info_remove(&c->info.untyped, key);
+		old.type = base_type(type);
+		map_expr_info_set(&c->info.untyped, key, old);
+		return;
+	}
 
-		if (old.is_lhs && !is_type_integer(type)) {
-			gbString expr_str = expr_to_string(e);
-			gbString type_str = type_to_string(type);
-			error_node(e, "Shifted operand %s must be an integer, got %s", expr_str, type_str);
-			gb_string_free(type_str);
-			gb_string_free(expr_str);
-			return;
-		}
+	// We need to remove it and then give it a new one
+	map_expr_info_remove(&c->info.untyped, key);
 
-		add_type_and_value(&c->info, e, found->mode, type, found->value);
+	if (old.is_lhs && !is_type_integer(type)) {
+		gbString expr_str = expr_to_string(e);
+		gbString type_str = type_to_string(type);
+		error_node(e, "Shifted operand %s must be an integer, got %s", expr_str, type_str);
+		gb_string_free(type_str);
+		gb_string_free(expr_str);
+		return;
 	}
+
+	add_type_and_value(&c->info, e, old.mode, type, old.value);
 }
 
 void update_expr_value(Checker *c, AstNode *e, ExactValue value) {
@@ -2426,7 +2302,7 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
 		return false;
 	}
 
-	if (!is_type_integer(base_enum_type(operand.type))) {
+	if (!is_type_integer(operand.type)) {
 		gbString expr_str = expr_to_string(operand.expr);
 		error_node(operand.expr, "Index `%s` must be an integer", expr_str);
 		gb_string_free(expr_str);
@@ -2665,7 +2541,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		if (op.mode == Addressing_Invalid) {
 			return false;
 		}
-		if (!is_type_integer(base_enum_type(op.type))) {
+		if (!is_type_integer(op.type)) {
 			gbString type_str = type_to_string(op.type);
 			error_node(call, "Length for `new_slice` must be an integer, got `%s`", type_str);
 			gb_string_free(type_str);
@@ -4605,7 +4481,6 @@ 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, Field, params.e[i]);
 		if (i > 0) {
 			str = gb_string_appendc(str, sep);
 		}
@@ -4615,6 +4490,18 @@ gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
 	return str;
 }
 
+gbString write_record_fields_to_string(gbString str, AstNodeArray params) {
+	for_array(i, params) {
+		if (i > 0) {
+			str = gb_string_appendc(str, " ");
+		}
+		str = write_expr_to_string(str, params.e[i]);
+		str = gb_string_appendc(str, ";");
+
+	}
+	return str;
+}
+
 gbString string_append_token(gbString str, Token token) {
 	if (token.string.len > 0) {
 		return gb_string_append_length(str, token.string.text, token.string.len);
@@ -4758,12 +4645,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = write_expr_to_string(str, vt->elem);
 	case_end;
 
-	case_ast_node(p, Field, node);
-		if (p->is_using) {
+	case_ast_node(f, Field, node);
+		if (f->flags&FieldFlag_using) {
 			str = gb_string_appendc(str, "using ");
 		}
-		for_array(i, p->names) {
-			AstNode *name = p->names.e[i];
+		for_array(i, f->names) {
+			AstNode *name = f->names.e[i];
 			if (i > 0) {
 				str = gb_string_appendc(str, ", ");
 			}
@@ -4771,7 +4658,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		}
 
 		str = gb_string_appendc(str, ": ");
-		str = write_expr_to_string(str, p->type);
+		if (f->flags&FieldFlag_ellipsis) {
+			str = gb_string_appendc(str, "...");
+		}
+		str = write_expr_to_string(str, f->type);
 	case_end;
 
 	case_ast_node(ce, CallExpr, node);
@@ -4798,37 +4688,22 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "struct ");
 		if (st->is_packed)  str = gb_string_appendc(str, "#packed ");
 		if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
-		for_array(i, st->fields) {
-			if (i > 0) {
-				str = gb_string_appendc(str, "; ");
-			}
-			str = write_expr_to_string(str, st->fields.e[i]);
-		}
-		// str = write_params_to_string(str, st->decl_list, ", ");
+		str = gb_string_appendc(str, "{");
+		str = write_record_fields_to_string(str, st->fields);
 		str = gb_string_appendc(str, "}");
 	case_end;
 
 	case_ast_node(st, RawUnionType, node);
-		str = gb_string_appendc(str, "raw_union {");
-		for_array(i, st->fields) {
-			if (i > 0) {
-				str = gb_string_appendc(str, "; ");
-			}
-			str = write_expr_to_string(str, st->fields.e[i]);
-		}
-		// str = write_params_to_string(str, st->decl_list, ", ");
+		str = gb_string_appendc(str, "raw_union ");
+		str = gb_string_appendc(str, "{");
+		str = write_record_fields_to_string(str, st->fields);
 		str = gb_string_appendc(str, "}");
 	case_end;
 
 	case_ast_node(st, UnionType, node);
-		str = gb_string_appendc(str, "union {");
-		for_array(i, st->fields) {
-			if (i > 0) {
-				str = gb_string_appendc(str, "; ");
-			}
-			str = write_expr_to_string(str, st->fields.e[i]);
-		}
-		// str = write_params_to_string(str, st->decl_list, ", ");
+		str = gb_string_appendc(str, "union ");
+		str = gb_string_appendc(str, "{");
+		str = write_record_fields_to_string(str, st->fields);
 		str = gb_string_appendc(str, "}");
 	case_end;
 
@@ -4839,6 +4714,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 			str = gb_string_appendc(str, " ");
 		}
 		str = gb_string_appendc(str, "{");
+		str = write_params_to_string(str, et->fields, ", ");
 		str = gb_string_appendc(str, "}");
 	case_end;
 

+ 7 - 8
src/check_stmt.c

@@ -3,7 +3,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
 		return;
 	}
 
-	check_scope_decls(c, stmts, 1.2*stmts.count, NULL);
+	check_scope_decls(c, stmts, 1.2*stmts.count);
 
 	bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
 	flags &= ~Stmt_FallthroughAllowed;
@@ -602,9 +602,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			}
 
 			Type *type = x.type;
-			Type *bt = base_type(base_enum_type(type));
-
-			if (!is_type_integer(bt) && !is_type_float(bt) && !is_type_pointer(bt)) {
+			if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type)) {
 				error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
 				goto skip_expr;
 			}
@@ -784,21 +782,21 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			for_array(j, cc->list) {
 				AstNode *expr = cc->list.e[j];
 				Operand y = {0};
-				Operand z = {0};
-				Token eq = {Token_CmpEq};
 
 				check_expr(c, &y, expr);
 				if (x.mode == Addressing_Invalid ||
 				    y.mode == Addressing_Invalid) {
 					continue;
 				}
+
 				convert_to_typed(c, &y, x.type, 0);
 				if (y.mode == Addressing_Invalid) {
 					continue;
 				}
 
-				z = y;
-				check_comparison(c, &z, &x, eq);
+				// NOTE(bill): the ordering here matters
+				Operand z = y;
+				check_comparison(c, &z, &x, Token_CmpEq);
 				if (z.mode == Addressing_Invalid) {
 					continue;
 				}
@@ -806,6 +804,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					continue;
 				}
 
+
 				if (y.value.kind != ExactValue_Invalid) {
 					HashKey key = hash_exact_value(y.value);
 					TypeAndToken *found = map_type_and_token_get(&seen, key);

+ 181 - 67
src/checker.c

@@ -206,11 +206,7 @@ gb_global ImplicitValueInfo implicit_value_infos[ImplicitValue_Count] = {0};
 
 
 
-typedef struct CheckerContext {
-	Scope *    scope;
-	DeclInfo * decl;
-	u32        stmt_state_flags;
-} CheckerContext;
+
 
 #define MAP_TYPE TypeAndValue
 #define MAP_PROC map_tav_
@@ -242,6 +238,11 @@ typedef struct DelayedDecl {
 	AstNode *decl;
 } DelayedDecl;
 
+typedef struct CheckerContext {
+	Scope *    scope;
+	DeclInfo * decl;
+	u32        stmt_state_flags;
+} CheckerContext;
 
 // NOTE(bill): Symbol tables
 typedef struct CheckerInfo {
@@ -284,6 +285,15 @@ typedef struct Checker {
 } Checker;
 
 
+typedef struct DelayedEntity {
+	AstNode *   ident;
+	Entity *    entity;
+	DeclInfo *  decl;
+} DelayedEntity;
+
+typedef Array(DelayedEntity) DelayedEntities;
+
+
 
 
 void init_declaration_info(DeclInfo *d, Scope *scope) {
@@ -388,6 +398,35 @@ void check_close_scope(Checker *c) {
 	c->context.scope = c->context.scope->parent;
 }
 
+
+Entity *current_scope_lookup_entity(Scope *s, String name) {
+	HashKey key = hash_string(name);
+	Entity **found = map_entity_get(&s->elements, key);
+	if (found) {
+		return *found;
+	}
+	for_array(i, s->shared) {
+		Scope *shared = s->shared.e[i];
+		Entity **found = map_entity_get(&shared->elements, key);
+		if (found) {
+			Entity *e = *found;
+			if (e->kind == Entity_Variable &&
+			    !e->scope->is_file &&
+			    !e->scope->is_global) {
+				continue;
+			}
+
+			if (e->scope != shared) {
+				// Do not return imported entities even #include ones
+				continue;
+			}
+
+			return e;
+		}
+	}
+	return NULL;
+}
+
 void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entity **entity_) {
 	bool gone_thru_proc = false;
 	bool gone_thru_file = false;
@@ -456,21 +495,6 @@ Entity *scope_lookup_entity(Scope *s, String name) {
 	return entity;
 }
 
-Entity *current_scope_lookup_entity(Scope *s, String name) {
-	HashKey key = hash_string(name);
-	Entity **found = map_entity_get(&s->elements, key);
-	if (found) {
-		return *found;
-	}
-	for_array(i, s->shared) {
-		Entity **found = map_entity_get(&s->shared.e[i]->elements, key);
-		if (found) {
-			return *found;
-		}
-	}
-	return NULL;
-}
-
 
 
 Entity *scope_insert_entity(Scope *s, Entity *entity) {
@@ -769,7 +793,8 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
 	if (identifier->kind != AstNode_Ident) {
 		return;
 	}
-	map_entity_set(&c->info.uses, hash_pointer(identifier), entity);
+	HashKey key = hash_pointer(identifier);
+	map_entity_set(&c->info.uses, key, entity);
 	add_declaration_dependency(c, entity); // TODO(bill): Should this be here?
 }
 
@@ -942,7 +967,8 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
 		TokenPos zero_pos = {0};
 		global_error_collector.prev = zero_pos;
 		c->curr_ast_file = file;
-		c->context.decl = file->decl_info;
+		c->context.decl  = file->decl_info;
+		c->context.scope = file->scope;
 	}
 }
 
@@ -1099,12 +1125,20 @@ void init_preload(Checker *c) {
 	c->done_preload = true;
 }
 
+
+
+
 bool check_arity_match(Checker *c, AstNodeValueDecl *d);
+void check_collect_entities(Checker *c, AstNodeArray nodes, MapScope *file_scopes, DelayedEntities *delayed_entities);
+void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, MapScope *file_scopes, DelayedEntities *delayed_entities);
 
 #include "check_expr.c"
 #include "check_decl.c"
 #include "check_stmt.c"
 
+
+
+
 bool check_arity_match(Checker *c, AstNodeValueDecl *d) {
 	isize lhs = d->names.count;
 	isize rhs = d->values.count;
@@ -1135,43 +1169,51 @@ bool check_arity_match(Checker *c, AstNodeValueDecl *d) {
 	return true;
 }
 
+void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, MapScope *file_scopes, DelayedEntities *delayed_entities) {
+	// NOTE(bill): File scope and local scope are different kinds of scopes
+	GB_ASSERT(file_scopes == NULL || delayed_entities == NULL);
 
-
-void check_all_global_entities(Checker *c) {
-	Scope *prev_file = {0};
-
-	for_array(i, c->info.entities.entries) {
-		MapDeclInfoEntry *entry = &c->info.entities.entries.e[i];
-		Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
-		DeclInfo *d = entry->value;
-
-		if (d->scope != e->scope) {
-			continue;
-		}
-		add_curr_ast_file(c, d->scope->file);
-
-		if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) {
-			if (e->scope->is_init) {
-				error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
-				continue;
+	Operand operand = {Addressing_Invalid};
+	check_expr(c, &operand, ws->cond);
+	if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
+		error_node(ws->cond, "Non-boolean condition in `when` statement");
+	}
+	if (operand.mode != Addressing_Constant) {
+		error_node(ws->cond, "Non-constant condition in `when` statement");
+	}
+	if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
+		error_node(ws->cond, "Invalid body for `when` statement");
+	} else {
+		if (operand.value.kind == ExactValue_Bool &&
+		    operand.value.value_bool) {
+			check_collect_entities(c, ws->body->BlockStmt.stmts, file_scopes, delayed_entities);
+		} else if (ws->else_stmt) {
+			switch (ws->else_stmt->kind) {
+			case AstNode_BlockStmt:
+				check_collect_entities(c, ws->else_stmt->BlockStmt.stmts, file_scopes, delayed_entities);
+				break;
+			case AstNode_WhenStmt:
+				check_collect_entities_from_when_stmt(c, &ws->else_stmt->WhenStmt, file_scopes, delayed_entities);
+				break;
+			default:
+				error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
+				break;
 			}
-		} else if (e->scope->is_global && str_eq(e->token.string, str_lit("main"))) {
-			error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
-			continue;
-		}
-
-		Scope *prev_scope = c->context.scope;
-		c->context.scope = d->scope;
-		check_entity_decl(c, e, d, NULL);
-
-
-		if (d->scope->is_init && !c->done_preload) {
-			init_preload(c);
 		}
 	}
 }
 
-void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) {
+// NOTE(bill): If file_scopes == NULL, this will act like a local scope
+void check_collect_entities(Checker *c, AstNodeArray nodes, MapScope *file_scopes, DelayedEntities *delayed_entities) {
+	// NOTE(bill): File scope and local scope are different kinds of scopes
+	GB_ASSERT(file_scopes == NULL || delayed_entities == NULL);
+	if (file_scopes != NULL) {
+		GB_ASSERT(c->context.scope->is_file);
+	}
+	if (delayed_entities != NULL) {
+		GB_ASSERT(!c->context.scope->is_file);
+	}
+
 	for_array(decl_index, nodes) {
 		AstNode *decl = nodes.e[decl_index];
 		if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) {
@@ -1182,15 +1224,27 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 		case_ast_node(bd, BadDecl, decl);
 		case_end;
 
+		case_ast_node(ws, WhenStmt, decl);
+			if (c->context.scope->is_file) {
+				error_node(decl, "`when` statements are not allowed at file scope");
+			} else {
+				// Will be handled later
+			}
+		case_end;
+
 		case_ast_node(vd, ValueDecl, decl);
 			if (vd->is_var) {
+				if (!c->context.scope->is_file) {
+					// NOTE(bill): local scope -> handle later and in order
+					break;
+				}
 				// NOTE(bill): You need to store the entity information here unline a constant declaration
 				isize entity_count = vd->names.count;
 				isize entity_index = 0;
 				Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
 				DeclInfo *di = NULL;
 				if (vd->values.count > 0) {
-					di = make_declaration_info(heap_allocator(), parent_scope);
+					di = make_declaration_info(heap_allocator(), c->context.scope);
 					di->entities = entities;
 					di->entity_count = entity_count;
 					di->type_expr = vd->type;
@@ -1207,7 +1261,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 						error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
 						continue;
 					}
-					Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL);
+					Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL);
 					e->identifier = name;
 					entities[entity_index++] = e;
 
@@ -1232,23 +1286,24 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 						continue;
 					}
 
-
 					AstNode *init = NULL;
 					if (i < vd->values.count) {
 						init = vd->values.e[i];
 					}
 
-					DeclInfo *d = make_declaration_info(c->allocator, parent_scope);
+					DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
 					Entity *e = NULL;
 
 					AstNode *up_init = unparen_expr(init);
 					if (init != NULL && is_ast_node_type(up_init)) {
 						e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
+						// TODO(bill): What if vd->type != NULL??? How to handle this case?
 						d->type_expr = init;
 						d->init_expr = init;
 					} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
 						e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
 						d->proc_lit = init;
+						d->type_expr = vd->type;
 					} else {
 						e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0});
 						d->type_expr = vd->type;
@@ -1265,33 +1320,88 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 		case_end;
 
 		case_ast_node(id, ImportDecl, decl);
-			if (!parent_scope->is_file) {
+			if (!c->context.scope->is_file) {
+				if (id->is_import) {
+					error_node(decl, "#import declarations are only allowed in the file scope");
+				} else {
+					error_node(decl, "#include declarations are only allowed in the file scope");
+				}
 				// NOTE(bill): _Should_ be caught by the parser
 				// TODO(bill): Better error handling if it isn't
 				continue;
 			}
-			DelayedDecl di = {parent_scope, decl};
+			DelayedDecl di = {c->context.scope, decl};
 			array_add(&c->delayed_imports, di);
 		case_end;
 		case_ast_node(fl, ForeignLibrary, decl);
-			if (!parent_scope->is_file) {
+			if (!c->context.scope->is_file) {
+				error_node(decl, "#foreign_library declarations are only allowed in the file scope");
 				// NOTE(bill): _Should_ be caught by the parser
 				// TODO(bill): Better error handling if it isn't
 				continue;
 			}
 
-			DelayedDecl di = {parent_scope, decl};
+			DelayedDecl di = {c->context.scope, decl};
 			array_add(&c->delayed_foreign_libraries, di);
 		case_end;
 		default:
-			if (parent_scope->is_file) {
+			if (c->context.scope->is_file) {
 				error_node(decl, "Only declarations are allowed at file scope");
 			}
 			break;
 		}
 	}
+
+	if (!c->context.scope->is_file) {
+		// NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something
+		// declared after this stmt in source
+		for_array(i, nodes) {
+			AstNode *node = nodes.e[i];
+			switch (node->kind) {
+			case_ast_node(ws, WhenStmt, node);
+				check_collect_entities_from_when_stmt(c, ws, file_scopes, delayed_entities);
+			case_end;
+			}
+		}
+	}
+}
+
+
+void check_all_global_entities(Checker *c) {
+	Scope *prev_file = {0};
+
+	for_array(i, c->info.entities.entries) {
+		MapDeclInfoEntry *entry = &c->info.entities.entries.e[i];
+		Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
+		DeclInfo *d = entry->value;
+
+		if (d->scope != e->scope) {
+			continue;
+		}
+		add_curr_ast_file(c, d->scope->file);
+
+		if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) {
+			if (e->scope->is_init) {
+				error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
+				continue;
+			}
+		} else if (e->scope->is_global && str_eq(e->token.string, str_lit("main"))) {
+			error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
+			continue;
+		}
+
+		Scope *prev_scope = c->context.scope;
+		c->context.scope = d->scope;
+		check_entity_decl(c, e, d, NULL);
+
+
+		if (d->scope->is_init && !c->done_preload) {
+			init_preload(c);
+		}
+	}
 }
 
+
 void check_import_entities(Checker *c, MapScope *file_scopes) {
 	for_array(i, c->delayed_imports) {
 		Scope *parent_scope = c->delayed_imports.e[i].parent;
@@ -1463,8 +1573,10 @@ void check_parsed_files(Checker *c) {
 	// Collect Entities
 	for_array(i, c->parser->files) {
 		AstFile *f = &c->parser->files.e[i];
+		CheckerContext prev_context = c->context;
 		add_curr_ast_file(c, f);
-		check_global_collect_entities_from_file(c, f->scope, f->decls, &file_scopes);
+		check_collect_entities(c, f->decls, &file_scopes, NULL);
+		c->context = prev_context;
 	}
 
 	check_import_entities(c, &file_scopes);
@@ -1472,7 +1584,7 @@ void check_parsed_files(Checker *c) {
 
 	check_all_global_entities(c);
 	init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)`
-	// NOTE(bill): Nothing is the global scope _should_ depend on this implicit value as implicit
+	// NOTE(bill): Nothing in the global scope _should_ depend on this implicit value as implicit
 	// values are only useful within procedures
 	add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context);
 
@@ -1497,12 +1609,12 @@ void check_parsed_files(Checker *c) {
 	// NOTE(bill): Nested procedures bodies will be added to this "queue"
 	for_array(i, c->procs) {
 		ProcedureInfo *pi = &c->procs.e[i];
+		CheckerContext prev_context = c->context;
 		add_curr_ast_file(c, pi->file);
 
 		bool bounds_check    = (pi->tags & ProcTag_bounds_check)    != 0;
 		bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0;
 
-		CheckerContext prev_context = c->context;
 
 		if (bounds_check) {
 			c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
@@ -1554,8 +1666,10 @@ void check_parsed_files(Checker *c) {
 	for_array(i, c->info.definitions.entries) {
 		Entity *e = c->info.definitions.entries.e[i].value;
 		if (e->kind == Entity_TypeName) {
-			// i64 size  = type_size_of(c->sizes, c->allocator, e->type);
-			i64 align = type_align_of(c->sizes, c->allocator, e->type);
+			if (e->type != NULL) {
+				// i64 size  = type_size_of(c->sizes, c->allocator, e->type);
+				i64 align = type_align_of(c->sizes, c->allocator, e->type);
+			}
 		}
 	}
 

+ 25 - 12
src/ir.c

@@ -1516,6 +1516,18 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 
 
 	switch (op) {
+	case Token_Shl:
+	case Token_Shr:
+		left = ir_emit_conv(proc, left, type);
+		if (!is_type_unsigned(ir_type(right))) {
+			Type *t = t_u64;
+			if (proc->module->sizes.word_size == 32) {
+				t = t_u32;
+			}
+			right = ir_emit_conv(proc, right, t);
+		}
+		break;
+
 	case Token_AndNot: {
 		// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
 		// NOTE(bill): "not" `x` == `x` "xor" `-1`
@@ -1534,8 +1546,6 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 	case Token_And:
 	case Token_Or:
 	case Token_Xor:
-	case Token_Shl:
-	case Token_Shr:
 		left  = ir_emit_conv(proc, left, type);
 		right = ir_emit_conv(proc, right, type);
 		break;
@@ -1949,15 +1959,15 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 		          dst->kind == Type_Basic);
 		i64 sz = type_size_of(proc->module->sizes, proc->module->allocator, src);
 		i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst);
+		irConvKind kind = irConv_trunc;
 		if (sz == dz) {
 			// NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment
-			return value;
-		}
-
-		irConvKind kind = irConv_trunc;
-		if (dz >= sz) {
+			// NOTE(bill): Copy the value just for type correctness
+			kind = irConv_bitcast;
+		} else if (dz > sz) {
 			kind = irConv_zext;
 		}
+
 		return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
 	}
 
@@ -2560,7 +2570,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 	expr = unparen_expr(expr);
 	switch (expr->kind) {
 	case_ast_node(bl, BasicLit, expr);
-		GB_PANIC("Non-constant basic literal");
+		TokenPos pos = bl->pos;
+		GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(token_strings[bl->kind]));
 	case_end;
 
 	case_ast_node(i, Ident, expr);
@@ -2596,7 +2607,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
 
 	case_ast_node(re, RunExpr, expr);
 		// TODO(bill): Run Expression
-		return ir_build_single_expr(proc, re->expr, tv);
+		return ir_build_expr(proc, re->expr);
 	case_end;
 
 	case_ast_node(de, DerefExpr, expr);
@@ -5834,9 +5845,10 @@ void ir_gen_tree(irGen *s) {
 				case Type_Proc: {
 					tag = ir_emit_conv(proc, ti_ptr, t_type_info_procedure_ptr);
 
-					irValue *params   = ir_emit_struct_ep(proc, tag, 0);
-					irValue *results  = ir_emit_struct_ep(proc, tag, 1);
-					irValue *variadic = ir_emit_struct_ep(proc, tag, 2);
+					irValue *params     = ir_emit_struct_ep(proc, tag, 0);
+					irValue *results    = ir_emit_struct_ep(proc, tag, 1);
+					irValue *variadic   = ir_emit_struct_ep(proc, tag, 2);
+					irValue *convention = ir_emit_struct_ep(proc, tag, 3);
 
 					if (t->Proc.params) {
 						ir_emit_store(proc, params, ir_get_type_info_ptr(proc, type_info_data, t->Proc.params));
@@ -5845,6 +5857,7 @@ void ir_gen_tree(irGen *s) {
 						ir_emit_store(proc, results, ir_get_type_info_ptr(proc, type_info_data, t->Proc.results));
 					}
 					ir_emit_store(proc, variadic, ir_make_const_bool(a, t->Proc.variadic));
+					ir_emit_store(proc, convention, ir_make_const_int(a, t->Proc.calling_convention));
 
 					// TODO(bill): Type_Info for procedures
 				} break;

+ 42 - 30
src/parser.c

@@ -62,36 +62,41 @@ typedef struct Parser {
 } Parser;
 
 typedef enum ProcTag {
-	ProcTag_bounds_check    = GB_BIT(0),
-	ProcTag_no_bounds_check = GB_BIT(1),
-
-	ProcTag_foreign         = GB_BIT(10),
-	ProcTag_export          = GB_BIT(11),
-	ProcTag_link_name       = GB_BIT(12),
-	ProcTag_inline          = GB_BIT(13),
-	ProcTag_no_inline       = GB_BIT(14),
-	ProcTag_dll_import      = GB_BIT(15),
-	// ProcTag_dll_export      = GB_BIT(16),
+	ProcTag_bounds_check    = 1<<0,
+	ProcTag_no_bounds_check = 1<<1,
+
+	ProcTag_foreign         = 1<<10,
+	ProcTag_export          = 1<<11,
+	ProcTag_link_name       = 1<<12,
+	ProcTag_inline          = 1<<13,
+	ProcTag_no_inline       = 1<<14,
+	ProcTag_dll_import      = 1<<15,
+	// ProcTag_dll_export      = 1<<16,
 } ProcTag;
 
 typedef enum ProcCallingConvention {
 	ProcCC_Odin = 0,
-	ProcCC_C,
-	ProcCC_Std,
-	ProcCC_Fast,
+	ProcCC_C    = 1,
+	ProcCC_Std  = 2,
+	ProcCC_Fast = 3,
 
 	ProcCC_Invalid,
 } ProcCallingConvention;
 
 typedef enum VarDeclTag {
-	VarDeclTag_thread_local = GB_BIT(0),
+	VarDeclTag_thread_local = 1<<0,
 } VarDeclTag;
 
 typedef enum StmtStateFlag {
-	StmtStateFlag_bounds_check    = GB_BIT(0),
-	StmtStateFlag_no_bounds_check = GB_BIT(1),
+	StmtStateFlag_bounds_check    = 1<<0,
+	StmtStateFlag_no_bounds_check = 1<<1,
 } StmtStateFlag;
 
+typedef enum FieldFlag {
+	FieldFlag_using    = 1<<0,
+	FieldFlag_ellipsis = 1<<1,
+} FieldListTag;
+
 AstNodeArray make_ast_node_array(AstFile *f) {
 	AstNodeArray a;
 	// array_init(&a, gb_arena_allocator(&f->arena));
@@ -228,7 +233,10 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
 	}) \
 	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(UsingStmt,  "using statement",  struct { \
+		Token token;   \
+		AstNode *node; \
+	}) \
 	AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
 		Token string;     \
 		AstNode *operand; \
@@ -283,7 +291,7 @@ AST_NODE_KIND(_DeclEnd,   "", i32) \
 	AST_NODE_KIND(Field, "field", struct { \
 		AstNodeArray names;    \
 		AstNode *    type;     \
-		bool         is_using; \
+		u32          flags;    \
 	}) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
 	AST_NODE_KIND(HelperType, "type", struct { \
@@ -955,11 +963,11 @@ AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
 	return result;
 }
 
-AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) {
+AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) {
 	AstNode *result = make_node(f, AstNode_Field);
 	result->Field.names = names;
 	result->Field.type = type;
-	result->Field.is_using = is_using;
+	result->Field.flags = flags;
 	return result;
 }
 
@@ -2217,7 +2225,7 @@ AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_)
 	return make_proc_type(f, proc_token, params, results, tags, cc);
 }
 
-AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, bool ellipsis_ok,
+AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
                               TokenKind separator, TokenKind follow) {
 	AstNodeArray params = make_ast_node_array(f);
 	isize name_count = 0;
@@ -2240,7 +2248,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using,
 			is_using = false;
 		}
 
-		if (!allow_using && is_using) {
+		if ((flags&FieldFlag_using) == 0 && is_using) {
 			syntax_error(f->curr_token, "`using` is not allowed within this parameter list");
 			is_using = false;
 		}
@@ -2250,7 +2258,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using,
 		expect_token_after(f, Token_Colon, "parameter list");
 
 		AstNode *type = NULL;
-		if (ellipsis_ok && f->curr_token.kind == Token_Ellipsis) {
+		if ((flags&FieldFlag_ellipsis) != 0 && f->curr_token.kind == Token_Ellipsis) {
 			Token ellipsis = f->curr_token;
 			next_token(f);
 			type = parse_type_attempt(f);
@@ -2273,7 +2281,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using,
 			syntax_error(f->curr_token, "Expected a type for this parameter declaration");
 		}
 
-		AstNode *param = make_field(f, names, type, is_using);
+		u32 flags = 0;
+		if (is_using) {
+			flags |= FieldFlag_using;
+		}
+		AstNode *param = make_field(f, names, type, flags);
 		array_add(&params, param);
 
 		if (separator == Token_Semicolon) {
@@ -2291,8 +2303,8 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using,
 }
 
 
-AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, bool allow_using, String context) {
-	return parse_field_list(f, field_count_, allow_using, false, Token_Semicolon, Token_CloseBrace);
+AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
+	return parse_field_list(f, field_count_, flags, Token_Semicolon, Token_CloseBrace);
 }
 
 AstNode *parse_identifier_or_type(AstFile *f) {
@@ -2385,7 +2397,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("struct"));
+		AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
 		Token close = expect_token(f, Token_CloseBrace);
 
 		return make_struct_type(f, token, decls, decl_count, is_packed, is_ordered);
@@ -2395,7 +2407,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		Token token = expect_token(f, Token_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, false, str_lit("union"));
+		AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
 		return make_union_type(f, token, decls, decl_count);
@@ -2405,7 +2417,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		Token token = expect_token(f, Token_raw_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("raw_union"));
+		AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
 		return make_raw_union_type(f, token, decls, decl_count);
@@ -2479,7 +2491,7 @@ void parse_proc_signature(AstFile *f,
                           AstNodeArray *params,
                           AstNodeArray *results) {
 	expect_token(f, Token_OpenParen);
-	*params = parse_field_list(f, NULL, true, true, Token_Comma, Token_CloseParen);
+	*params = parse_field_list(f, NULL, FieldFlag_using|FieldFlag_ellipsis, Token_Comma, Token_CloseParen);
 	expect_token_after(f, Token_CloseParen, "parameter list");
 	*results = parse_results(f);
 }

+ 48 - 25
src/types.c

@@ -74,8 +74,11 @@ typedef struct TypeRecord {
 
 	// All record types
 	// Theses are arrays
-	Entity **fields;      // Entity_Variable (otherwise Entity_TypeName if union)
-	i32      field_count; // == offset_count is struct
+	// Entity_Variable - struct/raw_union
+	// Entity_TypeName - union
+	// Entity_Constant - enum
+	Entity **fields;
+	i32      field_count; // == struct_offsets count
 	AstNode *node;
 
 	i64 *    struct_offsets;
@@ -84,10 +87,10 @@ typedef struct TypeRecord {
 	bool     struct_is_ordered;
 	Entity **fields_in_src_order; // Entity_Variable
 
-	Type *  enum_base_type;
-	Entity *enum_count;
-	Entity *enum_min_value;
-	Entity *enum_max_value;
+	Type *   enum_base_type;
+	Entity * enum_count;
+	Entity * enum_min_value;
+	Entity * enum_max_value;
 } TypeRecord;
 
 #define TYPE_KINDS \
@@ -481,28 +484,28 @@ bool is_type_named(Type *t) {
 	return t->kind == Type_Named;
 }
 bool is_type_boolean(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Boolean) != 0;
 	}
 	return false;
 }
 bool is_type_integer(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Integer) != 0;
 	}
 	return false;
 }
 bool is_type_unsigned(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Unsigned) != 0;
 	}
 	return false;
 }
 bool is_type_numeric(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Numeric) != 0;
 	}
@@ -536,7 +539,7 @@ bool is_type_untyped(Type *t) {
 	return false;
 }
 bool is_type_ordered(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Ordered) != 0;
 	}
@@ -553,21 +556,21 @@ bool is_type_constant_type(Type *t) {
 	return false;
 }
 bool is_type_float(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return (t->Basic.flags & BasicFlag_Float) != 0;
 	}
 	return false;
 }
 bool is_type_f32(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return t->Basic.kind == Basic_f32;
 	}
 	return false;
 }
 bool is_type_f64(Type *t) {
-	t = base_type(t);
+	t = base_type(base_enum_type(t));
 	if (t->kind == Type_Basic) {
 		return t->Basic.kind == Basic_f64;
 	}
@@ -677,8 +680,13 @@ bool is_type_indexable(Type *t) {
 bool type_has_nil(Type *t) {
 	t = base_type(t);
 	switch (t->kind) {
-	case Type_Basic:
-		return is_type_rawptr(t);
+	case Type_Basic: {
+		switch (t->Basic.kind) {
+		case Basic_rawptr:
+		case Basic_any:
+			return true;
+		}
+	}
 	case Type_Slice:
 	case Type_Proc:
 	case Type_Pointer:
@@ -693,24 +701,22 @@ bool is_type_comparable(Type *t) {
 	t = base_type(t);
 	switch (t->kind) {
 	case Type_Basic:
-		return t->kind != Basic_UntypedNil;
+		switch (t->Basic.kind) {
+		case Basic_UntypedNil:
+		case Basic_any:
+			return false;
+		}
+		return true;
 	case Type_Pointer:
 		return true;
 	case Type_Record: {
-		if (false && is_type_struct(t)) {
-			// TODO(bill): Should I even allow this?
-			for (isize i = 0; i < t->Record.field_count; i++) {
-				if (!is_type_comparable(t->Record.fields[i]->type))
-					return false;
-			}
-		} else if (is_type_enum(t)) {
+		if (is_type_enum(t)) {
 			return is_type_comparable(base_enum_type(t));
 		}
 		return false;
 	} break;
 	case Type_Array:
 		return false;
-		// return is_type_comparable(t->Array.elem);
 	case Type_Vector:
 		return is_type_comparable(t->Vector.elem);
 	case Type_Proc:
@@ -1189,6 +1195,9 @@ i64 align_formula(i64 size, i64 align) {
 }
 
 i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
+	if (t == NULL) {
+		return 0;
+	}
 	i64 size;
 	TypePath path = {0};
 	type_path_init(&path);
@@ -1198,6 +1207,9 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 }
 
 i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
+	if (t == NULL) {
+		return 1;
+	}
 	i64 align;
 	TypePath path = {0};
 	type_path_init(&path);
@@ -1214,6 +1226,17 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
 	t = base_type(t);
 
 	switch (t->kind) {
+	case Type_Basic: {
+		GB_ASSERT(is_type_typed(t));
+		switch (t->kind) {
+		case Basic_string: return s.word_size;
+		case Basic_any:    return s.word_size;
+
+		case Basic_int: case Basic_uint: case Basic_rawptr:
+			return s.word_size;
+		}
+	} break;
+
 	case Type_Array: {
 		Type *elem = t->Array.elem;
 		type_path_push(path, elem);