From 11f5236434ca08ae034a195639c8ed377e125015 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 2 Sep 2018 16:33:54 +0100 Subject: [PATCH] Add `$T: typeid/[]$E`; Deprecate `T: type/[]$E` `type` as a keyword will soon be removed in favour of polymorphic names (identifiers) in procedures --- core/fmt/fmt.odin | 2 +- core/math/math.odin | 2 +- core/mem/alloc.odin | 12 ++++----- examples/demo/demo.odin | 13 +++++----- src/check_type.cpp | 43 ++++++++++++++++++++++--------- src/parser.cpp | 56 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 101 insertions(+), 27 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 47a40b2e2..7f5d04727 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -767,7 +767,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) { return "", false; } -string_to_enum_value :: proc(T: type, s: string) -> (T, bool) { +string_to_enum_value :: proc($T: typeid, s: string) -> (T, bool) { ti := type_info_base(type_info_of(T)); if e, ok := ti.variant.(Type_Info_Enum); ok { for str, idx in e.names { diff --git a/core/math/math.odin b/core/math/math.odin index 4b891f942..daad97e5c 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -192,7 +192,7 @@ norm0 :: proc(v: $T/[$N]$E) -> T { -identity :: proc(T: type/[$N][N]$E) -> T { +identity :: proc($T: typeid/[$N][N]$E) -> T { m: T; for i in 0..N-1 do m[i][i] = E(1); return m; diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index c8c0c5855..e4357fe18 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -78,7 +78,7 @@ delete :: proc[ ]; -new :: inline proc(T: type, allocator := context.allocator, loc := #caller_location) -> ^T { +new :: inline proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> ^T { ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc)); if ptr != nil do ptr^ = T{}; return ptr; @@ -90,25 +90,25 @@ new_clone :: inline proc(data: $T, allocator := context.allocator, loc := #calle } -make_slice :: proc(T: type/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { +make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { runtime.make_slice_error_loc(loc, len); data := alloc(size_of(E)*len, align_of(E), allocator, loc); s := Raw_Slice{data, len}; return transmute(T)s; } -make_dynamic_array :: proc(T: type/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T { return make_dynamic_array_len_cap(T, 0, 16, allocator, loc); } -make_dynamic_array_len :: proc(T: type/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { return make_dynamic_array_len_cap(T, len, len, allocator, loc); } -make_dynamic_array_len_cap :: proc(T: type/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T { runtime.make_dynamic_array_error_loc(loc, len, cap); data := alloc(size_of(E)*cap, align_of(E), allocator, loc); s := Raw_Dynamic_Array{data, len, cap, allocator}; return transmute(T)s; } -make_map :: proc(T: type/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T { +make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T { runtime.make_map_expr_error_loc(loc, cap); c := context; diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index ed26b9664..2f3e9340e 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -187,7 +187,7 @@ union_type :: proc() { } // See `parametric_polymorphism` procedure for details - new_entity :: proc(T: type) -> ^Entity { + new_entity :: proc($T: typeid) -> ^Entity { t := new(T); t.derived = t^; return t; @@ -231,7 +231,7 @@ union_type :: proc() { } // See `parametric_polymorphism` procedure for details - new_entity :: proc(T: type) -> ^Entity { + new_entity :: proc($T: typeid) -> ^Entity { t := new(Entity); t.derived = T{entity = t}; return t; @@ -318,7 +318,7 @@ parametric_polymorphism :: proc() { fmt.printf("b: %T = %v\n", b, b); // This is how `new` is implemented - alloc_type :: proc(T: type) -> ^T { + alloc_type :: proc($T: typeid) -> ^T { t := cast(^T)alloc(size_of(T), align_of(T)); t^ = T{}; // Use default initialization value return t; @@ -341,21 +341,21 @@ parametric_polymorphism :: proc() { { // Polymorphic Types and Type Specialization - Table_Slot :: struct(Key, Value: type) { + Table_Slot :: struct(Key, Value: typeid) { occupied: bool, hash: u32, key: Key, value: Value, } TABLE_SIZE_MIN :: 32; - Table :: struct(Key, Value: type) { + Table :: struct(Key, Value: typeid) { count: int, allocator: mem.Allocator, slots: []Table_Slot(Key, Value), } // Only allow types that are specializations of a (polymorphic) slice - make_slice :: proc(T: type/[]$E, len: int) -> T { + make_slice :: proc($T: typeid/[]$E, len: int) -> T { return make(T, len); } @@ -767,6 +767,7 @@ bit_set_type :: proc() { } } + main :: proc() { when true { general_stuff(); diff --git a/src/check_type.cpp b/src/check_type.cpp index 2eff33922..98d35cf0b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -374,18 +374,20 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< type_expr = type_expr->Ellipsis.expr; error(param, "A polymorphic parameter cannot be variadic"); } - if (type_expr->kind == Ast_TypeType) { + if (type_expr->kind == Ast_TypeidType) { + is_type_param = true; + Type *specialization = nullptr; + if (type_expr->TypeidType.specialization != nullptr) { + Ast *s = type_expr->TypeidType.specialization; + specialization = check_type(ctx, s); + } + type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + } else if (type_expr->kind == Ast_TypeType) { is_type_param = true; Type *specialization = nullptr; if (type_expr->TypeType.specialization != nullptr) { Ast *s = type_expr->TypeType.specialization; specialization = check_type(ctx, s); - // if (!is_type_polymorphic_struct(specialization)) { - // gbString str = type_to_string(specialization); - // defer (gb_string_free(str)); - // error(s, "Expected a polymorphic struct, got %s", str); - // specialization = nullptr; - // } } type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); } else { @@ -1159,7 +1161,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is continue; } ast_node(p, Field, param); - Ast *type_expr = p->type; + Ast *type_expr = unparen_expr(p->type); Type *type = nullptr; Ast *default_value = unparen_expr(p->default_value); ParameterValue param_value = {}; @@ -1183,7 +1185,24 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is success = false; } } - if (type_expr->kind == Ast_TypeType) { + if (type_expr->kind == Ast_TypeidType) { + ast_node(tt, TypeidType, type_expr); + if (tt->specialization) { + specialization = check_type(ctx, tt->specialization); + if (specialization == t_invalid){ + specialization = nullptr; + } + + if (operands != nullptr) { + detemine_type_from_operand = true; + type = t_invalid; + } else { + type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + } + } else { + type = t_typeid; + } + } else if (type_expr->kind == Ast_TypeType) { ast_node(tt, TypeType, type_expr); is_type_param = true; specialization = check_type(ctx, tt->specialization); @@ -1213,7 +1232,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is } if (default_value != nullptr) { - if (type_expr != nullptr && type_expr->kind == Ast_TypeType) { + if (type_expr != nullptr && (type_expr->kind == Ast_TypeType || type_expr->kind == Ast_TypeidType)) { error(type_expr, "A type parameter may not have a default value"); } else { param_value = handle_parameter_value(ctx, type, nullptr, default_value, true); @@ -1281,7 +1300,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is } if (is_poly_name) { - if (type != nullptr && is_type_typeid(type)) { + if (type != nullptr && type_expr->kind == Ast_TypeidType) { is_type_param = true; } else { error(name, "Polymorphic names are not yet supported for non-typeid parameters"); @@ -1324,7 +1343,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is } if (p->flags&FieldFlag_auto_cast) { - error(name, "'auto_cast' can only be applied variable fields"); + error(name, "'auto_cast' can only be applied to variable fields"); p->flags &= ~FieldFlag_auto_cast; } diff --git a/src/parser.cpp b/src/parser.cpp index f30728682..45a8dc3aa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2435,6 +2435,7 @@ Ast *parse_value_decl(AstFile *f, Array names, CommentGroup *docs) { if (f->curr_token.kind == Token_type) { type = ast_type_type(f, advance_token(f), nullptr); + warning(type, "'type' is deprecated"); is_mutable = false; } else { type = parse_type_or_ident(f); @@ -2718,6 +2719,19 @@ Ast *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) { specialization = parse_type(f); } type = ast_type_type(f, token, specialization); + if (specialization) { + warning(type, "'type' is deprecated, please use something like '$T: typeid/[]$E'"); + } else { + warning(type, "'type' is deprecated, please use something like '$T: typeid'"); + } + } else if (allow_type_token && + f->curr_token.kind == Token_typeid) { + Token token = expect_token(f, Token_typeid); + Ast *specialization = nullptr; + if (allow_token(f, Token_Quo)) { + specialization = parse_type(f); + } + type = ast_typeid_type(f, token, specialization); } else { type = parse_type(f); } @@ -2855,7 +2869,7 @@ Array convert_to_ident_list(AstFile *f, Array list, bool ign case Ast_PolyType: if (allow_poly_names) { if (ident->PolyType.specialization == nullptr) { - syntax_error(ident, "Polymorphic identifiers are not yet supported"); + // syntax_error(ident, "Polymorphic identifiers are not yet supported"); break; } else { syntax_error(ident, "Expected a polymorphic identifier without any specialization"); @@ -2925,6 +2939,36 @@ Ast *parse_struct_field_list(AstFile *f, isize *name_count_) { return params; } + +// Returns true if any are polymorphic names +bool check_procedure_name_list(Array const &names) { + if (names.count == 0) { + return false; + } + bool first_is_polymorphic = names[0]->kind == Ast_PolyType; + bool any_polymorphic_names = first_is_polymorphic; + for (isize i = 1; i < names.count; i++) { + Ast *name = names[i]; + if (first_is_polymorphic) { + if (name->kind == Ast_PolyType) { + any_polymorphic_names = true; + } else { + syntax_error(name, "Mixture of polymorphic and non-polymorphic identifiers"); + return any_polymorphic_names; + } + } else { + if (name->kind == Ast_PolyType) { + any_polymorphic_names = true; + syntax_error(name, "Mixture of polymorphic and non-polymorphic identifiers"); + return any_polymorphic_names; + } else { + // Okay + } + } + } + return any_polymorphic_names; +} + Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_type_token) { Token start_token = f->curr_token; @@ -2965,6 +3009,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); } + bool any_polymorphic_names = check_procedure_name_list(names); u32 set_flags = 0; if (list.count > 0) { set_flags = list[0].flags; @@ -2978,6 +3023,10 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi expect_token_after(f, Token_Colon, "field list"); if (f->curr_token.kind != Token_Eq) { type = parse_var_type(f, allow_ellipsis, allow_type_token); + Ast *tt = unparen_expr(type); + if (!any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) { + syntax_error(type, "Specialization of typeid is not allowed without polymorphic names"); + } } if (allow_token(f, Token_Eq)) { @@ -3022,6 +3071,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Empty field declaration"); break; } + bool any_polymorphic_names = check_procedure_name_list(names); set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); total_name_count += names.count; @@ -3030,6 +3080,10 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi expect_token_after(f, Token_Colon, "field list"); if (f->curr_token.kind != Token_Eq) { type = parse_var_type(f, allow_ellipsis, allow_type_token); + Ast *tt = unparen_expr(type); + if (!any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) { + syntax_error(type, "Specialization of typeid is not allowed without polymorphic names"); + } } if (allow_token(f, Token_Eq)) {