Bladeren bron

More declaration differentiation in semantic stage e.g. make only variables and constants

Ginger Bill 8 jaren geleden
bovenliggende
commit
3f1195cd03
6 gewijzigde bestanden met toevoegingen van 315 en 150 verwijderingen
  1. 3 19
      code/demo.odin
  2. 33 9
      src/checker/checker.c
  3. 196 78
      src/checker/decl.c
  4. 25 11
      src/checker/expr.c
  5. 18 16
      src/parser.c
  6. 40 17
      src/ssa.c

+ 3 - 19
code/demo.odin

@@ -11,8 +11,7 @@ import {
 	win32 "sys/windows.odin";
 }
 
-
-type Thing enum f64 {
+const Thing = enum f64 {
 	_, // Ignore first value
 	A = 1<<(10*iota),
 	B,
@@ -20,21 +19,6 @@ type Thing enum f64 {
 	D,
 };
 
-proc main() {
-	var ti = type_info(Thing);
-	match type info : type_info_base(ti) {
-	case Type_Info.Enum:
-		for var i = 0; i < info.names.count; i++ {
-			if i > 0 {
-				fmt.print(", ");
-			}
-			fmt.print(info.names[i]);
-		}
-		fmt.println();
-	}
-
-	var x Thing = Thing.A;
-
-	fmt.println(x, Thing.B, Thing.C, Thing.D);
-
+const main = proc() {
+	fmt.println(Thing.A, Thing.B, Thing.C, Thing.D);
 }

+ 33 - 9
src/checker/checker.c

@@ -883,6 +883,9 @@ void add_type_info_type(Checker *c, Type *t) {
 
 	case Type_Record: {
 		switch (bt->Record.kind) {
+		case TypeRecord_Enum:
+			add_type_info_type(c, bt->Record.enum_base_type);
+			break;
 		case TypeRecord_Union:
 			add_type_info_type(c, t_int);
 			/* fallthrough */
@@ -1072,13 +1075,13 @@ void init_preload(Checker *c) {
 	c->done_preload = true;
 }
 
-void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init);
+bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init);
 
 #include "expr.c"
 #include "decl.c"
 #include "stmt.c"
 
-void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) {
+bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) {
 	isize lhs = s->names.count;
 	isize rhs = s->values.count;
 	if (init != NULL) {
@@ -1088,6 +1091,7 @@ void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init)
 	if (init == NULL && rhs == 0) {
 		if (s->type == NULL) {
 			error_node(s->names.e[0], "Missing type or initial expression");
+			return false;
 		}
 	} else if (lhs < rhs) {
 		if (lhs < s->values.count) {
@@ -1098,12 +1102,16 @@ void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init)
 		} else {
 			error_node(s->names.e[0], "Extra initial expression");
 		}
+		return false;
 	} else if (lhs > rhs && (init != NULL || rhs != 1)) {
 		AstNode *n = s->names.e[rhs];
 		gbString str = expr_to_string(n);
 		error_node(n, "Missing expression for `%s`", str);
 		gb_string_free(str);
+		return false;
 	}
+
+	return true;
 }
 
 
@@ -1234,19 +1242,34 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 								continue;
 							}
 
-							ExactValue v = make_exact_value_integer(iota);
-							Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v);
-							e->identifier = name;
 
 							AstNode *init = NULL;
 							if (i < prev_spec->values.count) {
 								init = prev_spec->values.e[i];
 							}
 
-							DeclInfo *di = make_declaration_info(c->allocator, e->scope);
-							di->type_expr = prev_spec->type;
-							di->init_expr = init;
-							add_entity_and_decl_info(c, name, e, di);
+							DeclInfo *d = make_declaration_info(c->allocator, parent_scope);
+							Entity *e = NULL;
+
+							ExactValue v_iota = make_exact_value_integer(iota);
+
+							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_decl = init;
+							} else {
+								e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota);
+								d->type_expr = prev_spec->type;
+								d->init_expr = init;
+							}
+							GB_ASSERT(e != NULL);
+							e->identifier = name;
+
+							add_entity_and_decl_info(c, name, e, d);
 						}
 
 						check_arity_match(c, vs, prev_spec);
