From 9f42ddb68d4b687c2afd8543fa4df214215c827e Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 25 Jul 2021 23:01:54 +0200 Subject: [PATCH] Fix foreach body copy. Moved deref / addr into special functions. Cleaned up access. Remove .sizeof .alignof .qnameof .nameof, create $qnameof $nameof --- resources/lib/std/linkedlist.c3 | 2 +- resources/lib/std/list.c3 | 2 +- resources/lib/std/mem.c3 | 2 +- src/compiler/compiler_internal.h | 13 +- src/compiler/copying.c | 2 +- src/compiler/enums.h | 2 + src/compiler/parse_expr.c | 2 + src/compiler/parse_stmt.c | 2 + src/compiler/sema_expr.c | 219 +++++++++++------- src/compiler/sema_stmts.c | 36 +++ src/compiler/sema_types.c | 38 +++ src/compiler/symtab.c | 19 +- src/compiler/tokens.c | 4 + .../compile_time_introspection/qnameof.c3t | 55 +++++ test/test_suite/enumerations/compile_time.c3t | 4 +- test/test_suite/struct/member_expr.c3 | 2 +- .../struct/struct_const_construct_simple.c3t | 2 +- .../struct/struct_pack_and_align.c3t | 12 +- 18 files changed, 296 insertions(+), 122 deletions(-) create mode 100644 test/test_suite/compile_time_introspection/qnameof.c3t diff --git a/resources/lib/std/linkedlist.c3 b/resources/lib/std/linkedlist.c3 index 1e034cd7e..25ab88bfa 100644 --- a/resources/lib/std/linkedlist.c3 +++ b/resources/lib/std/linkedlist.c3 @@ -40,7 +40,7 @@ private func void LinkedList.linkFirst(LinkedList *list, Type value) private func void LinkedList.linkLast(LinkedList *list, Type value) { Node *last = list.last; - Node *new_node = mem::alloc(Node.sizeof); + Node *new_node = mem::alloc($sizeof(Node)); *new_node = { .prev = last, .value = value }; list.last = new_node; if (!last) diff --git a/resources/lib/std/list.c3 b/resources/lib/std/list.c3 index 2afe884c9..a34902cea 100644 --- a/resources/lib/std/list.c3 +++ b/resources/lib/std/list.c3 @@ -13,7 +13,7 @@ private func void List.ensureCapacity(List *list) @inline if (list.capacity == list.size) { list.capacity = list.capacity ? 2 * list.capacity : 16; - list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity); + list.entries = mem::realloc(list.entries, $sizeof(Type) * list.capacity); } } diff --git a/resources/lib/std/mem.c3 b/resources/lib/std/mem.c3 index 36a4529ba..e014c4955 100644 --- a/resources/lib/std/mem.c3 +++ b/resources/lib/std/mem.c3 @@ -114,7 +114,7 @@ Allocator main_allocator = { &system_malloc_function, null }; macro malloc($Type) { - return ($Type*)(mem::alloc($Type.sizeof)); + return ($Type*)(mem::alloc($sizeof($Type))); } func void* alloc(usize size, usize elements = 1) @inline diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 66e3c997d..2601fbe9a 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1502,26 +1502,20 @@ extern const char *kw_max; extern const char *kw_min; extern const char *kw_elements; extern const char *kw_align; -extern const char *kw_alignof; extern const char *kw_deprecated; extern const char *kw_distinct; extern const char *kw_ensure; extern const char *kw_inline; -extern const char *kw_kindof; extern const char *kw_len; extern const char *kw_inf; extern const char *kw_nan; extern const char *kw_main; -extern const char *kw_nameof; -extern const char *kw_offsetof; extern const char *kw_ordinal; -extern const char *kw_qnameof; extern const char *kw_reqparse; extern const char *kw_require; extern const char *kw_pure; extern const char *kw_param; extern const char *kw_errors; -extern const char *kw_sizeof; extern const char *kw___ceil; extern const char *kw___round; extern const char *kw___sqrt; @@ -1530,6 +1524,9 @@ extern const char *kw_FILE; extern const char *kw_FUNC; extern const char *kw_LINE; extern const char *kw_LINEREAL; +extern const char *kw_default_iterator; +extern const char *kw_incr; +extern const char *kw_check_assign; #define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id((_token).id)) #define AST_NEW(_kind, _loc) new_ast(_kind, _loc) @@ -1711,6 +1708,8 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr); bool expr_const_int_overflowed(const ExprConst *expr); bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op); bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind); +void expr_insert_addr(Expr *original); +void expr_insert_deref(Expr *expr); bool expr_is_constant_eval(Expr *expr); const char *expr_const_to_error_string(const ExprConst *expr); static inline void expr_set_type(Expr *expr, Type *type) @@ -1788,6 +1787,7 @@ bool sema_analyse_decl(Context *context, Decl *decl); bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement); bool sema_analyse_statement(Context *context, Ast *statement); bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, ExprFailableStatus lhs_is_failable); +bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl); Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol); Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path); @@ -1796,6 +1796,7 @@ Decl *sema_find_extension_method_in_module(Module *module, Type *type, const cha Decl *sema_resolve_normal_symbol(Context *context, TokenId symbol, Path *path, bool handle_error); Decl *sema_resolve_string_symbol(Context *context, const char *symbol, SourceSpan span, Path *path); +bool sema_resolve_type(Context *context, Type *type); bool sema_resolve_type_info(Context *context, TypeInfo *type_info); bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type); bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 0a5e05e22..cfba76876 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -333,7 +333,7 @@ Ast *copy_ast(Ast *source) MACRO_COPY_DECL(ast->foreach_stmt.index); MACRO_COPY_DECL(ast->foreach_stmt.variable); MACRO_COPY_EXPR(ast->foreach_stmt.enumeration); - MACRO_COPY_AST(ast->for_stmt.body); + MACRO_COPY_AST(ast->foreach_stmt.body); return ast; case AST_IF_STMT: copy_flow(ast); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 331cda45a..b0274c870 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -454,7 +454,9 @@ typedef enum TOKEN_CT_ENDIF, // $endif TOKEN_CT_ENDSWITCH, // $endswitch TOKEN_CT_IF, // $if + TOKEN_CT_NAMEOF, // $nameof TOKEN_CT_OFFSETOF, // $offsetof + TOKEN_CT_QNAMEOF, // $qnameof TOKEN_CT_SIZEOF, // $sizeof TOKEN_CT_SWITCH, // $switch TOKEN_CT_TYPEOF, // $typeof diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index bcd5ac94c..44664dde6 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -1139,5 +1139,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_CT_SIZEOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_ALIGNOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE }, + [TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE }, + [TOKEN_CT_QNAMEOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_TYPEOF] = { parse_typeof_expr, NULL, PREC_NONE }, }; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 19a001ffb..31d53044f 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1070,6 +1070,8 @@ Ast *parse_stmt(Context *context) case TOKEN_CT_OFFSETOF: case TOKEN_CT_ALIGNOF: case TOKEN_CT_SIZEOF: + case TOKEN_CT_QNAMEOF: + case TOKEN_CT_NAMEOF: return parse_expr_stmt(context); case TOKEN_ASSERT: return parse_assert_stmt(context); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 1371d2f0c..6f951a78d 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -88,6 +88,48 @@ void expr_copy_types(Expr *to, Expr *from) to->original_type = from->original_type; } +void expr_insert_addr(Expr *original) +{ + assert(original->resolve_status == RESOLVE_DONE); + if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_DEREF) + { + *original = *original->unary_expr.expr; + return; + } + Expr *inner = expr_alloc(); + *inner = *original; + original->expr_kind = EXPR_UNARY; + expr_set_type(original, type_get_ptr(inner->type)); + original->unary_expr.operator = UNARYOP_ADDR; + original->unary_expr.expr = inner; + original->pure = false; + original->constant = false; + original->failable = inner->failable; +} + +void expr_insert_deref(Expr *original) +{ + assert(original->resolve_status == RESOLVE_DONE); + assert(original->type->canonical->type_kind == TYPE_POINTER); + if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_ADDR) + { + *original = *original->unary_expr.expr; + return; + } + + Type *pointee = original->type->type_kind == TYPE_POINTER ? original->type->pointer : original->type->canonical->pointer; + Expr *inner = expr_alloc(); + *inner = *original; + original->expr_kind = EXPR_UNARY; + expr_set_type(original, pointee); + original->unary_expr.operator = UNARYOP_DEREF; + original->unary_expr.expr = inner; + original->pure = false; + original->constant = false; + original->failable = inner->failable; +} + + static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right) { expr->pure = left->pure & right->pure; @@ -1145,7 +1187,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast) } } -static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl) +bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl) { assert(decl->decl_kind == DECL_MACRO); @@ -1574,12 +1616,8 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr if (decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO) { expr->call_expr.is_type_method = true; - struct_var = expr_new(EXPR_UNARY, func_expr->access_expr.parent->span); - struct_var->unary_expr.expr = func_expr->access_expr.parent; - struct_var->unary_expr.operator = UNARYOP_ADDR; - struct_var->resolve_status = RESOLVE_DONE; - assert(func_expr->access_expr.parent->resolve_status == RESOLVE_DONE); - expr_set_type(struct_var, type_get_ptr(struct_var->unary_expr.expr->type)); + expr_insert_addr(func_expr->access_expr.parent); + struct_var = func_expr->access_expr.parent; if (decl->decl_kind == DECL_MACRO) { return sema_expr_analyse_macro_call(context, to, expr, struct_var, decl); @@ -1843,17 +1881,6 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) return true; } -static inline void insert_access_deref(Expr *expr) -{ - Expr *deref = expr_new(EXPR_UNARY, expr->span); - deref->unary_expr.operator = UNARYOP_DEREF; - deref->unary_expr.expr = expr->access_expr.parent; - deref->resolve_status = RESOLVE_DONE; - assert(expr->access_expr.parent->type->canonical->type_kind == TYPE_POINTER); - expr_set_type(deref, expr->access_expr.parent->type->canonical->pointer); - deref->failable = expr->access_expr.parent->failable; - expr->access_expr.parent = deref; -} static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr) { @@ -2093,31 +2120,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b Type *canonical = parent->type->canonical; const char *name = TOKSTR(identifier_token); - // Foo.sizeof => return the size in bytes, e.g. 11 - if (name == kw_sizeof) - { - expr_rewrite_to_int_const(expr, type_compint, type_size(canonical)); - return true; - } - - // Foo.alignof => return the alignment, e.g. 4 - if (name == kw_alignof) - { - expr_rewrite_to_int_const(expr, type_compint, type_abi_alignment(canonical)); - return true; - } - // Foo.nameof => return the name, e.g. "Foo" - if (name == kw_nameof) - { - expr_rewrite_to_string(expr, canonical->name); - return true; - } - // Foo.qnameof => return the qualified name, e.g. "mylib::Foo" - if (name == kw_qnameof) - { - expr_rewrite_to_string(expr, type_generate_qname(canonical)); - return true; - } + // 3. Handle float.nan, double.inf etc if (type_is_float(canonical)) { if (name == kw_nan) @@ -2147,7 +2150,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b return true; } } - // + if (!type_may_have_sub_elements(canonical)) { SEMA_ERROR(expr, "'%s' does not have a property '%s'.", type_to_error_string(parent->type), name); @@ -2199,6 +2202,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b case DECL_ERR: case DECL_UNION: case DECL_STRUCT: + case DECL_DISTINCT: break; default: UNREACHABLE @@ -2215,18 +2219,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b return true; } } - VECEACH(decl->strukt.members, i) - { - Decl *member = decl->strukt.members[i]; - if (name == member->name) - { - expr->expr_kind = EXPR_MEMBER_ACCESS; - expr->access_expr.ref = member; - expr_set_type(expr, member->type); - return true; - } - } - SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(parent->type), name); + SEMA_ERROR(expr, "No function '%s.%s' found.", type_to_error_string(parent->type), name); return false; } @@ -2260,16 +2253,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr, expr->resolve_status = RESOLVE_DONE; return true; } - if (name == kw_sizeof && !is_macro) - { - expr_rewrite_to_int_const(expr, type_compint, type_size(ref->type)); - return true; - } - if (name == kw_alignof && !is_macro) - { - expr_rewrite_to_int_const(expr, type_compint, type_abi_alignment(ref->type)); - return true; - } if (name == kw_ordinal && !is_macro) { if (ref->decl_kind == DECL_ENUM_CONSTANT) @@ -2279,20 +2262,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr, } } - if (name == kw_nameof && !is_macro) - { - expr_rewrite_to_string(expr, ref->name); - return true; - } - if (name == kw_qnameof && !is_macro) - { - expr_rewrite_to_string(expr, ref->external_name ?: ref->name); - return true; - } - if (name == kw_kindof && !is_macro) - { - TODO - } // If we have something like struct Foo { Bar b; int c; struct d { int e; } } // If we are inspecting Foo.c we're done here. Otherwise handle struct d / Bar b case // The same way. @@ -2393,7 +2362,6 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) if (TOKEN_IS_INVALID(identifier_token)) return false; // 2. If our left hand side is a type, e.g. MyInt.abc, handle this here. - Type *parent_type = parent->type; if (parent->expr_kind == EXPR_TYPEINFO) { return sema_expr_analyse_type_access(expr, parent->type_expr, was_group, is_macro, identifier_token); @@ -2414,14 +2382,11 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) assert(parent->resolve_status == RESOLVE_DONE); // 7. Is this a pointer? If so we insert a deref. - Type *type = parent_type->canonical; - bool is_pointer = type->type_kind == TYPE_POINTER; + bool is_pointer = parent->type->canonical->type_kind == TYPE_POINTER; if (is_pointer) { - type = type->pointer->canonical; - parent_type = type; if (!sema_cast_rvalue(context, NULL, parent)) return false; - insert_access_deref(expr); + expr_insert_deref(expr->access_expr.parent); parent = expr->access_expr.parent; } @@ -2429,6 +2394,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) const char *kw = TOKSTR(identifier_token); Expr *current_parent = parent; + Type *type = parent->type->canonical; Type *flat_type = type_flatten(type); CHECK_DEEPER: @@ -2445,7 +2411,7 @@ CHECK_DEEPER: } if (flat_type->type_kind == TYPE_ARRAY) { - expr_rewrite_to_int_const(expr, type_compint, type->array.len); + expr_rewrite_to_int_const(expr, type_compint, flat_type->array.len); return true; } } @@ -2453,7 +2419,7 @@ CHECK_DEEPER: // 9. At this point we may only have distinct, struct, union, error, enum if (!type_may_have_sub_elements(type)) { - SEMA_ERROR(expr, "There is no member or method '%s' on '%s'", kw, type_to_error_string(parent_type)); + SEMA_ERROR(expr, "There is no member or method '%s' on '%s'", kw, type_to_error_string(parent->type)); return false; } @@ -5689,6 +5655,74 @@ static inline bool sema_expr_analyse_ct_sizeof(Context *context, Type *to, Expr return true; } +static inline bool decl_is_local(Decl *decl) +{ + if (decl->decl_kind != DECL_VAR) return false; + VarDeclKind kind = decl->var.kind; + return kind == VARDECL_PARAM_CT_TYPE + || kind == VARDECL_PARAM + || kind == VARDECL_PARAM_CT + || kind == VARDECL_LOCAL + || kind == VARDECL_LOCAL_CT_TYPE + || kind == VARDECL_LOCAL_CT + || kind == VARDECL_PARAM_REF + || kind == VARDECL_PARAM_EXPR + || kind == VARDECL_MEMBER; +} + +static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr *expr) +{ + if (expr->resolve_status == RESOLVE_DONE) return true; + + Expr **elements = expr->ct_call_expr.arguments; + unsigned count = vec_size(elements); + if (count > 1) + { + SEMA_ERROR(elements[1], "The function only takes one argument."); + return expr_poison(expr); + } + Expr *first_expr = elements[0]; + if (!sema_analyse_expr_value(context, NULL, first_expr)) return false; + + bool qualified = expr->ct_call_expr.token_type == TOKEN_CT_QNAMEOF; + + if (first_expr->expr_kind == EXPR_TYPEINFO) + { + Type *type = first_expr->type_expr->type->canonical; + if (!sema_resolve_type(context, type)) return false; + // TODO type_is_builtin is wrong also this does not cover virtual. + if (!qualified || type_is_builtin(type->type_kind)) + { + expr_rewrite_to_string(expr, type->name); + return true; + } + scratch_buffer_clear(); + scratch_buffer_append(type->decl->module->name->module); + scratch_buffer_append("::"); + scratch_buffer_append(type->name); + expr_rewrite_to_string(expr, scratch_buffer_interned()); + return true; + } + if (first_expr->expr_kind != EXPR_IDENTIFIER) + { + SEMA_ERROR(first_expr, "Expected an identifier."); + return false; + } + Decl *decl = first_expr->identifier_expr.decl; + + if (!decl->module || !qualified || decl_is_local(decl)) + { + expr_rewrite_to_string(expr, decl->name); + return true; + } + scratch_buffer_clear(); + scratch_buffer_append(decl->module->name->module); + scratch_buffer_append("::"); + scratch_buffer_append(decl->name); + expr_rewrite_to_string(expr, scratch_buffer_interned()); + return true; +} + static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr *expr) { @@ -5696,7 +5730,9 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr if (!sema_analyse_ct_call_parameters(context, expr)) return false; Type *type = expr->ct_call_expr.type->canonical; ExprFlatElement *elements = expr->ct_call_expr.flatpath; - AlignSize align = expr->ct_call_expr.decl ? expr->ct_call_expr.decl->alignment : type_abi_alignment(type); + + Decl *decl = expr->ct_call_expr.decl; + AlignSize align = decl && !decl_is_user_defined_type(decl) ? expr->ct_call_expr.decl->alignment : type_abi_alignment(type); VECEACH(elements, i) { ExprFlatElement element = elements[i]; @@ -5744,6 +5780,7 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr return true; } + static inline bool sema_expr_analyse_ct_offsetof(Context *context, Type *to, Expr *expr) { Expr *first = expr->ct_call_expr.arguments[0]; @@ -5812,6 +5849,10 @@ static inline bool sema_expr_analyse_ct_call(Context *context, Type *to, Expr *e return sema_expr_analyse_ct_alignof(context, to, expr); case TOKEN_CT_OFFSETOF: return sema_expr_analyse_ct_offsetof(context, to, expr); + case TOKEN_CT_QNAMEOF: + return sema_expr_analyse_ct_nameof(context, to, expr); + case TOKEN_CT_NAMEOF: + return sema_expr_analyse_ct_nameof(context, to, expr); default: UNREACHABLE } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index ad1925845..9fc5e3e94 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -591,7 +591,43 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) return success; } +static inline bool sema_inline_default_iterator(Context *context, Expr *expr) +{ + Type *type = expr->type->canonical; + if (!type_may_have_sub_elements(type)) return true; + Decl *ambiguous = NULL; + Decl *private = NULL; + Decl *result = sema_resolve_method(context, type->decl, kw_default_iterator, &ambiguous, &private); + if (!result) + { + SEMA_ERROR(expr, "There are multiple candidates for 'default_iterator' on %s.", + type_quoted_error_string(expr->type)); + return false; + } + Expr *call = expr_new(EXPR_CALL, expr->span); + call->call_expr.arguments = NULL; + call->call_expr.body = NULL; + call->call_expr.unsplat_last = false; + call->call_expr.is_type_method = true; + bool success; + switch (result->decl_kind) + { + case DECL_MACRO: + success = sema_expr_analyse_macro_call(context, NULL, call, expr, result); + break; + case DECL_GENERIC: + case DECL_FUNC: + TODO + default: + UNREACHABLE + } + if (success) + { + expr_replace(expr, call); + } + return success; +} static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) { // Pull out the relevant data. diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index dcb8b70ef..63389c576 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -137,6 +137,44 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) } +bool sema_resolve_type(Context *context, Type *type) +{ + switch (type->type_kind) + { + case TYPE_TYPEDEF: + return sema_resolve_type(context, type->canonical); + case TYPE_POISONED: + case ALL_INTS: + case ALL_FLOATS: + case TYPE_VOID: + case TYPE_BOOL: + case TYPE_TYPEID: + case TYPE_VIRTUAL_ANY: + case TYPE_ERR_UNION: + case TYPE_STRLIT: + case TYPE_VECTOR: + return true; + case TYPE_POINTER: + return sema_resolve_type(context, type->pointer); + case TYPE_ENUM: + case TYPE_FUNC: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ERRTYPE: + case TYPE_DISTINCT: + break; + case TYPE_ARRAY: + case TYPE_SUBARRAY: + case TYPE_INFERRED_ARRAY: + return sema_resolve_type(context, type->array.base); + case TYPE_TYPEINFO: + TODO + case TYPE_VIRTUAL: + TODO; + } + return sema_analyse_decl(context, type->decl); +} + bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow) { if (type_info->resolve_status == RESOLVE_DONE) return type_info_ok(type_info); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 3521cf071..bbd2bd7d9 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -37,7 +37,6 @@ static SymTab symtab; const char *attribute_list[NUMBER_OF_ATTRIBUTES]; const char *kw_align; -const char *kw_alignof; const char *kw_deprecated; const char *kw_distinct; const char *kw_ensure; @@ -45,21 +44,16 @@ const char *kw_elements; const char *kw_errors; const char *kw_inf; const char *kw_inline; -const char *kw_kindof; const char *kw_len; const char *kw_main; const char *kw_max; const char *kw_min; const char *kw_nan; -const char *kw_nameof; -const char *kw_offsetof; const char *kw_ordinal; const char *kw_param; const char *kw_pure; -const char *kw_qnameof; const char *kw_reqparse; const char *kw_require; -const char *kw_sizeof; const char *kw_std; const char *kw___ceil; const char *kw___round; @@ -69,6 +63,9 @@ const char *kw_FILE; const char *kw_FUNC; const char *kw_LINE; const char *kw_LINEREAL; +const char *kw_default_iterator; +const char *kw_incr; +const char *kw_check_assign; void symtab_init(uint32_t capacity) { @@ -103,7 +100,6 @@ void symtab_init(uint32_t capacity) TokenType type = TOKEN_IDENT; #define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type) kw_align = KW_DEF("align"); - kw_alignof = KW_DEF("alignof"); kw_deprecated = KW_DEF("deprecated"); kw_distinct = KW_DEF("distinct"); kw_elements = KW_DEF("elements"); @@ -111,20 +107,15 @@ void symtab_init(uint32_t capacity) kw_errors = KW_DEF("errors"); kw_inf = KW_DEF("inf"); kw_inline = KW_DEF("inline"); - kw_kindof = KW_DEF("kindof"); kw_len = KW_DEF("len"); kw_main = KW_DEF("main"); kw_max = KW_DEF("max"); kw_min = KW_DEF("min"); - kw_nameof = KW_DEF("nameof"); kw_nan = KW_DEF("nan"); - kw_offsetof = KW_DEF("offsetof"); kw_ordinal = KW_DEF("ordinal"); kw_param = KW_DEF("param"); kw_pure = KW_DEF("pure"); - kw_qnameof = KW_DEF("qnameof"); kw_require = KW_DEF("require"); - kw_sizeof = KW_DEF("sizeof"); kw_std = KW_DEF("std"); kw___ceil = KW_DEF("__ceil"); kw___round = KW_DEF("__round"); @@ -134,7 +125,9 @@ void symtab_init(uint32_t capacity) kw_LINEREAL = KW_DEF("LINEREAL"); kw_FILE = KW_DEF("FILE"); kw_FUNC = KW_DEF("FUNC"); - + kw_incr = KW_DEF("incr"); + kw_default_iterator = KW_DEF("default_iterator"); + kw_check_assign = KW_DEF("check_assign"); attribute_list[ATTRIBUTE_INLINE] = kw_inline; attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline"); attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque"); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 1309b61c9..8c8918dd8 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -339,8 +339,12 @@ const char *token_type_to_string(TokenType type) return "$endswitch"; case TOKEN_CT_IF: return "$if"; + case TOKEN_CT_NAMEOF: + return "$nameof"; case TOKEN_CT_OFFSETOF: return "$offsetof"; + case TOKEN_CT_QNAMEOF: + return "$qnameof"; case TOKEN_CT_SIZEOF: return "$sizeof"; case TOKEN_CT_SWITCH: diff --git a/test/test_suite/compile_time_introspection/qnameof.c3t b/test/test_suite/compile_time_introspection/qnameof.c3t new file mode 100644 index 000000000..f69cc1ce5 --- /dev/null +++ b/test/test_suite/compile_time_introspection/qnameof.c3t @@ -0,0 +1,55 @@ +module qnametest; + +extern func int printf(char *, ...); +int x; + +struct Blob { int z; int f; } + +func void main() +{ + int help; + printf("printf: %s\n", $nameof(printf)); + printf("printfq: %s\n", $qnameof(printf)); + printf("Blobq: %s\n", $qnameof(Blob)); + printf("Blob: %s\n", $nameof(Blob)); + printf("xq: %s\n", $qnameof(x)); + printf("x: %s\n", $nameof(x)); + printf("helpq: %s\n", $qnameof(help)); + printf("mainq: %s\n", $qnameof(main)); + printf("Blob**[3]: %s\n", $nameof(Blob**[3])); +} + +// #expect: qnametest.ll + +@.str = private constant [12 x i8] c"printf: %s\0A\00", align 1 +@.str.1 = private constant [7 x i8] c"printf\00", align 1 +@.str.2 = private constant [13 x i8] c"printfq: %s\0A\00", align 1 +@.str.3 = private constant [18 x i8] c"qnametest::printf\00", align 1 +@.str.4 = private constant [11 x i8] c"Blobq: %s\0A\00", align 1 +@.str.5 = private constant [16 x i8] c"qnametest::Blob\00", align 1 +@.str.6 = private constant [10 x i8] c"Blob: %s\0A\00", align 1 +@.str.7 = private constant [5 x i8] c"Blob\00", align 1 +@.str.8 = private constant [8 x i8] c"xq: %s\0A\00", align 1 +@.str.9 = private constant [13 x i8] c"qnametest::x\00", align 1 +@.str.10 = private constant [7 x i8] c"x: %s\0A\00", align 1 +@.str.11 = private constant [2 x i8] c"x\00", align 1 +@.str.12 = private constant [11 x i8] c"helpq: %s\0A\00", align 1 +@.str.13 = private constant [5 x i8] c"help\00", align 1 +@.str.14 = private constant [11 x i8] c"mainq: %s\0A\00", align 1 +@.str.15 = private constant [16 x i8] c"qnametest::main\00", align 1 +@.str.16 = private constant [15 x i8] c"Blob**[3]: %s\0A\00", align 1 +@.str.17 = private constant [10 x i8] c"Blob**[3]\00", align 1 + +define void @main() + %help = alloca i32, align 4 + store i32 0, i32* %help, align 4 + %0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0)) + %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.3, i32 0, i32 0)) + %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.5, i32 0, i32 0)) + %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.7, i32 0, i32 0)) + %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.8, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i32 0, i32 0)) + %5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.10, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.11, i32 0, i32 0)) + %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.12, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.13, i32 0, i32 0)) + %7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.14, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.15, i32 0, i32 0)) + %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.16, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0)) + ret void diff --git a/test/test_suite/enumerations/compile_time.c3t b/test/test_suite/enumerations/compile_time.c3t index ee04a0ef8..d51584493 100644 --- a/test/test_suite/enumerations/compile_time.c3t +++ b/test/test_suite/enumerations/compile_time.c3t @@ -8,8 +8,8 @@ enum MyEnum : short int myenum_max = MyEnum.max; int myenum_min = MyEnum.min; int myenum_elements = MyEnum.elements; -int myenum_alignof = MyEnum.alignof; -int myenum_sizeof = MyEnum.sizeof; +int myenum_alignof = $alignof(MyEnum); +int myenum_sizeof = $sizeof(MyEnum); // #expect: compile_time.ll diff --git a/test/test_suite/struct/member_expr.c3 b/test/test_suite/struct/member_expr.c3 index d34a5b29d..67661e68d 100644 --- a/test/test_suite/struct/member_expr.c3 +++ b/test/test_suite/struct/member_expr.c3 @@ -16,7 +16,7 @@ func int Foo.func2(Foo* f, int i) func void test_unknown_member() { - int a = Foo.b; // #error: No function or member 'Foo.b' found. + int a = Foo.b; // #error: No function 'Foo.b' found. } /* diff --git a/test/test_suite/struct/struct_const_construct_simple.c3t b/test/test_suite/struct/struct_const_construct_simple.c3t index 1fb02dbfe..57041cfb2 100644 --- a/test/test_suite/struct/struct_const_construct_simple.c3t +++ b/test/test_suite/struct/struct_const_construct_simple.c3t @@ -6,7 +6,7 @@ struct Foo long bar; } -private usize x = Foo.sizeof; +private usize x = $sizeof(Foo); private Foo foo1 = { 1, 2 }; private Foo foo2 = { .foo = 2 }; diff --git a/test/test_suite/struct/struct_pack_and_align.c3t b/test/test_suite/struct/struct_pack_and_align.c3t index dc87ff518..346e1ecf8 100644 --- a/test/test_suite/struct/struct_pack_and_align.c3t +++ b/test/test_suite/struct/struct_pack_and_align.c3t @@ -7,7 +7,7 @@ struct Foo1 @packed @align(4) char foo; } -$assert(Foo1.sizeof == 12); +$assert($sizeof(Foo1) == 12); Foo1 foo1 = { 1, 2 }; // <{ i8, i64, [3 x i8] }> @@ -17,7 +17,7 @@ struct Foo2 @packed @align(4) long bar; } -$assert(Foo2.sizeof == 12); +$assert($sizeof(Foo2) == 12); Foo2 foo2 = { 1, 2 }; // <{ i8, i64, [7 x i8] }> @@ -28,7 +28,7 @@ struct Foo3 @packed @align(8) } Foo3 foo3 = { 1, 2 }; -$assert(Foo3.sizeof == 16); +$assert($sizeof(Foo3) == 16); // <{ i8, i64 }> struct Foo4 @packed @@ -37,7 +37,7 @@ struct Foo4 @packed long bar; } -$assert(Foo4.sizeof == 9); +$assert($sizeof(Foo4) == 9); Foo4 foo4 = { 1, 2 }; // { i32, [12 x i8], i8, [15 x i8] } @@ -47,7 +47,7 @@ struct Foo5 ichar foo @align(16); } -$assert(Foo5.sizeof == 32); +$assert($sizeof(Foo5) == 32); Foo5 foo5 = { 1, 2 }; func int test5(ichar x) @@ -64,7 +64,7 @@ struct Foo6 @packed short c; } -$assert(Foo6.sizeof == 8); +$assert($sizeof(Foo6) == 8); Foo6 foo6 = { 1, 2, 3 }; // #expect: struct2.ll