aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/check_builtin.cpp42
-rw-r--r--src/check_expr.cpp36
-rw-r--r--src/checker_builtin_procs.hpp8
-rw-r--r--src/llvm_backend_proc.cpp3
-rw-r--r--src/llvm_backend_utility.cpp11
-rw-r--r--src/types.cpp44
6 files changed, 101 insertions, 43 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 8ada77b12..df22d82e2 100644
--- a/src/check_builtin.cpp
+++ b/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 = {};
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 3f31ac810..6db17a316 100644
--- a/src/check_expr.cpp
+++ b/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) {
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 1a9d7d7a0..c14c18412 100644
--- a/src/checker_builtin_procs.hpp
+++ b/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},
};
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 6de0aaed7..caa3dfa1a 100644
--- a/src/llvm_backend_proc.cpp
+++ b/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));
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index d92f711ba..8ef66df7a 100644
--- a/src/llvm_backend_utility.cpp
+++ b/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);
+
+} \ No newline at end of file
diff --git a/src/types.cpp b/src/types.cpp
index cdb31c6e1..024d644a2 100644
--- a/src/types.cpp
+++ b/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));