@@ -1263,6 +1286,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
 
 					Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
 					e->identifier = ts->name;
+
 					DeclInfo *d = make_declaration_info(c->allocator, e->scope);
 					d->type_expr = ts->type;
 					d->init_expr = ts->type;

+ 196 - 78
src/checker/decl.c

@@ -248,7 +248,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 	}
 	e->flags |= EntityFlag_Visited;
 
-	GB_ASSERT(c->context.iota.kind == ExactValue_Invalid);
 	c->context.iota = e->Constant.value;
 	e->Constant.value = (ExactValue){0};
 
@@ -267,7 +266,18 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 
 	Operand operand = {0};
 	if (init != NULL) {
-		check_expr(c, &operand, init);
+		check_expr_or_type(c, &operand, init);
+	}
+	if (operand.mode == Addressing_Type) {
+		c->context.iota = (ExactValue){0};
+
+		e->Constant.value = (ExactValue){0};
+		e->kind = Entity_TypeName;
+
+		DeclInfo *d = c->context.decl;
+		d->type_expr = d->init_expr;
+		check_type_decl(c, e, d->type_expr, named_type);
+		return;
 	}
 
 	check_init_constant(c, e, &operand);
@@ -319,113 +329,221 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 
 	Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
 	e->type = proc_type;
-	ast_node(pd, ProcDecl, d->proc_decl);
-
-	check_open_scope(c, pd->type);
-	check_procedure_type(c, proc_type, pd->type);
-
-	bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
-	bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
-	bool is_export       = (pd->tags & ProcTag_export)    != 0;
-	bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
-	bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
-
-	if ((d->scope->is_file || d->scope->is_global) &&
-	    str_eq(e->token.string, str_lit("main"))) {
-		if (proc_type != NULL) {
-			TypeProc *pt = &proc_type->Proc;
-			if (pt->param_count != 0 ||
-			    pt->result_count != 0) {
-				gbString str = type_to_string(proc_type);
-				error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
-				gb_string_free(str);
+	if (d->proc_decl->kind == AstNode_ProcDecl) {
+		ast_node(pd, ProcDecl, d->proc_decl);
+
+		check_open_scope(c, pd->type);
+		check_procedure_type(c, proc_type, pd->type);
+
+		bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
+		bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
+		bool is_export       = (pd->tags & ProcTag_export)    != 0;
+		bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
+		bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
+
+		if ((d->scope->is_file || d->scope->is_global) &&
+		    str_eq(e->token.string, str_lit("main"))) {
+			if (proc_type != NULL) {
+				TypeProc *pt = &proc_type->Proc;
+				if (pt->param_count != 0 ||
+				    pt->result_count != 0) {
+					gbString str = type_to_string(proc_type);
+					error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
+					gb_string_free(str);
+				}
 			}
 		}
-	}
 
-	if (is_inline && is_no_inline) {
-		error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
-	}
+		if (is_inline && is_no_inline) {
+			error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
+		}
 
-	if (is_foreign && is_link_name) {
-		error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
-	} else if (is_foreign && is_export) {
-		error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
-	}
+		if (is_foreign && is_link_name) {
+			error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
+		} else if (is_foreign && is_export) {
+			error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
+		}
 
 
-	if (pd->body != NULL) {
-		if (is_foreign) {
-			error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
+		if (pd->body != NULL) {
+			if (is_foreign) {
+				error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
+			}
+
+			if (proc_type->Proc.calling_convention != ProcCC_Odin) {
+				error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
+				proc_type->Proc.calling_convention = ProcCC_Odin;
+			}
+
+			d->scope = c->context.scope;
+
+			GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
+			check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
 		}
 
-		if (proc_type->Proc.calling_convention != ProcCC_Odin) {
-			error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
-			proc_type->Proc.calling_convention = ProcCC_Odin;
+		if (is_foreign) {
+			MapEntity *fp = &c->info.foreign_procs;
+			AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
+			String name = proc_decl->name->Ident.string;
+			if (proc_decl->foreign_name.len > 0) {
+				name = proc_decl->foreign_name;
+			}
+
+			e->Procedure.is_foreign = true;
+			e->Procedure.foreign_name = name;
+
+			HashKey key = hash_string(name);
+			Entity **found = map_entity_get(fp, key);
+			if (found) {
+				Entity *f = *found;
+				TokenPos pos = f->token.pos;
+				Type *this_type = base_type(e->type);
+				Type *other_type = base_type(f->type);
+				if (!are_signatures_similar_enough(this_type, other_type)) {
+					error_node(d->proc_decl,
+					           "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
+					           "\tat %.*s(%td:%td)",
+					           LIT(name), LIT(pos.file), pos.line, pos.column);
+				}
+			} else {
+				map_entity_set(fp, key, e);
+			}
+		} else {
+			String name = e->token.string;
+			if (is_link_name) {
+				AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
+				name = proc_decl->link_name;
+			}
+
+			if (is_link_name || is_export) {
+				MapEntity *fp = &c->info.foreign_procs;
+
+				e->Procedure.link_name = name;
+
+				HashKey key = hash_string(name);
+				Entity **found = map_entity_get(fp, key);
+				if (found) {
+					Entity *f = *found;
+					TokenPos pos = f->token.pos;
+					// TODO(bill): Better error message?
+					error_node(d->proc_decl,
+					           "Non unique linking name for procedure `%.*s`\n"
+					           "\tother at %.*s(%td:%td)",
+					           LIT(name), LIT(pos.file), pos.line, pos.column);
+				} else {
+					map_entity_set(fp, key, e);
+				}
+			}
 		}
 
-		d->scope = c->context.scope;
+		check_close_scope(c);
+	} else if (d->proc_decl->kind == AstNode_ProcLit) {
+		ast_node(pd, ProcLit, d->proc_decl);
+
+		check_open_scope(c, pd->type);
+		check_procedure_type(c, proc_type, pd->type);
+
+		bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
+		bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
+		bool is_export       = (pd->tags & ProcTag_export)    != 0;
+		bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
+		bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
+
+		if ((d->scope->is_file || d->scope->is_global) &&
+		    str_eq(e->token.string, str_lit("main"))) {
+			if (proc_type != NULL) {
+				TypeProc *pt = &proc_type->Proc;
+				if (pt->param_count != 0 ||
+				    pt->result_count != 0) {
+					gbString str = type_to_string(proc_type);
+					error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
+					gb_string_free(str);
+				}
+			}
+		}
 
-		GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
-		check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
-	}
+		if (is_inline && is_no_inline) {
+			error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
+		}
 
-	if (is_foreign) {
-		MapEntity *fp = &c->info.foreign_procs;
-		AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
-		String name = proc_decl->name->Ident.string;
-		if (proc_decl->foreign_name.len > 0) {
-			name = proc_decl->foreign_name;
+		if (is_foreign && is_link_name) {
+			error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
+		} else if (is_foreign && is_export) {
+			error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
 		}
 
-		e->Procedure.is_foreign = true;
-		e->Procedure.foreign_name = name;
 
-		HashKey key = hash_string(name);
-		Entity **found = map_entity_get(fp, key);
-		if (found) {
-			Entity *f = *found;
-			TokenPos pos = f->token.pos;
-			Type *this_type = base_type(e->type);
-			Type *other_type = base_type(f->type);
-			if (!are_signatures_similar_enough(this_type, other_type)) {
-				error_node(d->proc_decl,
-				           "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
-				           "\tat %.*s(%td:%td)",
-				           LIT(name), LIT(pos.file), pos.line, pos.column);
+		if (pd->body != NULL) {
+			if (is_foreign) {
+				error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
 			}
-		} else {
-			map_entity_set(fp, key, e);
-		}
-	} else {
-		String name = e->token.string;
-		if (is_link_name) {
-			AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
-			name = proc_decl->link_name;
+
+			if (proc_type->Proc.calling_convention != ProcCC_Odin) {
+				error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
+				proc_type->Proc.calling_convention = ProcCC_Odin;
+			}
+
+			d->scope = c->context.scope;
+
+			GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
+			check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
 		}
 
-		if (is_link_name || is_export) {
+		if (is_foreign) {
 			MapEntity *fp = &c->info.foreign_procs;
+			String name = e->token.string;
+			if (pd->foreign_name.len > 0) {
+				name = pd->foreign_name;
+			}
 
-			e->Procedure.link_name = name;
+			e->Procedure.is_foreign = true;
+			e->Procedure.foreign_name = name;
 
 			HashKey key = hash_string(name);
 			Entity **found = map_entity_get(fp, key);
 			if (found) {
 				Entity *f = *found;
 				TokenPos pos = f->token.pos;
-				// TODO(bill): Better error message?
-				error_node(d->proc_decl,
-				           "Non unique linking name for procedure `%.*s`\n"
-				           "\tother at %.*s(%td:%td)",
-				           LIT(name), LIT(pos.file), pos.line, pos.column);
+				Type *this_type = base_type(e->type);
+				Type *other_type = base_type(f->type);
+				if (!are_signatures_similar_enough(this_type, other_type)) {
+					error_node(d->proc_decl,
+					           "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
+					           "\tat %.*s(%td:%td)",
+					           LIT(name), LIT(pos.file), pos.line, pos.column);
+				}
 			} else {
 				map_entity_set(fp, key, e);
 			}
+		} else {
+			String name = e->token.string;
+			if (is_link_name) {
+				name = pd->link_name;
+			}
+
+			if (is_link_name || is_export) {
+				MapEntity *fp = &c->info.foreign_procs;
+
+				e->Procedure.link_name = name;
+
+				HashKey key = hash_string(name);
+				Entity **found = map_entity_get(fp, key);
+				if (found) {
+					Entity *f = *found;
+					TokenPos pos = f->token.pos;
+					// TODO(bill): Better error message?
+					error_node(d->proc_decl,
+					           "Non unique linking name for procedure `%.*s`\n"
+					           "\tother at %.*s(%td:%td)",
+					           LIT(name), LIT(pos.file), pos.line, pos.column);
+				} else {
+					map_entity_set(fp, key, e);
+				}
+			}
 		}
-	}
 
-	check_close_scope(c);
+		check_close_scope(c);
+	}
 }
 
 void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {

+ 25 - 11
src/checker/expr.c

@@ -113,21 +113,35 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
 								continue;
 							}
 
-							ExactValue v = make_exact_value_integer(iota);
-							Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
-							e->identifier = name;
-
 							AstNode *init = NULL;
-							if (i < last->values.count) {
-								init = last->values.e[i];
+							if (i < vs->values.count) {
+								init = vs->values.e[i];
+							}
+
+							DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
+							Entity *e = NULL;
+
+							ExactValue v_iota = make_exact_value_integer(iota);
+
+							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_decl = init;
+							} else {
+								e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota);
+								d->type_expr = vs->type;
+								d->init_expr = init;
 							}
+							GB_ASSERT(e != NULL);
+							e->identifier = name;
 
-							DeclInfo *di = make_declaration_info(c->allocator, e->scope);
-							di->type_expr = last->type;
-							di->init_expr = init;
-							add_entity_and_decl_info(c, name, e, di);
+							add_entity_and_decl_info(c, name, e, d);
 
-							DelayedEntity delay = {name, e, di};
+							DelayedEntity delay = {name, e, d};
 							array_add(delayed_entities, delay);
 						}
 

+ 18 - 16
src/parser.c

@@ -1740,31 +1740,25 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 
 	// Parse Procedure Type or Literal
 	case Token_proc: {
+		Token token = f->curr_token;
 		String foreign_name = {0};
 		String link_name = {0};
-		AstNode *curr_proc = f->curr_proc;
 		AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
-		f->curr_proc = type;
-
-		if (type->ProcType.tags & ProcTag_foreign) {
-			syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals");
-		}
-		if (type->ProcType.tags & ProcTag_export) {
-			syntax_error(f->curr_token, "#export cannot be applied to procedure literals");
-		}
 
 		if (f->curr_token.kind == Token_OpenBrace) {
-			AstNode *body;
+			u64 tags = type->ProcType.tags;
 
-			if ((type->ProcType.tags & ProcTag_foreign) != 0) {
-				syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body");
+			if ((tags & ProcTag_foreign) != 0) {
+				syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
 			}
+			AstNode *curr_proc = f->curr_proc;
+			f->curr_proc = type;
+			AstNode *body = parse_body(f);
+			f->curr_proc = curr_proc;
 
-			body = parse_body(f);
-			type = make_proc_lit(f, type, body, type->ProcType.tags, foreign_name, link_name);
+			return make_proc_lit(f, type, body, tags, foreign_name, link_name);
 		}
 
-		f->curr_proc = curr_proc;
 		return type;
 	}
 
@@ -1941,7 +1935,15 @@ AstNode *parse_type(AstFile *f);
 
 AstNode *parse_unary_expr(AstFile *f, bool lhs) {
 	switch (f->curr_token.kind) {
-	case Token_Pointer:
+	case Token_Pointer: {
+		Token op = f->curr_token;
+		next_token(f);
+		AstNode *expr = parse_unary_expr(f, lhs);
+		if (is_ast_node_type(expr)) {
+			return make_pointer_type(f, op, expr);
+		}
+		return make_unary_expr(f, op, expr);
+	} break;
 	case Token_Maybe:
 	case Token_Add:
 	case Token_Sub:

+ 40 - 17
src/ssa.c

@@ -5038,25 +5038,48 @@ void ssa_gen_tree(ssaGen *s) {
 		} break;
 
 		case Entity_Procedure: {
-			AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
-			String original_name = name;
-			AstNode *body = pd->body;
-			if (e->Procedure.is_foreign) {
-				name = e->token.string; // NOTE(bill): Don't use the mangled name
-			}
-			if (pd->foreign_name.len > 0) {
-				name = pd->foreign_name;
-			} else if (pd->link_name.len > 0) {
-				name = pd->link_name;
-			}
+			if (decl->proc_decl->kind == AstNode_ProcDecl) {
+				AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
+				String original_name = name;
+				AstNode *body = pd->body;
+				if (e->Procedure.is_foreign) {
+					name = e->token.string; // NOTE(bill): Don't use the mangled name
+				}
+				if (pd->foreign_name.len > 0) {
+					name = pd->foreign_name;
+				} else if (pd->link_name.len > 0) {
+					name = pd->link_name;
+				}
 
-			ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
-			p->Proc.tags = pd->tags;
+				ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
+				p->Proc.tags = pd->tags;
 
-			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);
+				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);
+				}
+			} else if (decl->proc_decl->kind == AstNode_ProcLit) {
+				AstNodeProcLit *pd = &decl->proc_decl->ProcLit;
+				String original_name = name;
+				AstNode *body = pd->body;
+				if (e->Procedure.is_foreign) {
+					name = e->token.string; // NOTE(bill): Don't use the mangled name
+				}
+				if (pd->foreign_name.len > 0) {
+					name = pd->foreign_name;
+				} else if (pd->link_name.len > 0) {
+					name = pd->link_name;
+				}
+
+				ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
+				p->Proc.tags = pd->tags;
+
+				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);
+				}
 			}
 		} break;
 		}