Browse Source

Add `intrinsics.type_is_subtype_of`; `intrinsics.objc_selector_name`

gingerBill 3 years ago
parent
commit
c5d348515d
6 changed files with 101 additions and 43 deletions
  1. 37 5
      src/check_builtin.cpp
  2. 0 36
      src/check_expr.cpp
  3. 6 2
      src/checker_builtin_procs.hpp
  4. 3 0
      src/llvm_backend_proc.cpp
  5. 11 0
      src/llvm_backend_utility.cpp
  6. 44 0
      src/types.cpp

+ 37 - 5
src/check_builtin.cpp

@@ -350,9 +350,15 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
 		return true;
 	} break;
 
-	case BuiltinProc_objc_create: {
-		GB_PANIC("TODO: BuiltinProc_objc_create");
-		return false;
+	case BuiltinProc_objc_selector_name: {
+		String sel_name = {};
+		if (!is_constant_string(c, builtin_name, ce->args[0], &sel_name)) {
+			return false;
+		}
+
+		operand->type = t_objc_SEL;
+		operand->mode = Addressing_Value;
+		return true;
 	} break;
 	}
 }
@@ -392,8 +398,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 	case BuiltinProc_len:
 	case BuiltinProc_min:
 	case BuiltinProc_max:
+	case BuiltinProc_type_is_subtype_of:
 	case BuiltinProc_objc_send:
-	case BuiltinProc_objc_create:
+	case BuiltinProc_objc_selector_name:
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		break;
 
@@ -435,7 +442,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		break;
 
 	case BuiltinProc_objc_send:
-	case BuiltinProc_objc_create:
+	case BuiltinProc_objc_selector_name:
 		return check_builtin_objc_procedure(c, operand, call, id, type_hint);
 
 	case BuiltinProc___entry_point:
@@ -3945,6 +3952,31 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 
 		break;
 
+	case BuiltinProc_type_is_subtype_of:
+		{
+			Operand op_src = {};
+			Operand op_dst = {};
+
+			check_expr_or_type(c, &op_src, ce->args[0]);
+			if (op_src.mode != Addressing_Type) {
+				gbString e = expr_to_string(op_src.expr);
+				error(op_src.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e);
+				gb_string_free(e);
+				return false;
+			}
+			check_expr_or_type(c, &op_dst, ce->args[1]);
+			if (op_dst.mode != Addressing_Type) {
+				gbString e = expr_to_string(op_dst.expr);
+				error(op_dst.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e);
+				gb_string_free(e);
+				return false;
+			}
+
+			operand->value = exact_value_bool(is_type_subtype_of(op_src.type, op_dst.type));
+			operand->mode = Addressing_Constant;
+			operand->type = t_untyped_bool;
+		} break;
+
 	case BuiltinProc_type_field_index_of:
 		{
 			Operand op = {};

+ 0 - 36
src/check_expr.cpp

@@ -228,42 +228,6 @@ void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes, isize reser
 	}
 }
 
-
-isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) {
-	Type *prev_src = src;
-	src = type_deref(src);
-	if (!src_is_ptr) {
-		src_is_ptr = src != prev_src;
-	}
-	src = base_type(src);
-
-	if (!is_type_struct(src)) {
-		return 0;
-	}
-
-	for_array(i, src->Struct.fields) {
-		Entity *f = src->Struct.fields[i];
-		if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
-			continue;
-		}
-
-		if (are_types_identical(f->type, dst)) {
-			return level+1;
-		}
-		if (src_is_ptr && is_type_pointer(dst)) {
-			if (are_types_identical(f->type, type_deref(dst))) {
-				return level+1;
-			}
-		}
-		isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr);
-		if (nested_level > 0) {
-			return nested_level;
-		}
-	}
-
-	return 0;
-}
-
 bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_entity, Type *type,
                                             Array<Operand> *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) {
 	///////////////////////////////////////////////////////////////////////////////

+ 6 - 2
src/checker_builtin_procs.hpp

@@ -241,6 +241,8 @@ BuiltinProc__type_simple_boolean_end,
 	BuiltinProc_type_polymorphic_record_parameter_count,
 	BuiltinProc_type_polymorphic_record_parameter_value,
 
+	BuiltinProc_type_is_subtype_of,
+
 	BuiltinProc_type_field_index_of,
 
 	BuiltinProc_type_equal_proc,
@@ -251,7 +253,7 @@ BuiltinProc__type_end,
 	BuiltinProc___entry_point,
 
 	BuiltinProc_objc_send,
-	BuiltinProc_objc_create,
+	BuiltinProc_objc_selector_name,
 
 	BuiltinProc_COUNT,
 };
@@ -494,6 +496,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("type_polymorphic_record_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 
+	{STR_LIT("type_is_subtype_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
 	{STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 
 	{STR_LIT("type_equal_proc"),  1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -505,5 +509,5 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 
 	{STR_LIT("objc_send"),   3, true,  Expr_Expr, BuiltinProcPkg_intrinsics},
-	{STR_LIT("objc_create"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("objc_selector_name"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 };

+ 3 - 0
src/llvm_backend_proc.cpp

@@ -2109,6 +2109,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 
 	case BuiltinProc_objc_send:
 		return lb_handle_obj_send(p, expr);
+
+	case BuiltinProc_objc_selector_name:
+		return lb_handle_obj_selector_name(p, expr);
 	}
 
 	GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));

+ 11 - 0
src/llvm_backend_utility.cpp

@@ -1915,3 +1915,14 @@ lbValue lb_handle_obj_send(lbProcedure *p, Ast *expr) {
 
 	return lb_emit_call(p, the_proc, args);
 }
+
+
+lbValue lb_handle_obj_selector_name(lbProcedure *p, Ast *expr) {
+	ast_node(ce, CallExpr, expr);
+
+	auto tav = ce->args[0]->tav;
+	GB_ASSERT(tav.value.kind == ExactValue_String);
+	String name = tav.value.value_string;
+	return lb_handle_obj_selector(p, name);
+
+}

+ 44 - 0
src/types.cpp

@@ -3748,6 +3748,50 @@ i64 type_offset_of_from_selection(Type *type, Selection sel) {
 	return offset;
 }
 
+isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) {
+	Type *prev_src = src;
+	src = type_deref(src);
+	if (!src_is_ptr) {
+		src_is_ptr = src != prev_src;
+	}
+	src = base_type(src);
+
+	if (!is_type_struct(src)) {
+		return 0;
+	}
+
+	for_array(i, src->Struct.fields) {
+		Entity *f = src->Struct.fields[i];
+		if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
+			continue;
+		}
+
+		if (are_types_identical(f->type, dst)) {
+			return level+1;
+		}
+		if (src_is_ptr && is_type_pointer(dst)) {
+			if (are_types_identical(f->type, type_deref(dst))) {
+				return level+1;
+			}
+		}
+		isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr);
+		if (nested_level > 0) {
+			return nested_level;
+		}
+	}
+
+	return 0;
+}
+
+bool is_type_subtype_of(Type *src, Type *dst) {
+	if (are_types_identical(src, dst)) {
+		return true;
+	}
+
+	return 0 < check_is_assignable_to_using_subtype(src, dst, 0, is_type_pointer(src));
+}
+
+
 
 Type *get_struct_field_type(Type *t, isize index) {
 	t = base_type(type_deref(t));