Explorar o código

Add `#require_results` for procedures

Ginger Bill %!s(int64=8) %!d(string=hai) anos
pai
achega
187b186112
Modificáronse 5 ficheiros con 36 adicións e 9 borrados
  1. 17 5
      src/check_decl.c
  2. 1 1
      src/check_expr.c
  3. 14 3
      src/check_stmt.c
  4. 3 0
      src/parser.c
  5. 1 0
      src/types.c

+ 17 - 5
src/check_decl.c

@@ -242,11 +242,13 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
 	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;
+	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;
+	bool is_require_results = (pd->tags & ProcTag_require_results) != 0;
+
 
 	if (d->scope->is_file && str_eq(e->token.string, str_lit("main"))) {
 		if (proc_type != NULL) {
@@ -282,6 +284,16 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
 		check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
 	}
 
+
+	if (proc_type != NULL && is_type_proc(proc_type)) {
+		TypeProc *tp = &proc_type->Proc;
+		if (tp->result_count == 0 && is_require_results) {
+			error_node(pd->type, "`#require_results` is not needed on a procedure with no results");
+		} else {
+			tp->require_results = is_require_results;
+		}
+	}
+
 	if (is_foreign) {
 		MapEntity *fp = &c->info.foreigns;
 		String name = e->token.string;

+ 1 - 1
src/check_expr.c

@@ -4796,7 +4796,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 	}
 
 	operand->expr = call;
-	return Expr_Stmt;
+	return Expr_Expr;
 }
 
 

+ 14 - 3
src/check_stmt.c

@@ -442,9 +442,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		Operand operand = {Addressing_Invalid};
 		ExprKind kind = check_expr_base(c, &operand, es->expr, NULL);
 		switch (operand.mode) {
-		case Addressing_Type:
-			error_node(node, "Is not an expression");
-			break;
+		case Addressing_Type: {
+			gbString str = type_to_string(operand.type);
+			error_node(node, "`%s` is not an expression", str);
+			gb_string_free(str);
+		} break;
 		case Addressing_NoValue:
 			return;
 		default: {
@@ -452,6 +454,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 				return;
 			}
 			if (operand.expr->kind == AstNode_CallExpr) {
+				AstNodeCallExpr *ce = &operand.expr->CallExpr;
+				Type *t = type_of_expr(&c->info, ce->proc);
+				if (is_type_proc(t)) {
+					if (t->Proc.require_results) {
+						gbString expr_str = expr_to_string(ce->proc);
+						error_node(node, "`%s` requires that its results must be handled", expr_str);
+						gb_string_free(expr_str);
+					}
+				}
 				return;
 			}
 			gbString expr_str = expr_to_string(operand.expr);

+ 3 - 0
src/parser.c

@@ -65,6 +65,8 @@ typedef enum ProcTag {
 	ProcTag_bounds_check    = 1<<0,
 	ProcTag_no_bounds_check = 1<<1,
 
+	ProcTag_require_results = 1<<4,
+
 	ProcTag_foreign         = 1<<10,
 	ProcTag_export          = 1<<11,
 	ProcTag_link_name       = 1<<12,
@@ -1570,6 +1572,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str
 				expect_token(f, Token_String);
 			}
 		}
+		ELSE_IF_ADD_TAG(require_results)
 		ELSE_IF_ADD_TAG(export)
 		ELSE_IF_ADD_TAG(bounds_check)
 		ELSE_IF_ADD_TAG(no_bounds_check)

+ 1 - 0
src/types.c

@@ -135,6 +135,7 @@ typedef struct TypeRecord {
 		Type **abi_compat_params;                         \
 		Type **abi_compat_results;                        \
 		bool   variadic;                                  \
+		bool   require_results;                           \
 		ProcCallingConvention calling_convention;         \
 	})                                                    \
 	TYPE_KIND(Map, struct {                               \