Browse Source

Extra check for `type_info` cycle checking

gingerBill 7 years ago
parent
commit
83d90f1463
3 changed files with 31 additions and 9 deletions
  1. 26 9
      src/check_expr.cpp
  2. 4 0
      src/check_type.cpp
  3. 1 0
      src/checker.hpp

+ 26 - 9
src/check_expr.cpp

@@ -3242,23 +3242,40 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 	}
 	}
 
 
 
 
-	case BuiltinProc_type_of:
+	case BuiltinProc_type_of: {
 		// proc type_of(val: Type) -> type(Type)
 		// proc type_of(val: Type) -> type(Type)
-		check_assignment(c, operand, nullptr, str_lit("argument of 'type_of'"));
-		if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin) {
+		AstNode *expr = ce->args[0];
+		Operand o = {};
+		check_expr_or_type(c, &o, expr);
+
+		// check_assignment(c, operand, nullptr, str_lit("argument of 'type_of'"));
+		if (o.mode == Addressing_Invalid || o.mode == Addressing_Builtin) {
+			return false;
+		}
+		if (o.type == nullptr || o.type == t_invalid) {
+			error(o.expr, "Invalid argument to 'type_of'");
+			return false;
+		}
+		if (o.type == nullptr || o.type == t_invalid) {
+			error(o.expr, "Invalid argument to 'type_of'");
 			return false;
 			return false;
 		}
 		}
-		if (operand->type == nullptr || operand->type == t_invalid) {
-			error(operand->expr, "Invalid argument to 'type_of'");
+		// NOTE(bill): Prevent type cycles for procedure declarations
+		if (c->context.curr_proc_sig == o.type) {
+			gbString s = expr_to_string(o.expr);
+			error(o.expr, "Invalid cyclic type usage from 'type_of', got '%s'", s);
+			gb_string_free(s);
 			return false;
 			return false;
 		}
 		}
-		if (is_type_polymorphic(operand->type)) {
-			error(operand->expr, "'type_of' of polymorphic type cannot be determined");
+
+		if (is_type_polymorphic(o.type)) {
+			error(o.expr, "'type_of' of polymorphic type cannot be determined");
 			return false;
 			return false;
 		}
 		}
 		operand->mode = Addressing_Type;
 		operand->mode = Addressing_Type;
+		operand->type = o.type;
 		break;
 		break;
-
+	}
 
 
 	case BuiltinProc_type_info_of: {
 	case BuiltinProc_type_info_of: {
 		// proc type_info_of(Type) -> ^Type_Info
 		// proc type_info_of(Type) -> ^Type_Info
@@ -3270,7 +3287,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		init_preload(c);
 		init_preload(c);
 		AstNode *expr = ce->args[0];
 		AstNode *expr = ce->args[0];
 		Operand o = {};
 		Operand o = {};
-		check_expr_or_type(c, &o, ce->args[0]);
+		check_expr_or_type(c, &o, expr);
 		if (o.mode == Addressing_Invalid) {
 		if (o.mode == Addressing_Invalid) {
 			return false;
 			return false;
 		}
 		}

+ 4 - 0
src/check_type.cpp

@@ -1671,6 +1671,10 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
 		c->context.polymorphic_scope = c->context.scope;
 		c->context.polymorphic_scope = c->context.scope;
 	}
 	}
 
 
+	CheckerContext prev = c->context;
+	defer (c->context = prev);
+	c->context.curr_proc_sig = type;
+
 	bool variadic = false;
 	bool variadic = false;
 	isize variadic_index = -1;
 	isize variadic_index = -1;
 	bool success = true;
 	bool success = true;

+ 1 - 0
src/checker.hpp

@@ -275,6 +275,7 @@ struct CheckerContext {
 	String     proc_name;
 	String     proc_name;
 	Type *     type_hint;
 	Type *     type_hint;
 	DeclInfo * curr_proc_decl;
 	DeclInfo * curr_proc_decl;
+	Type *     curr_proc_sig;
 	ForeignContext foreign_context;
 	ForeignContext foreign_context;
 
 
 	bool       collect_delayed_decls;
 	bool       collect_delayed_decls;