From c4b27bf6043d64da4b427ecb5bbf4a376926f9a6 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 2 Apr 2023 14:14:30 +0200 Subject: [PATCH] WOO YEE Basic polymorphism for untyped values, not working for typed expressions yet --- build/examples/_polymorphism.core | 11 ++- core_polymorph.cpp | 118 +++++++++++++++++++++++++++--- core_typechecking.cpp | 9 +-- core_typechecking.h | 3 + 4 files changed, 122 insertions(+), 19 deletions(-) diff --git a/build/examples/_polymorphism.core b/build/examples/_polymorphism.core index 1c879f9..52bb129 100644 --- a/build/examples/_polymorphism.core +++ b/build/examples/_polymorphism.core @@ -47,12 +47,16 @@ MakeArray :: (a: *int, count: int): Array(int) // @todo: maybe disallow multiple arguments in current form // and use polimorphism. Then we could make var unpacking, // unpack structs making it more powerful +// a,b := MultipleArgs() // @todo var unpacking MultipleArgs :: (): Tuple(int, F32) return {32, 32} PolyLambda :: ($T: Type = *int): T return 32 +PolyType :: (a: $T): T + return a + GetCount :: (a: int): int return a @@ -78,7 +82,7 @@ main :: (argc: int, argv: **char): int // c := MakeArray(buff, GetCount(GetCount(32))) - // a,b := MultipleArgs() + a := MultipleArgs() Test(10) @@ -89,5 +93,10 @@ main :: (argc: int, argv: **char): int Test(a = 10, b = 10, c = 20) value := PolyLambda(**int) + PolyType_r1 := PolyType(10) + PolyType_r2 := PolyType(int) + // PolyType_r3 := PolyType(array) + // PolyType_r4 := PolyType(seventh) + // PolyType_r5 := PolyType(sixth) return 0 \ No newline at end of file diff --git a/core_polymorph.cpp b/core_polymorph.cpp index 899a3a2..75e8262 100644 --- a/core_polymorph.cpp +++ b/core_polymorph.cpp @@ -14,6 +14,69 @@ get_unique_name_for_decl(Ast_Decl *decl) { return pctx->internf("%c%u_%Q", char_counter++, decl->di, decl->name); } +CORE_Static String core_type_to_string(Ast_Type *type); +Ast_Expr *create_typespec_from_type(Token *pos, Ast_Scope *parent_scope, Ast_Type *type) { + Ast_Expr *result = 0; + switch (type->kind) { + case TYPE_NONE: + case TYPE_TUPLE: + case TYPE_COMPLETING: + case TYPE_INCOMPLETE: + case TYPE_POLYMORPH: + case TYPE_UNTYPED_BOOL: + case TYPE_UNTYPED_INT: + case TYPE_UNTYPED_FLOAT: + case TYPE_UNTYPED_STRING: { + invalid_codepath; + } break; + + case TYPE_TYPE: + case TYPE_S64: + case TYPE_S32: + case TYPE_S16: + case TYPE_S8: + case TYPE_INT: + case TYPE_CHAR: + case TYPE_U64: + case TYPE_U32: + case TYPE_U16: + case TYPE_U8: + case TYPE_F32: + case TYPE_F64: + case TYPE_BOOL: + case TYPE_STRING: + case TYPE_VOID: { + String s = core_type_to_string(type); + result = ast_ident(pos, pctx->intern(s)); + } break; + + case TYPE_POINTER: { + result = ast_expr_unary(pos, TK_Pointer, create_typespec_from_type(pos, parent_scope, type->base)); + } break; + case TYPE_ARRAY: { + Ast_Array *arr = ast_array(pos, create_typespec_from_type(pos, parent_scope, type->arr.base)); + arr->expr = ast_int(pos, type->arr.size); + arr->expr->parent_scope = parent_scope; + result = arr; + } break; + case TYPE_SLICE: { + Ast_Array *arr = ast_array(pos, create_typespec_from_type(pos, parent_scope, type->arr.base)); + result = arr; + } break; + case TYPE_LAMBDA: { + invalid_codepath; + } break; + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ENUM: { + Ast_Decl *decl = (Ast_Decl *)type->ast; + result = ast_ident(pos, decl->name); + } break; + } + result->parent_scope = parent_scope; + return result; +} + #define ast_create_copy(parent_scope, T, ast) (T *)ast__create_copy(parent_scope, sizeof(T), ast) Ast *ast__create_copy(Ast_Scope *parent_scope, size_t size, Ast *ast) { if (ast == 0) return 0; @@ -57,12 +120,32 @@ Ast *ast_copy(Ast *ast, Ast_Scope *parent_scope, Array *replace, Arr if (replace && with) { // @todo: IF ITS STRUCT we only want to replace TYPESPECS For(*replace) { - assert(it->type == pctx->type_type); - if (it->name == dst->intern_val) { - S64 it_index = replace->get_index(it); - Ast_Call_Item *replacement = with[0][it_index]; - Ast *replacement_v = replacement->item; - dst = (Ast_Atom *)ast_copy(replacement_v, parent_scope, 0, 0); + if (it->flags & AST_IDENT_POLYMORPH) { + assert(it->type == pctx->type_type); + if (it->name == dst->intern_val) { + S64 it_index = replace->get_index(it); + Ast_Call_Item *replacement = with[0][it_index]; + Ast *replacement_v = replacement->item; + dst = (Ast_Atom *)ast_copy(replacement_v, parent_scope, 0, 0); + } + } + else if (it->flags & AST_TYPE_POLYMORPH) { + Ast_Expr *typespec = it->typespec; + assert(typespec); + assert(typespec->kind == AST_IDENT); + Ast_Atom *t = (Ast_Atom *)typespec; + + if (t->intern_val == dst->intern_val) { + S64 it_index = replace->get_index(it); + + // @todo: This probably should be resolved + // before calling the ast_copy function + // or something + Ast_Call_Item *replacement = with[0][it_index]; + Ast_Type *type_to_replace = replacement->item->resolved_type; + dst = (Ast_Atom *)create_typespec_from_type(dst->pos, parent_scope, type_to_replace); + // dst = (Ast_Atom *)ast_copy(replacement_v, parent_scope, 0, 0); + } } } } @@ -333,19 +416,30 @@ Ast_Decl *get_or_instantiate_polymorph_type(Token *pos, Ast_Decl *poly, Array params, Ast_Scope *field_access_scope) { if (params.len != poly->polymorph_parameters.len) compiler_error(pos, "Invalid count of polymorphic arguments"); + Scoped_Arena scratch(pctx->scratch); int i = 0; uint64_t hash = 91; For(params) { Ast_Decl *poly_decl = poly->polymorph_parameters[i++]; - resolve_decl(poly_decl); - if (poly_decl->type != pctx->type_type) compiler_error(poly_decl->pos, "Invalid type of polymorphic struct argument"); + if (poly_decl->flags & AST_IDENT_POLYMORPH) { + resolve_decl(poly_decl); + if (poly_decl->type != pctx->type_type) compiler_error(poly_decl->pos, "Invalid type of polymorphic struct argument"); - Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope); - if (!op.is_const) compiler_error(it->pos, "Argument is required to be compile time known"); - if (op.type != pctx->type_type) compiler_error(it->pos, "Struct argument required to be a type"); + Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope); + if (!op.is_const) compiler_error(it->pos, "Argument is required to be compile time known"); + if (op.type != pctx->type_type) compiler_error(it->pos, "Struct argument required to be a type"); - hash = hash_mix(hash, hash_ptr(op.type_val)); + hash = hash_mix(hash, hash_ptr(op.type_val)); + } + else { + Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope); + try_converting_untyped_to_default_type(&op); + try_propagating_resolved_type_to_untyped_literals(it->item, op.type); + assert(it->item->resolved_type == op.type); + + hash = hash_mix(hash, hash_ptr(op.type)); + } } Ast_Decl *result = 0; diff --git a/core_typechecking.cpp b/core_typechecking.cpp index 1048db5..bac7a2d 100644 --- a/core_typechecking.cpp +++ b/core_typechecking.cpp @@ -625,7 +625,7 @@ insert_into_scope(Ast_Scope *scope, Ast_Decl *decl) { // need to propagate int to untyped_int // CORE_Static void -try_propagating_resolved_type_to_untyped_literals(Ast *ast, Ast_Type *type, Ast_Type *additional_not_bool_type = 0) { +try_propagating_resolved_type_to_untyped_literals(Ast *ast, Ast_Type *type, Ast_Type *additional_not_bool_type) { if (!type) compiler_error(ast->pos, "Internal compiler error: Type passed to try_propagating_resolved_type_to_untyped_literals is null"); if (!ast) return; if (is_untyped(type)) return; @@ -1699,11 +1699,8 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str Array replacements = {scratch.arena}; ForArrayRemovable(matches) { ForArrayRemovablePrepare(matches); - - if (it.lambda_arg->flags & AST_POLYMORPH) { - replacements.add(it.call_arg); - ForArrayRemovableDeclare(); - } + if (it.lambda_arg->flags & AST_POLYMORPH) replacements.add(it.call_arg); + if (it.lambda_arg->flags & AST_IDENT_POLYMORPH) ForArrayRemovableDeclare(); } Ast_Decl *poly = name.resolved_decl; diff --git a/core_typechecking.h b/core_typechecking.h index dae4466..016e25d 100644 --- a/core_typechecking.h +++ b/core_typechecking.h @@ -57,6 +57,9 @@ enum { RESOLVE_NAME_MAKE_SURE_OPERATOR_OVERLOAD_IS_NOT_EVER_CALLED = bit_flag(2), }; +CORE_Static void try_converting_untyped_to_default_type(Operand *op); +CORE_Static void try_propagating_resolved_type_to_untyped_literals(Ast *ast, Ast_Type *type, Ast_Type *additional_not_bool_type = 0); + CORE_Static Operand resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context, Ast_Scope *field_access_scope); CORE_Static void resolve_decl(Ast_Decl *ast); CORE_Static Ast_Decl *resolve_name(Ast_Scope *parent_scope, Token *pos, Intern_String name, Search_Flag search_flags = 0);