From 4afec24434deda1ba3fd4868b50ff41cf79dd5e6 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 19 Jul 2022 19:02:55 +0200 Subject: [PATCH] More advanced introspection. --- lib/std/io_printf.c3 | 50 +++++++- src/compiler/ast.c | 28 ++++- src/compiler/codegen_internal.h | 10 ++ src/compiler/compiler_internal.h | 12 +- src/compiler/copying.c | 4 + src/compiler/enums.h | 2 + src/compiler/llvm_codegen.c | 2 - src/compiler/llvm_codegen_expr.c | 45 +++++-- src/compiler/llvm_codegen_internal.h | 2 + src/compiler/llvm_codegen_module.c | 22 ++++ src/compiler/llvm_codegen_stmt.c | 2 +- src/compiler/llvm_codegen_type.c | 178 ++++++++++++--------------- src/compiler/parse_expr.c | 15 ++- src/compiler/sema_casts.c | 2 + src/compiler/sema_decls.c | 8 +- src/compiler/sema_expr.c | 45 ++++++- src/compiler/types.c | 63 ++++++++++ 17 files changed, 365 insertions(+), 125 deletions(-) diff --git a/lib/std/io_printf.c3 b/lib/std/io_printf.c3 index a3c20abae..31bd03526 100644 --- a/lib/std/io_printf.c3 +++ b/lib/std/io_printf.c3 @@ -85,11 +85,55 @@ private fn void! out_str(PrintParam* param, variant arg) case FLOAT: return ftoa(param, float_from_variant(arg)); case ARRAY: - return out_substr(param, "[]"); + // this is SomeType[*] so grab the "SomeType" + typeid inner = arg.type.inner; + usize size = inner.sizeof; + usize len = arg.type.len; + // Pretend this is a char[] + void* ptr = (void*)arg.ptr; + param.out('[')?; + for (usize i = 0; i < len; i++) + { + if (i != 0) out_substr(param, ", ")?; + out_str(param, variant { ptr, inner })?; + ptr += size; + } + return param.out(']'); case VECTOR: - return out_substr(param, "[]"); + // this is SomeType[*] so grab the "SomeType" + typeid inner = arg.type.inner; + usize size = inner.sizeof; + usize len = arg.type.len; + // Pretend this is a char[] + void* ptr = (void*)arg.ptr; + out_substr(param, "[<")?; + for (usize i = 0; i < len; i++) + { + if (i != 0) out_substr(param, ", ")?; + out_str(param, variant { ptr, inner })?; + ptr += size; + } + return out_substr(param, ">]"); case SUBARRAY: - return out_substr(param, *(char[]*)arg.ptr); + // this is SomeType[] so grab the "SomeType" + typeid inner = arg.type.inner; + if (inner == char.typeid) + { + return out_substr(param, *(char[]*)arg); + } + usize size = inner.sizeof; + // Pretend this is a char[] + char[]* temp = (void*)arg.ptr; + void* ptr = (void*)temp.ptr; + usize len = temp.len; + param.out('[')?; + for (usize i = 0; i < len; i++) + { + if (i != 0) out_substr(param, ", ")?; + out_str(param, variant { ptr, inner })?; + ptr += size; + } + param.out(']')?; case BOOL: if (*(bool*)arg.ptr) { diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 4f4ad6ba7..a22b1a442 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -118,6 +118,28 @@ const char *decl_to_name(Decl *decl) } UNREACHABLE } + +void module_append_name_to_scratch(Module *module) +{ + const char *name = module->name->module; + char c; + while ((c = *(name++)) != 0) + { + switch (c) + { + case '_': + scratch_buffer_append("__"); + break; + case ':': + scratch_buffer_append_char('_'); + name++; + break; + default: + scratch_buffer_append_char(c); + break; + } + } +} void decl_set_external_name(Decl *decl) { if (decl->has_extname) return; @@ -128,8 +150,8 @@ void decl_set_external_name(Decl *decl) return; } scratch_buffer_clear(); - scratch_buffer_append(decl->module->name->module); - scratch_buffer_append("."); + module_append_name_to_scratch(decl->module); + scratch_buffer_append("__"); scratch_buffer_append(decl->name ? decl->name : "anon"); decl->extname = scratch_buffer_copy(); } @@ -229,6 +251,8 @@ bool expr_is_pure(Expr *expr) { case EXPR_BUILTIN: return false; + case EXPR_VARIANT: + return exprid_is_pure(expr->variant_expr.type_id) && exprid_is_pure(expr->variant_expr.ptr); case EXPR_COMPILER_CONST: case EXPR_CONST: case EXPR_IDENTIFIER: diff --git a/src/compiler/codegen_internal.h b/src/compiler/codegen_internal.h index e73d138ff..dd7312a6d 100644 --- a/src/compiler/codegen_internal.h +++ b/src/compiler/codegen_internal.h @@ -1,5 +1,15 @@ #include "compiler_internal.h" +enum IntrospectIndex +{ + INTROSPECT_INDEX_KIND = 0, + INTROSPECT_INDEX_SIZEOF = 1, + INTROSPECT_INDEX_INNER = 2, + INTROSPECT_INDEX_LEN = 3, + INTROSPECT_INDEX_ADDITIONAL = 4, + INTROSPECT_INDEX_TOTAL, +}; + bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements); static inline Type *type_reduced_from_expr(Expr *expr); static inline bool abi_type_is_type(AbiType type); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index e2e0e8252..a84739bc6 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -114,10 +114,6 @@ typedef struct ConstInitializer_ }; } ConstInitializer; - - - - typedef struct { ConstKind const_kind : 8; @@ -146,6 +142,7 @@ typedef struct }; } ExprConst; + typedef uint16_t FileId; typedef struct { @@ -725,6 +722,11 @@ typedef struct ExprId right; } ExprSliceAssign; +typedef struct +{ + ExprId ptr; + ExprId type_id; +} ExprVariant; typedef struct { @@ -949,6 +951,7 @@ struct Expr_ ExprVariantSwitch variant_switch; // 32 ExprLen len_expr; // 8 ExprCast cast_expr; // 12 + ExprVariant variant_expr; TypeInfo *type_expr; // 8 ExprConst const_expr; // 32 ExprArgv argv_expr; // 16 @@ -2044,6 +2047,7 @@ void c_abi_func_create(FunctionPrototype *proto); bool token_is_any_type(TokenType type); const char *token_type_to_string(TokenType type); +void type_mangle_introspect_name_to_buffer(Type *type); AlignSize type_abi_alignment(Type *type); AlignSize type_alloca_alignment(Type *type); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index cc5931615..8e9680e13 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -187,6 +187,10 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_DECL: MACRO_COPY_DECL(expr->decl_expr); return expr; + case EXPR_VARIANT: + MACRO_COPY_EXPRID(expr->variant_expr.ptr); + MACRO_COPY_EXPRID(expr->variant_expr.type_id); + return expr; case EXPR_CT_CALL: MACRO_COPY_EXPR(expr->ct_call_expr.main_var); return expr; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 57363334d..979c8e807 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -248,6 +248,7 @@ typedef enum EXPR_VARIANTSWITCH, EXPR_NOP, EXPR_TYPEID_INFO, + EXPR_VARIANT, } ExprKind; typedef enum @@ -257,6 +258,7 @@ typedef enum TYPEID_INFO_MAX, TYPEID_INFO_INNER, TYPEID_INFO_LEN, + TYPEID_INFO_SIZEOF, } TypeIdInfoKind; typedef enum diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 585c1a673..7c586af7e 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -41,8 +41,6 @@ static void gencontext_init(GenContext *context, Module *module) { memset(context, 0, sizeof(GenContext)); context->context = LLVMContextCreate(); - context->bool_type = LLVMInt1TypeInContext(context->context); - context->byte_type = LLVMInt8TypeInContext(context->context); LLVMContextSetDiagnosticHandler(context->context, &diagnostics_handler, context); context->code_module = module; } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index e3664beb5..817e63e0a 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -5321,10 +5321,13 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex llvm_value_rvalue(c, value); LLVMValueRef kind; + LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, LLVMPointerType(c->introspect_type, 0), "introspect*"); + AlignSize align = llvm_abi_alignment(c, c->introspect_type); + AlignSize alignment; if (active_target.feature.safe_mode || expr->typeid_info_expr.kind == TYPEID_INFO_KIND) { - LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_ptr_type(c, type_char), ""); - kind = llvm_load(c, c->byte_type, ref, 1, ""); + kind = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_KIND, align, &alignment); + kind = llvm_load(c, c->byte_type, ref, alignment, "typeid.kind"); } switch (expr->typeid_info_expr.kind) { @@ -5356,9 +5359,8 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex } { LLVMTypeRef typeid = llvm_get_type(c, type_typeid); - LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_ptr_type(c, type_typeid), ""); - LLVMValueRef val = llvm_emit_pointer_gep_raw(c, typeid, ref, llvm_const_int(c, type_usize, 1)); - val = llvm_load(c, typeid, val, type_abi_alignment(type_typeid), ""); + LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_INNER, align, &alignment); + val = llvm_load(c, typeid, val, alignment, "typeid.inner"); llvm_value_set(value, val, expr->type); } break; @@ -5384,10 +5386,17 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex llvm_emit_block(c, exit); } { - LLVMTypeRef typeid = llvm_get_type(c, type_usize); - LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_ptr_type(c, type_usize), ""); - LLVMValueRef val = llvm_emit_pointer_gep_raw(c, typeid, ref, llvm_const_int(c, type_usize, 2)); - val = llvm_load(c, typeid, val, type_abi_alignment(type_usize), ""); + LLVMTypeRef usize = llvm_get_type(c, type_usize); + LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_LEN, align, &alignment); + val = llvm_load(c, usize, val, alignment, "typeid.len"); + llvm_value_set(value, val, expr->type); + } + break; + case TYPEID_INFO_SIZEOF: + { + LLVMTypeRef usize = llvm_get_type(c, type_usize); + LLVMValueRef val = llvm_emit_struct_gep_raw(c, ref, c->introspect_type, INTROSPECT_INDEX_SIZEOF, align, &alignment); + val = llvm_load(c, usize, val, alignment, "typeid.size"); llvm_value_set(value, val, expr->type); } break; @@ -5445,6 +5454,21 @@ void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr) } +static inline void llvm_emit_variant(GenContext *c, BEValue *value, Expr *expr) +{ + BEValue ptr; + llvm_emit_exprid(c, &ptr, expr->variant_expr.ptr); + llvm_value_rvalue(c, &ptr); + BEValue typeid; + llvm_emit_exprid(c, &typeid, expr->variant_expr.type_id); + llvm_value_rvalue(c, &typeid); + LLVMTypeRef variant_type = llvm_get_type(c, type_any); + LLVMValueRef var = LLVMGetUndef(variant_type); + var = llvm_emit_insert_value(c, var, ptr.value, 0); + var = llvm_emit_insert_value(c, var, typeid.value, 1); + llvm_value_set(value, var, type_any); +} + static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Expr *expr) { EMIT_LOC(c, expr); @@ -5539,6 +5563,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_RETVAL: *value = c->retval; return; + case EXPR_VARIANT: + llvm_emit_variant(c, value, expr); + return; case EXPR_ARGV_TO_SUBARRAY: llvm_emit_argv_to_subarray(c, value, expr); return; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 0a9c30849..d5f3d2058 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -85,6 +85,7 @@ typedef struct LLVMValueRef error_var; LLVMTypeRef bool_type; LLVMTypeRef byte_type; + LLVMTypeRef introspect_type; Decl *panicfn; Decl *cur_code_decl; Decl *cur_func_decl; @@ -208,6 +209,7 @@ void gencontext_init_file_emit(GenContext *c, CompilationUnit *unit); void gencontext_end_file_emit(GenContext *c, CompilationUnit *ast); void gencontext_end_module(GenContext *context); +void LLVMEnableOpaquePointers(LLVMContextRef ctx); LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal); #ifndef LLVMCreateTypeAttribute LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID, diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 5d6e7d5ed..88cbdd327 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -5,6 +5,24 @@ #include "llvm_codegen_internal.h" + +static inline LLVMTypeRef create_introspection_type(GenContext *c) +{ + LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".introspect"); + LLVMTypeRef typeid_type = llvm_get_type(c, type_typeid); + LLVMTypeRef kind_type = llvm_get_type(c, type_char); + LLVMTypeRef usize_type = llvm_get_type(c, type_usize); + LLVMTypeRef introspect_type[INTROSPECT_INDEX_TOTAL] = { + [INTROSPECT_INDEX_KIND] = kind_type, + [INTROSPECT_INDEX_SIZEOF] = usize_type, + [INTROSPECT_INDEX_INNER] = typeid_type, + [INTROSPECT_INDEX_LEN] = usize_type, + [INTROSPECT_INDEX_ADDITIONAL] = LLVMArrayType(typeid_type, 0), + }; + LLVMStructSetBody(type, introspect_type, INTROSPECT_INDEX_TOTAL, false); + return type; +} + void gencontext_begin_module(GenContext *c) { assert(!c->module && "Expected no module"); @@ -84,6 +102,10 @@ void gencontext_begin_module(GenContext *c) break; } } + c->bool_type = LLVMInt1TypeInContext(c->context); + c->byte_type = LLVMInt8TypeInContext(c->context); + c->introspect_type = create_introspection_type(c); + if (c->panicfn) c->panicfn->backend_ref = NULL; if (active_target.debug_info != DEBUG_INFO_NONE) diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 0e9a220ea..941c9a061 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -47,7 +47,7 @@ void llvm_emit_local_decl(GenContext *c, Decl *decl, BEValue *value) { scratch_buffer_clear(); scratch_buffer_append(decl->extname); - scratch_buffer_append(".f"); + scratch_buffer_append("$f"); decl->var.failable_ref = llvm_add_global_var(c, scratch_buffer_to_string(), type_anyerr, 0); } llvm_emit_global_variable_init(c, decl); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 4235cf411..b0a148494 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -496,79 +496,70 @@ static inline Module *type_base_module(Type *type) } UNREACHABLE } -LLVMValueRef llvm_get_introspection_for_derived_type(GenContext *c, IntrospectType kind, Type *type, Type *inner, LLVMValueRef extra) + +static inline LLVMValueRef llvm_generate_temp_introspection_global(GenContext *c, Type *type) { - LLVMValueRef value = llvm_get_typeid(c, inner); - LLVMValueRef values[3] = { llvm_const_int(c, type_char, kind), value }; - int count = 2; - if (extra) - { - values[2] = extra; - count = 3; - } - LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, count, false); - scratch_buffer_clear(); - scratch_buffer_append(".typeid."); - Module *module = type_base_module(inner); - if (module) - { - scratch_buffer_append(module->name->module); - scratch_buffer_append_char('.'); - } - scratch_buffer_append(type->name); - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(strukt), scratch_buffer_to_string()); - LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(strukt))); - LLVMSetGlobalConstant(global_name, 1); - LLVMSetInitializer(global_name, strukt); - llvm_set_linkonce(c, global_name); - return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid)); + assert(!type->backend_typeid); + LLVMValueRef temp = LLVMAddGlobal(c->module, c->introspect_type, "tempid"); + type->backend_typeid = LLVMConstPointerCast(temp, llvm_get_type(c, type_typeid)); + return temp; } +static inline LLVMValueRef llvm_generate_introspection_global(GenContext *c, LLVMValueRef original_global, Type *type, IntrospectType introspect_type, + Type *inner, size_t len, LLVMValueRef additional, bool is_external) +{ + if (original_global) + { + assert(type->backend_typeid); + } + LLVMValueRef values[INTROSPECT_INDEX_TOTAL] = { + [INTROSPECT_INDEX_KIND] = llvm_const_int(c, type_char, introspect_type), + [INTROSPECT_INDEX_SIZEOF] = llvm_const_int(c, type_usize, type_size(type)), + [INTROSPECT_INDEX_INNER] = inner ? llvm_get_typeid(c, inner) : llvm_get_zero(c, type_typeid), + [INTROSPECT_INDEX_LEN] = llvm_const_int(c, type_usize, len), + [INTROSPECT_INDEX_ADDITIONAL] = additional ? additional : LLVMConstArray(llvm_get_type(c, type_typeid), NULL, 0) + }; + LLVMValueRef global_name; + scratch_buffer_clear(); + scratch_buffer_append("ct$"); + type_mangle_introspect_name_to_buffer(type); + if (additional) + { + LLVMValueRef constant = LLVMConstStructInContext(c->context, values, INTROSPECT_INDEX_TOTAL, false); + global_name = LLVMAddGlobal(c->module, LLVMTypeOf(constant), scratch_buffer_to_string()); + LLVMSetInitializer(global_name, constant); + } + else + { + LLVMValueRef strukt = LLVMConstNamedStruct(c->introspect_type, values, INTROSPECT_INDEX_TOTAL); + global_name = LLVMAddGlobal(c->module, c->introspect_type, scratch_buffer_to_string()); + LLVMSetInitializer(global_name, strukt); + } + LLVMSetAlignment(global_name, llvm_abi_alignment(c, c->introspect_type)); + LLVMSetGlobalConstant(global_name, 1); + if (is_external) + { + LLVMSetLinkage(global_name, LLVMExternalLinkage); + } + else + { + llvm_set_linkonce(c, global_name); + } + if (original_global) + { + LLVMReplaceAllUsesWith(original_global, global_name); + } + else + { + type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid)); + } + return type->backend_typeid; +} static LLVMValueRef llvm_get_introspection_for_builtin_type(GenContext *c, Type *type, IntrospectType introspect_type, int bits) { - LLVMValueRef values[2]; - int count = 1; - values[0] = llvm_const_int(c, type_char, introspect_type); - if (bits) - { - values[1] = llvm_const_int(c, type_ushort, bits); - count = 2; - } - LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, count, false); - scratch_buffer_clear(); - scratch_buffer_append(".typeid."); - scratch_buffer_append(type->name); - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(strukt), scratch_buffer_to_string()); - LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(strukt))); - LLVMSetGlobalConstant(global_name, 1); - LLVMSetInitializer(global_name, strukt); - llvm_set_linkonce(c, global_name); - return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid)); + return llvm_generate_introspection_global(c, NULL, type, introspect_type, NULL, 0, NULL, false); } -static LLVMValueRef llvm_get_introspection_weak(GenContext *c, Type *type, const char *name, LLVMValueRef data) -{ - scratch_buffer_clear(); - scratch_buffer_append(".typeid."); - scratch_buffer_append(name); - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(data), scratch_buffer_to_string()); - LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(data))); - LLVMSetGlobalConstant(global_name, 1); - LLVMSetInitializer(global_name, data); - llvm_set_linkonce(c, global_name); - return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid)); -} - -static LLVMValueRef llvm_get_introspection_external(GenContext *c, Type *type, LLVMValueRef data) -{ - scratch_buffer_clear(); - scratch_buffer_append(".typeid."); - scratch_buffer_append(type->name); - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMTypeOf(data), scratch_buffer_to_string()); - LLVMSetAlignment(global_name, llvm_abi_alignment(c, LLVMTypeOf(data))); - LLVMSetLinkage(global_name, LLVMExternalLinkage); - return type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid)); -} static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type) { @@ -589,12 +580,10 @@ static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type) llvm_const_int(c, type_usize, associated_value_count) }; LLVMValueRef strukt = LLVMConstStructInContext(c->context, en_values, 3, false); - if (is_external && !is_dynamic) - { - return llvm_get_introspection_external(c, type, strukt); - } + if (!is_dynamic) is_external = false; - LLVMValueRef val = llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt); + LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); + LLVMValueRef val = llvm_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_ENUM, type_flatten(type), elements, NULL, is_external); if (!associated_value_count) return val; LLVMValueRef *values = elements ? malloc_arena(elements * sizeof(LLVMValueRef)) : NULL; @@ -624,7 +613,7 @@ static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type) elements); scratch_buffer_clear(); scratch_buffer_append(decl->extname); - scratch_buffer_append("."); + scratch_buffer_append("$"); scratch_buffer_append(associated_value->name); LLVMValueRef global_ref = llvm_add_global_type(c, scratch_buffer_to_string(), @@ -650,6 +639,7 @@ static LLVMValueRef llvm_get_introspection_for_struct_union(GenContext *c, Type { Decl *decl = type->decl; Decl **decls = decl->strukt.members; + LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); VECEACH(decls, i) { Decl *member_decl = decls[i]; @@ -658,10 +648,10 @@ static LLVMValueRef llvm_get_introspection_for_struct_union(GenContext *c, Type llvm_get_typeid(c, member_decl->type); } } - LLVMValueRef values[] = { llvm_const_int(c, type_char, decl->decl_kind == DECL_STRUCT ? INTROSPECT_TYPE_STRUCT : INTROSPECT_TYPE_UNION ), - llvm_const_int(c, type_usize, vec_size(decls)) }; - LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 2, false); - return llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt); + + return llvm_generate_introspection_global(c, ref, type, decl->decl_kind == DECL_UNION ? INTROSPECT_TYPE_UNION : INTROSPECT_TYPE_STRUCT, + NULL, + vec_size(decls), NULL, false); } static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type) @@ -669,12 +659,13 @@ static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type) Decl *decl = type->decl; Decl **fault_vals = decl->enums.values; unsigned elements = vec_size(fault_vals); + LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); AlignSize store_align; for (unsigned i = 0; i < elements; i++) { scratch_buffer_clear(); scratch_buffer_append(decl_get_extname(decl)); - scratch_buffer_append_char('.'); + scratch_buffer_append_char('$'); Decl *val = fault_vals[i]; scratch_buffer_append(val->name); LLVMValueRef global_name = llvm_add_global_var(c, scratch_buffer_to_string(), type_char, 0); @@ -689,10 +680,7 @@ static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type) { values[i] = LLVMConstBitCast(fault_vals[i]->backend_ref, element_type); } - LLVMValueRef svalues[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FAULT ), llvm_const_int(c, type_usize, elements), - LLVMConstArray(element_type, values, elements) }; - LLVMValueRef strukt = LLVMConstStructInContext(c->context, svalues, 3, false); - return llvm_get_introspection_weak(c, type, decl_get_extname(decl), strukt); + return llvm_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_FAULT, NULL, elements, NULL, false); } @@ -703,22 +691,19 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) switch (type->type_kind) { case TYPE_FAILABLE: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_FAILABLE, type, type->failable, NULL); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_FAILABLE, type->failable, 0, NULL, false); case TYPE_FLEXIBLE_ARRAY: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base, - llvm_const_int(c, type_usize, 0)); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_ARRAY, type->array.base, 0, NULL, false); case TYPE_VECTOR: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_VECTOR, type, type->array.base, - llvm_const_int(c, type_usize, type->array.len)); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_VECTOR, type->array.base, type->array.len, NULL, false); case TYPE_ARRAY: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_ARRAY, type, type->array.base, - llvm_const_int(c, type_usize, type->array.len)); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_ARRAY, type->array.base, type->array.len, NULL, false); case TYPE_SUBARRAY: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_SUBARRAY, type, type->array.base, NULL); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_SUBARRAY, type->array.base, 0, NULL, false); case TYPE_POINTER: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_POINTER, type, type->pointer, NULL); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_POINTER, type->pointer, 0, NULL, false); case TYPE_DISTINCT: - return llvm_get_introspection_for_derived_type(c, INTROSPECT_TYPE_DISTINCT, type, type->decl->distinct_decl.base_type, NULL); + return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct_decl.base_type, 0, NULL, false); case TYPE_ENUM: return llvm_get_introspection_for_enum(c, type); case TYPE_FAULTTYPE: @@ -728,16 +713,13 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) return llvm_get_introspection_for_struct_union(c, type); case TYPE_FUNC: { - LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_FUNC ) }; - LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 1, false); - return llvm_get_introspection_weak(c, type, decl_get_extname(type->decl), strukt); - + LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); + return llvm_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_FUNC, NULL, 0, NULL, false); } case TYPE_BITSTRUCT: { - LLVMValueRef values[] = { llvm_const_int(c, type_char, INTROSPECT_TYPE_BITSTRUCT ) }; - LLVMValueRef strukt = LLVMConstStructInContext(c->context, values, 1, false); - return llvm_get_introspection_weak(c, type, decl_get_extname(type->decl), strukt); + LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); + return llvm_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_BITSTRUCT, NULL, 0, NULL, false); } case TYPE_TYPEDEF: return llvm_get_typeid(c, type->canonical); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index eed2fb6c6..766cd26a7 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -1626,7 +1626,16 @@ Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *typ } - +Expr *parse_any_expression(ParseContext *c, TypeInfo *type) +{ + Expr *expr = expr_new(EXPR_VARIANT, type->span); + advance_and_verify(c, TOKEN_LBRACE); + ASSIGN_EXPRID_OR_RET(expr->variant_expr.ptr, parse_expr(c), poisoned_expr); + TRY_CONSUME_OR_RET(TOKEN_COMMA, "Expected a ','", poisoned_expr); + ASSIGN_EXPRID_OR_RET(expr->variant_expr.type_id, parse_expr(c), poisoned_expr); + TRY_CONSUME_OR_RET(TOKEN_RBRACE, "Missing end '}'", poisoned_expr); + return expr; +} /** * type_identifier ::= TYPE_IDENT initializer_list? * @@ -1652,6 +1661,10 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path) } if (tok_is(c, TOKEN_LBRACE)) { + if (type->resolve_status == RESOLVE_DONE && type->type == type_any) + { + return parse_any_expression(c, type); + } return parse_type_compound_literal_expr_after_type(c, type); } Expr *expr = expr_new(EXPR_TYPEINFO, type->span); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 62fa0443d..b049ce951 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -836,6 +836,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case EXPR_COMPILER_CONST: case EXPR_STRINGIFY: case EXPR_CT_EVAL: + case EXPR_VARIANT: UNREACHABLE case EXPR_POST_UNARY: return recursive_may_narrow_float(expr->unary_expr.expr, type); @@ -989,6 +990,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) case EXPR_COMPILER_CONST: case EXPR_STRINGIFY: case EXPR_CT_EVAL: + case EXPR_VARIANT: UNREACHABLE case EXPR_POST_UNARY: return recursive_may_narrow_int(expr->unary_expr.expr, type); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 1bf7f8bdb..d7ebd69e5 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1080,7 +1080,7 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type if (method_like->visibility <= VISIBLE_MODULE) { scratch_buffer_append(parent->name); - scratch_buffer_append_char('.'); + scratch_buffer_append_char('$'); scratch_buffer_append(method_like->name); } else @@ -2094,7 +2094,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) { scratch_buffer_clear(); scratch_buffer_append(context->current_function->name); - scratch_buffer_append_char('.'); + scratch_buffer_append_char('$'); scratch_buffer_append(decl->name); decl->extname = scratch_buffer_copy(); } @@ -2241,12 +2241,12 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl) } scratch_buffer_clear(); scratch_buffer_append_len(module->name->module, module->name->len); - scratch_buffer_append_char('.'); + scratch_buffer_append_char('$'); VECEACH(decl->define_decl.generic_params, i) { TypeInfo *type_info = decl->define_decl.generic_params[i]; if (!sema_resolve_type_info(c, type_info)) return decl_poison(decl); - if (i != 0) scratch_buffer_append_char('.'); + if (i != 0) scratch_buffer_append_char('$'); const char *type_name = type_info->type->canonical->name; scratch_buffer_append(type_name); } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f9283b36c..5313e7c2b 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -326,6 +326,8 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) return false; case EXPR_BITASSIGN: return false; + case EXPR_VARIANT: + return exprid_is_constant_eval(expr->variant_expr.type_id, eval_kind) && exprid_is_constant_eval(expr->variant_expr.ptr, eval_kind); case EXPR_BINARY: return expr_binary_is_constant_eval(expr, eval_kind); case EXPR_CAST: @@ -3502,6 +3504,21 @@ static inline bool sema_rewrite_typeid_len(Expr *expr, Expr *parent, Expr *curre return true; } +static inline bool sema_rewrite_typeid_sizeof(Expr *expr, Expr *parent, Expr *current_parent) +{ + if (current_parent->expr_kind == EXPR_CONST) + { + Type *type = type_flatten_distinct(current_parent->const_expr.typeid); + expr_rewrite_to_int_const(expr, type_usize, type_size(type), true); + return true; + } + expr->expr_kind = EXPR_TYPEID_INFO; + expr->typeid_info_expr.parent = exprid(parent); + expr->typeid_info_expr.kind = TYPEID_INFO_SIZEOF; + expr->type = type_usize; + return true; +} + /** * Analyse "x.y" */ @@ -3594,7 +3611,7 @@ CHECK_DEEPER: expr->resolve_status = RESOLVE_DONE; return true; } - if (flat_type->type_kind == TYPE_ARRAY) + if (flat_type->type_kind == TYPE_ARRAY || flat_type->type_kind == TYPE_VECTOR) { expr_rewrite_to_int_const(expr, type_isize, flat_type->array.len, true); return true; @@ -3615,6 +3632,10 @@ CHECK_DEEPER: { return sema_rewrite_typeid_len(expr, parent, current_parent); } + if (kw == kw_sizeof) + { + return sema_rewrite_typeid_sizeof(expr, parent, current_parent); + } } // Hard coded ptr on subarrays and variant @@ -7120,6 +7141,26 @@ NOT_DEFINED: return true; } +static inline bool sema_expr_analyse_variant(SemaContext *context, Expr *expr) +{ + Expr *ptr = exprptr(expr->variant_expr.ptr); + Expr *typeid = exprptr(expr->variant_expr.type_id); + if (!sema_analyse_expr(context, ptr)) return false; + if (!sema_analyse_expr(context, typeid)) return false; + if (!type_is_pointer(ptr->type)) + { + SEMA_ERROR(ptr, "This must be a pointer, but is %s.", type_quoted_error_string(ptr->type)); + return false; + } + if (typeid->type != type_typeid) + { + SEMA_ERROR(ptr, "This must of type 'typeid', but was %s.", type_quoted_error_string(ptr->type)); + return false; + } + expr->type = type_any; + return true; +} + static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *expr) { Expr *inner = expr->inner_expr; @@ -7282,6 +7323,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) case EXPR_VARIANTSWITCH: case EXPR_TYPEID_INFO: UNREACHABLE + case EXPR_VARIANT: + return sema_expr_analyse_variant(context, expr); case EXPR_STRINGIFY: if (!sema_expr_analyse_ct_stringify(context, expr)) return false; return true; diff --git a/src/compiler/types.c b/src/compiler/types.c index 671a3f9e4..e9a1e03ca 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -462,6 +462,69 @@ bool type_is_comparable(Type *type) } } +void type_mangle_introspect_name_to_buffer(Type *type) +{ + switch (type->type_kind) + { + case TYPE_POISONED: + case TYPE_TYPEINFO: + case TYPE_INFERRED_ARRAY: + case TYPE_UNTYPED_LIST: + case TYPE_FAILABLE_ANY: + UNREACHABLE + case TYPE_VOID: + case TYPE_BOOL: + case ALL_INTS: + case ALL_FLOATS: + case TYPE_ANY: + case TYPE_ANYERR: + case TYPE_TYPEID: + scratch_buffer_append(type->name); + return; + case TYPE_POINTER: + scratch_buffer_append("p$"); + type_mangle_introspect_name_to_buffer(type->pointer); + return; + case TYPE_SUBARRAY: + scratch_buffer_append("sa$"); + type_mangle_introspect_name_to_buffer(type->array.base); + return; + case TYPE_FLEXIBLE_ARRAY: + scratch_buffer_append("a0$"); + type_mangle_introspect_name_to_buffer(type->array.base); + return; + case TYPE_FAILABLE: + scratch_buffer_append("f$"); + type_mangle_introspect_name_to_buffer(type->failable); + return; + case TYPE_VECTOR: + scratch_buffer_append_char('v'); + scratch_buffer_append_unsigned_int(type->array.len); + scratch_buffer_append_char('$'); + type_mangle_introspect_name_to_buffer(type->array.base); + return; + case TYPE_ARRAY: + scratch_buffer_append_char('a'); + scratch_buffer_append_unsigned_int(type->array.len); + scratch_buffer_append_char('$'); + type_mangle_introspect_name_to_buffer(type->array.base); + return; + case TYPE_ENUM: + case TYPE_FUNC: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_BITSTRUCT: + case TYPE_FAULTTYPE: + case TYPE_DISTINCT: + scratch_buffer_append(type->decl->extname); + return; + case TYPE_TYPEDEF: + type_mangle_introspect_name_to_buffer(type->canonical); + return; + } + UNREACHABLE +} + AlignSize type_abi_alignment(Type *type) { RETRY: