Browse Source

Add `$T: typeid/[]$E`; Deprecate `T: type/[]$E`

`type` as a keyword will soon be removed in favour of polymorphic names (identifiers) in procedures
gingerBill 7 years ago
parent
commit
11f5236434
6 changed files with 101 additions and 27 deletions
  1. 1 1
      core/fmt/fmt.odin
  2. 1 1
      core/math/math.odin
  3. 6 6
      core/mem/alloc.odin
  4. 7 6
      examples/demo/demo.odin
  5. 31 12
      src/check_type.cpp
  6. 55 1
      src/parser.cpp

+ 1 - 1
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 {

+ 1 - 1
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;

+ 6 - 6
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;

+ 7 - 6
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();

+ 31 - 12
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;
 				}
 

+ 55 - 1
src/parser.cpp

@@ -2435,6 +2435,7 @@ Ast *parse_value_decl(AstFile *f, Array<Ast *> 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<Ast *> convert_to_ident_list(AstFile *f, Array<AstAndFlags> 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<Ast *> 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)) {