mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-16 19:02:23 -07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -86,7 +86,6 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc
|
||||
return
|
||||
}
|
||||
|
||||
array.allocator = allocator
|
||||
footer := raw_soa_footer(&array)
|
||||
if size_of(E) == 0 {
|
||||
footer.len = length
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package relative_types
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
Pointer :: struct($Type: typeid, $Backing: typeid)
|
||||
where
|
||||
intrinsics.type_is_pointer(Type) || intrinsics.type_is_multi_pointer(Type),
|
||||
intrinsics.type_is_integer(Backing) {
|
||||
offset: Backing,
|
||||
}
|
||||
|
||||
Slice :: struct($Type: typeid, $Backing: typeid)
|
||||
where
|
||||
intrinsics.type_is_slice(Type),
|
||||
intrinsics.type_is_integer(Backing) {
|
||||
offset: Backing,
|
||||
len: Backing,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
pointer_get :: proc "contextless" (p: ^$P/Pointer($T, $B)) -> T {
|
||||
if p.offset == 0 {
|
||||
return nil
|
||||
}
|
||||
ptr := ([^]byte)(p)[p.offset:]
|
||||
return (T)(ptr)
|
||||
}
|
||||
|
||||
pointer_set :: proc "contextless" (p: ^$P/Pointer($T, $B), ptr: T) {
|
||||
if ptr == nil {
|
||||
p.offset = 0
|
||||
} else {
|
||||
p.offset = B(int(uintptr(ptr)) - int(uintptr(p)))
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
slice_get :: proc "contextless" (p: ^$S/Slice($T/[]$E, $B)) -> (slice: T) {
|
||||
if p.offset == 0 {
|
||||
when size_of(E) == 0 {
|
||||
slice = T(([^]E)(nil)[:p.len])
|
||||
}
|
||||
} else {
|
||||
ptr := ([^]E)(([^]byte)(p)[p.offset:])
|
||||
slice = T(ptr[:p.len])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
slice_set :: proc "contextless" (p: ^$S/Slice($T, $B), slice: T) {
|
||||
if slice == nil {
|
||||
p.offset, p.len = 0, 0
|
||||
} else {
|
||||
ptr := raw_data(slice)
|
||||
p.offset = B(int(uintptr(ptr)) - int(uintptr(p)))
|
||||
p.len = B(len(slice))
|
||||
}
|
||||
}
|
||||
|
||||
get :: proc{
|
||||
pointer_get,
|
||||
slice_get,
|
||||
}
|
||||
|
||||
set :: proc{
|
||||
pointer_set,
|
||||
slice_set,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Set_Safe_Error :: enum {
|
||||
None,
|
||||
Memory_Too_Far_Apart,
|
||||
Length_Out_Of_Bounds,
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
pointer_set_safe :: proc "contextless" (p: ^$P/Pointer($T, $B), ptr: T) -> Set_Safe_Error {
|
||||
if ptr == nil {
|
||||
p.offset = 0
|
||||
} else {
|
||||
when intrinsics.type_is_unsigned(B) {
|
||||
diff := uint(uintptr(ptr) - uintptr(p))
|
||||
when size_of(B) < size_of(uint) {
|
||||
if diff > uint(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
}
|
||||
} else {
|
||||
diff := int(uintptr(ptr)) - int(uintptr(p))
|
||||
when size_of(B) < size_of(int) {
|
||||
if diff > int(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
}
|
||||
}
|
||||
p.offset = B(diff)
|
||||
}
|
||||
return .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
slice_set_safe :: proc "contextless" (p: ^$S/Slice($T, $B), slice: T) -> Set_Safe_Error {
|
||||
if slice == nil {
|
||||
p.offset, p.len = 0, 0
|
||||
} else {
|
||||
ptr := raw_data(slice)
|
||||
when intrinsics.type_is_unsigned(B) {
|
||||
diff := uint(uintptr(ptr) - uintptr(p))
|
||||
when size_of(B) < size_of(uint) {
|
||||
if diff > uint(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
|
||||
if uint(len(slice)) > uint(max(B)) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
if B(len(slice)) > max(B) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
}
|
||||
p.offset = B(diff)
|
||||
p.len = B(len(slice))
|
||||
} else {
|
||||
diff := int(uintptr(ptr)) - int(uintptr(p))
|
||||
when size_of(B) < size_of(int) {
|
||||
if diff > int(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
if len(slice) > int(max(B)) || len(slice) < int(min(B)) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
if B(len(slice)) > max(B) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
if B(len(slice)) > max(B) || B(len(slice)) < min(B) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
}
|
||||
}
|
||||
p.offset = B(diff)
|
||||
p.len = B(len(slice))
|
||||
}
|
||||
return .None
|
||||
}
|
||||
|
||||
|
||||
set_safe :: proc{
|
||||
pointer_set_safe,
|
||||
slice_set_safe,
|
||||
}
|
||||
@@ -5686,7 +5686,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->value = exact_value_bool(is_type_subtype_of(op_src.type, op_dst.type));
|
||||
operand->value = exact_value_bool(is_type_subtype_of_and_allow_polymorphic(op_src.type, op_dst.type));
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->type = t_untyped_bool;
|
||||
} break;
|
||||
|
||||
+25
-6
@@ -1,4 +1,6 @@
|
||||
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
|
||||
gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand);
|
||||
gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> const *operands);
|
||||
|
||||
gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
|
||||
t = base_type(t);
|
||||
@@ -393,7 +395,6 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
bool *is_polymorphic_,
|
||||
Ast *node, Array<Operand> *poly_operands) {
|
||||
Type *polymorphic_params_type = nullptr;
|
||||
bool can_check_fields = true;
|
||||
GB_ASSERT(is_polymorphic_ != nullptr);
|
||||
|
||||
if (polymorphic_params == nullptr) {
|
||||
@@ -403,6 +404,17 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
return polymorphic_params_type;
|
||||
}
|
||||
|
||||
|
||||
// bool is_variadic = false;
|
||||
// isize variadic_index = 0;
|
||||
// bool success = false;
|
||||
// isize specialization_count = 0;
|
||||
// polymorphic_params_type = check_get_params(ctx, ctx->scope, polymorphic_params, &is_variadic, &variadic_index, &success, &specialization_count, poly_operands);
|
||||
// if (success) {
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
bool can_check_fields = true;
|
||||
ast_node(field_list, FieldList, polymorphic_params);
|
||||
Slice<Ast *> params = field_list->list;
|
||||
if (params.count != 0) {
|
||||
@@ -417,11 +429,13 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
|
||||
auto entities = array_make<Entity *>(permanent_allocator(), 0, variable_count);
|
||||
|
||||
i32 field_group_index = -1;
|
||||
for_array(i, params) {
|
||||
Ast *param = params[i];
|
||||
if (param->kind != Ast_Field) {
|
||||
continue;
|
||||
}
|
||||
field_group_index += 1;
|
||||
ast_node(p, Field, param);
|
||||
Ast *type_expr = p->type;
|
||||
Ast *default_value = unparen_expr(p->default_value);
|
||||
@@ -481,7 +495,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
type = t_invalid;
|
||||
}
|
||||
|
||||
if (is_type_polymorphic_type) {
|
||||
if (is_type_polymorphic_type && !is_type_proc(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(params[i], "Parameter types cannot be polymorphic, got %s", str);
|
||||
gb_string_free(str);
|
||||
@@ -523,13 +537,18 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
e->TypeName.is_type_alias = true;
|
||||
e->flags |= EntityFlag_PolyConst;
|
||||
} else {
|
||||
if (is_type_polymorphic(base_type(operand.type))) {
|
||||
Type *t = operand.type;
|
||||
if (is_type_proc(type)) {
|
||||
t = determine_type_from_polymorphic(ctx, type, operand);
|
||||
}
|
||||
if (is_type_polymorphic(base_type(t))) {
|
||||
*is_polymorphic_ = true;
|
||||
can_check_fields = false;
|
||||
}
|
||||
if (e == nullptr) {
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
e = alloc_entity_const_param(scope, token, t, operand.value, is_type_polymorphic(t));
|
||||
e->Constant.param_value = param_value;
|
||||
e->Constant.field_group_index = field_group_index;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -538,7 +557,8 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
e->TypeName.is_type_alias = true;
|
||||
e->flags |= EntityFlag_PolyConst;
|
||||
} else {
|
||||
e = alloc_entity_constant(scope, token, type, param_value.value);
|
||||
e = alloc_entity_const_param(scope, token, type, param_value.value, is_type_polymorphic(type));
|
||||
e->Constant.field_group_index = field_group_index;
|
||||
e->Constant.param_value = param_value;
|
||||
}
|
||||
}
|
||||
@@ -559,7 +579,6 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
if (!*is_polymorphic_) {
|
||||
*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
|
||||
}
|
||||
|
||||
return polymorphic_params_type;
|
||||
}
|
||||
|
||||
|
||||
@@ -2164,6 +2164,49 @@ gb_internal Array<Ast *> parse_union_variant_list(AstFile *f) {
|
||||
return variants;
|
||||
}
|
||||
|
||||
gb_internal void parser_check_polymorphic_record_parameters(AstFile *f, Ast *polymorphic_params) {
|
||||
if (polymorphic_params == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (polymorphic_params->kind != Ast_FieldList) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
enum {Unknown, Dollar, Bare} prefix = Unknown;
|
||||
gb_unused(prefix);
|
||||
|
||||
for (Ast *field : polymorphic_params->FieldList.list) {
|
||||
if (field == nullptr || field->kind != Ast_Field) {
|
||||
continue;
|
||||
}
|
||||
for (Ast *name : field->Field.names) {
|
||||
if (name == nullptr) {
|
||||
continue;
|
||||
}
|
||||
bool error = false;
|
||||
|
||||
if (name->kind == Ast_Ident) {
|
||||
switch (prefix) {
|
||||
case Unknown: prefix = Bare; break;
|
||||
case Dollar: error = true; break;
|
||||
case Bare: break;
|
||||
}
|
||||
} else if (name->kind == Ast_PolyType) {
|
||||
switch (prefix) {
|
||||
case Unknown: prefix = Dollar; break;
|
||||
case Dollar: break;
|
||||
case Bare: error = true; break;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
syntax_error(name, "Mixture of polymorphic $ names and normal identifiers are not allowed within record parameters");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
Ast *operand = nullptr; // Operand
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -2610,6 +2653,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
parser_check_polymorphic_record_parameters(f, polymorphic_params);
|
||||
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, field_align, where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
@@ -2702,6 +2747,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
auto variants = parse_union_variant_list(f);
|
||||
Token close = expect_closing_brace_of_field_list(f);
|
||||
|
||||
parser_check_polymorphic_record_parameters(f, polymorphic_params);
|
||||
|
||||
return ast_union_type(f, token, variants, polymorphic_params, align, union_kind, where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
|
||||
+17
-2
@@ -4093,7 +4093,7 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) {
|
||||
gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false, bool allow_polymorphic=false) {
|
||||
Type *prev_src = src;
|
||||
src = type_deref(src);
|
||||
if (!src_is_ptr) {
|
||||
@@ -4105,11 +4105,19 @@ gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isi
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool dst_is_polymorphic = is_type_polymorphic(dst);
|
||||
|
||||
for_array(i, src->Struct.fields) {
|
||||
Entity *f = src->Struct.fields[i];
|
||||
if (f->kind != Entity_Variable || (f->flags&EntityFlags_IsSubtype) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (allow_polymorphic && dst_is_polymorphic) {
|
||||
Type *fb = base_type(type_deref(f->type));
|
||||
if (fb->kind == Type_Struct && fb->Struct.polymorphic_parent == dst) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (are_types_identical(f->type, dst)) {
|
||||
return level+1;
|
||||
@@ -4119,7 +4127,7 @@ gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isi
|
||||
return level+1;
|
||||
}
|
||||
}
|
||||
isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr);
|
||||
isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr, allow_polymorphic);
|
||||
if (nested_level > 0) {
|
||||
return nested_level;
|
||||
}
|
||||
@@ -4135,6 +4143,13 @@ gb_internal bool is_type_subtype_of(Type *src, Type *dst) {
|
||||
|
||||
return 0 < check_is_assignable_to_using_subtype(src, dst, 0, is_type_pointer(src));
|
||||
}
|
||||
gb_internal bool is_type_subtype_of_and_allow_polymorphic(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), true);
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool has_type_got_objc_class_attribute(Type *t) {
|
||||
|
||||
Reference in New Issue
Block a user