From 69d97758760381eacb9618306ce374ec9d4fea2d Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 30 Aug 2021 17:28:34 +0200 Subject: [PATCH] Removed `define` for declaring ct vars and replaced it with `var` for declarations. Updated error messages. Added $defined. --- src/build/build_options.c | 2 +- src/compiler/ast.c | 7 +- src/compiler/compiler.c | 2 +- src/compiler/compiler_internal.h | 14 +- src/compiler/copying.c | 7 +- src/compiler/enums.h | 3 +- src/compiler/llvm_codegen_c_abi_x64.c | 8 +- src/compiler/llvm_codegen_c_abi_x86.c | 7 +- src/compiler/llvm_codegen_debug_info.c | 10 +- src/compiler/llvm_codegen_expr.c | 5 +- src/compiler/llvm_codegen_type.c | 4 +- src/compiler/parse_expr.c | 93 +-- src/compiler/parse_global.c | 6 +- src/compiler/parse_stmt.c | 23 +- src/compiler/sema_casts.c | 23 +- src/compiler/sema_expr.c | 753 ++++++++++-------- src/compiler/sema_name_resolution.c | 14 +- src/compiler/tokens.c | 2 + src/compiler/types.c | 7 +- src/compiler_tests/tests.c | 2 +- src/utils/errors.c | 2 +- src/utils/errors.h | 16 +- src/utils/lib.h | 21 +- test/test_suite/arrays/array_invalid_casts.c3 | 4 +- .../compile_time/typeof_from_literal.c3 | 4 +- .../compile_time_introspection/alignof.c3t | 16 +- .../compile_time_introspection/defined.c3t | 97 +++ .../compile_time_introspection/defined_err.c3 | 23 + .../compile_time_introspection/offsetof.c3t | 12 +- .../compile_time_introspection/sizeof.c3t | 8 +- .../sizeof_errors.c3 | 11 +- test/test_suite/distinct/test_errors.c3 | 2 +- test/test_suite/expressions/call_arg_types.c3 | 6 +- .../expressions/casts/cast_const.c3 | 2 +- .../expressions/casts/cast_func_to_various.c3 | 2 +- .../expressions/casts/explicit_cast.c3 | 4 +- .../expressions/pointer_conv_error.c3 | 6 +- test/test_suite/globals/global_init.c3 | 9 +- test/test_suite/macros/hash_ident.c3 | 2 +- test/test_suite/statements/for_errors.c3 | 2 +- test/test_suite/statements/foreach_errors.c3 | 2 +- test/test_suite/statements/switch_errors.c3 | 2 +- test/test_suite/struct/member_access.c3 | 2 +- test/test_suite/subarrays/sub_array_init.c3 | 2 +- test/test_suite/symbols/various.c3 | 42 +- test/test_suite/types/enum_errors.c3 | 4 +- test/test_suite/types/typedefs.c3 | 4 +- 47 files changed, 760 insertions(+), 539 deletions(-) create mode 100644 test/test_suite/compile_time_introspection/defined.c3t create mode 100644 test/test_suite/compile_time_introspection/defined_err.c3 diff --git a/src/build/build_options.c b/src/build/build_options.c index e69ffbeee..891e82df3 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -163,7 +163,7 @@ void append_file(BuildOptions *build_options) fprintf(stderr, "Max %d files may be specified\n", MAX_FILES); exit(EXIT_FAILURE); } - build_options->files = VECADD(build_options->files, current_arg); + vec_add(build_options->files, current_arg); } static bool arg_match(const char *candidate) diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 2b62bae02..b55f03b1f 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -638,11 +638,6 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent) DUMPEXPC(expr); DUMPEXPR(expr->try_unwrap_expr.init); break; - case EXPR_TRY_DECL: - DUMP("(try-decl"); - DUMPEXPC(expr); - DUMPDECL(expr->try_decl_expr.decl); - break; case EXPR_NOP: DUMP("(nop)"); return; @@ -1212,7 +1207,7 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind DUMPEND(); case AST_DEFINE_STMT: DUMP("(define"); - DUMPDECL(ast->define_stmt); + DUMPDECL(ast->var_stmt); DUMPEND(); case AST_DECLARE_STMT: DUMP("(declare"); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 653cc05d0..5fd1bf73b 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -531,7 +531,7 @@ void global_context_add_type(Type *type) { DEBUG_LOG("Created type %s.", type->name); assert(type_ok(type)); - VECADD(global_context.type, type); + vec_add(global_context.type, type); } Module *global_context_find_module(const char *name) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 6d47b7905..91902bcdd 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -789,14 +789,10 @@ typedef struct typedef struct { TokenType token_type; - union + struct { - Expr **arguments; - struct { - Decl *decl; - Type *type; - ExprFlatElement *flatpath; - }; + Expr *main_var; + ExprFlatElement *flat_path; }; } ExprCtCall; @@ -1271,7 +1267,7 @@ typedef struct Ast_ Decl *declare_stmt; // 8 Expr *expr_stmt; // 8 Ast *try_stmt; - Decl *define_stmt; // 8 + Decl *var_stmt; // 8 Ast *volatile_stmt; // 8 AstReturnStmt return_stmt; // 16 AstWhileStmt while_stmt; // 24 @@ -1911,7 +1907,7 @@ Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path * Decl *sema_resolve_method(Context *context, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref); Decl *sema_find_extension_method_in_module(Module *module, Type *type, const char *method_name); 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); +Decl *sema_resolve_string_symbol(Context *context, const char *symbol, SourceSpan span, Path *path, bool report_error); bool sema_resolve_type(Context *context, Type *type); bool sema_resolve_type_info(Context *context, TypeInfo *type_info); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 1c5acf43c..e80b6e710 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -76,14 +76,11 @@ Expr *copy_expr(Expr *source_expr) case EXPR_NOP: case EXPR_BYTES: return expr; - case EXPR_TRY_DECL: - MACRO_COPY_DECL(expr->try_decl_expr.decl); - return expr; case EXPR_DECL: MACRO_COPY_DECL(expr->decl_expr); return expr; case EXPR_CT_CALL: - MACRO_COPY_EXPR_LIST(expr->ct_call_expr.arguments); + MACRO_COPY_EXPR(expr->ct_call_expr.main_var); return expr; case EXPR_TRY_UNWRAP: MACRO_COPY_EXPR(expr->try_unwrap_expr.init); @@ -303,7 +300,7 @@ Ast *copy_ast(Ast *source) MACRO_COPY_AST(ast->case_stmt.body); return ast; case AST_DEFINE_STMT: - ast->define_stmt = copy_decl(ast->define_stmt); + ast->var_stmt = copy_decl(ast->var_stmt); return ast; case AST_DEFER_STMT: assert(!ast->defer_stmt.prev_defer); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 11373ae01..e10990375 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -215,7 +215,6 @@ typedef enum EXPR_TRY_UNWRAP, EXPR_TRY_UNWRAP_CHAIN, EXPR_TRY_ASSIGN, - EXPR_TRY_DECL, EXPR_TYPEID, EXPR_TYPEINFO, EXPR_TYPEOF, @@ -458,6 +457,7 @@ typedef enum TOKEN_CT_ASSERT, // $assert TOKEN_CT_CASE, // $case TOKEN_CT_DEFAULT, // $default + TOKEN_CT_DEFINED, // $defined TOKEN_CT_FOR, // $for TOKEN_CT_ELIF, // $elif TOKEN_CT_ELSE, // $else @@ -542,6 +542,7 @@ typedef enum TYPE_LAST = TYPE_VIRTUAL_ANY } TypeKind; +#define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_POISONED #define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \ case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128: case TYPE_IXX #define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128 diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index b239ffb14..84a2b9c6a 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -393,20 +393,18 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X type = type_lowering(type); switch (type->type_kind) { - case TYPE_POISONED: case TYPE_ENUM: case TYPE_TYPEDEF: case TYPE_FXX: case TYPE_IXX: case TYPE_TYPEID: case TYPE_FUNC: - case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_STRLIT: - case TYPE_INFERRED_ARRAY: case TYPE_ANYERR: case TYPE_ERRTYPE: case TYPE_BITSTRUCT: + case CT_TYPES: UNREACHABLE case TYPE_VOID: *current = CLASS_NO_CLASS; @@ -590,7 +588,6 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty ByteSize element_offset = (offset / element_size) * element_size; return x64_get_int_type_at_offset(element, offset - element_offset, source_type, source_offset); } - case TYPE_POISONED: case TYPE_VOID: case TYPE_FXX: case TYPE_IXX: @@ -598,13 +595,12 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty case TYPE_ENUM: case TYPE_FUNC: case TYPE_TYPEDEF: - case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_STRLIT: - case TYPE_INFERRED_ARRAY: case TYPE_ANYERR: case TYPE_ERRTYPE: case TYPE_BITSTRUCT: + case CT_TYPES: UNREACHABLE case TYPE_I128: case TYPE_U128: diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index 904cba5ae..e5a278220 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -586,7 +586,6 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) switch (type->type_kind) { - case TYPE_POISONED: case TYPE_TYPEDEF: case TYPE_VOID: case TYPE_ENUM: @@ -595,9 +594,9 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEID: - case TYPE_STRLIT: - case TYPE_INFERRED_ARRAY: case TYPE_BITSTRUCT: + case TYPE_STRLIT: + case CT_TYPES: UNREACHABLE case ALL_FLOATS: case ALL_INTS: @@ -613,8 +612,6 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) case TYPE_VIRTUAL: case TYPE_ARRAY: return x86_classify_aggregate(call, regs, type); - case TYPE_TYPEINFO: - UNREACHABLE } UNREACHABLE } diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 86e268a6c..c533b305f 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -52,7 +52,7 @@ static inline LLVMMetadataRef llvm_get_debug_member(GenContext *c, Type *type, c void llvm_debug_scope_push(GenContext *context, LLVMMetadataRef debug_scope) { - VECADD(context->debug.lexical_block_stack, debug_scope); + vec_add(context->debug.lexical_block_stack, debug_scope); } void llvm_debug_scope_pop(GenContext *context) @@ -385,7 +385,7 @@ static LLVMMetadataRef llvm_debug_array_type(GenContext *c, Type *type) Type *current_type = type; while (current_type->canonical->type_kind == TYPE_ARRAY) { - VECADD(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->array.len)); + vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->array.len)); current_type = current_type->canonical->array.base; } if (!current_type->backend_debug_type) @@ -446,7 +446,7 @@ static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type) REMINDER("Handle Recursive Vector type"); while (current_type->canonical->type_kind == TYPE_VECTOR) { - VECADD(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->vector.len)); + vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->vector.len)); current_type = current_type->canonical->vector.base; } return LLVMDIBuilderCreateVectorType( @@ -480,13 +480,11 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * // Consider special handling of UTF8 arrays. switch (type->type_kind) { - case TYPE_POISONED: case TYPE_IXX: case TYPE_FXX: case TYPE_TYPEID: - case TYPE_TYPEINFO: - case TYPE_INFERRED_ARRAY: case TYPE_STRLIT: + case CT_TYPES: UNREACHABLE case TYPE_BOOL: return llvm_debug_simple_type(c, type, DW_ATE_boolean); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 832392ef8..0c4e0c09a 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -2735,20 +2735,18 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM REDO: switch (type_lowering(param_type)->type_kind) { - case TYPE_POISONED: case TYPE_VOID: case TYPE_IXX: case TYPE_FXX: case TYPE_TYPEID: case TYPE_FUNC: - case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_STRLIT: - case TYPE_INFERRED_ARRAY: case TYPE_ENUM: case TYPE_ERRTYPE: case TYPE_ANYERR: case TYPE_BITSTRUCT: + case CT_TYPES: UNREACHABLE break; case TYPE_BOOL: @@ -3756,7 +3754,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_PLACEHOLDER: case EXPR_CT_CALL: case EXPR_FLATPATH: - case EXPR_TRY_DECL: UNREACHABLE case EXPR_TRY_UNWRAP_CHAIN: llvm_emit_try_unwrap_chain(c, value, expr); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 70f1449fd..cbb471a83 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -307,9 +307,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) } switch (any_type->type_kind) { - case TYPE_POISONED: - case TYPE_TYPEINFO: - case TYPE_INFERRED_ARRAY: + case CT_TYPES: UNREACHABLE case TYPE_TYPEID: case TYPE_ANYERR: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 1d24b5c8c..6ebe4e212 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -720,66 +720,56 @@ static Expr *parse_ct_call(Context *context, Expr *left) expr->ct_call_expr.token_type = context->tok.type; advance(context); CONSUME_OR(TOKEN_LPAREN, poisoned_expr); - Expr *element = TRY_EXPR_OR(parse_expr(context), poisoned_expr); - vec_add(expr->ct_call_expr.arguments, element); - if (try_consume(context, TOKEN_COMMA)) + Expr *internal = TRY_EXPR_OR(parse_precedence(context, PREC_FIRST + 1), poisoned_expr); + ExprFlatElement *flat_path = NULL; + if (context->tok.type == TOKEN_DOT || context->tok.type == TOKEN_LBRACKET) { - if (context->tok.type == TOKEN_IDENT || context->tok.type == TOKEN_LBRACKET) + while (1) { - Expr *idents = EXPR_NEW_TOKEN(EXPR_FLATPATH, context->tok); - bool first = true; - while (1) + ExprFlatElement flat_element; + if (try_consume(context, TOKEN_LBRACKET)) { - ExprFlatElement flat_element; - if (try_consume(context, TOKEN_LBRACKET)) + Expr *int_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr); + if (int_expr->expr_kind != EXPR_CONST || int_expr->const_expr.const_kind != CONST_INTEGER) { - Expr *int_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr); - if (int_expr->expr_kind != EXPR_CONST || int_expr->const_expr.const_kind != CONST_INTEGER) - { - SEMA_TOKEN_ERROR(context->tok, "Expected an integer index."); - return poisoned_expr; - } - BigInt *value = &int_expr->const_expr.i; - BigInt limit; - bigint_init_unsigned(&limit, MAX_ARRAYINDEX); - if (bigint_cmp(value, &limit) == CMP_GT) - { - SEMA_ERROR(int_expr, "Array index out of range."); - return poisoned_expr; - } - if (bigint_cmp_zero(value) == CMP_LT) - { - SEMA_ERROR(int_expr, "Array index must be zero or greater."); - return poisoned_expr; - } - TRY_CONSUME_OR(TOKEN_RBRACKET, "Expected a ']' after the number.", poisoned_expr); - flat_element.array = true; - flat_element.index = (ArrayIndex)bigint_as_unsigned(value); - } - else if (try_consume(context, TOKEN_DOT) || first) - { - TRY_CONSUME_OR(TOKEN_IDENT, "Expected an identifier here.", poisoned_expr); - flat_element.array = false; - flat_element.ident = TOKSTR(context->prev_tok); - } - else - { - SEMA_TOKEN_ERROR(context->tok, "Expected '.' or '[' here."); + SEMA_TOKEN_ERROR(context->tok, "Expected an integer index."); return poisoned_expr; } - first = false; - vec_add(idents->flatpath_expr, flat_element); - if (TOKEN_IS(TOKEN_RPAREN)) break; + BigInt *value = &int_expr->const_expr.i; + BigInt limit; + bigint_init_unsigned(&limit, MAX_ARRAYINDEX); + if (bigint_cmp(value, &limit) == CMP_GT) + { + SEMA_ERROR(int_expr, "Array index out of range."); + return poisoned_expr; + } + if (bigint_cmp_zero(value) == CMP_LT) + { + SEMA_ERROR(int_expr, "Array index must be zero or greater."); + return poisoned_expr; + } + TRY_CONSUME_OR(TOKEN_RBRACKET, "Expected a ']' after the number.", poisoned_expr); + flat_element.array = true; + flat_element.index = (ArrayIndex)bigint_as_unsigned(value); } - vec_add(expr->ct_call_expr.arguments, idents); - RANGE_EXTEND_PREV(expr); - } - else - { - Expr *idents = TRY_EXPR_OR(parse_expr(context), poisoned_expr); - vec_add(expr->ct_call_expr.arguments, idents); + else if (try_consume(context, TOKEN_DOT)) + { + TRY_CONSUME_OR(TOKEN_IDENT, "Expected an identifier here.", poisoned_expr); + flat_element.array = false; + flat_element.ident = TOKSTR(context->prev_tok); + } + else + { + SEMA_TOKEN_ERROR(context->tok, "Expected '.' or '[' here."); + return poisoned_expr; + } + vec_add(flat_path, flat_element); + if (TOKEN_IS(TOKEN_RPAREN)) break; } + RANGE_EXTEND_PREV(internal); } + expr->ct_call_expr.main_var = internal; + expr->ct_call_expr.flat_path = flat_path; CONSUME_OR(TOKEN_RPAREN, poisoned_expr); RANGE_EXTEND_PREV(expr); return expr; @@ -1419,6 +1409,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_DEFINED] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_EXTNAMEOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE }, diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index f6a47d695..b143a7ecd 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -318,7 +318,7 @@ static inline bool parse_optional_module_params(Context *context, TokenId **toke SEMA_TOKEN_ERROR(context->tok, "Only generic parameters are allowed here as parameters to the module."); return false; } - *tokens = VECADD(*tokens, context->tok.id); + vec_add(*tokens, context->tok.id); advance(context); if (!try_consume(context, TOKEN_COMMA)) { @@ -961,7 +961,7 @@ bool parse_attributes(Context *context, Attr ***attributes_ref) return false; } } - *attributes_ref = VECADD(*attributes_ref, attr); + vec_add(*attributes_ref, attr); } return true; } @@ -1054,7 +1054,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili param->var.init_expr = TRY_EXPR_OR(parse_initializer(context), false); } - *parameters = VECADD(*parameters, param); + vec_add(*parameters, param); RANGE_EXTEND_PREV(param); return true; } diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 6475ab959..5d0141505 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -603,18 +603,16 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context) } /** - * define_stmt - * : define CT_IDENT '=' const_expr EOS - * | define CT_TYPE '=' const_expr EOS - * | define CT_IDENT EOS - * | define CT_TYPE EOS + * var_stmt + * : var CT_IDENT '=' const_expr EOS + * | var CT_TYPE '=' const_expr EOS * ; */ -static inline Ast *parse_define_stmt(Context *context) +static inline Ast *parse_var_stmt(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_DEFINE_STMT, context->tok); TokenId start = context->tok.id; - advance_and_verify(context, TOKEN_DEFINE); + advance_and_verify(context, TOKEN_VAR); Decl *decl; switch (context->tok.type) { @@ -639,7 +637,7 @@ static inline Ast *parse_define_stmt(Context *context) return poisoned_ast; } decl->span.loc = start; - ast->define_stmt = decl; + ast->var_stmt = decl; RANGE_EXTEND_PREV(decl); RANGE_EXTEND_PREV(ast); TRY_CONSUME_EOS(); @@ -885,8 +883,8 @@ Ast *parse_stmt(Context *context) case TOKEN_IDENT: case TOKEN_CONST_IDENT: return parse_decl_or_expr_stmt(context); - case TOKEN_DEFINE: - return parse_define_stmt(context); + case TOKEN_VAR: + return parse_var_stmt(context); case TOKEN_STATIC: // Static means declaration! case TOKEN_CONST: // Const means declaration! return parse_declaration_stmt(context); @@ -976,6 +974,7 @@ Ast *parse_stmt(Context *context) case TOKEN_CT_SIZEOF: case TOKEN_CT_QNAMEOF: case TOKEN_CT_NAMEOF: + case TOKEN_CT_DEFINED: case TOKEN_TRY: case TOKEN_CATCH: case TOKEN_BYTES: @@ -1034,7 +1033,7 @@ Ast *parse_stmt(Context *context) case TOKEN_INTERFACE: case TOKEN_UNION: case TOKEN_ATTRIBUTE: - case TOKEN_VAR: + case TOKEN_DEFINE: case TOKEN_DOCS_START: case TOKEN_DOCS_END: case TOKEN_DOCS_EOL: @@ -1119,7 +1118,7 @@ Ast* parse_compound_stmt(Context *context) while (!try_consume(context, TOKEN_RBRACE)) { Ast *stmt = TRY_AST(parse_stmt(context)); - ast->compound_stmt.stmts = VECADD(ast->compound_stmt.stmts, stmt); + vec_add(ast->compound_stmt.stmts, stmt); } return ast; } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index d90d65bdd..dabe61549 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -428,14 +428,14 @@ bool cast_may_explicit(Type *from_type, Type *to_type) TypeKind to_kind = to->type_kind; switch (from->type_kind) { - case TYPE_INFERRED_ARRAY: case TYPE_POISONED: + case TYPE_INFERRED_ARRAY: case TYPE_VOID: case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEDEF: - UNREACHABLE + return false; case TYPE_TYPEID: // May convert to anything pointer sized or larger, no enums return type_is_pointer_sized_or_more(to); @@ -454,7 +454,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type) // Allow conversion int/enum -> float/bool/enum int/enum -> pointer is only allowed if the int/enum is pointer sized. if (type_is_integer(to) || type_is_float(to) || to == type_bool || to_kind == TYPE_ENUM) return true; // TODO think about this, maybe we should require a bitcast? - if (to_kind == TYPE_POINTER && (from_type == type_compint || type_is_pointer_sized(from_type))) return true; + if (to_kind == TYPE_POINTER && (from == type_compint || type_is_pointer_sized(from))) return true; return false; case ALL_FLOATS: // Allow conversion float -> float/int/bool/enum @@ -478,9 +478,9 @@ bool cast_may_explicit(Type *from_type, Type *to_type) } FALLTHROUGH; case TYPE_STRUCT: - if (type_is_substruct(from_type)) + if (type_is_substruct(from)) { - if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type)) return true; + if (cast_may_explicit(from->decl->strukt.members[0]->type, to)) return true; } FALLTHROUGH; case TYPE_UNION: @@ -735,7 +735,14 @@ bool cast_implicit(Expr *expr, Type *to_type) if (expr->type == to_type) return true; if (!cast_may_implicit(expr->original_type, to_type) && !cast_may_implicit(expr->type->canonical, to_type)) { - SEMA_ERROR(expr, "Cannot implicitly cast %s to %s.", type_quoted_error_string(expr->original_type), type_quoted_error_string(to_type)); + if (cast_may_explicit(expr->original_type, to_type) || cast_may_implicit(expr->type->canonical, to_type)) + { + SEMA_ERROR(expr, "Implicitly casting %s to %s is not permitted, but you can do an explicit cast using '()(value)'.", type_quoted_error_string(expr->original_type), type_quoted_error_string(to_type)); + } + else + { + SEMA_ERROR(expr, "You cannot cast anything %s into %s even with an explicit cast, so this looks like an error.", type_quoted_error_string(expr->original_type), type_quoted_error_string(to_type)); + } return false; } // Additional checks for compile time values. @@ -812,14 +819,12 @@ bool cast(Expr *expr, Type *to_type) } switch (from_type->type_kind) { - case TYPE_INFERRED_ARRAY: - case TYPE_POISONED: case TYPE_VOID: case TYPE_TYPEID: - case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEDEF: + case CT_TYPES: UNREACHABLE case TYPE_BITSTRUCT: UNREACHABLE diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 42b9f8a43..d267e8123 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -5327,6 +5327,7 @@ static inline bool sema_analyse_idents_string(Context *context, MiniLexer *lexer while (1) { minilex_skip_whitespace(lexer); + if (minilex_match(lexer, '\0')) break; if (minilex_match(lexer, '[')) { minilex_skip_whitespace(lexer); @@ -5336,8 +5337,10 @@ static inline bool sema_analyse_idents_string(Context *context, MiniLexer *lexer if (!minilex_match(lexer, ']')) return false; element.array = true; element.index = (ArrayIndex)value; + vec_add(elements, element); + continue; } - else + if (minilex_match(lexer, '.')) { scratch_buffer_clear(); while (is_alphanum_(minilex_peek(lexer, 0))) @@ -5353,28 +5356,25 @@ static inline bool sema_analyse_idents_string(Context *context, MiniLexer *lexer if (!ident || token_type != TOKEN_IDENT) return false; element.array = false; element.ident = ident; + vec_add(elements, element); + continue; } - vec_add(elements, element); - minilex_skip_whitespace(lexer); - if (minilex_match(lexer, '\0')) break; - if (!minilex_match(lexer, '.') && minilex_peek(lexer, 0) != '[') return false; + return false; } *elements_ref = elements; return true; } -static inline bool sema_analyse_identifier_path_string(Context *context, Expr *expr, Decl **decl_ref, Type **type_ref, ExprFlatElement **idents_ref) +static inline bool sema_analyse_identifier_path_string(Context *context, SourceSpan span, Expr *expr, Decl **decl_ref, Type **type_ref, ExprFlatElement **idents_ref, bool report_missing) { const char *chars = expr->const_expr.string.chars; uint32_t len = expr->const_expr.string.len; if (!len) { - SEMA_ERROR(expr, "Expected a name here."); + sema_error_range(span, "Expected a name here."); return false; } - // TODO HANDLE VIRTUAL! - MiniLexer lexer = { .chars = chars }; // Do we parse a path? @@ -5419,6 +5419,7 @@ static inline bool sema_analyse_identifier_path_string(Context *context, Expr *e } lexer.index = start_index; path = path_create_from_string(scratch_buffer_to_string(), global_context.scratch_buffer_len, expr->span); + if (!path) return false; } else { @@ -5431,7 +5432,11 @@ static inline bool sema_analyse_identifier_path_string(Context *context, Expr *e { scratch_buffer_append_char(minilex_next(&lexer)); } - if (!global_context.scratch_buffer_len) goto FAIL; + if (!global_context.scratch_buffer_len) + { + sema_error_range(span, "'%s' is not a valid identifier, did you misspell it?", chars); + return false; + } TokenType token_type; const char *symbol = symtab_find(global_context.scratch_buffer, global_context.scratch_buffer_len, @@ -5439,8 +5444,12 @@ static inline bool sema_analyse_identifier_path_string(Context *context, Expr *e &token_type); if (!symbol) { - SEMA_ERROR(expr, "'%s' could not be found, did you misspell it?", chars); - return false; + if (report_missing) + { + sema_error_range(span, "'%s' could not be found, did you misspell it?", chars); + return false; + } + return true; } Type *type = NULL; Decl *decl = NULL; @@ -5450,7 +5459,9 @@ static inline bool sema_analyse_identifier_path_string(Context *context, Expr *e } else { - decl = TRY_DECL_OR(sema_resolve_string_symbol(context, symbol, expr->span, path), false); + decl = TRY_DECL_OR(sema_resolve_string_symbol(context, symbol, expr->span, path, report_missing), report_missing); + if (!decl) return true; + if (!sema_analyse_decl(context, decl)) return false; if (decl->decl_kind == DECL_TYPEDEF) { type = decl->typedef_decl.type_info->type; @@ -5486,7 +5497,7 @@ static inline bool sema_analyse_identifier_path_string(Context *context, Expr *e array_size = array_size * 10 + minilex_next(&lexer) - '0'; if (old_array_size > array_size || array_size > MAX_ARRAYINDEX) { - SEMA_ERROR(expr, "Array index out of bounds."); + sema_error_range(span, "Array index out of bounds."); return false; } } @@ -5496,31 +5507,23 @@ static inline bool sema_analyse_identifier_path_string(Context *context, Expr *e } } - minilex_skip_whitespace(&lexer); - if (minilex_match(&lexer, '\0')) goto EXIT; - - - minilex_skip_whitespace(&lexer); - if (!minilex_match(&lexer, '.')) - { - SEMA_ERROR(expr, "A '.' was expected after '%s'.", symbol); - return false; - } - if (!sema_analyse_idents_string(context, &lexer, idents_ref)) { - SEMA_ERROR(expr, "The path to an existing member was expected after '%s', did you make a mistake?", symbol); - return false; + if (report_missing) + { + sema_error_range(span, "The path to an existing member was expected after '%s', did you make a mistake?", symbol); + return false; + } + else + { + return true; + } } -EXIT: *decl_ref = decl; *type_ref = type; return true; -FAIL: - SEMA_ERROR(expr, "'%s' is not a known identifier, did you misspell it?", chars); - return false; FAIL_PARSE: SEMA_ERROR(expr, "'%s' could not be parsed as an identifier, did you make a mistake?", chars); @@ -5529,163 +5532,6 @@ FAIL_PARSE: } -static inline bool sema_analyse_ct_call_parameters(Context *context, Expr *expr) -{ - if (expr->resolve_status == RESOLVE_DONE) return true; - - Expr **elements = expr->ct_call_expr.arguments; - unsigned count = vec_size(elements); - if (count > 2) - { - SEMA_ERROR(elements[2], "The function can only take one or two arguments."); - return expr_poison(expr); - } - Expr *first_expr = elements[0]; - if (!sema_analyse_expr_value(context, NULL, first_expr)) return false; - ExprFlatElement *flatpath = NULL; - Expr *second_expr = NULL; - if (count == 2) - { - second_expr = elements[1]; - if (second_expr->expr_kind != EXPR_FLATPATH) - { - if (!sema_analyse_expr_value(context, NULL, second_expr)) return false; - if (second_expr->expr_kind != EXPR_CONST || second_expr->const_expr.const_kind != CONST_STRING) - { - SEMA_ERROR(second_expr, "Expected a string here."); - return false; - } - MiniLexer lexer = { .chars = second_expr->const_expr.string.chars }; - if (!sema_analyse_idents_string(context, &lexer, &flatpath)) - { - SEMA_ERROR(expr, "The path to an existing member was expected, did you make a mistake?"); - return false; - } - } - else - { - flatpath = second_expr->flatpath_expr; - } - } - Decl *decl = NULL; - Type *type = NULL; - if (first_expr->expr_kind == EXPR_CONST && first_expr->const_expr.const_kind == CONST_STRING) - { - ExprFlatElement *path_elements = NULL; - if (!sema_analyse_identifier_path_string(context, first_expr, &decl, &type, &path_elements)) return false; - if (path_elements) - { - if (flatpath) - { - SEMA_ERROR(elements[1], "You cannot combine a string with a member path with a separate path here."); - return false; - } - flatpath = path_elements; - } - } - else - { - switch (first_expr->expr_kind) - { - case EXPR_IDENTIFIER: - decl = first_expr->identifier_expr.decl; - break; - case EXPR_TYPEINFO: - type = first_expr->type_expr->type; - break; - case EXPR_TYPEOF: - type = first_expr->typeof_expr->type; - break; - default: - break; - } - } - if (!type && !decl) - { - SEMA_ERROR(first_expr, "A type or declaration was expected."); - return false; - } - if (!decl && type_is_user_defined(type)) decl = type->decl; - if (decl) - { - if (!sema_analyse_decl(context, decl)) return false; - if (decl) - { - switch (decl->decl_kind) - { - case DECL_DISTINCT: - case DECL_ENUM: - case DECL_ERRTYPE: - case DECL_FUNC: - case DECL_STRUCT: - case DECL_TYPEDEF: - case DECL_UNION: - break; - case DECL_VAR: - if (decl->type) break; - FALLTHROUGH; - default: - SEMA_ERROR(first_expr, "A type or typed declaration was expected."); - return false; - } - } - type = decl->type; - } - expr->ct_call_expr.flatpath = flatpath; - expr->ct_call_expr.decl = decl; - expr->ct_call_expr.type = type; - - return true; -} - -static inline bool sema_expr_analyse_ct_sizeof(Context *context, Type *to, Expr *expr) -{ - Expr *first = expr->ct_call_expr.arguments[0]; - 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; - VECEACH(elements, i) - { - ExprFlatElement element = elements[i]; - type = type_flatten_distinct(type); - if (element.array) - { - if (type->type_kind != TYPE_ARRAY) - { - SEMA_ERROR(first, "%s is not a fixed size array.", type_quoted_error_string(expr->ct_call_expr.type)); - return false; - } - type = type->array.base; - continue; - } - if (!type_is_structlike(type)) - { - if (i == 0) - { - SEMA_ERROR(first, "%s has no members.", type_quoted_error_string(expr->ct_call_expr.type)); - } - else - { - SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); - } - return false; - } - Decl *decl = type->decl; - SCOPE_START - add_members_to_context(context, type->decl); - decl = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); - SCOPE_END; - if (!decl) - { - SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); - return false; - } - type = decl->type; - } - expr_rewrite_to_int_const(expr, type_compint, type_size(type)); - return true; -} - static inline bool decl_is_local(Decl *decl) { if (decl->decl_kind != DECL_VAR) return false; @@ -5701,148 +5547,94 @@ static inline bool decl_is_local(Decl *decl) || kind == VARDECL_MEMBER; } -static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr *expr) + +static bool sema_expr_analyse_type_var_path(Context *context, Expr *expr, ExprFlatElement **elements, Type **type_ref, + Decl **decl_ref) { - 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; - - TokenType name_type = expr->ct_call_expr.token_type; - + if (!sema_analyse_expr_value(context, NULL, expr)) return false; + Expr *current = expr; Decl *decl = NULL; Type *type = NULL; - if (first_expr->expr_kind == EXPR_CONST && first_expr->const_expr.const_kind == CONST_STRING) +RETRY: + switch (current->expr_kind) { - ExprFlatElement *path_elements = NULL; - if (!sema_analyse_identifier_path_string(context, first_expr, &decl, &type, &path_elements)) return false; - if (path_elements) - { - SEMA_ERROR(first_expr, "You cannot take the name of sub elements by string name."); - return false; - } - } - else if (first_expr->expr_kind == EXPR_TYPEINFO) - { - type = first_expr->type_expr->type->canonical; - } - else - { - if (first_expr->expr_kind != EXPR_IDENTIFIER) - { - SEMA_ERROR(first_expr, "Expected an identifier or a string."); - return false; - } - decl = first_expr->identifier_expr.decl; - } - if (type) - { - if (!sema_resolve_type(context, type)) return false; - - // TODO type_is_builtin is wrong also this does not cover virtual. - if (name_type == TOKEN_CT_EXTNAMEOF) - { - if (!type_is_user_defined(type)) + case EXPR_CT_IDENT: + current = current->identifier_expr.decl->var.init_expr; + goto RETRY; + case EXPR_CONST_IDENTIFIER: + case EXPR_IDENTIFIER: + decl = current->identifier_expr.decl; + break; + case EXPR_TYPEINFO: + type = current->type_expr->type; + break; + case EXPR_CONST: + if (expr->const_expr.const_kind == CONST_STRING) { - SEMA_ERROR(first_expr, "Only user defined types have an external name."); - return false; + if (!sema_analyse_identifier_path_string(context, expr->span, current, &decl, &type, elements, true)) return false; + break; } - expr_rewrite_to_string(expr, type->decl->extname ?: type->decl->external_name); - return true; - } - if (name_type == TOKEN_CT_NAMEOF || 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; - } - - assert(decl); - - if (!sema_analyse_decl(context, decl)) return false; - - if (name_type == TOKEN_CT_EXTNAMEOF) - { - if (!decl->external_name) - { - SEMA_ERROR(first_expr, "'%s' does not have an external name.", decl->name); + FALLTHROUGH; + default: + SEMA_ERROR(expr, "A type or a variable was expected here."); return false; - } - expr_rewrite_to_string(expr, decl->extname ?: decl->external_name); - return true; } - if (!decl->module || name_type == TOKEN_CT_NAMEOF || decl_is_local(decl)) + if (decl) { - expr_rewrite_to_string(expr, decl->name); - return true; + if (!sema_analyse_decl(context, decl)) return false; + type = decl->type; } - 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()); + *decl_ref = decl; + *type_ref = type; return true; } - static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr *expr) { - Expr *first = expr->ct_call_expr.arguments[0]; - 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; + Expr *main_var = expr->ct_call_expr.main_var; + Type *type = NULL; + Decl *decl = NULL; + ExprFlatElement *path = expr->ct_call_expr.flat_path; - 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) + if (!sema_expr_analyse_type_var_path(context, main_var, &path, &type, &decl)) return false; + + AlignSize align = decl && !decl_is_user_defined_type(decl) ? decl->alignment : type_abi_alignment(type); + VECEACH(path, i) { - ExprFlatElement element = elements[i]; - type = type_flatten_distinct(type); + ExprFlatElement element = path[i]; + Type *actual_type = type_flatten_distinct(type); if (element.array) { - if (type->type_kind != TYPE_ARRAY) + if (actual_type->type_kind != TYPE_ARRAY) { - SEMA_ERROR(first, "%s is not a fixed size array.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(expr, "It's possible to index into a non fixed size array."); return false; } - type = type->array.base; + type = actual_type->array.base; ByteSize size = type_size(type); align = (AlignSize)type_min_alignment(size * element.index, align); continue; } - if (!type_is_structlike(type)) + if (!type_is_structlike(actual_type)) { if (i == 0) { - SEMA_ERROR(first, "%s has no members.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(main_var, "%s has no members.", type_quoted_error_string(type)); } else { - SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(expr, "There is no such member in %s.", type_quoted_error_string(type)); } return false; } Decl *member; SCOPE_START - add_members_to_context(context, type->decl); + add_members_to_context(context, actual_type->decl); member = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); SCOPE_END; if (!member) { - SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(expr, "There is no such member in %s.", type_quoted_error_string(type)); return false; } type = member->type; @@ -5854,58 +5646,379 @@ 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) +static inline bool sema_expr_analyse_ct_sizeof(Context *context, Type *to, Expr *expr) { - Expr *first = expr->ct_call_expr.arguments[0]; - 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; - if (!vec_size(elements)) + Expr *main_var = expr->ct_call_expr.main_var; + Type *type = NULL; + Decl *decl = NULL; + ExprFlatElement *path = expr->ct_call_expr.flat_path; + if (!sema_expr_analyse_type_var_path(context, main_var, &path, &type, &decl)) return false; + + if (!type) return false; + + VECEACH(path, i) { - SEMA_ERROR(first, "Expected a path to get the offset of."); - return false; - } - ByteSize offset = 0; - VECEACH(elements, i) - { - ExprFlatElement element = elements[i]; - type = type_flatten_distinct(type); + ExprFlatElement element = path[i]; + Type *actual_type = type_flatten_distinct(type); if (element.array) { - if (type->type_kind != TYPE_ARRAY) + if (actual_type->type_kind != TYPE_ARRAY) { - SEMA_ERROR(first, "%s is not a fixed size array.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(expr, "It's possible to index into a non fixed size array."); return false; } - type = type->array.base; - offset += type_size(type) * element.index; + type = actual_type->array.base; continue; } - if (!type_is_structlike(type)) + if (!type_is_structlike(actual_type)) { if (i == 0) { - SEMA_ERROR(first, "%s has no members.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(main_var, "%s has no members.", type_quoted_error_string(type)); } else { - SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(expr, "There is no such member in %s.", type_quoted_error_string(type)); } return false; } - Decl *decl = type->decl; + Decl *member; SCOPE_START - add_members_to_context(context, type->decl); - decl = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); + add_members_to_context(context, actual_type->decl); + member = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); SCOPE_END; - if (!decl) + if (!member) { - SEMA_ERROR(first, "There is no such member in %s.", type_quoted_error_string(expr->ct_call_expr.type)); + SEMA_ERROR(expr, "There is no such member in %s.", type_quoted_error_string(type)); return false; } - type = decl->type; - offset += decl->offset; + type = member->type; + } + + expr_rewrite_to_int_const(expr, type_compint, type_size(type)); + return true; +} + +static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr *expr) +{ + + Expr *main_var = expr->ct_call_expr.main_var; + Type *type = NULL; + Decl *decl = NULL; + ExprFlatElement *path = expr->ct_call_expr.flat_path; + if (!sema_expr_analyse_type_var_path(context, main_var, &path, &type, &decl)) return false; + + TokenType name_type = expr->ct_call_expr.token_type; + + if (vec_size(path)) + { + SEMA_ERROR(main_var, "You can only take the name of types and variables, not their sub elements."); + return false; + } + + if (decl) + { + if (name_type == TOKEN_CT_EXTNAMEOF) + { + if (!decl->external_name) + { + SEMA_ERROR(main_var, "'%s' does not have an external name.", decl->name); + return false; + } + expr_rewrite_to_string(expr, decl->extname ?: decl->external_name); + return true; + } + if (!decl->module || name_type == TOKEN_CT_NAMEOF || 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; + } + + assert(type); + if (name_type == TOKEN_CT_EXTNAMEOF) + { + if (!type_is_user_defined(type)) + { + SEMA_ERROR(main_var, "Only user defined types have an external name."); + return false; + } + expr_rewrite_to_string(expr, type->decl->extname ?: type->decl->external_name); + return true; + } + + // TODO type_is_builtin is wrong also this does not cover virtual. + if (name_type == TOKEN_CT_NAMEOF || 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; +} + +static inline bool sema_expr_resolve_maybe_identifier(Context *c, Expr *expr, Decl **decl_ref, Type **type_ref, ExprFlatElement **flatpath) +{ + switch (expr->expr_kind) + { + case EXPR_CONST_IDENTIFIER: + case EXPR_IDENTIFIER: + *decl_ref = TRY_DECL_OR(sema_resolve_normal_symbol(c, expr->identifier_expr.identifier, expr->identifier_expr.path, false), false); + return true; + case EXPR_TYPEINFO: + if (expr->resolve_status == RESOLVE_DONE) + { + *type_ref = expr->type_expr->type; + return true; + } + if (expr->type_expr->kind != TYPE_INFO_IDENTIFIER) + { + SEMA_ERROR(expr, "Expected a plain type name here."); + return false; + } + *decl_ref = TRY_DECL_OR(sema_resolve_normal_symbol(c, + expr->type_expr->unresolved.name_loc, + expr->type_expr->unresolved.path, + false), false); + return true; + case EXPR_CONST: + switch (expr->const_expr.const_kind) + { + case CONST_STRING: + return sema_analyse_identifier_path_string(c, expr->span, expr, decl_ref, type_ref, flatpath, false); + case CONST_ERR: + case CONST_ENUM: + // This should not be possible, they should only be found after analysing access. + UNREACHABLE + default: + SEMA_ERROR(expr, "You can only do $define on identifiers and types."); + break; + } + case EXPR_ACCESS: + TODO // This will handle enum and errs + default: + return false; + } + +} + +static inline Type *sema_expr_check_type_exists(Context *context, TypeInfo *type_info) +{ + if (type_info->resolve_status == RESOLVE_DONE) + { + return type_info->type; + } + switch (type_info->kind) + { + case TYPE_INFO_POISON: + return poisoned_type; + case TYPE_INFO_ARRAY: + { + // If it's an array, make sure we can resolve the length + Expr *len = type_info->array.len; + if (!sema_analyse_expr(context, type_usize, len)) return false; + if (len->expr_kind != EXPR_CONST || !type_is_any_integer(len->type->canonical)) + { + SEMA_ERROR(len, "Expected a constant integer value here."); + return poisoned_type; + } + Type *type = sema_expr_check_type_exists(context, type_info->array.base); + if (!type) return NULL; + if (!type_ok(type)) return type; + return type_get_array(type, bigint_as_unsigned(&len->const_expr.i)); + } + case TYPE_INFO_IDENTIFIER: + { + Decl *decl = sema_resolve_normal_symbol(context, type_info->unresolved.name_loc, type_info->unresolved.path, false); + if (!decl) return NULL; + if (!decl_ok(decl)) return poisoned_type; + return decl->type->canonical; + } + break; + case TYPE_INFO_EXPRESSION: + if (!sema_resolve_type_info(context, type_info)) return poisoned_type; + return type_info->type; + case TYPE_INFO_SUBARRAY: + { + // If it's an array, make sure we can resolve the length + Type *type = sema_expr_check_type_exists(context, type_info->array.base); + if (!type) return NULL; + if (!type_ok(type)) return type; + return type_get_subarray(type); + } + case TYPE_INFO_INC_ARRAY: + TODO + case TYPE_INFO_INFERRED_ARRAY: + { + // If it's an array, make sure we can resolve the length + Type *type = sema_expr_check_type_exists(context, type_info->array.base); + if (!type) return NULL; + if (!type_ok(type)) return type; + return type_get_inferred_array(type); + } + case TYPE_INFO_POINTER: + { + // If it's an array, make sure we can resolve the length + Type *type = sema_expr_check_type_exists(context, type_info->array.base); + if (!type) return NULL; + if (!type_ok(type)) return type; + return type_get_ptr(type); + } + } + UNREACHABLE +} +static inline bool sema_expr_analyse_ct_defined(Context *context, Expr *expr) +{ + if (expr->resolve_status == RESOLVE_DONE) return expr_ok(expr); + + Expr *main_var = expr->ct_call_expr.main_var; + Type *type = NULL; + Decl *decl = NULL; + ExprFlatElement *path = expr->ct_call_expr.flat_path; + switch (main_var->expr_kind) + { + case EXPR_CONST_IDENTIFIER: + case EXPR_IDENTIFIER: + // 2. An identifier does a lookup + decl = sema_resolve_normal_symbol(context, main_var->identifier_expr.identifier, main_var->identifier_expr.path, false); + // 2a. If it failed, then error + if (!decl_ok(decl)) return false; + // 2b. If it's missing, goto not defined + if (!decl) goto NOT_DEFINED; + type = decl->type; + break; + case EXPR_TYPEINFO: + { + type = sema_expr_check_type_exists(context, main_var->type_expr); + if (!type) goto NOT_DEFINED; + if (!type_ok(type)) return false; + break; + } + default: + if (!sema_analyse_expr_value(context, NULL, main_var)) return false; + if (main_var->expr_kind == EXPR_TYPEINFO) + { + type = expr->type_expr->type; + break; + } + if (main_var->expr_kind != EXPR_CONST || main_var->const_expr.const_kind != CONST_STRING) + { + SEMA_ERROR(main_var, "A constant string containing an identifier or type was expected here."); + return false; + } + if (!sema_analyse_identifier_path_string(context, + expr->span, + main_var, + &decl, + &type, + &path, + true)) + { + return false; + } + break; + } + + VECEACH(path, i) + { + ExprFlatElement element = path[i]; + Type *actual_type = type_flatten_distinct(type); + if (element.array) + { + if (actual_type->type_kind != TYPE_ARRAY) + { + SEMA_ERROR(expr, "It's possible to index into a non fixed size array."); + return false; + } + type = actual_type->array.base; + continue; + } + if (!type_is_structlike(actual_type)) goto NOT_DEFINED; + Decl *member; + SCOPE_START + add_members_to_context(context, actual_type->decl); + member = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); + SCOPE_END; + if (!member) goto NOT_DEFINED; + type = member->type; + } + + expr_set_type(expr, type_bool); + expr->expr_kind = EXPR_CONST; + expr_const_set_bool(&expr->const_expr, true); + return true; + +NOT_DEFINED: + expr_set_type(expr, type_bool); + expr->expr_kind = EXPR_CONST; + expr_const_set_bool(&expr->const_expr, false); + return true; +} + + +static inline bool sema_expr_analyse_ct_offsetof(Context *context, Type *to, Expr *expr) +{ + Expr *main_var = expr->ct_call_expr.main_var; + Type *type = NULL; + Decl *decl = NULL; + ExprFlatElement *path = expr->ct_call_expr.flat_path; + if (!sema_expr_analyse_type_var_path(context, main_var, &path, &type, &decl)) return false; + if (!vec_size(path)) + { + SEMA_ERROR(expr, "Expected a path to get the offset of."); + return false; + } + + ByteSize offset = 0; + VECEACH(path, i) + { + ExprFlatElement element = path[i]; + Type *actual_type = type_flatten_distinct(type); + if (element.array) + { + if (actual_type->type_kind != TYPE_ARRAY) + { + SEMA_ERROR(expr, "It's possible to index into a non fixed size array."); + return false; + } + type = actual_type->array.base; + offset += type_size(type) * element.index; + continue; + } + if (!type_is_structlike(actual_type)) + { + if (i == 0) + { + SEMA_ERROR(main_var, "%s has no members.", type_quoted_error_string(type)); + } + else + { + SEMA_ERROR(expr, "There is no such member in %s.", type_quoted_error_string(type)); + } + return false; + } + Decl *member; + SCOPE_START + add_members_to_context(context, actual_type->decl); + member = sema_resolve_symbol_in_current_dynamic_scope(context, element.ident); + SCOPE_END; + if (!member) + { + SEMA_ERROR(expr, "There is no such member in %s.", type_quoted_error_string(type)); + return false; + } + type = member->type; + offset += member->offset; } expr_rewrite_to_int_const(expr, type_compint, offset); @@ -5917,6 +6030,8 @@ static inline bool sema_expr_analyse_ct_call(Context *context, Type *to, Expr *e { switch (expr->ct_call_expr.token_type) { + case TOKEN_CT_DEFINED: + return sema_expr_analyse_ct_defined(context, expr); case TOKEN_CT_SIZEOF: return sema_expr_analyse_ct_sizeof(context, to, expr); case TOKEN_CT_ALIGNOF: @@ -5954,8 +6069,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * case EXPR_TRY_UNWRAP: case EXPR_CATCH_UNWRAP: UNREACHABLE - case EXPR_TRY_DECL: - TODO case EXPR_DECL: return sema_expr_analyse_decl(context, to, expr); case EXPR_CT_CALL: diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index fb16ab8cf..655a66092 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -220,10 +220,14 @@ static Decl *sema_resolve_symbol(Context *context, const char *symbol_str, Sourc if (path) { decl = sema_resolve_path_symbol(context, symbol_str, path, &ambiguous_other_decl, &private_decl, &path_found); - if (!decl && !path_found && report_error) + if (!decl && !path_found) { - SEMA_ERROR(path, "Unknown module '%.*s', did you forget to import it?", path->len, path->module); - return poisoned_decl; + if (report_error) + { + SEMA_ERROR(path, "Unknown module '%.*s', did you forget to import it?", path->len, path->module); + return poisoned_decl; + } + return NULL; } } else @@ -413,9 +417,9 @@ Decl *sema_resolve_normal_symbol(Context *context, TokenId symbol, Path *path, b return sema_resolve_symbol(context, TOKSTR(symbol), source_span_from_token_id(symbol), path, handle_error); } -Decl *sema_resolve_string_symbol(Context *context, const char *symbol, SourceSpan span, Path *path) +Decl *sema_resolve_string_symbol(Context *context, const char *symbol, SourceSpan span, Path *path, bool report_error) { - return sema_resolve_symbol(context, symbol, span, path, true); + return sema_resolve_symbol(context, symbol, span, path, report_error); } static inline bool sema_append_local(Context *context, Decl *decl) diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 5fbcfe788..d4f05ecef 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -331,6 +331,8 @@ const char *token_type_to_string(TokenType type) return "$case"; case TOKEN_CT_DEFAULT: return "$default"; + case TOKEN_CT_DEFINED: + return "$defined"; case TOKEN_CT_FOR: return "$for"; case TOKEN_CT_ELSE: diff --git a/src/compiler/types.c b/src/compiler/types.c index db1b54c50..bffb0024d 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -13,7 +13,6 @@ static struct Type usz, isz, uptr, iptr, uptrdiff, iptrdiff; Type voidstar, typeid, anyerr, typeinfo; Type str, varheader, virtual, virtual_generic; - } t; Type *type_bool = &t.u1; @@ -1037,7 +1036,7 @@ static Type *type_create_array(Type *element_type, uint64_t len, bool vector, bo { vec_arr->canonical = type_create_array(element_type, len, vector, true); } - VECADD(element_type->type_cache, vec_arr); + vec_add(element_type->type_cache, vec_arr); return vec_arr; } @@ -1272,9 +1271,7 @@ bool type_is_scalar(Type *type) RETRY: switch (type->type_kind) { - case TYPE_POISONED: - case TYPE_TYPEINFO: - case TYPE_INFERRED_ARRAY: + case CT_TYPES: UNREACHABLE case TYPE_VOID: case TYPE_FUNC: diff --git a/src/compiler_tests/tests.c b/src/compiler_tests/tests.c index f606e4272..3864b8398 100644 --- a/src/compiler_tests/tests.c +++ b/src/compiler_tests/tests.c @@ -16,7 +16,7 @@ void test_file(void) File file; memset(&file, 0, sizeof(file)); file.start_id = 3; - VECADD(file.lines, file.start_id); + vec_add(file.lines, file.start_id); TEST_ASSERT(source_file_find_position_in_file(&file, 3).line == 1, "Expected first line"); TEST_ASSERT(source_file_find_position_in_file(&file, 10).line == 1, "Expected first line"); source_file_append_line_end(&file, 9); diff --git a/src/utils/errors.c b/src/utils/errors.c index 000e3ece7..06813927f 100644 --- a/src/utils/errors.c +++ b/src/utils/errors.c @@ -18,7 +18,7 @@ void eprintf(const char *format, ...) va_end(arglist); } -void __attribute__((noreturn)) error_exit(const char *format, ...) +NORETURN void error_exit(const char *format, ...) { va_list arglist; va_start(arglist, format); diff --git a/src/utils/errors.h b/src/utils/errors.h index 66b399539..595f89e39 100644 --- a/src/utils/errors.h +++ b/src/utils/errors.h @@ -7,9 +7,6 @@ #include #include -void evprintf(const char *format, va_list list); -void eprintf(const char *format, ...); -void error_exit(const char *format, ...) __attribute__((noreturn)); #ifdef NDEBUG #define REMINDER(_string, ...) do {} while (0) @@ -34,6 +31,16 @@ void error_exit(const char *format, ...) __attribute__((noreturn)); #else #define FALLTHROUGH ((void)0) #endif + + +#if defined(_MSC_VER) +#define NORETURN __declspec(noreturn) +#elif defined(__GNUC__) +#define NORETURN __attribute__((noreturn)) +#else +#define NORETURN +#endif + #define TODO FATAL_ERROR("TODO reached"); #define TEST_ASSERT(_condition, _string, ...) while (!(_condition)) { FATAL_ERROR(_string, ##__VA_ARGS__); } @@ -44,3 +51,6 @@ void error_exit(const char *format, ...) __attribute__((noreturn)); #define LOG_FUNC DEBUG_LOG("ENTER %s.", __func__); +void evprintf(const char *format, va_list list); +void eprintf(const char *format, ...); +NORETURN void error_exit(const char *format, ...) ; diff --git a/src/utils/lib.h b/src/utils/lib.h index d90460ae4..2ebe29c6f 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -400,14 +400,17 @@ static inline void* expand_(void *vec, size_t element_size) #define VECNEW(_type, _capacity) ((_type *)(vec_new_(sizeof(_type), _capacity) + 1)) -#define VECADD(vec_, value_) \ - ({ \ - typeof(vec_) __temp = (typeof(vec_))expand_((vec_), sizeof(typeof(*(vec_)))); \ - __temp[vec_size(__temp) - 1] = value_; \ - (vec_) = __temp; }) -#define vec_add(_vec, value_) do { (_vec) = VECADD((_vec), value_); } while (0) +#define vec_add(vec_, value_) do { \ + void *__temp = expand_((vec_), sizeof(*(vec_))); \ + (vec_) = __temp; \ + (vec_)[vec_size(vec_) - 1] = value_; \ + } while (0) +#if IS_GCC || IS_CLANG #define VECLAST(_vec) ({ unsigned _size = vec_size(_vec); _size ? (_vec)[_size - 1] : NULL; }) +#else +#define VECLAST(_vec) (vec_size(_vec) ? (_vec)[vec_size(_vec) - 1] : NULL) +#endif static inline bool is_all_upper(const char* string) @@ -456,6 +459,8 @@ static inline StringSlice strtoslice(const char *data) } void slicetrim(StringSlice *slice); +#if IS_GCC || IS_CLANG + #define MAX(_a, _b) ({ \ typeof(_a) __a__ = (_a); \ typeof(_b) __b__ = (_b); \ @@ -466,6 +471,10 @@ void slicetrim(StringSlice *slice); typeof(_b) __b__ = (_b); \ __a__ < __b__ ? __a__ : __b__; }) +#else +#define MAX(a_, b_) ((a_) > (b_) ? (a_) : (b_)) +#define MIN(a_, b_) ((a_) < (b_) ? (a_) : (b_)) +#endif // Windows-specific code diff --git a/test/test_suite/arrays/array_invalid_casts.c3 b/test/test_suite/arrays/array_invalid_casts.c3 index 3835f84b3..d58930909 100644 --- a/test/test_suite/arrays/array_invalid_casts.c3 +++ b/test/test_suite/arrays/array_invalid_casts.c3 @@ -2,11 +2,11 @@ func void test() { int[3] x; - double *y = &x; // #error: Cannot implicitly cast 'int[3]*' to 'double* + double *y = &x; // #error: 'int[3]*' to 'double* } func void test2() { int[3] x; - double[] z = &x; // #error: Cannot implicitly cast 'int[3]*' to 'double[]' + double[] z = &x; // #error: 'int[3]*' into 'double[]' } \ No newline at end of file diff --git a/test/test_suite/compile_time/typeof_from_literal.c3 b/test/test_suite/compile_time/typeof_from_literal.c3 index 72e0a33cf..52d74c819 100644 --- a/test/test_suite/compile_time/typeof_from_literal.c3 +++ b/test/test_suite/compile_time/typeof_from_literal.c3 @@ -3,12 +3,12 @@ module foo; func void a() { $typeof(9146744073709551615) ef; - int fffx = ef; // #error: Cannot implicitly cast 'long' to 'int' + int fffx = ef; // #error: 'long' to 'int' } func void b() { $typeof(9223372036854775809) ef; - int fffx = ef; // #error: Cannot implicitly cast 'ulong' to 'int' + int fffx = ef; // #error: 'ulong' to 'int' } diff --git a/test/test_suite/compile_time_introspection/alignof.c3t b/test/test_suite/compile_time_introspection/alignof.c3t index 65c633c97..259cf2831 100644 --- a/test/test_suite/compile_time_introspection/alignof.c3t +++ b/test/test_suite/compile_time_introspection/alignof.c3t @@ -40,19 +40,19 @@ Ar izzy; long x = $alignof(zfe); short y = $alignof("Bob.y"); int z = $alignof("Bob.y"); -int w = $alignof(Bob, y); +int w = $alignof(Bob.y); int v = $alignof(v); int x1 = $alignof("Ex.c"); -int x2 = $alignof("Ex", y); +int x2 = $alignof(Ex.y); int x3 = $alignof(char[8]); int x4 = $alignof("Ar.br[1]"); -int x5 = $alignof("Ar", "br[1]"); -int x6 = $alignof(Ar, "br[1]"); -int x7 = $alignof("Ar", br[1]); -int x8 = $alignof(Ar, br[2]); +int x5 = $alignof(Ar.br[1]); +int x6 = $alignof(Ar.br[1]); +int x7 = $alignof(Ar.br[1]); +int x8 = $alignof(Ar.br[2]); int x9 = $alignof("izzy.br[1]"); -int x10 = $alignof("izzy", "br[1]"); -int x11 = $alignof("izzy", br[1]); +int x10 = $alignof("izzy.br[1]"); +int x11 = $alignof(izzy.br[1]); int z0 = $alignof("Foob.c"); int z00 = $alignof("Foob.c[0]"); int z01 = $alignof("Foob.c[1]"); diff --git a/test/test_suite/compile_time_introspection/defined.c3t b/test/test_suite/compile_time_introspection/defined.c3t new file mode 100644 index 000000000..a3cd5f0ae --- /dev/null +++ b/test/test_suite/compile_time_introspection/defined.c3t @@ -0,0 +1,97 @@ +// #target: x64-darwin + +module mymodule; + +extern func void printf(char *, ...); + +struct Foo +{ + int a; + int ab; + struct bob + { + int j; + } +} +func void main() +{ + int x = 0; + var $counter = 0; + $if ($defined(x)): + x++; + $counter++; + $endif; + $if ($defined(Foo.ab)): + int y = 10; + $counter++; + x++; + $endif; + $if ($defined(Foo.ab.x)): + x = 0; + $counter = 0; + $endif; + $if ($defined(Foo.bob)): + x++; + $counter++; + $endif; + $if ($defined("x")): + x++; + $counter++; + $endif; + $if ($defined("Foo.ab")): + x++; + $counter++; + $endif; + $if ($defined("mymodule::Foo.bob")): + x++; + $counter++; + $endif; + $if ($defined(y)): + x++; + $counter++; + y = 1; + $endif; + $if ($defined(z)): + $counter = 0; + x = 0; + $endif; + int z = $counter; + printf("%d\n", x); +} + +// #expect: mymodule.ll + +define void @main() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 0, i32* %x, align 4 + %0 = load i32, i32* %x, align 4 + %add = add i32 %0, 1 + store i32 %add, i32* %x, align 4 + store i32 10, i32* %y, align 4 + %1 = load i32, i32* %x, align 4 + %add1 = add i32 %1, 1 + store i32 %add1, i32* %x, align 4 + %2 = load i32, i32* %x, align 4 + %add2 = add i32 %2, 1 + store i32 %add2, i32* %x, align 4 + %3 = load i32, i32* %x, align 4 + %add3 = add i32 %3, 1 + store i32 %add3, i32* %x, align 4 + %4 = load i32, i32* %x, align 4 + %add4 = add i32 %4, 1 + store i32 %add4, i32* %x, align 4 + %5 = load i32, i32* %x, align 4 + %add5 = add i32 %5, 1 + store i32 %add5, i32* %x, align 4 + %6 = load i32, i32* %x, align 4 + %add6 = add i32 %6, 1 + store i32 %add6, i32* %x, align 4 + store i32 1, i32* %y, align 4 + store i32 7, i32* %z, align 4 + %7 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %7) + ret void +} \ No newline at end of file diff --git a/test/test_suite/compile_time_introspection/defined_err.c3 b/test/test_suite/compile_time_introspection/defined_err.c3 new file mode 100644 index 000000000..194c144ad --- /dev/null +++ b/test/test_suite/compile_time_introspection/defined_err.c3 @@ -0,0 +1,23 @@ +func void test1() +{ + bool x = $defined(1); // #error: constant string containing an identifier or type was expected +} + +struct Foo +{} + +func void test2() +{ + $assert($defined(int[1])); + bool x = $defined(int[y]); // #error: 'y' could not be found, did you spell it right? +} + +func void test3() +{ + $assert($defined(Foo[1])); + $assert($defined(Foo*)); + $assert($defined(Foo[])); + $assert($defined(Foo[*])); + bool x = $defined(Foo[y]); // #error: 'y' could not be found, did you spell it right? +} + diff --git a/test/test_suite/compile_time_introspection/offsetof.c3t b/test/test_suite/compile_time_introspection/offsetof.c3t index 21bc63548..5ad956f71 100644 --- a/test/test_suite/compile_time_introspection/offsetof.c3t +++ b/test/test_suite/compile_time_introspection/offsetof.c3t @@ -38,14 +38,14 @@ union Foob short y = $offsetof("Bob.y"); int z = $offsetof("Bob.y"); -int w = $offsetof(Bob, y); +int w = $offsetof(Bob.y); int x1 = $offsetof("Ex.c[3]"); -int x2 = $offsetof("Ex", y[1]); +int x2 = $offsetof("Ex.y[1]"); int x4 = $offsetof("Ar.br[1]"); -int x6 = $offsetof(Ar, "br[1].x"); -int x5 = $offsetof("Ar", "br[1]"); -int x7 = $offsetof("Ar", br[2].x); -int x8 = $offsetof(Ar, br[2]); +int x6 = $offsetof(Ar.br[1].x); +int x5 = $offsetof(Ar.br[1]); +int x7 = $offsetof("Ar.br[2].x"); +int x8 = $offsetof(Ar.br[2]); int z0 = $offsetof("Foob.c"); int z00 = $offsetof("Foob.c[0]"); int z01 = $offsetof("Foob.c[1]"); diff --git a/test/test_suite/compile_time_introspection/sizeof.c3t b/test/test_suite/compile_time_introspection/sizeof.c3t index 536784a0e..a0e8fe74d 100644 --- a/test/test_suite/compile_time_introspection/sizeof.c3t +++ b/test/test_suite/compile_time_introspection/sizeof.c3t @@ -14,10 +14,10 @@ int b = $sizeof("Deep.a.b"); int c = $sizeof("Deep.a.b.c"); int d = $sizeof("Deep[][100]"); int e = $sizeof("Deep[][100]**[100][]*"); -int a2 = $sizeof("Baz", "y"); -int a3 = $sizeof("Baz", y); -int a4 = $sizeof(Baz, "y"); -int a5 = $sizeof(Baz, y); +int a2 = $sizeof("Baz.y"); +int a3 = $sizeof(Baz.y); +int a4 = $sizeof(Baz.y); +int a5 = $sizeof(Baz.y); module bar; diff --git a/test/test_suite/compile_time_introspection/sizeof_errors.c3 b/test/test_suite/compile_time_introspection/sizeof_errors.c3 index e9f5ceeed..dd110af2a 100644 --- a/test/test_suite/compile_time_introspection/sizeof_errors.c3 +++ b/test/test_suite/compile_time_introspection/sizeof_errors.c3 @@ -14,12 +14,12 @@ func void b() func void c() { - int x = $sizeof("Baz#"); // #error: A '.' was expected after 'Baz' + int x = $sizeof("Baz#"); // #error: The path to an existing member was expected after 'Baz', did you make a mistake? } func void c2() { - int x = $sizeof("#Baz"); // #error: '#Baz' is not a known identifier, did you misspell it? + int x = $sizeof("#Baz"); // #error: '#Baz' is not a valid identifier, did you misspell it? } func void d() @@ -39,7 +39,7 @@ func void f() func void g() { - int x = $sizeof("bar::"); // #error: 'bar::' is not a known identifier, did you misspell it? + int x = $sizeof("bar::"); // #error: 'bar::' is not a valid identifier, did you misspell it? } func void k() @@ -62,10 +62,7 @@ func void n() int v = $sizeof("Baz.x1"); // #error: The path to an existing member was expected after } -func void o() -{ - int v = $sizeof("Baz.x", x); // #error: You cannot combine a string with a member path with a separate path here -} + module bar; diff --git a/test/test_suite/distinct/test_errors.c3 b/test/test_suite/distinct/test_errors.c3 index 253d567bc..f64d8a527 100644 --- a/test/test_suite/distinct/test_errors.c3 +++ b/test/test_suite/distinct/test_errors.c3 @@ -7,5 +7,5 @@ func void test() Int2 a = 1; a = a + 1; int b; - a = b; // #error: Cannot implicitly cast 'int' to 'Int2' + a = b; // #error: 'int' to 'Int2' } \ No newline at end of file diff --git a/test/test_suite/expressions/call_arg_types.c3 b/test/test_suite/expressions/call_arg_types.c3 index 089161e72..ba86aaea2 100644 --- a/test/test_suite/expressions/call_arg_types.c3 +++ b/test/test_suite/expressions/call_arg_types.c3 @@ -8,11 +8,11 @@ func void test1() test2(c); int a = 1; - test2(a); // #error: Cannot implicitly cast 'int' to 'ichar'. - test2(100 + a); // #error: Cannot implicitly cast 'int' to 'ichar'. + test2(a); // #error: 'int' to 'ichar' + test2(100 + a); // #error: 'int' to 'ichar' const int X = 120; - test2(X); // #error: Cannot implicitly cast 'int' to 'ichar'. + test2(X); // #error: 'int' to 'ichar' test2(100 + 100); // #error: '200' is out of range for 'ichar' } diff --git a/test/test_suite/expressions/casts/cast_const.c3 b/test/test_suite/expressions/casts/cast_const.c3 index a85552f24..5c4eb5ed8 100644 --- a/test/test_suite/expressions/casts/cast_const.c3 +++ b/test/test_suite/expressions/casts/cast_const.c3 @@ -2,5 +2,5 @@ func void test1() { ichar a = (ichar)(256 + 1); ushort b = (ushort)(65536+1); - ichar c = (ushort)(65536+400); // #error: Cannot implicitly cast 'ushort' to 'ichar' + ichar c = (ushort)(65536+400); // #error: 'ushort' to 'ichar' } diff --git a/test/test_suite/expressions/casts/cast_func_to_various.c3 b/test/test_suite/expressions/casts/cast_func_to_various.c3 index e1ba0e1d1..887a689f7 100644 --- a/test/test_suite/expressions/casts/cast_func_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_func_to_various.c3 @@ -39,7 +39,7 @@ func void test7(Func arg) usize g = (usize)(arg); FuncOther k = (FuncOther)(arg); FuncSame l = (FuncSame)(arg); - FuncOther ke = arg; // #error: Cannot implicitly cast 'Func' (func void(int)) to 'FuncOther' (func bool(char*)) + FuncOther ke = arg; // #error: 'Func' (func void(int)) to 'FuncOther' (func bool(char*)) FuncSame fe = arg; Enum j = (Enum)(arg); // #error: Cannot cast 'Func' (func void(int)) to 'Enum'. } diff --git a/test/test_suite/expressions/casts/explicit_cast.c3 b/test/test_suite/expressions/casts/explicit_cast.c3 index 535d9a81f..c216acaf1 100644 --- a/test/test_suite/expressions/casts/explicit_cast.c3 +++ b/test/test_suite/expressions/casts/explicit_cast.c3 @@ -6,10 +6,10 @@ func void test1() int a = (ichar)(10); int b = (ichar)(200); int c = (int)(200); - ichar d = (int)(200); // #error: Cannot implicitly cast 'int' to 'ichar'. + ichar d = (int)(200); // #error: 'int' to 'ichar' } func void test2() { - char e = (Number32)(200); // #error: Cannot implicitly cast 'Number32' (int) to 'char'. + char e = (Number32)(200); // #error: 'Number32' (int) to 'char' } \ No newline at end of file diff --git a/test/test_suite/expressions/pointer_conv_error.c3 b/test/test_suite/expressions/pointer_conv_error.c3 index 0e1681dec..4b611205a 100644 --- a/test/test_suite/expressions/pointer_conv_error.c3 +++ b/test/test_suite/expressions/pointer_conv_error.c3 @@ -1,18 +1,18 @@ func void test1() { int myInt = 1; - int* p1 = myInt; // #error: Cannot implicitly cast 'int' to 'int*'. + int* p1 = myInt; // #error: 'int' into 'int*' } func void test2() { uint myUInt = 1; - int* p2 = myUInt; // #error: Cannot implicitly cast 'uint' to 'int*'. + int* p2 = myUInt; // #error: 'uint' into 'int*' } func void test3() { uint myUInt = 1; - int* p2 = (int*)(myUInt); // #error: Cannot cast 'uint' to 'int*'. + int* p2 = (int*)(myUInt); // #error: 'uint' to 'int*' } diff --git a/test/test_suite/globals/global_init.c3 b/test/test_suite/globals/global_init.c3 index fe177f375..b4144e45f 100644 --- a/test/test_suite/globals/global_init.c3 +++ b/test/test_suite/globals/global_init.c3 @@ -1,15 +1,14 @@ // TODO string str = "hello"; -//char* str2 = "hello"; - -//char[] str3 = "hello"; +char* str2 = "hello"; +char[] str3 = "hello"; int[2] a1 = { 1, 2 }; -int[2] a2 = 30; // #error: Cannot implicitly cast 'compint' to 'int[2]' +int[2] a2 = 30; // #error: 'compint' into 'int[2]' // TODO int[2] a3 = a1; -// i8[] a; // @error{definition of variable with array type needs an explicit size or an initializer} +ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers ichar ca = 0; ichar cb = 1; diff --git a/test/test_suite/macros/hash_ident.c3 b/test/test_suite/macros/hash_ident.c3 index f8b71e421..ebb2e1ea5 100644 --- a/test/test_suite/macros/hash_ident.c3 +++ b/test/test_suite/macros/hash_ident.c3 @@ -14,7 +14,7 @@ func int xx() func void main() { - define $x = 0; + var $x = 0; int x = 0; @cofefe(x += 1); @cofefe(xx()); diff --git a/test/test_suite/statements/for_errors.c3 b/test/test_suite/statements/for_errors.c3 index f0980cfcd..27ee0c284 100644 --- a/test/test_suite/statements/for_errors.c3 +++ b/test/test_suite/statements/for_errors.c3 @@ -2,6 +2,6 @@ func void foo() {} func int main() { - for (; foo() ; ) {} // #error: Cannot implicitly cast 'void' to 'bool' + for (; foo() ; ) {} // #error: 'void' into 'bool' return 0; } \ No newline at end of file diff --git a/test/test_suite/statements/foreach_errors.c3 b/test/test_suite/statements/foreach_errors.c3 index 571b55786..c12396034 100644 --- a/test/test_suite/statements/foreach_errors.c3 +++ b/test/test_suite/statements/foreach_errors.c3 @@ -49,7 +49,7 @@ func void test7() func void test8() { - foreach (int a : { z }) foo(); // #error: Cannot implicitly cast 'int[3]' to 'int' + foreach (int a : { z }) foo(); // #error: 'int[3]' into 'int' } func void test9() diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 index 237b0a356..9b6414d0a 100644 --- a/test/test_suite/statements/switch_errors.c3 +++ b/test/test_suite/statements/switch_errors.c3 @@ -18,7 +18,7 @@ func void test_other_enum() break; case B: break; - case Bar.B: // #error: Cannot implicitly cast 'Bar' to 'Foo' + case Bar.B: // #error: 'Bar' to 'Foo' break; } } diff --git a/test/test_suite/struct/member_access.c3 b/test/test_suite/struct/member_access.c3 index ee850e06a..a9ef250da 100644 --- a/test/test_suite/struct/member_access.c3 +++ b/test/test_suite/struct/member_access.c3 @@ -71,7 +71,7 @@ struct Aa1 func void test_conversion_struct() { Aa1 a1; - int aa = a1.bb; // #error: Cannot implicitly cast 'bb' to 'int' + int aa = a1.bb; // #error: 'bb' into 'int' } struct Struct diff --git a/test/test_suite/subarrays/sub_array_init.c3 b/test/test_suite/subarrays/sub_array_init.c3 index a8ec1120b..187338cd7 100644 --- a/test/test_suite/subarrays/sub_array_init.c3 +++ b/test/test_suite/subarrays/sub_array_init.c3 @@ -2,6 +2,6 @@ func void test2() { int[2] a = { 1, 2 }; - int[2] b = 30; // #error: Cannot implicitly cast 'compint' to 'int[2]' + int[2] b = 30; // #error: 'compint' into 'int[2]' int[2] c = a; } diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 index 8b823ac48..b49e7614f 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -18,7 +18,7 @@ func void test3() { ichar a = 1; int b = 2; - ichar c = a + b; // #error: Cannot implicitly cast 'int' to 'ichar' + ichar c = a + b; // #error: 'int' to 'ichar' } func void test4() @@ -54,7 +54,7 @@ define Number = int; func void test8() { Number a = 10; - ichar c = a; // #error: implicitly cast 'Number' (int) to 'ichar' + ichar c = a; // #error: 'Number' (int) to 'ichar' } @@ -82,19 +82,19 @@ enum Enum : int func void test11() { int a = Enum.A; - ichar b = Enum.B; // #error: Cannot implicitly cast 'Enum' to 'ichar' + ichar b = Enum.B; // #error: 'Enum' to 'ichar' } func void test12() { float f = 3.14; - ichar a = f; // #error: cast 'float' to 'ichar' + ichar a = f; // #error: 'float' to 'ichar' } func void test13() { int a = 1; - ichar b = a; // #error: cast 'int' to 'ichar' + ichar b = a; // #error: 'int' to 'ichar' } func void test14() @@ -107,7 +107,7 @@ func void test15() { float f = 3.14; ichar c = 1; - ichar* a = &f; // #error: cast 'float*' to 'ichar*' + ichar* a = &f; // #error: 'float*' to 'ichar*' ichar* b = &c; } @@ -117,15 +117,15 @@ func void test16() int i = 1; ichar c = 1 ? 'c' : 'd'; - ichar d = 1 ? 'c' : i; // #error: cast 'int' to 'ichar' - ichar e = 1 ? i : 0; // #error: cast 'int' to 'ichar' - int g = 1 ? i : f; // #error: cast 'float' to 'int' + ichar d = 1 ? 'c' : i; // #error: 'int' to 'ichar' + ichar e = 1 ? i : 0; // #error: 'int' to 'ichar' + int g = 1 ? i : f; // #error: 'float' to 'int' int a = f ? 1 : 0; } func void test17() { - int a = "test"; // #error: cast 'string literal' to 'int' + int a = "test"; // #error: 'string literal' into 'int' } func void test18() @@ -157,15 +157,15 @@ func void foo() {} func void test22() { - ichar a = foo(); // #error: cast 'void' to 'ichar' - short b = foo(); // #error: cast 'void' to 'short' - int c = foo(); // #error: cast 'void' to 'int' - long d = foo(); // #error: cast 'void' to 'long' - char e = foo(); // #error: cast 'void' to 'char' - ushort f = foo(); // #error: cast 'void' to 'ushort' - uint g = foo(); // #error: cast 'void' to 'uint' - ulong h = foo(); // #error: cast 'void' to 'ulong' - bool i = foo(); // #error: cast 'void' to 'bool' + ichar a = foo(); // #error: 'void' into 'ichar' + short b = foo(); // #error: 'void' into 'short' + int c = foo(); // #error: 'void' into 'int' + long d = foo(); // #error: 'void' into 'long' + char e = foo(); // #error: 'void' into 'char' + ushort f = foo(); // #error: 'void' into 'ushort' + uint g = foo(); // #error: 'void' into 'uint' + ulong h = foo(); // #error: 'void' into 'ulong' + bool i = foo(); // #error: 'void' into 'bool' } @@ -175,14 +175,14 @@ func void test23() { int a = num; int b = test::num; - char c = test::num; // #error: cast 'int' to 'char' + char c = test::num; // #error: 'int' to 'char' } int[2][3] b123; func void test24() { - int a = b123; // #error: cast 'int[2][3]' to 'int' + int a = b123; // #error: 'int[2][3]' into 'int' } func void test25() diff --git a/test/test_suite/types/enum_errors.c3 b/test/test_suite/types/enum_errors.c3 index 0dbf94be8..7936d78d8 100644 --- a/test/test_suite/types/enum_errors.c3 +++ b/test/test_suite/types/enum_errors.c3 @@ -12,6 +12,6 @@ func int foo() enum State { A = foo(), // #error: Expected a constant expression for enum - B = "hello", // #error: Cannot implicitly cast 'string literal' to 'int' - C = true, // #error: Cannot implicitly cast 'bool' to 'int' + B = "hello", // #error: 'string literal' into 'int' + C = true, // #error: 'bool' to 'int' } diff --git a/test/test_suite/types/typedefs.c3 b/test/test_suite/types/typedefs.c3 index 662b9f82b..6f3259050 100644 --- a/test/test_suite/types/typedefs.c3 +++ b/test/test_suite/types/typedefs.c3 @@ -5,7 +5,7 @@ Arr a = { 3, 4, 5, 6 }; func void test1() { Arr b = { 3, 4, 5, 6 }; - int c = b; // #error: cast 'Arr' (int[4]) to 'int' - int d = a; // #error: cast 'Arr' (int[4]) to 'int' + int c = b; // #error: 'Arr' (int[4]) into 'int' + int d = a; // #error: 'Arr' (int[4]) into 'int' }