diff --git a/.clang-tidy b/.clang-tidy index 974a806d3..845d4d6b0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -25,7 +25,7 @@ Checks: > WarningsAsErrors: "*" CheckOptions: - - { key: readability-function-cognitive-complexity.Threshold, value: 40 } + - { key: readability-function-cognitive-complexity.Threshold, value: 100 } - { key: readability-identifier-naming.StructCase, value: CamelCase } - { key: readability-identifier-naming.FunctionCase, value: lower_case } - { key: readability-identifier-naming.VariableCase, value: lower_case } diff --git a/resources/examples/hash.c3 b/resources/examples/hash.c3 index c49758ad4..db42be07d 100644 --- a/resources/examples/hash.c3 +++ b/resources/examples/hash.c3 @@ -57,7 +57,7 @@ public func uint fnv32(char[] data) uint h = 0x811c9dc5; foreach (char x : data) { - h = (h *% 0x01000193) ^ x; + h = (h * 0x01000193) ^ x; } return h; } @@ -67,7 +67,7 @@ public func ulong fnv64(char[] data) ulong h = 0xcbf29ce484222325; foreach (char x : data) { - h = (h *% 0x100000001b3) ^ x; + h = (h * 0x100000001b3) ^ x; } return h; } @@ -77,7 +77,7 @@ public func uint fnv32a(char[] data) uint h = 0x811c9dc5; foreach (char x : data) { - h = (h ^ x) *% 0x01000193; + h = (h ^ x) * 0x01000193; } return h; } @@ -87,7 +87,7 @@ public func ulong fnv64a(char[] data) ulong h = 0xcbf29ce484222325; foreach (char x : data) { - h = (h ^ x) *% 0x100000001b3; + h = (h ^ x) * 0x100000001b3; } return h; } diff --git a/src/build/build_options.h b/src/build/build_options.h index 1fe464dd1..c8ab93a72 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -169,6 +169,7 @@ typedef struct bool emit_llvm; bool emit_bitcode; bool test_mode; + bool trap_wrapping; } BuildOptions; diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 80c57ca63..4227c58dc 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -161,7 +161,7 @@ Expr *expr_new(ExprKind kind, SourceSpan start) Expr *expr = expr_calloc(); expr->expr_kind = kind; expr->span = start; - expr->type = NULL; + expr->type = expr->original_type = NULL; return expr; } @@ -170,12 +170,9 @@ Expr *poisoned_expr = &poison_expr; BinaryOp binary_op[TOKEN_LAST + 1] = { [TOKEN_STAR] = BINARYOP_MULT, - [TOKEN_MULT_MOD] = BINARYOP_MULT_MOD, [TOKEN_DIV] = BINARYOP_DIV, [TOKEN_PLUS] = BINARYOP_ADD, - [TOKEN_PLUS_MOD] = BINARYOP_ADD_MOD, [TOKEN_MINUS] = BINARYOP_SUB, - [TOKEN_MINUS_MOD] = BINARYOP_SUB_MOD, [TOKEN_MOD] = BINARYOP_MOD, [TOKEN_SHL] = BINARYOP_SHL, [TOKEN_SHR] = BINARYOP_SHR, @@ -192,13 +189,9 @@ BinaryOp binary_op[TOKEN_LAST + 1] = { [TOKEN_GREATER_EQ] = BINARYOP_GE, [TOKEN_EQ] = BINARYOP_ASSIGN, [TOKEN_MULT_ASSIGN] = BINARYOP_MULT_ASSIGN, - [TOKEN_MULT_MOD_ASSIGN] = BINARYOP_MULT_MOD_ASSIGN, [TOKEN_PLUS_ASSIGN] = BINARYOP_ADD_ASSIGN, - [TOKEN_PLUS_MOD_ASSIGN] = BINARYOP_ADD_MOD_ASSIGN, [TOKEN_MINUS_ASSIGN] = BINARYOP_SUB_ASSIGN, - [TOKEN_MINUS_MOD_ASSIGN] = BINARYOP_SUB_MOD_ASSIGN, [TOKEN_DIV_ASSIGN] = BINARYOP_DIV_ASSIGN, - [TOKEN_MOD_ASSIGN] = BINARYOP_MOD_ASSIGN, [TOKEN_BIT_AND_ASSIGN] = BINARYOP_BIT_AND_ASSIGN, [TOKEN_BIT_OR_ASSIGN] = BINARYOP_BIT_OR_ASSIGN, [TOKEN_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR_ASSIGN, @@ -209,13 +202,9 @@ BinaryOp binary_op[TOKEN_LAST + 1] = { static BinaryOp assign_binop[BINARYOP_LAST + 1] = { [BINARYOP_MULT_ASSIGN] = BINARYOP_MULT, - [BINARYOP_MULT_MOD_ASSIGN] = BINARYOP_MULT_MOD, [BINARYOP_ADD_ASSIGN] = BINARYOP_ADD, - [BINARYOP_ADD_MOD_ASSIGN] = BINARYOP_ADD_MOD, [BINARYOP_SUB_ASSIGN] = BINARYOP_SUB, - [BINARYOP_SUB_MOD_ASSIGN] = BINARYOP_SUB_MOD, [BINARYOP_DIV_ASSIGN] = BINARYOP_DIV, - [BINARYOP_MOD_ASSIGN] = BINARYOP_MOD, [BINARYOP_BIT_AND_ASSIGN] = BINARYOP_BIT_AND, [BINARYOP_BIT_OR_ASSIGN] = BINARYOP_BIT_OR, [BINARYOP_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR, @@ -235,7 +224,6 @@ UnaryOp unary_op[TOKEN_LAST + 1] = { [TOKEN_BIT_NOT] = UNARYOP_BITNEG, [TOKEN_BANG] = UNARYOP_NOT, [TOKEN_MINUS] = UNARYOP_NEG, - [TOKEN_MINUS_MOD] = UNARYOP_NEGMOD, [TOKEN_PLUSPLUS] = UNARYOP_INC, [TOKEN_MINUSMINUS] = UNARYOP_DEC, }; @@ -397,7 +385,7 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent) case TYPE_FXX: DUMP("(ct float)"); return; - case TYPE_CTSTR: + case TYPE_STRLIT: DUMP("(ct string)"); return; case TYPE_ERR_UNION: diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 4825d118d..415c92f36 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -765,6 +765,7 @@ struct _Expr bool reeval : 1; SourceSpan span; Type *type; + Type *original_type; union { Expr *group_expr; ExprLen len_expr; @@ -1368,6 +1369,7 @@ extern Type *type_bool, *type_void, *type_compstr, *type_voidptr; extern Type *type_half, *type_float, *type_double, *type_quad; extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isize; extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usize; +extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff; extern Type *type_u128, *type_i128; extern Type *type_compint, *type_compfloat; extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong; @@ -1438,13 +1440,8 @@ static inline bool builtin_may_negate(Type *canonical) assert(canonical->canonical == canonical); switch (canonical->type_kind) { - case TYPE_FXX: - case TYPE_F32: - case TYPE_F64: - case TYPE_I8: - case TYPE_I16: - case TYPE_I32: - case TYPE_I64: + case ALL_FLOATS: + case ALL_SIGNED_INTS: case TYPE_IXX: return true; default: @@ -1453,12 +1450,16 @@ static inline bool builtin_may_negate(Type *canonical) } +bool cast_implicit(Expr *expr, Type *to_type); +bool cast(Expr *expr, Type *to_type); +bool cast_to_bool_implicit(Expr *expr); +bool cast_may_implicit(Type *from_type, Type *to_type); +bool cast_may_explicit(Type *from_type, Type *to_type); +bool cast_implicit_bit_width(Expr *expr, Type *to_type); -bool cast_implicit(Context *context, Expr *expr, Type *to_type); -bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type); CastKind cast_to_bool_kind(Type *type); -bool cast_implicitly_to_runtime(Context *context, Expr *expr); +bool cast_implicitly_to_runtime(Expr *expr); void llvm_codegen(void *module); void *llvm_gen(Context *context); @@ -1512,6 +1513,8 @@ static inline void expr_replace(Expr *expr, Expr *replacement) *expr = *replacement; expr->span = loc; } +void expr_copy_types(Expr *to, Expr *from); +void expr_copy_properties(Expr *to, Expr *from); void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind); void expr_const_set_float(ExprConst *expr, long double d, TypeKind kind); void expr_const_set_bool(ExprConst *expr, bool b); @@ -1519,8 +1522,15 @@ void expr_const_set_null(ExprConst *expr); 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); 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) +{ + assert(type); + expr->type = type; + expr->original_type = type; +} void fprint_decl(Context *context, FILE *file, Decl *dec); void fprint_type_info_recursive(Context *context, FILE *file, TypeInfo *type_info, int indent); @@ -1681,12 +1691,14 @@ static inline size_t type_min_alignment(size_t a, size_t b); bool type_is_subtype(Type *type, Type *possible_subtype); bool type_is_union_struct(Type *type); bool type_is_user_defined(Type *type); +bool type_is_structurally_equivalent(Type *type1, Type *type); static inline Type *type_lowering(Type *type); bool type_may_have_sub_elements(Type *type); static inline bool type_ok(Type *type); static inline Type *type_reduced_from_expr(Expr *expr); ByteSize type_size(Type *type); const char *type_to_error_string(Type *type); +const char *type_quoted_error_string(Type *type); static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span); static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span); @@ -1706,10 +1718,20 @@ static inline Type *type_reduced_from_expr(Expr *expr) } +static inline bool type_is_pointer_sized_or_more(Type *type) +{ + return type_is_integer(type) && type_size(type) >= type_size(type_iptr); +} + +static inline bool type_is_pointer_sized(Type *type) +{ + return type_is_integer(type) && type_size(type) == type_size(type_iptr); +} + static inline bool type_is_integer(Type *type) { assert(type == type->canonical); - return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_U128; + return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_IXX; } @@ -1722,19 +1744,19 @@ static inline bool type_is_any_integer(Type *type) static inline bool type_is_integer_signed(Type *type) { assert(type == type->canonical); - return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I128; + return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; } static inline bool type_is_integer_kind(Type *type) { assert(type == type->canonical); - return type->type_kind >= TYPE_BOOL && type->type_kind <= TYPE_U128; + return type->type_kind >= TYPE_BOOL && type->type_kind < TYPE_IXX; } static inline bool type_is_integer_unsigned(Type *type) { assert(type == type->canonical); - return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U128; + return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX; } static inline bool type_info_poison(TypeInfo *type) @@ -1780,7 +1802,7 @@ static inline bool type_is_substruct(Type *type) static inline bool type_is_float(Type *type) { assert(type == type->canonical); - return type->type_kind >= TYPE_F32 && type->type_kind <= TYPE_FXX; + return type->type_kind >= TYPE_F16 && type->type_kind <= TYPE_FXX; } static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span) @@ -1847,17 +1869,40 @@ static inline void advance_and_verify(Context *context, TokenType token_type) } +static inline Type *type_flatten_distinct(Type *type) +{ + type = type->canonical; + while (type->type_kind == TYPE_DISTINCT) + { + type = type->decl->distinct_decl.base_type->canonical; + } + return type; +} + static inline Type *type_flatten(Type *type) { type = type->canonical; - return type->type_kind == TYPE_DISTINCT ? type->decl->distinct_decl.base_type : type; + while (1) + { + if (type->type_kind == TYPE_DISTINCT) + { + type = type->decl->distinct_decl.base_type; + continue; + } + if (type->type_kind == TYPE_ENUM) + { + type = type->decl->enums.type_info->type; + continue; + } + return type; + } } static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; } -static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; } -static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; } +static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind < TYPE_U8; } +static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind < TYPE_IXX; } static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; } -static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I64; } -static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64; } +static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; } +static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX; } static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; } static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; } bool type_is_scalar(Type *type); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 1955742bf..cdea2c4bb 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -8,11 +8,8 @@ typedef enum { BINARYOP_ERROR, BINARYOP_MULT, - BINARYOP_MULT_MOD, BINARYOP_SUB, - BINARYOP_SUB_MOD, BINARYOP_ADD, - BINARYOP_ADD_MOD, BINARYOP_DIV, BINARYOP_MOD, BINARYOP_SHR, @@ -31,20 +28,17 @@ typedef enum BINARYOP_EQ, // Only "assign" BINOPS after this point BINARYOP_ASSIGN, - BINARYOP_MULT_ASSIGN, - BINARYOP_MULT_MOD_ASSIGN, BINARYOP_ADD_ASSIGN, - BINARYOP_ADD_MOD_ASSIGN, - BINARYOP_SUB_ASSIGN, - BINARYOP_SUB_MOD_ASSIGN, - BINARYOP_DIV_ASSIGN, - BINARYOP_MOD_ASSIGN, BINARYOP_BIT_AND_ASSIGN, BINARYOP_BIT_OR_ASSIGN, BINARYOP_BIT_XOR_ASSIGN, + BINARYOP_DIV_ASSIGN, + BINARYOP_MOD_ASSIGN, + BINARYOP_MULT_ASSIGN, BINARYOP_SHR_ASSIGN, BINARYOP_SHL_ASSIGN, - BINARYOP_LAST = BINARYOP_SHL_ASSIGN + BINARYOP_SUB_ASSIGN, + BINARYOP_LAST = BINARYOP_SUB_ASSIGN } BinaryOp; typedef enum @@ -96,12 +90,17 @@ typedef enum CAST_XIERR, CAST_PTRPTR, CAST_PTRXI, - CAST_VARRPTR, + CAST_PTRVAR, + CAST_VARPTR, + CAST_VARSA, + CAST_VARVAR, + CAST_VARBOOL, CAST_ARRPTR, CAST_STRPTR, CAST_PTRBOOL, CAST_BOOLINT, CAST_BOOLFP, + CAST_BOOLBOOL, CAST_FPBOOL, CAST_INTBOOL, CAST_CXBOOL, @@ -118,6 +117,8 @@ typedef enum CAST_ENUMLOW, CAST_APTSA, CAST_SAPTR, + CAST_SABOOL, + CAST_STST, } CastKind; typedef enum @@ -322,15 +323,12 @@ typedef enum TOKEN_LESS_EQ, // <= TOKEN_LBRAPIPE, // {| TOKEN_MINUS_ASSIGN, // -= - TOKEN_MINUS_MOD, // -% TOKEN_MINUSMINUS, // -- TOKEN_MOD_ASSIGN, // %= TOKEN_MULT_ASSIGN, // *= - TOKEN_MULT_MOD, // *% TOKEN_NOT_EQUAL, // != TOKEN_OR, // || TOKEN_PLUS_ASSIGN, // += - TOKEN_PLUS_MOD, // +% TOKEN_PLUSPLUS, // ++ TOKEN_RBRAPIPE, // |} TOKEN_SCOPE, // :: @@ -339,9 +337,6 @@ typedef enum // Three or more TOKEN_ELLIPSIS, // ... - TOKEN_MINUS_MOD_ASSIGN, // -%= - TOKEN_MULT_MOD_ASSIGN, // *%= - TOKEN_PLUS_MOD_ASSIGN, // +%= TOKEN_SHL_ASSIGN, // <<= TOKEN_SHR_ASSIGN, // >>= @@ -354,27 +349,20 @@ typedef enum TOKEN_HALF, TOKEN_ICHAR, TOKEN_INT, + TOKEN_IPTR, + TOKEN_IPTRDIFF, TOKEN_ISIZE, TOKEN_LONG, TOKEN_SHORT, TOKEN_UINT, TOKEN_ULONG, + TOKEN_UPTR, + TOKEN_UPTRDIFF, TOKEN_USHORT, TOKEN_USIZE, TOKEN_QUAD, TOKEN_TYPEID, - // C types - TOKEN_C_SHORT, - TOKEN_C_INT, - TOKEN_C_LONG, - TOKEN_C_LONGLONG, - TOKEN_C_USHORT, - TOKEN_C_UINT, - TOKEN_C_ULONG, - TOKEN_C_ULONGLONG, - - // Literals. TOKEN_IDENT, // Any normal ident. TOKEN_CONST_IDENT, // Any purely upper case ident, @@ -506,7 +494,7 @@ typedef enum TYPE_ERRTYPE, TYPE_ERR_UNION, TYPE_TYPEDEF, - TYPE_CTSTR, + TYPE_STRLIT, TYPE_DISTINCT, TYPE_ARRAY, TYPE_VARARRAY, @@ -534,7 +522,6 @@ typedef enum UNARYOP_DEREF, UNARYOP_ADDR, UNARYOP_NEG, - UNARYOP_NEGMOD, UNARYOP_BITNEG, UNARYOP_NOT, UNARYOP_INC, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 38cf5ea8f..79646660e 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -105,7 +105,7 @@ static void header_print_type(FILE *file, Type *type) break; case TYPE_TYPEDEF: break; - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_ARRAY: diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 304130d22..782b9291e 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -44,7 +44,7 @@ static inline void backtrack(Lexer *lexer) void lexer_store_line_end(Lexer *lexer) { lexer->current_line++; - lexer->line_start = lexer->current; + lexer->line_start = lexer->current + 1; source_file_append_line_end(lexer->current_file, lexer->current_file->start_id + lexer->current - lexer->file_begin); } @@ -129,7 +129,7 @@ static inline void add_generic_token(Lexer *lexer, TokenType type) // The simple case, where the parsing started on the current line. location->line = lexer->current_line; // Col is simple difference. - location->col = (unsigned)(lexer->lexing_start - lexer->line_start); + location->col = (unsigned)(lexer->lexing_start - lexer->line_start) + 1; // Start is offset to file begin. location->start = lexer->lexing_start - lexer->file_begin; // Length is diff between current and start. @@ -1066,11 +1066,6 @@ static bool lexer_scan_token_inner(Lexer *lexer, LexMode mode) } return match(lexer, '=') ? add_token(lexer, TOKEN_DIV_ASSIGN, "/=") : add_token(lexer, TOKEN_DIV, "/"); case '*': - if (match(lexer, '%')) - { - if (match(lexer, '=')) return add_token(lexer, TOKEN_MULT_MOD_ASSIGN, "*%="); - return add_token(lexer, TOKEN_MULT_MOD, "*%"); - } return match(lexer, '=') ? add_token(lexer, TOKEN_MULT_ASSIGN, "*=") : add_token(lexer, TOKEN_STAR, "*"); case '=': return match(lexer, '=') ? add_token(lexer, TOKEN_EQEQ, "==") : add_token(lexer, TOKEN_EQ, "="); @@ -1106,21 +1101,11 @@ static bool lexer_scan_token_inner(Lexer *lexer, LexMode mode) TOKEN_BIT_OR, "|"); case '+': - if (match(lexer, '%')) - { - if (match(lexer, '=')) return add_token(lexer, TOKEN_PLUS_MOD_ASSIGN, "+%="); - return add_token(lexer, TOKEN_PLUS_MOD, "+%"); - } if (match(lexer, '+')) return add_token(lexer, TOKEN_PLUSPLUS, "++"); if (match(lexer, '=')) return add_token(lexer, TOKEN_PLUS_ASSIGN, "+="); return add_token(lexer, TOKEN_PLUS, "+"); case '-': if (match(lexer, '>')) return add_token(lexer, TOKEN_ARROW, "->"); - if (match(lexer, '%')) - { - if (match(lexer, '=')) return add_token(lexer, TOKEN_MINUS_MOD_ASSIGN, "-%="); - return add_token(lexer, TOKEN_MINUS_MOD, "-%"); - } if (match(lexer, '-')) return add_token(lexer, TOKEN_MINUSMINUS, "--"); if (match(lexer, '=')) return add_token(lexer, TOKEN_MINUS_ASSIGN, "-="); return add_token(lexer, TOKEN_MINUS, "-"); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index ee7f0fd52..c899c6701 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -315,7 +315,7 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value) llvm_emit_load_aligned(c, pointer_type, pointer_addr, 0, "subarrptr"), value->type, alignment); return; } - case TYPE_CTSTR: + case TYPE_STRLIT: TODO case TYPE_VARARRAY: default: diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index b1c3f2391..ba2110154 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -438,7 +438,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_VOID: @@ -632,7 +632,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_INFERRED_ARRAY: UNREACHABLE case TYPE_I128: diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index c1fb0bde8..73d688048 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -116,7 +116,7 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_TYPEINFO: case TYPE_DISTINCT: case TYPE_ENUM: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_INFERRED_ARRAY: UNREACHABLE case ALL_INTS: @@ -593,7 +593,7 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type * case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEID: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_INFERRED_ARRAY: UNREACHABLE case ALL_FLOATS: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 4e1675e29..4b44ff244 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -530,7 +530,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * TODO case TYPE_TYPEDEF: return type->backend_debug_type = llvm_debug_typedef_type(c, type); - case TYPE_CTSTR: + case TYPE_STRLIT: TODO case TYPE_ARRAY: return type->backend_debug_type = llvm_debug_array_type(c, type); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 3c7afa2d8..b56d832bc 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -32,14 +32,9 @@ LLVMValueRef llvm_emit_const_padding(GenContext *c, ByteSize size) return LLVMGetUndef(llvm_const_padding_type(c, size)); } -static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right) +static inline LLVMValueRef llvm_emit_add_int(GenContext *context, Type *type, LLVMValueRef left, LLVMValueRef right) { - if (use_mod) - { - return LLVMBuildAdd(context->builder, left, right, "add_mod"); - } - - if (build_options.debug_mode) + if (build_options.trap_wrapping) { LLVMTypeRef type_to_use = llvm_get_type(context, type->canonical); LLVMValueRef args[2] = { left, right }; @@ -58,9 +53,8 @@ static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *ty llvm_emit_panic_on_true(context, ok, "Addition overflow"); return result; } - return type_is_integer_unsigned(type) - ? LLVMBuildNUWAdd(context->builder, left, right, "uadd") - : LLVMBuildNSWAdd(context->builder, left, right, "add"); + + return LLVMBuildAdd(context->builder, left, right, "add"); } LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type) @@ -99,14 +93,10 @@ LLVMValueRef llvm_emit_convert_value_from_coerced(GenContext *context, LLVMTypeR return llvm_emit_load_aligned(context, llvm_get_type(context, original_type), temp, max_align, "coerced"); } -static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right) +static inline LLVMValueRef +llvm_emit_sub_int(GenContext *context, Type *type, LLVMValueRef left, LLVMValueRef right) { - if (use_mod) - { - return LLVMBuildSub(context->builder, left, right, "sub_mod"); - } - - if (build_options.debug_mode) + if (build_options.trap_wrapping) { LLVMTypeRef type_to_use = llvm_get_type(context, type); LLVMValueRef args[2] = { left, right }; @@ -126,10 +116,7 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty return result; } - - return type_is_integer_unsigned(type) - ? LLVMBuildNUWSub(context->builder, left, right, "usub") - : LLVMBuildNSWSub(context->builder, left, right, "sub"); + return LLVMBuildSub(context->builder, left, right, "sub"); } static inline void llvm_emit_subscript_addr_base(GenContext *context, BEValue *value, Expr *parent) @@ -227,7 +214,7 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, case TYPE_VARARRAY: // TODO insert trap on overflow. TODO - case TYPE_CTSTR: + case TYPE_STRLIT: // TODO insert trap on overflow. return LLVMBuildInBoundsGEP(c->builder, parent->value, &index->value, 1, "ptridx"); default: @@ -354,8 +341,11 @@ LLVMValueRef gencontext_emit_value_bitcast(GenContext *context, LLVMValueRef val } -static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type) +void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type) { + to_type = type_flatten(to_type); + from_type = type_flatten(from_type); + switch (cast_kind) { case CAST_CXBOOL: @@ -363,7 +353,7 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind case CAST_XIERR: // TODO Insert zero check. llvm_value_rvalue(c, value); - return value->value; + break; case CAST_ERROR: UNREACHABLE case CAST_STRPTR: @@ -371,36 +361,47 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind llvm_value_rvalue(c, value); if (c->builder) { - return LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr"); + value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr"); } - return LLVMConstPointerCast(value->value, llvm_get_type(c, to_type)); + else + { + value->value = LLVMConstPointerCast(value->value, llvm_get_type(c, to_type)); + } + break; case CAST_PTRXI: llvm_value_rvalue(c, value); if (c->builder) { - return LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi"); + value->value = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi"); } - return LLVMConstBitCast(value->value, llvm_get_type(c, to_type)); + else + { + value->value = LLVMConstBitCast(value->value, llvm_get_type(c, to_type)); + } + break; case CAST_APTSA: gencontext_emit_arr_to_subarray_cast(c, value, to_type, from_type); - return value->value; + break; case CAST_SAPTR: if (llvm_value_is_addr(value)) { llvm_value_fold_failable(c, value); - return llvm_emit_load_aligned(c, llvm_get_type(c, to_type), - LLVMBuildStructGEP(c->builder, value->value, 0, ""), - value->alignment, ""); + value->value = llvm_emit_load_aligned(c, llvm_get_type(c, to_type), + LLVMBuildStructGEP(c->builder, value->value, 0, ""), + value->alignment, ""); } - return LLVMBuildExtractValue(c->builder, value->value, 0, ""); - case CAST_VARRPTR: - return value->value; + else + { + value->value = LLVMBuildExtractValue(c->builder, value->value, 0, ""); + } + break; + case CAST_VARPTR: + break; case CAST_ARRPTR: TODO case CAST_EREU: case CAST_EUER: - TODO - return gencontext_emit_value_bitcast(c, value->value, to_type, from_type); + TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type); case CAST_EUBOOL: if (value->kind == BE_VALUE) { @@ -415,76 +416,103 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind type_abi_alignment(type_usize), ""); } - return LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, type_usize), "eubool"); + value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, type_usize), "eubool"); + value->kind = BE_BOOLEAN; + break; case CAST_PTRBOOL: llvm_value_rvalue(c, value); - return LLVMBuildIsNotNull(c->builder, value->value, "ptrbool"); + value->value = LLVMBuildIsNotNull(c->builder, value->value, "ptrbool"); + value->kind = BE_BOOLEAN; + break; case CAST_BOOLINT: llvm_value_rvalue(c, value); - return LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "boolsi"); + value->value = LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "boolsi"); + value->kind = BE_VALUE; + break; case CAST_FPBOOL: llvm_value_rvalue(c, value); - return LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, from_type), "fpbool"); + value->value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, from_type), "fpbool"); + value->kind = BE_BOOLEAN; + break; case CAST_BOOLFP: llvm_value_rvalue(c, value); - return LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp"); + value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp"); + value->kind = BE_VALUE; + break; case CAST_INTBOOL: llvm_value_rvalue(c, value); - return LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool"); + value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool"); + value->kind = BE_BOOLEAN; + break; case CAST_FPFP: llvm_value_rvalue(c, value); - return type_convert_will_trunc(to_type, from_type) + value->value = type_convert_will_trunc(to_type, from_type) ? LLVMBuildFPTrunc(c->builder, value->value, llvm_get_type(c, to_type), "fpfptrunc") : LLVMBuildFPExt(c->builder, value->value, llvm_get_type(c, to_type), "fpfpext"); + break; case CAST_FPSI: llvm_value_rvalue(c, value); - return LLVMBuildFPToSI(c->builder, value->value, llvm_get_type(c, to_type), "fpsi"); + value->value = LLVMBuildFPToSI(c->builder, value->value, llvm_get_type(c, to_type), "fpsi"); + break; case CAST_FPUI: llvm_value_rvalue(c, value); - return LLVMBuildFPToUI(c->builder, value->value, llvm_get_type(c, to_type), "fpui"); + value->value = LLVMBuildFPToUI(c->builder, value->value, llvm_get_type(c, to_type), "fpui"); + break; case CAST_SISI: llvm_value_rvalue(c, value); - return type_convert_will_trunc(to_type, from_type) + value->value = type_convert_will_trunc(to_type, from_type) ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "sisitrunc") : LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "sisiext"); + break; case CAST_SIUI: llvm_value_rvalue(c, value); - return type_convert_will_trunc(to_type, from_type) + value->value = type_convert_will_trunc(to_type, from_type) ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "siuitrunc") : LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "siuiext"); + break; case CAST_SIFP: llvm_value_rvalue(c, value); - return LLVMBuildSIToFP(c->builder, value->value, llvm_get_type(c, to_type), "sifp"); + value->value = LLVMBuildSIToFP(c->builder, value->value, llvm_get_type(c, to_type), "sifp"); + break; case CAST_XIPTR: llvm_value_rvalue(c, value); - return LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr"); + value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr"); + break; case CAST_UISI: llvm_value_rvalue(c, value); - return type_convert_will_trunc(to_type, from_type) + value->value = type_convert_will_trunc(to_type, from_type) ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uisitrunc") : LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uisiext"); + break; case CAST_UIUI: llvm_value_rvalue(c, value); - return type_convert_will_trunc(to_type, from_type) + value->value = type_convert_will_trunc(to_type, from_type) ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uiuitrunc") : LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uiuiext"); + break; case CAST_UIFP: llvm_value_rvalue(c, value); - return LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "uifp"); + value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "uifp"); + break; case CAST_ENUMLOW: llvm_value_rvalue(c, value); - return value->value; + value->value = value->value; + break; + case CAST_STST: + llvm_value_addr(c, value); + value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), ""); + value->type = to_type; + return; + case CAST_PTRVAR: + case CAST_VARSA: + case CAST_VARVAR: + case CAST_VARBOOL: + case CAST_BOOLBOOL: + case CAST_SABOOL: + TODO + break; } - UNREACHABLE -} - -void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type) -{ - to_type = type_flatten(to_type); - from_type = type_flatten(from_type); - value->value = gencontext_emit_cast_inner(c, cast_kind, value, to_type, from_type); - value->type = type_flatten(to_type); - value->kind = value->type->type_kind == TYPE_BOOL ? BE_BOOLEAN : BE_VALUE; + value->type = to_type; } static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_value, Expr *expr) @@ -954,8 +982,8 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue LLVMTypeRef llvm_type = llvm_get_type(c, type); LLVMValueRef diff_value = LLVMConstInt(llvm_type, 1, false); after_value = diff > 0 - ? gencontext_emit_add_int(c, type, use_mod, value.value, diff_value) - : gencontext_emit_sub_int(c, type, use_mod, value.value, diff_value); + ? llvm_emit_add_int(c, type, value.value, diff_value) + : llvm_emit_sub_int(c, type, value.value, diff_value); break; } default: @@ -1036,11 +1064,6 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_value_rvalue(c, value); value->value = LLVMBuildNot(c->builder, value->value, "bnot"); return; - case UNARYOP_NEGMOD: - llvm_emit_expr(c, value, expr->unary_expr.expr); - llvm_value_rvalue(c, value); - value->value = LLVMBuildNeg(c->builder, value->value, "negmod"); - return; case UNARYOP_NEG: llvm_emit_expr(c, value, expr->unary_expr.expr); llvm_value_rvalue(c, value); @@ -1053,7 +1076,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr assert(!type_is_unsigned(type)); { LLVMValueRef zero = llvm_get_zero(c, expr->unary_expr.expr->type); - if (build_options.debug_mode) + if (build_options.trap_wrapping) { // TODO LLVMTypeRef type_to_use = llvm_get_type(c, type->canonical); @@ -1065,7 +1088,9 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_emit_panic_on_true(c, ok, "Signed negation overflow"); return; } - value->value = LLVMBuildNSWSub(c->builder, zero, value->value, "neg"); + llvm_emit_expr(c, value, expr->unary_expr.expr); + llvm_value_rvalue(c, value); + value->value = LLVMBuildNeg(c->builder, value->value, "neg"); return; } case UNARYOP_ADDR: @@ -1109,7 +1134,7 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l case TYPE_ARRAY: llvm_value_set(be_value, llvm_const_int(c, type_usize, expr_to_len->type->array.len), type_usize); break; - case TYPE_CTSTR: + case TYPE_STRLIT: TODO break; @@ -1163,7 +1188,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ parent_base = parent_addr; break; case TYPE_VARARRAY: - case TYPE_CTSTR: + case TYPE_STRLIT: TODO default: UNREACHABLE @@ -1193,7 +1218,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ len = llvm_const_int(context, type_usize, parent_type->array.len); break; case TYPE_VARARRAY: - case TYPE_CTSTR: + case TYPE_STRLIT: TODO default: UNREACHABLE @@ -1203,7 +1228,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ // Walk from end if it is slice from the back. if (slice->slice_expr.start_from_back) { - start_index.value = gencontext_emit_sub_int(context, start_type, false, len, start_index.value); + start_index.value = llvm_emit_sub_int(context, start_type, len, start_index.value); } // Check that index does not extend beyond the length. @@ -1238,7 +1263,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ // Reverse if it is "from back" if (slice->slice_expr.end_from_back) { - end_index.value = gencontext_emit_sub_int(context, end_type, false, len, end_index.value); + end_index.value = llvm_emit_sub_int(context, end_type, len, end_index.value); llvm_value_rvalue(context, &end_index); } @@ -1385,7 +1410,7 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr llvm_store_bevalue_aligned(c, target, be_value, 0); // Create the new offset - LLVMValueRef next_offset = gencontext_emit_add_int(c, start_type, false, offset, llvm_const_int(c, start_type, 1)); + LLVMValueRef next_offset = llvm_emit_add_int(c, start_type, offset, llvm_const_int(c, start_type, 1)); // And jump back llvm_emit_br(c, cond_block); @@ -1576,6 +1601,44 @@ LLVMValueRef llvm_emit_int_comparison(GenContext *c, Type *lhs_type, Type *rhs_t } +static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left, LLVMValueRef right) +{ + LLVMTypeRef left_type = LLVMTypeOf(left); + LLVMTypeRef right_type = LLVMTypeOf(right); + if (left_type == right_type) return right; + if (LLVMStoreSizeOfType(build_target.target, left_type) < LLVMStoreSizeOfType(build_target.target, right_type)) + { + return LLVMBuildTrunc(c->builder, right, left_type, ""); + } + else + { + return LLVMBuildZExt(c->builder, right, left_type, ""); + } +} + +static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right) +{ + if (build_options.trap_wrapping) + { + LLVMTypeRef type_to_use = llvm_get_type(c, type); + LLVMValueRef args[2] = { left, right }; + LLVMTypeRef types[2] = { type_to_use, type_to_use }; + unsigned operation = type_is_integer_unsigned(type) ? intrinsic_id_umul_overflow + : intrinsic_id_smul_overflow; + LLVMValueRef call_res = llvm_emit_call_intrinsic(c, + operation, + types, + 1, + args, + 2); + LLVMValueRef val = LLVMBuildExtractValue(c->builder, call_res, 0, "mul"); + LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); + llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow"); + return val; + } + return LLVMBuildMul(c->builder, left, right, "mul"); +} + static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_addr, BinaryOp binary_op) { @@ -1627,50 +1690,9 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, val = LLVMBuildFMul(c->builder, lhs_value, rhs_value, "fmul"); break; } - if (type_is_integer_unsigned(lhs_type)) - { - if (build_options.debug_mode) - { - LLVMTypeRef type_to_use = llvm_get_type(c, lhs_type); - LLVMValueRef args[2] = { lhs_value, rhs_value }; - LLVMTypeRef types[2] = { type_to_use, type_to_use }; - LLVMValueRef call_res = llvm_emit_call_intrinsic(c, - intrinsic_id_umul_overflow, - types, - 1, - args, - 2); - val = LLVMBuildExtractValue(c->builder, call_res, 0, ""); - LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); - llvm_emit_panic_on_true(c, ok, "Unsigned multiplication overflow"); - break; - } - val = LLVMBuildNUWMul(c->builder, lhs_value, rhs_value, "umul"); - break; - } - if (build_options.debug_mode) - { - LLVMTypeRef type_to_use = llvm_get_type(c, lhs_type); - LLVMValueRef args[2] = { lhs_value, rhs_value }; - LLVMTypeRef types[2] = { type_to_use, type_to_use }; - LLVMValueRef call_res = llvm_emit_call_intrinsic(c, - intrinsic_id_smul_overflow, - types, - 1, - args, - 2); - val = LLVMBuildExtractValue(c->builder, call_res, 0, ""); - LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); - llvm_emit_panic_on_true(c, ok, "Signed multiplication overflow"); - break; - } - val = LLVMBuildNSWMul(c->builder, lhs_value, rhs_value, "mul"); - break; - case BINARYOP_MULT_MOD: - val = LLVMBuildMul(c->builder, lhs_value, rhs_value, "mul"); + val = llvm_emit_mult_int(c, lhs_type, lhs_value, rhs_value); break; case BINARYOP_SUB: - case BINARYOP_SUB_MOD: if (lhs_type->type_kind == TYPE_POINTER) { if (lhs_type == rhs_type) @@ -1687,10 +1709,9 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, val = LLVMBuildFSub(c->builder, lhs_value, rhs_value, "fsub"); break; } - val = gencontext_emit_sub_int(c, lhs_type, binary_op == BINARYOP_SUB_MOD, lhs_value, rhs_value); + val = llvm_emit_sub_int(c, lhs_type, lhs_value, rhs_value); break; case BINARYOP_ADD: - case BINARYOP_ADD_MOD: if (lhs_type->type_kind == TYPE_POINTER) { assert(type_is_integer(rhs_type)); @@ -1702,7 +1723,7 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, val = LLVMBuildFAdd(c->builder, lhs_value, rhs_value, "fadd"); break; } - val = gencontext_emit_add_int(c, lhs_type, binary_op == BINARYOP_ADD_MOD, lhs_value, rhs_value); + val = llvm_emit_add_int(c, lhs_type, lhs_value, rhs_value); break; case BINARYOP_DIV: if (is_float) @@ -1720,11 +1741,13 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, : LLVMBuildSRem(c->builder, lhs_value, rhs_value, "smod"); break; case BINARYOP_SHR: + rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value); val = type_is_unsigned(lhs_type) ? LLVMBuildLShr(c->builder, lhs_value, rhs_value, "lshr") : LLVMBuildAShr(c->builder, lhs_value, rhs_value, "ashr"); break; case BINARYOP_SHL: + rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value); val = LLVMBuildShl(c->builder, lhs_value, rhs_value, "shl"); break; case BINARYOP_BIT_AND: @@ -1766,11 +1789,8 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, case BINARYOP_OR: case BINARYOP_ASSIGN: case BINARYOP_MULT_ASSIGN: - case BINARYOP_MULT_MOD_ASSIGN: case BINARYOP_ADD_ASSIGN: - case BINARYOP_ADD_MOD_ASSIGN: case BINARYOP_SUB_ASSIGN: - case BINARYOP_SUB_MOD_ASSIGN: case BINARYOP_DIV_ASSIGN: case BINARYOP_MOD_ASSIGN: case BINARYOP_BIT_AND_ASSIGN: @@ -2156,15 +2176,16 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) case TYPE_BOOL: llvm_value_set_bool(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0)); return; - case TYPE_CTSTR: + case TYPE_STRLIT: { - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_ichar), expr->const_expr.string.len + 1), ""); + LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), expr->const_expr.string.len + 1), ""); LLVMSetLinkage(global_name, LLVMInternalLinkage); LLVMSetGlobalConstant(global_name, 1); LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context, expr->const_expr.string.chars, expr->const_expr.string.len, 0)); + global_name = LLVMConstBitCast(global_name, LLVMPointerType(llvm_get_type(c, type_char), 0)); llvm_value_set(be_value, global_name, type); return; } @@ -2216,7 +2237,7 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_INFERRED_ARRAY: UNREACHABLE break; diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index c4f7f2b7e..de917c127 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -366,7 +366,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U); case TYPE_POINTER: return any_type->backend_type = llvm_type_from_ptr(c, any_type); - case TYPE_CTSTR: + case TYPE_STRLIT: return any_type->backend_type = LLVMPointerType(llvm_get_type(c, type_char), 0); case TYPE_ARRAY: return any_type->backend_type = llvm_type_from_array(c, any_type); diff --git a/src/compiler/number.c b/src/compiler/number.c index 41fce52a5..1a2db1369 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -61,7 +61,7 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr) case TYPE_FXX: fprintf(file, "%Lf", expr->f); break; - case TYPE_CTSTR: + case TYPE_STRLIT: fprintf(file, "%.*s", expr->string.len, expr->string.chars); break; default: @@ -173,7 +173,7 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp return compare_fps(left->f, right->f, op); case TYPE_POINTER: return true; - case TYPE_CTSTR: + case TYPE_STRLIT: if (left->string.len != right->string.len) { is_eq = false; @@ -193,9 +193,9 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp return (op == BINARYOP_EQ) && is_eq; } -bool expr_const_int_overflowed(const ExprConst *expr) +bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind) { - switch (expr->kind) + switch (kind) { case TYPE_I8: return !bigint_fits_in_bits(&expr->i, 8, true); @@ -206,19 +206,31 @@ bool expr_const_int_overflowed(const ExprConst *expr) case TYPE_I64: return !bigint_fits_in_bits(&expr->i, 64, true); case TYPE_U8: - return !bigint_fits_in_bits(&expr->i, 8, false); + return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 8, false); case TYPE_U16: - return !bigint_fits_in_bits(&expr->i, 16, false); + return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 16, false); case TYPE_U32: - return !bigint_fits_in_bits(&expr->i, 32, false); + return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 32, false); case TYPE_U64: - return !bigint_fits_in_bits(&expr->i, 64, false); + return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 64, false); + case TYPE_F16: + return !bigint_fits_in_bits(&expr->i, 17, false); case TYPE_IXX: + case TYPE_F32: + case TYPE_F64: + case TYPE_F128: + case TYPE_FXX: + case TYPE_BOOL: return false; default: UNREACHABLE } } + +bool expr_const_int_overflowed(const ExprConst *expr) +{ + return expr_const_will_overflow(expr, expr->kind); +} const char *expr_const_to_error_string(const ExprConst *expr) { char *buff = NULL; @@ -243,7 +255,7 @@ const char *expr_const_to_error_string(const ExprConst *expr) case TYPE_FXX: asprintf(&buff, "%Lf", expr->f); return buff; - case TYPE_CTSTR: + case TYPE_STRLIT: asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars); return buff; default: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index b1de6033d..1e1898e41 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -476,7 +476,7 @@ static Expr *parse_subscript_expr(Context *context, Expr *left) else { index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); - index->type = type_uint; + expr_set_type(index, type_uint); index->constant = true; index->resolve_status = RESOLVE_DONE; expr_const_set_int(&index->const_expr, 0, type_uint->type_kind); @@ -711,7 +711,7 @@ static Expr *parse_integer(Context *context, Expr *left) break; } expr_int->const_expr.kind = TYPE_IXX; - expr_int->type = type_compint; + expr_set_type(expr_int, type_compint); advance(context); return expr_int; } @@ -725,19 +725,19 @@ static Expr *parse_char_lit(Context *context, Expr *left) { case 1: expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_IXX); - expr_int->type = type_compint; + expr_set_type(expr_int, type_compint); break; case 2: expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_IXX); - expr_int->type = type_compint; + expr_set_type(expr_int, type_compint); break; case 4: expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_IXX); - expr_int->type = type_compint; + expr_set_type(expr_int, type_compint); break; case 8: expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64); - expr_int->type = type_ulong; + expr_set_type(expr_int, type_compint); break; default: UNREACHABLE @@ -753,7 +753,7 @@ static Expr *parse_double(Context *context, Expr *left) assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); number->const_expr.f = TOKREAL(context->tok.id); - number->type = type_compfloat; + expr_set_type(number, type_compfloat); number->const_expr.kind = TYPE_FXX; advance(context); return number; @@ -855,7 +855,7 @@ static Expr *parse_string_literal(Context *context, Expr *left) { assert(!left && "Had left hand side"); Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); - expr_string->type = type_compstr; + expr_set_type(expr_string, type_compstr); char *str = NULL; size_t len = 0; @@ -889,8 +889,8 @@ static Expr *parse_string_literal(Context *context, Expr *left) str[len] = '\0'; expr_string->const_expr.string.chars = str; expr_string->const_expr.string.len = len; - expr_string->type = type_compstr; - expr_string->const_expr.kind = TYPE_CTSTR; + expr_set_type(expr_string, type_compstr); + expr_string->const_expr.kind = TYPE_STRLIT; return expr_string; } @@ -899,7 +899,7 @@ static Expr *parse_bool(Context *context, Expr *left) assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .kind = TYPE_BOOL }; - number->type = type_bool; + expr_set_type(number, type_bool); advance(context); return number; } @@ -909,7 +909,7 @@ static Expr *parse_null(Context *context, Expr *left) assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); number->const_expr.kind = TYPE_POINTER; - number->type = type_voidptr; + expr_set_type(number, type_voidptr); advance(context); return number; } @@ -995,6 +995,10 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_ULONG] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_ISIZE] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_USIZE] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_IPTR] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_UPTR] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_IPTRDIFF] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_UPTRDIFF] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_FLOAT] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_DOUBLE] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_HALF] = { parse_type_identifier, NULL, PREC_NONE }, @@ -1016,13 +1020,10 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_BANGBANG] = { NULL, parse_bangbang_expr, PREC_CALL }, [TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL }, [TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, - [TOKEN_MINUS_MOD] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, [TOKEN_PLUS] = { NULL, parse_binary, PREC_ADDITIVE }, - [TOKEN_PLUS_MOD] = { NULL, parse_binary, PREC_ADDITIVE }, [TOKEN_DIV] = { NULL, parse_binary, PREC_MULTIPLICATIVE }, [TOKEN_MOD] = { NULL, parse_binary, PREC_MULTIPLICATIVE }, [TOKEN_STAR] = { parse_unary_expr, parse_binary, PREC_MULTIPLICATIVE }, - [TOKEN_MULT_MOD] = { NULL, parse_binary, PREC_MULTIPLICATIVE }, [TOKEN_DOT] = { NULL, parse_access_expr, PREC_CALL }, [TOKEN_BANG] = { parse_unary_expr, parse_failable, PREC_UNARY }, [TOKEN_BIT_NOT] = { parse_unary_expr, NULL, PREC_UNARY }, @@ -1049,11 +1050,8 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_AND] = { parse_unary_expr, parse_binary, PREC_LOGICAL }, [TOKEN_EQ] = { NULL, parse_binary, PREC_ASSIGNMENT }, [TOKEN_PLUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, - [TOKEN_PLUS_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, [TOKEN_MINUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, - [TOKEN_MINUS_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, [TOKEN_MULT_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, - [TOKEN_MULT_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, [TOKEN_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, [TOKEN_DIV_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, [TOKEN_BIT_XOR_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT }, diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 5c7c1c0d7..7e01ea41d 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -506,6 +506,12 @@ static inline TypeInfo *parse_base_type(Context *context) case TOKEN_INT: type_found = type_int; break; + case TOKEN_IPTR: + type_found = type_iptr; + break; + case TOKEN_IPTRDIFF: + type_found = type_iptrdiff; + break; case TOKEN_ISIZE: type_found = type_isize; break; @@ -521,36 +527,18 @@ static inline TypeInfo *parse_base_type(Context *context) case TOKEN_ULONG: type_found = type_ulong; break; + case TOKEN_UPTR: + type_found = type_uptr; + break; + case TOKEN_UPTRDIFF: + type_found = type_uptrdiff; + break; case TOKEN_USHORT: type_found = type_ushort; break; case TOKEN_USIZE: type_found = type_usize; break; - case TOKEN_C_SHORT: - type_found = type_c_short; - break; - case TOKEN_C_INT: - type_found = type_c_int; - break; - case TOKEN_C_LONG: - type_found = type_c_long; - break; - case TOKEN_C_LONGLONG: - type_found = type_c_longlong; - break; - case TOKEN_C_USHORT: - type_found = type_c_ushort; - break; - case TOKEN_C_UINT: - type_found = type_c_uint; - break; - case TOKEN_C_ULONG: - type_found = type_c_ulong; - break; - case TOKEN_C_ULONGLONG: - type_found = type_c_ulonglong; - break; case TOKEN_TYPEID: type_found = type_typeid; break; @@ -890,14 +878,6 @@ bool parse_next_is_decl(Context *context) case TOKEN_USHORT: case TOKEN_USIZE: case TOKEN_QUAD: - case TOKEN_C_SHORT: - case TOKEN_C_INT: - case TOKEN_C_LONG: - case TOKEN_C_LONGLONG: - case TOKEN_C_USHORT: - case TOKEN_C_UINT: - case TOKEN_C_ULONG: - case TOKEN_C_ULONGLONG: case TOKEN_TYPE_IDENT: case TOKEN_CT_TYPE_IDENT: case TOKEN_ERR: @@ -934,14 +914,6 @@ bool parse_next_is_case_type(Context *context) case TOKEN_USHORT: case TOKEN_USIZE: case TOKEN_QUAD: - case TOKEN_C_SHORT: - case TOKEN_C_INT: - case TOKEN_C_LONG: - case TOKEN_C_LONGLONG: - case TOKEN_C_USHORT: - case TOKEN_C_UINT: - case TOKEN_C_ULONG: - case TOKEN_C_ULONGLONG: case TOKEN_TYPE_IDENT: case TOKEN_CT_TYPE_IDENT: case TOKEN_ERR: diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index a084c0764..a29f6f1b8 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -976,14 +976,10 @@ Ast *parse_stmt(Context *context) case TOKEN_ULONG: case TOKEN_USHORT: case TOKEN_USIZE: - case TOKEN_C_SHORT: - case TOKEN_C_INT: - case TOKEN_C_LONG: - case TOKEN_C_LONGLONG: - case TOKEN_C_USHORT: - case TOKEN_C_UINT: - case TOKEN_C_ULONG: - case TOKEN_C_ULONGLONG: + case TOKEN_IPTRDIFF: + case TOKEN_UPTRDIFF: + case TOKEN_IPTR: + case TOKEN_UPTR: case TOKEN_TYPEID: case TOKEN_CT_TYPE_IDENT: case TOKEN_HASH_TYPE_IDENT: @@ -1108,9 +1104,6 @@ Ast *parse_stmt(Context *context) case TOKEN_BIT_AND_ASSIGN: case TOKEN_BIT_OR_ASSIGN: case TOKEN_BIT_XOR_ASSIGN: - case TOKEN_PLUS_MOD: - case TOKEN_MINUS_MOD: - case TOKEN_MULT_MOD: case TOKEN_DIV_ASSIGN: case TOKEN_DOTDOT: case TOKEN_ELVIS: @@ -1126,9 +1119,6 @@ Ast *parse_stmt(Context *context) case TOKEN_SCOPE: case TOKEN_SHR: case TOKEN_SHL: - case TOKEN_MULT_MOD_ASSIGN: - case TOKEN_PLUS_MOD_ASSIGN: - case TOKEN_MINUS_MOD_ASSIGN: case TOKEN_SHR_ASSIGN: case TOKEN_SHL_ASSIGN: case TOKEN_ALIAS: diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 220a79e54..eaf67bc6c 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -6,14 +6,12 @@ #include "bigint.h" #define EXIT_T_MISMATCH() return sema_type_mismatch(context, left, canonical, cast_type) -#define IS_EXPLICT() -#define RETURN_NON_CONST_CAST(kind) do { if (left->expr_kind != EXPR_CONST) { insert_cast(left, kind, type); return true; } } while (0) -#define REQUIRE_EXPLICIT_CAST(_cast_type)\ - do { if (_cast_type == CAST_TYPE_EXPLICIT) break;\ - if (_cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;\ - EXIT_T_MISMATCH(); } while (0) -static inline void insert_cast(Expr *expr, CastKind kind, Type *type) +#define FLOAT32_LIMIT 340282346638528859811704183484516925440.0000000000000000 +#define FLOAT64_LIMIT 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0000000000000000 +#define FLOAT16_LIMIT 65504 + +static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) { assert(expr->resolve_status == RESOLVE_DONE); assert(expr->type); @@ -22,7 +20,14 @@ static inline void insert_cast(Expr *expr, CastKind kind, Type *type) expr->cast_expr.kind = kind; expr->cast_expr.expr = inner; expr->cast_expr.type_info = NULL; - expr->type = type; + expr_set_type(expr, type); + return true; +} + +static inline bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) +{ + if (expr->expr_kind == EXPR_CONST) return false; + return insert_cast(expr, kind, type); } static bool sema_type_mismatch(Context *context, Expr *expr, Type *type, CastType cast_type) @@ -70,34 +75,23 @@ static bool sema_type_mismatch(Context *context, Expr *expr, Type *type, CastTyp return false; } - -bool erro(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool pointer_to_integer(Expr *expr, Type *type) { - EXIT_T_MISMATCH(); -} - -bool ptxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - REQUIRE_EXPLICIT_CAST(cast_type); - - RETURN_NON_CONST_CAST(CAST_PTRXI); - assert(left->const_expr.kind == TYPE_POINTER); - expr_const_set_int(&left->const_expr, 0, type->type_kind); - left->type = type; + if (insert_runtime_cast_unless_const(expr, CAST_PTRXI, type)) return true; + // Must have been a null + expr_const_set_int(&expr->const_expr, 0, TYPE_POINTER); + expr_set_type(expr, type); return true; } - -bool ptbo(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +bool pointer_to_bool(Expr *expr, Type *type) { - RETURN_NON_CONST_CAST(CAST_PTRBOOL); - - assert(left->const_expr.kind == TYPE_POINTER); - left->const_expr.b = false; - - left->type = type; + if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return true; + // Must have been a null + expr->const_expr.b = false; + expr_set_type(expr, type); return true; } @@ -121,126 +115,66 @@ static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *targ return false; } - -bool stst(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool pointer_to_pointer(Expr* expr, Type *type) { - TODO -} + if (insert_runtime_cast_unless_const(expr, CAST_PTRPTR, type)) return true; -bool unst(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool stun(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool unun(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool arpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool arsa(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool ptpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - if (cast_type != CAST_TYPE_EXPLICIT && !may_implicitly_cast_ptr_to_ptr(from_canonical, canonical)) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(context, left, type, cast_type); - } - RETURN_NON_CONST_CAST(CAST_PTRPTR); - assert(left->const_expr.kind == TYPE_POINTER); - left->type = type; + // Must have been a null + expr_set_type(expr, type); return true; } -bool strpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - if (canonical->array.base->type_kind != TYPE_U8 && cast_type != CAST_TYPE_EXPLICIT) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(context, left, type, cast_type); - } - insert_cast(left, CAST_STRPTR, type); - return true; -} -bool strsa(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool string_literal_to_subarray(Expr* left, Type *type) { - if (canonical->array.base->type_kind != TYPE_U8) return false; Type *array_type = type_get_array(type_char, left->const_expr.string.len); insert_cast(left, CAST_STRPTR, type_get_ptr(array_type)); insert_cast(left, CAST_APTSA, type); return true; } -bool stpt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +static void const_int_to_fp_cast(Expr *expr, Type *canonical, Type *type) { - if (canonical->pointer != type_ichar && canonical->pointer != type_char) - { - return sema_type_mismatch(context, left, type, cast_type); - } - left->type = canonical; - return true; -} - -void const_int_to_fp_cast(Context *context, Expr *left, Type *canonical, Type *type) -{ - long double f = bigint_as_float(&left->const_expr.i); + long double f = bigint_as_float(&expr->const_expr.i); switch (canonical->type_kind) { case TYPE_F32: - left->const_expr.f = (float)f; + expr->const_expr.f = (float)f; break; case TYPE_F64: - left->const_expr.f = (double)f; + expr->const_expr.f = (double)f; break; default: - left->const_expr.f = f; + expr->const_expr.f = f; break; } - left->type = type; - left->const_expr.kind = canonical->type_kind; + expr_set_type(expr, type); + expr->const_expr.kind = canonical->type_kind; } + /** - * Bool into a signed or unsigned int. Explicit conversions only. - * @return true unless this is not an explicit conversion. + * Bool into a signed or unsigned int. */ -bool boxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +bool bool_to_int(Expr *expr, Type *canonical, Type *type) { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); - RETURN_NON_CONST_CAST(CAST_BOOLINT); - assert(left->const_expr.kind == TYPE_BOOL); - expr_const_set_int(&left->const_expr, left->const_expr.b ? 1 : 0, canonical->type_kind); - left->type = type; + if (insert_runtime_cast_unless_const(expr, CAST_BOOLINT, type)) return true; + expr_const_set_int(&expr->const_expr, expr->const_expr.b ? 1 : 0, canonical->type_kind); + expr_set_type(expr, type); return true; } -/** - * Bool into a float. Explicit conversions only. - * @return true unless this is not an explicit conversion. - */ -bool bofp(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ -// if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); - RETURN_NON_CONST_CAST(CAST_BOOLFP); - assert(left->const_expr.kind == TYPE_BOOL); - expr_const_set_float(&left->const_expr, left->const_expr.b ? 1.0 : 0.0, canonical->type_kind); - left->type = type; +/** + * Cast bool to float. + */ +bool bool_to_float(Expr *expr, Type *canonical, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_BOOLFP, type)) return true; + + assert(expr->const_expr.kind == TYPE_BOOL); + expr_const_set_float(&expr->const_expr, expr->const_expr.b ? 1.0 : 0.0, canonical->type_kind); + expr_set_type(expr, type); return true; } @@ -248,74 +182,63 @@ bool bofp(Context *context, Expr *left, Type *canonical, Type *type, CastType ca * Convert from any into to bool. * @return true for any implicit conversion except assign and assign add. */ -bool xibo(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +bool integer_to_bool(Expr *expr, Type *type) { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; -// if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); - RETURN_NON_CONST_CAST(CAST_INTBOOL); + if (insert_runtime_cast_unless_const(expr, CAST_INTBOOL, type)) return true; - expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ); - left->type = type; + expr_const_set_bool(&expr->const_expr, bigint_cmp_zero(&expr->const_expr.i) != CMP_EQ); + expr_set_type(expr, type); return true; } /** * Convert from any float to bool - * @return true for any implicit conversion except assign and assign add */ -bool fpbo(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +bool float_to_bool(Expr *expr, Type *type) { -// if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); - RETURN_NON_CONST_CAST(CAST_FPBOOL); + if (insert_runtime_cast_unless_const(expr, CAST_FPBOOL, type)) return true; - expr_const_set_bool(&left->const_expr, left->const_expr.f != 0.0); - left->type = type; + expr_const_set_bool(&expr->const_expr, expr->const_expr.f != 0.0); + expr_set_type(expr, type); return true; } /** * Convert from any fp to fp - * @return true for all except implicit assign (but allowing assign add) */ -bool fpfp(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +static bool float_to_float(Expr* expr, Type *canonical, Type *type) { - bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->type_kind != TYPE_FXX; + if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return true; -// if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); - - RETURN_NON_CONST_CAST(CAST_FPFP); - - expr_const_set_float(&left->const_expr, left->const_expr.f, canonical->type_kind); - left->type = type; + expr_const_set_float(&expr->const_expr, expr->const_expr.f, canonical->type_kind); + expr_set_type(expr, type); return true; } /** * Convert from any floating point to int - * @return true only on explicit conversions. */ -bool fpxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +bool float_to_integer(Expr *expr, Type *canonical, Type *type) { - REQUIRE_EXPLICIT_CAST(cast_type); + bool is_signed = type_is_unsigned(canonical); + if (insert_runtime_cast_unless_const(expr, is_signed ? CAST_FPSI : CAST_FPUI, type)) return true; - RETURN_NON_CONST_CAST(CAST_FPUI); - - assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_U64); - long double d = left->const_expr.f; + assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind < TYPE_IXX); + long double d = expr->const_expr.f; BigInt temp; - if (canonical->type_kind >= TYPE_U8) + if (is_signed) { - bigint_init_unsigned(&temp, (uint64_t)d); - bigint_truncate(&left->const_expr.i, &temp, canonical->builtin.bitsize, false); + bigint_init_signed(&temp, (int64_t)d); + bigint_truncate(&expr->const_expr.i, &temp, canonical->builtin.bitsize, true); } else { - bigint_init_signed(&temp, (int64_t)d); - bigint_truncate(&left->const_expr.i, &temp, canonical->builtin.bitsize, true); + bigint_init_unsigned(&temp, (uint64_t)d); + bigint_truncate(&expr->const_expr.i, &temp, canonical->builtin.bitsize, false); } - left->const_expr.kind = canonical->type_kind; - left->type = type; + expr->const_expr.kind = canonical->type_kind; + expr_set_type(expr, type); return true; } @@ -324,420 +247,169 @@ bool fpxi(Context *context, Expr *left, Type *canonical, Type *type, CastType ca * Convert from compile time int to any signed or unsigned int * @return true unless the conversion was lossy. */ -bool ixxxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +static bool int_literal_to_int(Expr *expr, Type *canonical, Type *type) { - if (left->expr_kind != EXPR_CONST) + if (expr->expr_kind != EXPR_CONST) { - SEMA_ERROR(left, "This expression could not be resolved to a concrete type. Please add more type annotations."); - return false; + SEMA_ERROR(expr, "This expression could not be resolved to a concrete type. Please add more type annotations."); + UNREACHABLE } bool is_signed = canonical->type_kind < TYPE_U8; - int bitsize = canonical->builtin.bitsize; - if (!is_signed && bigint_cmp_zero(&left->const_expr.i) == CMP_LT) - { - SEMA_ERROR(left, "Negative number '%s' cannot be assigned to type '%s'", expr_const_to_error_string(&left->const_expr), canonical->name); - return false; - } - if (cast_type != CAST_TYPE_EXPLICIT && !bigint_fits_in_bits(&left->const_expr.i, bitsize, is_signed)) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - SEMA_ERROR(left, "'%s' does not fit in type '%s'", expr_const_to_error_string(&left->const_expr), canonical->name); - return false; - } BigInt temp; - bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, is_signed); - left->const_expr.i = temp; - left->const_expr.kind = canonical->type_kind; - left->type = type; + bigint_truncate(&temp, &expr->const_expr.i, canonical->builtin.bitsize, is_signed); + expr->const_expr.i = temp; + expr->const_expr.kind = canonical->type_kind; + expr_set_type(expr, type); return true; } /** - * Convert from compile time int to any signed or unsigned int - * @return true unless the conversion was lossy. + * Convert from compile time int to any enum */ -bool ixxen(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +bool lit_integer_to_enum(Expr *expr, Type *canonical, Type *type) { assert(canonical->type_kind == TYPE_ENUM); - canonical = canonical->decl->enums.type_info->type->canonical; - return ixxxi(context, left, canonical, type, cast_type); + canonical = type_flatten(canonical->decl->enums.type_info->type); + return int_literal_to_int(expr, canonical, type); } -/** - * Convert from compile time int to error union - */ -bool ixxeu(Context *context, Expr *left, Type *type) + +static bool int_conversion(Expr *expr, CastKind kind, Type *canonical, Type *type) { - UNREACHABLE -} - -/** - * Cast signed int -> signed int - * @return true if this is a widening, an explicit cast or if it is an implicit assign add - */ -bool sisi(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize; - - if (is_narrowing && cast_type != CAST_TYPE_EXPLICIT) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - EXIT_T_MISMATCH(); - } - - RETURN_NON_CONST_CAST(CAST_SISI); + if (insert_runtime_cast_unless_const(expr, kind, type)) return true; BigInt temp; - bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, true); - left->const_expr.i = temp; - left->const_expr.kind = canonical->type_kind; - left->type = type; - return true; -} - -/** - * Cast unsigned int -> unsigned int - * @return true if this was not a narrowing implicit assign or narrowing implicit assign add - */ -bool uiui(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize; - - if (is_narrowing && cast_type != CAST_TYPE_EXPLICIT) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - EXIT_T_MISMATCH(); - } - - RETURN_NON_CONST_CAST(CAST_UIUI); - - BigInt temp; - bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, false); - left->const_expr.i = temp; - left->const_expr.kind = canonical->type_kind; - left->type = type; - return true; -} - - -/** - * Cast unsigned int -> signed int - * @return true if this is an explicit cast or if it is an implicit assign add or if it is a widening cast. - */ -bool uisi(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - bool is_widening = from_canonical->builtin.bytesize < canonical->builtin.bytesize; - - if (!is_widening && cast_type != CAST_TYPE_EXPLICIT) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - EXIT_T_MISMATCH(); - } - - RETURN_NON_CONST_CAST(CAST_UISI); - - BigInt temp; - bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, true); - left->const_expr.i = temp; - left->const_expr.kind = canonical->type_kind; - left->type = type; - return true; -} - -/* - * Cast signed int -> unsigned int - * @return true if this was an implicit add or or explicit cast. - */ -bool siui(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - REQUIRE_EXPLICIT_CAST(cast_type); - - RETURN_NON_CONST_CAST(CAST_SIUI); - - BigInt temp; - bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, false); - left->const_expr.i = temp; - left->const_expr.kind = canonical->type_kind; - left->type = type; + bigint_truncate(&temp, &expr->const_expr.i, canonical->builtin.bitsize, kind == CAST_UISI || kind == CAST_SISI); + expr->const_expr.i = temp; + expr->const_expr.kind = canonical->type_kind; + expr_set_type(expr, type); return true; } /** * Cast a signed or unsigned integer -> floating point - * @return true always */ -bool sifp(Context *context, Expr *left, Type *canonical, Type *type) +static bool int_to_float(Expr *expr, CastKind kind, Type *canonical, Type *type) { - RETURN_NON_CONST_CAST(CAST_SIFP); - const_int_to_fp_cast(context, left, canonical, type); + if (insert_runtime_cast_unless_const(expr, kind, type)) return true; + const_int_to_fp_cast(expr, canonical, type); return true; } -/** - * Cast a signed or unsigned integer -> floating point - * @return true always - */ -bool uifp(Context *context, Expr *left, Type *canonical, Type *type) -{ - RETURN_NON_CONST_CAST(CAST_UIFP); - const_int_to_fp_cast(context, left, canonical, type); - return true; -} -bool ixxfp(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) +static bool int_literal_to_float(Expr *expr, Type *canonical, Type *type) { assert(type_is_float(canonical)); - assert(left->expr_kind == EXPR_CONST); - const_int_to_fp_cast(context, left, canonical, type); + assert(expr->expr_kind == EXPR_CONST); + const_int_to_fp_cast(expr, canonical, type); return true; } /** * Convert a compile time into to a boolean. - * @return true always */ -bool ixxbo(Context *context, Expr *left, Type *type) +static bool int_literal_to_bool(Expr *expr, Type *type) { - assert(left->expr_kind == EXPR_CONST); - expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ); - left->type = type; + assert(expr->expr_kind == EXPR_CONST); + expr_const_set_bool(&expr->const_expr, bigint_cmp_zero(&expr->const_expr.i) != CMP_EQ); + expr_set_type(expr, type); return true; } /** - * Cast comptime, signed or unsigned -> pointer. - * @return true if the cast succeeds. + * Cast any int to a pointer -> pointer. */ -bool xipt(Context *context, Expr *left, Type *from, Type *canonical, Type *type, CastType cast_type) +static bool int_to_pointer(Expr *expr, Type *type) { - REQUIRE_EXPLICIT_CAST(cast_type); - if (left->expr_kind == EXPR_CONST) + if (expr->expr_kind == EXPR_CONST) { - RETURN_NON_CONST_CAST(CAST_XIPTR); - if (bigint_cmp_zero(&left->const_expr.i) == CMP_EQ) + if (bigint_cmp_zero(&expr->const_expr.i) == CMP_EQ) { - expr_const_set_null(&left->const_expr); - left->type = type; - } - } - if (type_size(from) < type_size(type_voidptr)) - { - // Widen. - if (!cast(context, left, type_usize, cast_type)) return false; - } - // If we have a *larger* int type - narrow it. - if (!cast(context, left, type_usize, cast_type)) return false; - insert_cast(left, CAST_XIPTR, canonical); - return true; -} - -bool usus(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - assert(canonical->canonical == canonical); - assert(canonical->type_kind == TYPE_POINTER); - assert(from->type_kind == TYPE_POINTER); - - if (cast_type != CAST_TYPE_EXPLICIT) - { - if (type_is_subtype(from->pointer, canonical->pointer)) - { - insert_cast(left, CAST_PTRPTR, canonical); + expr_const_set_null(&expr->const_expr); + expr_set_type(expr, type); return true; } - sema_type_mismatch(context, left, type, cast_type); - return false; } - insert_cast(left, CAST_PTRPTR, canonical); - return true; + cast(expr, type_uptr); + return insert_cast(expr, CAST_XIPTR, type); } -bool xixi(Context *context, Expr *left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) + +static bool int_to_int(Expr *left, Type *from_canonical, Type *canonical, Type *type) { assert(from_canonical->canonical == from_canonical); switch (from_canonical->type_kind) { case TYPE_IXX: - return ixxxi(context, left, canonical, type, cast_type); + return int_literal_to_int(left, canonical, type); case ALL_SIGNED_INTS: - if (type_is_unsigned(canonical)) return siui(context, left, canonical, type, cast_type); - return sisi(context, left, from_canonical, canonical, type, cast_type); + return int_conversion(left, type_is_unsigned(canonical) ? CAST_SIUI : CAST_SISI, canonical, type); case ALL_UNSIGNED_INTS: - if (type_is_unsigned(canonical)) return uiui(context, left, from_canonical, canonical, type, cast_type); - return uisi(context, left, from_canonical, canonical, type, cast_type); + return int_conversion(left, type_is_unsigned(canonical) ? CAST_UIUI : CAST_UISI, canonical, type); default: UNREACHABLE } } -bool enxi(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +static bool enum_to_integer(Expr* expr, Type *from, Type *canonical, Type *type) { Type *enum_type = from->decl->enums.type_info->type; - Type *enum_type_canonical = enum_type->canonical; + Type *enum_type_canonical = type_flatten(enum_type); // 1. If the underlying type is the same, this is just setting the type. if (canonical == enum_type_canonical) { - left->type = type; + expr_set_type(expr, type); return true; } - // 2. See if we can convert to the target type. - if (cast_type != CAST_TYPE_EXPLICIT && type_find_max_type(enum_type_canonical, canonical) != canonical) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - SEMA_ERROR(left, "Cannot implicitly convert '%s' with underlying type of '%s' to '%s'," - " use an explicit cast if this is what you want.", type_to_error_string(from), - type_to_error_string(enum_type_canonical), type_to_error_string(canonical)); - return false; - } - // 3. Dispatch to the right cast: - insert_cast(left, CAST_ENUMLOW, enum_type_canonical); - return xixi(context, left, enum_type_canonical, canonical, type, cast_type); + // 2. Dispatch to the right cast: + // TODO can be inlined if enums are constants + insert_cast(expr, CAST_ENUMLOW, enum_type_canonical); + return int_to_int(expr, enum_type_canonical, canonical, type); } -bool enfp(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +static bool enum_to_float(Expr* expr, Type *from, Type *canonical, Type *type) { - REQUIRE_EXPLICIT_CAST(cast_type); Type *enum_type = from->decl->enums.type_info->type; - Type *enum_type_canonical = enum_type->canonical; - if (type_is_integer_unsigned(enum_type_canonical)) - { - return uifp(context, left, enum_type_canonical, type); - } - return sifp(context, left, enum_type_canonical, type); + Type *enum_type_canonical = type_flatten(enum_type); + // TODO can be inlined if enums are constants + insert_cast(expr, CAST_ENUMLOW, enum_type_canonical); + return int_to_float(expr, type_is_unsigned(enum_type_canonical) ? CAST_UIFP : CAST_SIFP, canonical, type); } -bool enbo(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool enum_to_bool(Expr* expr, Type *from, Type *type) { - REQUIRE_EXPLICIT_CAST(cast_type); Type *enum_type = from->decl->enums.type_info->type; - Type *enum_type_canonical = enum_type->canonical; - return xibo(context, left, enum_type_canonical, type, cast_type); + Type *enum_type_canonical = type_flatten(enum_type); + // TODO can be inlined if enums are constants + insert_cast(expr, CAST_ENUMLOW, enum_type_canonical); + return integer_to_bool(expr, type); } -bool enpt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool enum_to_pointer(Expr* expr, Type *from, Type *type) { - REQUIRE_EXPLICIT_CAST(cast_type); Type *enum_type = from->decl->enums.type_info->type; - Type *enum_type_canonical = enum_type->canonical; - return xipt(context, left, enum_type_canonical, canonical, type, cast_type); + Type *enum_type_canonical = type_flatten(enum_type); + // TODO can be inlined if enums are constants + insert_cast(expr, CAST_ENUMLOW, enum_type_canonical); + return int_to_pointer(expr, type); } -bool vava(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool sapt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - bool is_subtype = type_is_subtype(canonical->pointer, from->array.base); - if (!is_subtype) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(context, left, type, cast_type); - } - insert_cast(left, CAST_SAPTR, canonical); - return true; -} - -bool vasa(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - - - - -bool xieu(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool xierr(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - - -/** - * Convert error union to error. This is always a required cast. - * @return false if an error was reported. - */ -bool eubool(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - insert_cast(left, CAST_EUBOOL, canonical); - return true; -} - - -bool euer(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - REQUIRE_EXPLICIT_CAST(cast_type); - insert_cast(left, CAST_EUER, canonical); - return true; -} - - -bool ereu(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) -{ - insert_cast(left, CAST_EREU, canonical); - return true; -} -bool ptva(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool ptsa(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - if (from->pointer->type_kind != TYPE_ARRAY) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - sema_type_mismatch(context, left, type, CAST_TYPE_EXPLICIT); - return false; - } - if (!type_is_subtype(canonical->array.base, from->pointer->array.base)) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - sema_type_mismatch(context, left, type, CAST_TYPE_EXPLICIT); - return false; - } - insert_cast(left, CAST_APTSA, canonical); - return true; -} - -bool usbo(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool vapt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - - -bool cast_implicitly_to_runtime(Context *context, Expr *expr) +bool cast_implicitly_to_runtime(Expr *expr) { Type *canonical = expr->type->canonical; - int success; switch (canonical->type_kind) { case TYPE_IXX: - return cast(context, expr, type_long, CAST_TYPE_IMPLICIT); + return cast(expr, type_long); case TYPE_FXX: - return cast(context, expr, type_double, CAST_TYPE_IMPLICIT); + return cast(expr, type_double); default: return true; } - assert(success && "This should always work"); } -bool cast_implicit(Context *context, Expr *expr, Type *to_type) -{ - if (!to_type) return true; - return cast(context, expr, to_type, CAST_TYPE_IMPLICIT); -} CastKind cast_to_bool_kind(Type *type) { @@ -747,25 +419,14 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_DISTINCT: case TYPE_INFERRED_ARRAY: UNREACHABLE - case TYPE_POISONED: - case TYPE_VOID: - case TYPE_ERR_UNION: - case TYPE_STRUCT: - case TYPE_UNION: - case TYPE_CTSTR: - case TYPE_ERRTYPE: - case TYPE_ENUM: - case TYPE_FUNC: - case TYPE_ARRAY: - case TYPE_VARARRAY: - case TYPE_SUBARRAY: - case TYPE_TYPEID: - case TYPE_TYPEINFO: - case TYPE_MEMBER: - // Improve consider vararray / subarray conversion to boolean. - return CAST_ERROR; case TYPE_BOOL: - UNREACHABLE + return CAST_BOOLBOOL; + case TYPE_ERR_UNION: + return CAST_EUBOOL; + case TYPE_VARARRAY: + return CAST_VARBOOL; + case TYPE_SUBARRAY: + return CAST_SABOOL; case ALL_INTS: return CAST_INTBOOL; case TYPE_COMPLEX: @@ -774,143 +435,451 @@ CastKind cast_to_bool_kind(Type *type) return CAST_FPBOOL; case TYPE_POINTER: return CAST_PTRBOOL; + case TYPE_POISONED: + case TYPE_VOID: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_STRLIT: + case TYPE_ERRTYPE: + case TYPE_ENUM: + case TYPE_FUNC: + case TYPE_ARRAY: + case TYPE_TYPEID: + case TYPE_TYPEINFO: + case TYPE_MEMBER: case TYPE_VECTOR: return CAST_ERROR; } UNREACHABLE } - -bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) +bool cast_to_bool_implicit(Expr *expr) { - Type *from_type = expr->type->canonical; - Type *canonical = to_type->canonical; - if (from_type == canonical) return true; - if (cast_type == CAST_TYPE_EXPLICIT) + assert(expr->resolve_status == RESOLVE_DONE); + if (cast_to_bool_kind(expr->type) == CAST_ERROR) return false; + return cast(expr, type_bool); +} + +bool cast_may_explicit(Type *from_type, Type *to_type) +{ + // 1. We flatten the distinct types, since they should be freely convertible + Type *from = type_flatten_distinct(from_type); + Type *to = type_flatten_distinct(to_type); + + // 2. Same underlying type, always ok + if (from == to) return true; + + TypeKind to_kind = to->type_kind; + switch (from->type_kind) { - canonical = type_flatten(canonical); - from_type = type_flatten(from_type); - if (from_type == canonical) + case TYPE_INFERRED_ARRAY: + case TYPE_POISONED: + case TYPE_VOID: + case TYPE_TYPEINFO: + case TYPE_MEMBER: + case TYPE_DISTINCT: + case TYPE_FUNC: + case TYPE_TYPEDEF: + UNREACHABLE + case TYPE_TYPEID: + // May convert to anything pointer sized or larger, no enums + return type_is_pointer_sized_or_more(to); + case TYPE_BOOL: + // May convert to any integer / distinct integer / float, no enums + return type_is_integer(to) || type_is_float(to); + case TYPE_ERR_UNION: + // May convert to a bool, or an error type. + return to == type_bool || to_kind == TYPE_ERRTYPE; + case TYPE_IXX: + case ALL_SIGNED_INTS: + case ALL_UNSIGNED_INTS: + case TYPE_ENUM: + // 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; + return false; + case ALL_FLOATS: + // Allow conversion float -> float/int/bool/enum + return type_is_any_integer(to) || type_is_float(to) || to == type_bool || to_kind == TYPE_ENUM; + case TYPE_POINTER: + // Allow conversion ptr -> int (min pointer size)/bool/pointer/vararray + if ((type_is_integer(to) && type_size(to) >= type_size(type_iptr)) || to == type_bool || to_kind == TYPE_POINTER || to_kind == TYPE_VARARRAY) return true; + // Special subarray conversion: someType[N]* -> someType[] + if (to_kind == TYPE_SUBARRAY && from->pointer->type_kind == TYPE_ARRAY && from->pointer->array.base == to->array.base) return true; + return false; + case TYPE_ERRTYPE: + // Allow only MyError.A -> error + return to->type_kind == TYPE_ERR_UNION; + case TYPE_ARRAY: + if (to_kind == TYPE_VECTOR) + { + return to->array.len == from->vector.len && to->array.base == from->array.base; + } + FALLTHROUGH; + case TYPE_STRUCT: + if (type_is_substruct(from_type)) + { + if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type)) return true; + } + FALLTHROUGH; + case TYPE_UNION: + return type_is_structurally_equivalent(from, to); + case TYPE_STRLIT: + if (to_kind == TYPE_POINTER) return true; + if (to_kind == TYPE_SUBARRAY && (to->array.base == type_char || to->array.base == type_ichar)) return true; + return false; + case TYPE_VARARRAY: + if (to_kind == TYPE_POINTER) return true; + if (to_kind == TYPE_SUBARRAY || to_kind == TYPE_VARARRAY) + { + return type_is_structurally_equivalent(from->array.base, from->pointer->array.base); + } + return false; + case TYPE_SUBARRAY: + return to_kind == TYPE_POINTER; + case TYPE_VECTOR: + return type_is_structurally_equivalent(type_get_array(from->vector.base, from->vector.len), to); + case TYPE_COMPLEX: + return type_is_structurally_equivalent(type_get_array(from->complex, 2), to); + } + UNREACHABLE +} + +bool cast_may_implicit(Type *from_type, Type *to_type) +{ + Type *from = from_type->canonical; + Type *to = to_type->canonical; + + // 1. Same canonical type - we're fine. + if (from == to) return true; + + // 2. Handle floats + if (type_is_float(to)) + { + // 2a. Any integer may convert to a float. + if (type_is_any_integer(from)) return true; + + // 2b. Any narrower float or FXX may convert to a float. + if (type_is_float(from)) { - expr->type = to_type; - return true; + // This works because the type_size of FXX = 0 + unsigned a = type_size(to); + unsigned b = type_size(from); + return type_size(to) >= type_size(from); } + return false; + } + + // 3. Handle ints + if (type_is_integer(to)) + { + // TODO, consider size here, and maybe the type should b removed. + if (from->type_kind == TYPE_IXX) return true; + + // For an enum, lower to the underlying enum type. + if (from->type_kind == TYPE_ENUM) + { + from = from->decl->enums.type_info->type->canonical; + } + + // 3a. Any narrower int may convert to a wider or same int, regardless of signedness. + if (type_is_integer(from)) + { + return type_size(to) >= type_size(from); + } + return false; + } + + // 4. Handle pointers + if (type_is_pointer(to)) + { + // 4a. Assigning a subarray or vararray to a pointer of the same base type is fine + if (from->type_kind == TYPE_SUBARRAY || from->type_kind == TYPE_VARARRAY) + { + // void* conversion always work. + if (to == type_voidptr) return true; + + // Use subtype matching + return type_is_subtype(to->pointer->canonical, from->array.base->canonical); + } + + // 4b. Assigning a pointer + if (from->type_kind == TYPE_POINTER) + { + // For void* on either side, no checks. + if (to == type_voidptr || from == type_voidptr) return true; + + // Special handling of int* = int[4]* + if (from->pointer->type_kind == TYPE_ARRAY) + { + if (type_is_subtype(to->pointer, from->pointer->array.base)) return true; + } + + // Use subtype matching + return type_is_subtype(to->pointer, from->pointer); + } + + // 4c. Assigning a compile time string to char* is fine. TODO fix correct later + if (from->type_kind == TYPE_STRLIT && to->pointer == type_char) return true; + + return false; + } + + // 5. Handle sub arrays + if (to->type_kind == TYPE_SUBARRAY) + { + // 5a. Assign sized array pointer int[] = int[4]* + if (type_is_pointer(from)) + { + return from->pointer->type_kind == TYPE_ARRAY && from->pointer->array.base == to->array.base; + } + + // 5b. Assign var array int[] = int[*] + if (from->type_kind == TYPE_VARARRAY) + { + return from->array.base == to->array.base; + } + + return false; + } + + // 7. In the case of distinct types, we allow implicit conversion from literal types. + if (to->type_kind == TYPE_DISTINCT) + { + if (from->type_kind == TYPE_STRLIT || from->type_kind == TYPE_FXX || from->type_kind == TYPE_IXX) + { + return cast_may_implicit(from, type_flatten(to)); + } + } + + + if (to->type_kind == TYPE_BOOL) + { + return cast_to_bool_kind(from) != CAST_ERROR; + } + + // TODO struct embedding + + return false; +} + +bool may_convert_float_const_implicit(Expr *expr, Type *to_type) +{ + Type *to_type_flat = type_flatten(to_type); + long double limit; + switch (to_type_flat->type_kind) + { + case TYPE_F16: + limit = FLOAT16_LIMIT; + break; + case TYPE_F32: + limit = FLOAT32_LIMIT; + break; + case TYPE_F64: + limit = FLOAT64_LIMIT; + break; + case TYPE_F128: + // Assume this to be true + return true; + default: + UNREACHABLE + } + if (expr->const_expr.f < -limit && expr->const_expr.f > limit) + { + SEMA_ERROR(expr, "The value '%Lg' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.f, type_quoted_error_string(to_type)); + return false; + } + return true; +} + +bool may_convert_int_const_implicit(Expr *expr, Type *to_type) +{ + Type *to_type_flat = type_flatten(to_type); + if (expr_const_will_overflow(&expr->const_expr, to_type_flat->type_kind)) + { + SEMA_ERROR(expr, "The value '%s' is out of range for %s, it can be truncated with an explicit cast.", bigint_to_error_string(&expr->const_expr.i, 10), type_quoted_error_string(to_type)); + return false; + } + return true; +} + +bool may_convert_const_implicit(Expr *expr, Type *to_type) +{ + switch (expr->type->canonical->type_kind) + { + case TYPE_FXX: + return may_convert_float_const_implicit(expr, to_type); + case TYPE_IXX: + return may_convert_int_const_implicit(expr, to_type); + default: + UNREACHABLE + + } +} +bool cast_implicit(Expr *expr, Type *to_type) +{ + assert(expr->original_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)); + return false; + } + // Additional checks for compile time values. + if (expr->expr_kind == EXPR_CONST) + { + if (expr->type->type_kind == TYPE_FXX) + { + if (!may_convert_float_const_implicit(expr, to_type)) return false; + } + else if (expr->type->type_kind == TYPE_IXX) + { + if (!may_convert_int_const_implicit(expr, to_type)) return false; + } + } + Type *original_type = expr->original_type ? expr->original_type : expr->type; + cast(expr, to_type); + expr->original_type = original_type; + return true; +} + +bool cast_implicit_bit_width(Expr *expr, Type *to_type) +{ + Type *to_canonical = to_type->canonical; + Type *from_canonical = expr->type->canonical; + if (type_is_integer(to_canonical) && type_is_integer(from_canonical)) + { + if (type_is_unsigned(to_canonical) != type_is_unsigned(from_canonical)) + { + if (type_is_unsigned(from_canonical)) + { + to_type = type_int_unsigned_by_bitsize(type_size(to_canonical) * 8); + } + else + { + to_type = type_int_signed_by_bitsize(type_size(to_canonical) * 8); + } + } + } + return cast_implicit(expr, to_type); +} + +bool cast(Expr *expr, Type *to_type) +{ + Type *from_type = type_flatten(expr->type->canonical); + Type *canonical = type_lowering(to_type); + if (from_type == canonical) + { + expr_set_type(expr, to_type); + return true; } switch (from_type->type_kind) { case TYPE_INFERRED_ARRAY: case TYPE_POISONED: - UNREACHABLE case TYPE_VOID: case TYPE_TYPEID: case TYPE_TYPEINFO: case TYPE_MEMBER: case TYPE_DISTINCT: - break; + case TYPE_FUNC: + case TYPE_TYPEDEF: + UNREACHABLE case TYPE_BOOL: // Bool may convert into integers and floats but only explicitly. - if (type_is_integer(canonical)) return boxi(context, expr, canonical, to_type, cast_type); - if (type_is_float(canonical)) return bofp(context, expr, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return bool_to_int(expr, canonical, to_type); + if (type_is_float(canonical)) return bool_to_float(expr, canonical, to_type); break; case TYPE_ERR_UNION: - if (to_type->type_kind == TYPE_BOOL) return eubool(context, expr, canonical, to_type, cast_type); - if (to_type->type_kind == TYPE_ERRTYPE) return euer(context, expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_BOOL) return insert_cast(expr, CAST_EUBOOL, to_type); + if (canonical->type_kind == TYPE_ERRTYPE) return insert_cast(expr, CAST_EUER, to_type); break; case TYPE_IXX: - canonical = type_flatten(canonical); // Compile time integers may convert into ints, floats, bools if (expr->expr_kind != EXPR_CONST && !expr->reeval) { expr->resolve_status = RESOLVE_NOT_DONE; expr->reeval = true; - return sema_analyse_expr(context, to_type, expr); + TODO + // return sema_analyse_expr(context, to_type, expr); } - if (type_is_integer(canonical)) return ixxxi(context, expr, canonical, to_type, cast_type); - if (type_is_float(canonical)) return ixxfp(context, expr, canonical, to_type, cast_type); - if (canonical == type_bool) return ixxbo(context, expr, to_type); - if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_ENUM) return ixxen(context, expr, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return int_literal_to_int(expr, canonical, to_type); + if (type_is_float(canonical)) return int_literal_to_float(expr, canonical, to_type); + if (canonical == type_bool) return int_literal_to_bool(expr, to_type); + if (canonical->type_kind == TYPE_POINTER) return int_to_pointer(expr, to_type); + if (canonical->type_kind == TYPE_ENUM) return lit_integer_to_enum(expr, canonical, to_type); break; case ALL_SIGNED_INTS: - if (type_is_integer_unsigned(canonical)) return siui(context, expr, canonical, to_type, cast_type); - if (type_is_integer_signed(canonical)) return sisi(context, expr, from_type, canonical, to_type, cast_type); - if (type_is_float(canonical)) return sifp(context, expr, canonical, to_type); - if (canonical == type_bool) return xibo(context, expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_integer_unsigned(canonical)) return int_conversion(expr, CAST_SIUI, canonical, to_type); + if (type_is_integer_signed(canonical)) return int_conversion(expr, CAST_SISI, canonical, to_type); + if (type_is_float(canonical)) return int_to_float(expr, CAST_SIFP, canonical, to_type); + if (canonical == type_bool) return integer_to_bool(expr, to_type); + if (canonical->type_kind == TYPE_POINTER) return int_to_pointer(expr, to_type); + if (canonical->type_kind == TYPE_ENUM) return lit_integer_to_enum(expr, canonical, to_type); break; case ALL_UNSIGNED_INTS: - if (type_is_integer_unsigned(canonical)) return uiui(context, expr, from_type, canonical, to_type, cast_type); - if (type_is_integer_signed(canonical)) return uisi(context, expr, from_type, canonical, to_type, cast_type); - if (type_is_float(canonical)) return uifp(context, expr, canonical, to_type); - if (canonical == type_bool) return xibo(context, expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_integer_unsigned(canonical)) return int_conversion(expr, CAST_UIUI, canonical, to_type); + if (type_is_integer_signed(canonical)) return int_conversion(expr, CAST_UISI, canonical, to_type); + if (type_is_float(canonical)) return int_to_float(expr, CAST_UIFP, canonical, to_type); + if (canonical == type_bool) return integer_to_bool(expr, to_type); + if (canonical->type_kind == TYPE_POINTER) return int_to_pointer(expr, to_type); break; case ALL_FLOATS: - if (from_type->type_kind == TYPE_FXX) - { - canonical = type_flatten(canonical); - } // Compile time integers may convert into ints, floats, bools if (from_type->type_kind == TYPE_FXX && expr->expr_kind != EXPR_CONST && !expr->reeval) { expr->resolve_status = RESOLVE_NOT_DONE; expr->reeval = true; - return sema_analyse_expr(context, to_type, expr); + TODO +// return sema_analyse_expr(context, to_type, expr); } - if (type_is_integer(canonical)) return fpxi(context, expr, canonical, to_type, cast_type); - if (canonical == type_bool) return fpbo(context, expr, canonical, to_type, cast_type); - if (type_is_float(canonical)) return fpfp(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return float_to_integer(expr, canonical, to_type); + if (canonical == type_bool) return float_to_bool(expr, to_type); + if (type_is_float(canonical)) return float_to_float(expr, canonical, to_type); break; case TYPE_POINTER: - if (type_is_integer(canonical)) return ptxi(context, expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_BOOL) return ptbo(context, expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return ptpt(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_VARARRAY) return ptva(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_SUBARRAY) return ptsa(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return pointer_to_integer(expr, to_type); + if (canonical->type_kind == TYPE_BOOL) return pointer_to_bool(expr, to_type); + if (canonical->type_kind == TYPE_POINTER) return pointer_to_pointer(expr, to_type); + if (canonical->type_kind == TYPE_VARARRAY) return insert_cast(expr, CAST_PTRVAR, to_type); + if (canonical->type_kind == TYPE_SUBARRAY) return insert_cast(expr, CAST_APTSA, to_type); break; case TYPE_ENUM: - if (type_is_integer(canonical)) return enxi(context, expr, from_type, canonical, to_type, cast_type); - if (type_is_float(canonical)) return enfp(context, expr, from_type, canonical, to_type, cast_type); - if (canonical == type_bool) return enbo(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return enpt(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return enum_to_integer(expr, from_type, canonical, to_type); + if (type_is_float(canonical)) return enum_to_float(expr, from_type, canonical, to_type); + if (canonical == type_bool) return enum_to_bool(expr, from_type, to_type); + if (canonical->type_kind == TYPE_POINTER) return enum_to_pointer(expr, from_type, to_type); break; case TYPE_ERRTYPE: - if (canonical->type_kind == TYPE_ERR_UNION) return ereu(context, expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_ERR_UNION) return insert_cast(expr, CAST_EREU, to_type); break; - case TYPE_FUNC: - SEMA_ERROR(expr, "The function call is missing (...), if you want to take the address of a function it must be prefixed with '&'."); - return false; case TYPE_STRUCT: - if (canonical->type_kind == TYPE_STRUCT) return stst(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_UNION) return stun(context, expr, from_type, canonical, to_type, cast_type); - break; case TYPE_UNION: - if (canonical->type_kind == TYPE_STRUCT) return unst(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_UNION) return unun(context, expr, from_type, canonical, to_type, cast_type); - break; - case TYPE_TYPEDEF: - UNREACHABLE - case TYPE_CTSTR: - canonical = type_flatten(canonical); - if (canonical->type_kind == TYPE_POINTER) return strpt(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_SUBARRAY) return strsa(context, expr, from_type, canonical, to_type, cast_type); - break; case TYPE_ARRAY: - // There is no valid cast from array to anything else. + if (canonical->type_kind == TYPE_ARRAY || canonical->type_kind == TYPE_STRUCT || canonical->type_kind == TYPE_UNION) + { + return insert_cast(expr, CAST_STST, to_type); + } + break; + UNREACHABLE + case TYPE_STRLIT: + canonical = type_flatten(canonical); + if (canonical->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_STRPTR, to_type); + if (canonical->type_kind == TYPE_SUBARRAY) return string_literal_to_subarray(expr, to_type); break; case TYPE_VARARRAY: - if (canonical->type_kind == TYPE_SUBARRAY) return vasa(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_VARARRAY) return vava(context, expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return vapt(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_SUBARRAY) return insert_cast(expr, CAST_VARSA, to_type); + if (canonical->type_kind == TYPE_VARARRAY) return insert_cast(expr, CAST_VARVAR, to_type); + if (canonical->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_VARPTR, to_type); break; case TYPE_SUBARRAY: - if (canonical->type_kind == TYPE_POINTER) return sapt(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_SAPTR, canonical); break; case TYPE_VECTOR: TODO case TYPE_COMPLEX: TODO } - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(context, expr, canonical, cast_type); + UNREACHABLE } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index af8a01eb9..5dd22f2cd 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -456,7 +456,46 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl) } TypeInfo *info = decl->distinct_decl.typedef_decl.type_info; if (!sema_resolve_type_info(context, info)) return false; - decl->distinct_decl.base_type = info->type->canonical; + Type *base = type_flatten_distinct(info->type); + decl->distinct_decl.base_type = base; + switch (base->type_kind) + { + case TYPE_POISONED: + case TYPE_STRLIT: + case TYPE_IXX: + case TYPE_FXX: + case TYPE_FUNC: + case TYPE_TYPEDEF: + case TYPE_DISTINCT: + case TYPE_INFERRED_ARRAY: + case TYPE_TYPEINFO: + case TYPE_MEMBER: + UNREACHABLE + return false; + case TYPE_ERRTYPE: + SEMA_ERROR(decl, "You cannot create a distinct type from an error."); + return false; + case TYPE_ERR_UNION: + SEMA_ERROR(decl, "You cannot create a distinct type from an error union."); + return false; + case TYPE_VOID: + case TYPE_TYPEID: + SEMA_ERROR(decl, "Cannot create a distinct type from %s.", type_quoted_error_string(base)); + case TYPE_BOOL: + case ALL_SIGNED_INTS: + case ALL_UNSIGNED_INTS: + case ALL_REAL_FLOATS: + case TYPE_POINTER: + case TYPE_ENUM: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ARRAY: + case TYPE_VARARRAY: + case TYPE_SUBARRAY: + case TYPE_VECTOR: + case TYPE_COMPLEX: + break; + } // Do we need anything else? return true; } @@ -503,11 +542,11 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl) if (!expr) { expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token)); - expr->type = type; + expr_set_type(expr, type); expr->resolve_status = RESOLVE_NOT_DONE; bigint_init_bigint(&expr->const_expr.i, &value); expr->const_expr.kind = TYPE_IXX; - expr->type = type_compint; + expr_set_type(expr, type_compint); enum_value->enum_constant.expr = expr; } @@ -861,6 +900,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) if (decl->var.init_expr && decl->type) { Expr *init_expr = decl->var.init_expr; + // 1. Check type. if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 9b4042ddf..e765e0a8d 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -32,7 +32,7 @@ static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl) embedded_struct->resolve_status = RESOLVE_DONE; embedded_struct->access_expr.parent = parent; embedded_struct->access_expr.ref = parent_decl->strukt.members[0]; - embedded_struct->type = embedded_struct->access_expr.ref->type; + expr_set_type(embedded_struct, embedded_struct->access_expr.ref->type); return embedded_struct; } @@ -68,6 +68,33 @@ static inline bool both_any_integer(Expr *left, Expr *right) return type_is_any_integer(type_flatten(left->type)) && type_is_any_integer(type_flatten(right->type)); } +void expr_copy_properties(Expr *to, Expr *from) +{ + to->failable = from->failable; + to->pure = from->pure; + to->constant = from->constant; +} + +void expr_copy_types(Expr *to, Expr *from) +{ + to->type = from->type; + to->original_type = from->original_type; +} + +static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right) +{ + expr->pure = left->pure & right->pure; + expr->constant = left->constant & right->constant; + expr->failable = left->failable | right->failable; +} + +static void expr_unify_binary(Expr *expr, Expr *left, Expr *right) +{ + expr->type = left->type; + expr->original_type = type_find_max_type(left->original_type->canonical, right->original_type->canonical); + expr_unify_binary_properties(expr, left, right); +} + static inline void context_pop_returns(Context *context, Ast **restore) { if (!context->returns_cache && context->returns) @@ -255,7 +282,7 @@ static inline bool sema_type_error_on_binop(Context *context, Expr *expr) return false; } -static bool expr_cast_to_index(Context *context, Expr *index) +static bool expr_cast_to_index(Expr *index) { switch (index->type->canonical->type_kind) { @@ -265,17 +292,17 @@ static bool expr_cast_to_index(Context *context, Expr *index) SEMA_ERROR(index, "The index is out of range, it must fit in a signed 64 bit integer."); return false; } - return cast_implicit(context, index, type_isize); + return cast(index, type_iptrdiff); case TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: - return cast_implicit(context, index, type_isize); + return cast(index, type_iptrdiff); case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: - return cast_implicit(context, index, type_usize); + return cast(index, type_uptrdiff); case TYPE_U128: SEMA_ERROR(index, "You need to explicitly cast this to a uint or ulong."); return false; @@ -296,7 +323,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e if (left) { if (!sema_analyse_expr(context, type_bool, cond)) return expr_poison(expr); - if (!cast_implicit(context, cond, type_bool)) return expr_poison(expr); + if (!cast_implicit(cond, type_bool)) return expr_poison(expr); if (!sema_analyse_expr(context, to, left)) return expr_poison(expr); expr->failable = left->failable | cond->failable; } @@ -325,8 +352,14 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e Type *right_canonical = right->type->canonical; if (type_is_ct(left_canonical) && type_is_ct(right_canonical)) { - if (!cast_implicitly_to_runtime(context, left)) return false; - if (!cast_implicitly_to_runtime(context, right)) return false; + if (to) + { + if (!cast_implicit(left, to) || !cast_implicit(right, to)) return false; + } + else + { + if (!cast_implicitly_to_runtime(left) || !cast_implicitly_to_runtime(right)) return false; + } left_canonical = left->type->canonical; right_canonical = right->type->canonical; } @@ -339,10 +372,11 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e type_to_error_string(left_canonical), type_to_error_string(right_canonical)); return false; } - if (!cast_implicit(context, left, max) || !cast_implicit(context, right, max)) return false; + if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false; } - expr->type = left->type; + expr_unify_binary(expr, left, right); + return true; } @@ -383,7 +417,7 @@ static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, if (!enum_constant) return false; assert(enum_constant->resolve_status == RESOLVE_DONE); - expr->type = decl->type; + expr_set_type(expr, decl->type); expr->access_expr.ref = enum_constant; expr->expr_kind = EXPR_MEMBER_ACCESS; return true; @@ -467,7 +501,7 @@ static inline bool sema_expr_analyse_identifier_resolve(Context *context, Type * return false; } id_expr->decl = decl; - expr->type = type_void; + expr_set_type(expr, type_void); return true; } if (expr->expr_kind == EXPR_MACRO_IDENTIFIER) @@ -491,7 +525,7 @@ static inline bool sema_expr_analyse_identifier_resolve(Context *context, Type * } assert(decl->type); expr->identifier_expr.decl = decl; - expr->type = decl->type; + expr_set_type(expr, decl->type); expr->pure = true; expr->constant = false; DEBUG_LOG("Resolution successful of %s.", decl->name); @@ -589,7 +623,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr return false; } expr->identifier_expr.decl = decl; - expr->type = type_void; + expr_set_type(expr, type_void); return true; } if (expr->expr_kind == EXPR_MACRO_IDENTIFIER) @@ -633,14 +667,14 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr } if (!decl->type) decl->type = type_void; expr->identifier_expr.decl = decl; - expr->type = decl->type; + expr_set_type(expr, decl->type); expr->pure = true; expr->constant = false; DEBUG_LOG("Resolution successful of %s.", decl->name); return true; } -static inline bool sema_expr_analyse_ct_identifier(Context *context, Type *to __unused, Expr *expr) +static inline bool sema_expr_analyse_ct_identifier(Context *context, Expr *expr) { Decl *ambiguous_decl = NULL; Decl *private_symbol = NULL; @@ -671,13 +705,13 @@ static inline bool sema_expr_analyse_ct_identifier(Context *context, Type *to __ assert(decl->resolve_status == RESOLVE_DONE); expr->ct_ident_expr.decl = decl; - expr->type = decl->type; + expr_set_type(expr, decl->type); expr->pure = true; expr->constant = true; return true; } -static inline bool sema_expr_analyse_hash_identifier(Context *context, Type *to __unused, Expr *expr) +static inline bool sema_expr_analyse_hash_identifier(Context *context, Type *to, Expr *expr) { Decl *ambiguous_decl = NULL; Decl *private_symbol = NULL; @@ -752,7 +786,7 @@ static inline bool sema_expr_analyse_intrinsic_fp_invocation(Context *context, E // Convert ints to float comptime float. if (type_is_any_integer(arg->type->canonical)) { - if (!cast_implicit(context, arg, type_compfloat)) return false; + if (!cast_implicit(arg, type_compfloat)) return false; } // If this is not a float argument => error. if (!type_is_float(arg->type->canonical)) @@ -761,10 +795,10 @@ static inline bool sema_expr_analyse_intrinsic_fp_invocation(Context *context, E return false; } // We lower to a real float in case we got a compfloat. - if (!cast_implicitly_to_runtime(context, arg)) return false; + if (!cast_implicitly_to_runtime(arg)) return false; // The expression type is the argument type. - expr->type = arg->type; + expr_set_type(expr, arg->type); return true; } @@ -825,7 +859,7 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS SEMA_ERROR(expr, "Too many parameters for this function."); return false; } - if (!sema_analyse_expr_of_required_type(context, NULL, arg, true)) return false; + if (!sema_analyse_expr(context, NULL, arg)) return false; // In the case of a compile time variable we cast to c_int / double. Type *arg_type = arg->type->canonical; @@ -833,23 +867,18 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS { // Pick double / CInt Type *target_type = type_is_any_integer(arg_type) ? type_c_int->canonical : type_double; - if (!cast_implicit(context, arg, target_type)) return false; + if (!cast_implicit(arg, target_type)) return false; arg_type = target_type; } - // bools need explicit promotion. - if (arg_type == type_bool) - { - if (!cast(context, arg, type_c_int->canonical, CAST_TYPE_EXPLICIT)) return false; - } - // Promote any integer to at least CInt + // Promote any integer or bool to at least CInt if (type_is_promotable_integer(arg_type) || arg_type == type_bool) { - if (!cast_implicit(context, arg, type_c_int->canonical)) return false; + cast(arg, type_c_int->canonical); arg_type = type_c_int->canonical; } if (type_is_promotable_float(arg->type)) { - if (!cast_implicit(context, arg, type_double)) return false; + cast(arg, type_double); arg_type = type_double; } actual_args[i] = arg; @@ -879,7 +908,7 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS SEMA_ERROR(expr, "Parameter '%s' was not set.", func_params[i]->name); return false; } - expr->type = signature->rtype->type; + expr_set_type(expr, signature->rtype->type); expr->call_expr.arguments = actual_args; expr->failable |= signature->failable; return true; @@ -932,7 +961,7 @@ static inline Type *unify_returns(Context *context, Type *to) SEMA_ERROR(return_stmt, "The return must be a value of type '%s'.", type_to_error_string(to)); return NULL; } - if (!cast_implicit(context, ret_expr, to)) + if (!cast_implicit(ret_expr, to)) { return NULL; } @@ -960,7 +989,7 @@ static inline Type *unify_returns(Context *context, Type *to) { Ast *return_stmt = context->returns[i]; Expr *ret_expr = return_stmt->return_stmt.expr; - if (!cast_implicit(context, ret_expr, to)) + if (!cast_implicit(ret_expr, to)) { return NULL; } @@ -1111,7 +1140,8 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr } if (param->type) { - if (!cast_implicit(context, arg, param->type)) return false; + TODO +// if (!cast_implicit(context, arg, param->type)) return false; } else { @@ -1170,7 +1200,7 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr ok = false; goto EXIT; } - call_expr->type = left_canonical; + expr_set_type(call_expr, left_canonical); if (vec_size(context->returns) == 1) { Expr *result = context->returns[0]->return_stmt.expr; @@ -1220,7 +1250,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr struct_var->unary_expr.operator = UNARYOP_ADDR; struct_var->resolve_status = RESOLVE_DONE; assert(func_expr->access_expr.parent->resolve_status == RESOLVE_DONE); - struct_var->type = type_get_ptr(struct_var->unary_expr.expr->type); + expr_set_type(struct_var, type_get_ptr(struct_var->unary_expr.expr->type)); } break; case EXPR_MACRO_IDENTIFIER: @@ -1228,8 +1258,8 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr case EXPR_LEN: if (func_expr->type == type_void) { - func_expr->type = type_usize; expr_replace(expr, func_expr); + expr_set_type(expr, type_usize); return true; } FALLTHROUGH; @@ -1279,7 +1309,7 @@ static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *exp if (left_canonical != right_canonical) { Type *type = type_find_max_type(left_canonical, right_canonical); - if (!cast_implicit(context, left, type) || !cast_implicit(context, right, type)) return expr_poison(expr); + if (!cast_implicit(left, type) || !cast_implicit(right, type)) return expr_poison(expr); } if (left->expr_kind == EXPR_CONST && right && right->expr_kind == EXPR_CONST) { @@ -1289,7 +1319,7 @@ static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *exp return false; } } - expr->type = left->type; + expr_copy_types(expr, left); return true; } @@ -1333,7 +1363,7 @@ static bool expr_check_index_in_range(Context *context, Type *type, Expr *index_ } break; } - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_VARARRAY: case TYPE_SUBARRAY: // If not from end, just check the negative values. @@ -1396,14 +1426,14 @@ static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr) expr->pure = index->pure & subscripted->pure; // Cast to an appropriate type for index. - if (!expr_cast_to_index(context, index)) return false; + if (!expr_cast_to_index(index)) return false; // Check range if (!expr_check_index_in_range(context, current_type, index, false, expr->subscript_expr.from_back)) return false; expr->subscript_expr.expr = current_expr; expr->failable |= index->failable; - expr->type = inner_type; + expr_set_type(expr, inner_type); return true; } @@ -1437,8 +1467,8 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) expr->constant &= !end || end->constant; // Fix index sizes - if (!expr_cast_to_index(context, start)) return false; - if (end && !expr_cast_to_index(context, end)) return false; + if (!expr_cast_to_index(start)) return false; + if (end && !expr_cast_to_index(end)) return false; // Check range if (type->type_kind == TYPE_POINTER) @@ -1501,7 +1531,7 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) } expr->failable |= start->failable; - expr->type = type_get_subarray(inner_type); + expr_set_type(expr, type_get_subarray(inner_type)); return true; } @@ -1512,7 +1542,7 @@ static inline void insert_access_deref(Expr *expr) deref->unary_expr.expr = expr->access_expr.parent; deref->resolve_status = RESOLVE_DONE; assert(expr->access_expr.parent->type->canonical->type_kind == TYPE_POINTER); - deref->type = expr->access_expr.parent->type->canonical->pointer; + expr_set_type(deref, expr->access_expr.parent->type->canonical->pointer); deref->failable = expr->access_expr.parent->failable; expr->access_expr.parent = deref; } @@ -1529,7 +1559,7 @@ static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, { expr_to_rewrite->expr_kind = EXPR_CONST; expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind); - expr_to_rewrite->type = type; + expr_set_type(expr_to_rewrite, type); expr_to_rewrite->resolve_status = RESOLVE_DONE; } @@ -1537,12 +1567,12 @@ static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *str { expr_to_rewrite->expr_kind = EXPR_CONST; expr_to_rewrite->constant = true; - expr_to_rewrite->const_expr.kind = TYPE_CTSTR; + expr_to_rewrite->const_expr.kind = TYPE_STRLIT; expr_to_rewrite->const_expr.string.chars = (char *)string; expr_to_rewrite->const_expr.string.len = (int)strlen(string); expr_to_rewrite->pure = true; expr_to_rewrite->resolve_status = RESOLVE_DONE; - expr_to_rewrite->type = type_compstr; + expr_set_type(expr_to_rewrite, type_compstr); } @@ -1553,7 +1583,7 @@ static bool sema_expr_analyse_typeinfo(Context *context, Expr *expr) TypeInfo *type_info = expr->type_expr; if (!sema_resolve_type_info(context, type_info)) return false; - expr->type = type_typeinfo; + expr_set_type(expr, type_typeinfo); return true; } @@ -1660,7 +1690,7 @@ static void add_members_to_context(Context *context, Decl *decl) } } -static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, TypeInfo *parent, bool was_group) +static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, bool was_group) { if (!was_group && type_kind_is_derived(parent->type->type_kind)) { @@ -1676,7 +1706,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T const char *name = TOKSTR(expr->access_expr.sub_element); if (type == TOKEN_TYPEID) { - expr->type = type_typeid; + expr_set_type(expr, type_typeid); expr->expr_kind = EXPR_TYPEID; expr->typeid_expr = parent; expr->resolve_status = RESOLVE_DONE; @@ -1758,7 +1788,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T if (name == function->name) { expr->access_expr.ref = function; - expr->type = function->type; + expr_set_type(expr, function->type); return true; } } @@ -1769,7 +1799,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T { expr->expr_kind = EXPR_MEMBER_ACCESS; expr->access_expr.ref = member; - expr->type = member->type; + expr_set_type(expr, member->type); return true; } } @@ -1792,7 +1822,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) bool is_plain_member = ref->decl_kind == DECL_VAR; if (type == TOKEN_TYPEID) { - expr->type = type_typeid; + expr_set_type(expr, type_typeid); expr->expr_kind = EXPR_TYPEID; if (is_plain_member) { @@ -1854,7 +1884,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) if (name == function->name) { expr->access_expr.ref = function; - expr->type = function->type; + expr_set_type(expr, function->type); return true; } } @@ -1865,7 +1895,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) { expr->expr_kind = EXPR_MEMBER_ACCESS; expr->access_expr.ref = member; - expr->type = member->type; + expr_set_type(expr, member->type); return true; } } @@ -1883,7 +1913,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) if (parent->type == type_typeinfo) { - return sema_expr_analyse_type_access(context, expr, parent->type_expr, was_group); + return sema_expr_analyse_type_access(expr, parent->type_expr, was_group); } if (parent->expr_kind == EXPR_MEMBER_ACCESS) { @@ -1921,7 +1951,7 @@ CHECK_DEEPER: { expr->expr_kind = EXPR_LEN; expr->len_expr.inner = parent; - expr->type = type_void; + expr_set_type(expr, type_void); expr->resolve_status = RESOLVE_DONE; return true; } @@ -1973,7 +2003,7 @@ CHECK_DEEPER: expr->constant = expr->access_expr.parent->constant; expr->pure = expr->access_expr.parent->pure; - expr->type = member->type; + expr_set_type(expr, member->type); expr->access_expr.ref = member; return true; } @@ -2031,7 +2061,7 @@ static int64_t sema_analyse_designator_index(Context *context, Expr *index) } // Unless we already have type_usize, cast to type_isize; - if (!expr_cast_to_index(context, index)) + if (!expr_cast_to_index(index)) { return -1; } @@ -2715,7 +2745,7 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *externa { external_type = sema_type_lower_by_size(external_type, 0); assigned = sema_type_lower_by_size(assigned, 0); - expr->type = external_type; + expr_set_type(expr, external_type); ConstInitializer *initializer = CALLOCS(ConstInitializer); initializer->kind = CONST_INIT_ZERO; initializer->type = type_flatten(expr->type); @@ -2730,13 +2760,13 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *externa // this means that in this case we're actually not resolving macros here. if (init_expressions[0]->expr_kind == EXPR_DESIGNATOR) { - expr->type = external_type; + expr_set_type(expr, external_type); return sema_expr_analyse_designated_initializer(context, assigned, expr); } external_type = sema_type_lower_by_size(external_type, init_expression_count); assigned = sema_type_lower_by_size(assigned, init_expression_count); - expr->type = external_type; + expr_set_type(expr, external_type); // 3. Otherwise use the plain initializer. if (assigned->type_kind == TYPE_ARRAY || assigned->type_kind == TYPE_INFERRED_ARRAY) @@ -2799,14 +2829,16 @@ static inline bool sema_expr_analyse_cast(Context *context, Type *to, Expr *expr expr->constant = inner->constant; if (!success) return false; - if (!cast(context, inner, expr->cast_expr.type_info->type, CAST_TYPE_EXPLICIT)) return false; + Type *target_type = expr->cast_expr.type_info->type; + if (!cast_may_explicit(inner->type, target_type)) + { + SEMA_ERROR(expr, "Cannot cast %s to %s.", type_quoted_error_string(inner->type), type_quoted_error_string(target_type)); + return false; + } - // TODO above is probably not right, cast type not set. - // Overwrite cast. - SourceSpan loc = expr->span; - *expr = *inner; - expr->span = loc; - expr->failable = expr->failable; + cast(inner, target_type); + + expr_replace(expr, inner); return true; } @@ -2817,7 +2849,7 @@ static inline bool sema_expr_analyse_slice_assign(Context *context, Expr *expr, if (!sema_analyse_expr_of_required_type(context, left_type->array.base, right, lhs_is_failable != FAILABLE_NO)) return false; Expr *left = expr->binary_expr.left; - expr->type = right->type; + expr_copy_types(expr, right); expr->expr_kind = EXPR_SLICE_ASSIGN; expr->slice_assign_expr.left = left; expr->slice_assign_expr.right = right; @@ -2835,7 +2867,7 @@ bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *lef if (!sema_analyse_expr_of_required_type(context, left_type, right, lhs_is_failable != FAILABLE_NO)) return false; // 2. Set the result to the type on the right side. - if (expr) expr->type = right->type; + if (expr) expr_copy_types(expr, right); return true; } @@ -2940,7 +2972,7 @@ static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, E /** - * Analyse *%= *= /= %= ^= |= &= + * Analyse define $foo = ... * * @return true if analysis worked. */ @@ -2974,7 +3006,7 @@ static bool sema_expr_analyse_ct_common_assign(Context *context, Expr *expr, Exp } /** - * Analyse *%= *= /= %= ^= |= &= + * Analyse *= /= %= ^= |= &= * * @return true if analysis worked. */ @@ -3057,48 +3089,22 @@ static bool sema_expr_analyse_common_assign(Context *context, Expr *expr, Expr * } // 7. Assign type - expr->type = left->type; + expr_copy_types(expr, left); return true; } -static BinaryOp binary_mod_op_to_non_mod(BinaryOp op) -{ - switch (op) - { - case BINARYOP_MULT_MOD: - return BINARYOP_MULT; - case BINARYOP_MULT_MOD_ASSIGN: - return BINARYOP_MULT_ASSIGN; - case BINARYOP_SUB_MOD: - return BINARYOP_SUB; - case BINARYOP_SUB_MOD_ASSIGN: - return BINARYOP_SUB_ASSIGN; - case BINARYOP_ADD_MOD: - return BINARYOP_ADD; - case BINARYOP_ADD_MOD_ASSIGN: - return BINARYOP_ADD_ASSIGN; - default: - return op; - } -} /** - * Handle a += b, a +%= b, a -= b, a -%= b + * Handle a += b, a -= b * @return true if analysis succeeded. */ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr *left, Expr *right) { - expr->pure = false; - expr->constant = false; - if (left->expr_kind == EXPR_CT_IDENT) { return sema_expr_analyse_ct_common_assign(context, expr, left); } - bool is_mod = expr->binary_expr.operator == BINARYOP_ADD_MOD_ASSIGN - || expr->binary_expr.operator == BINARYOP_SUB_MOD_ASSIGN; - // 1. Analyse the left hand side if (!sema_analyse_expr(context, NULL, left)) return false; @@ -3110,27 +3116,25 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr } Type *left_type_canonical = left->type->canonical; - expr->type = left->type; - // 3. Attempt to analyse and cast this side to the same type if possible. + // 4. Attempt to analyse and cast this side to the same type if possible. if (!sema_analyse_expr(context, left->type, right)) return false; - // 4. In the pointer case we have to treat this differently. + // 3. Copy type & set properties. + expr_copy_types(expr, left); + expr->pure = false; + expr->constant = false; + expr->failable = left->failable | right->failable; + + + // 5. In the pointer case we have to treat this differently. if (left_type_canonical->type_kind == TYPE_POINTER) { - // 5. Prevent +%= and -%= - if (is_mod) - { - SEMA_ERROR(expr, "Cannot use %s with pointer arithmetics, use %s instead.", - token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), - token_type_to_string(binaryop_to_token(binary_mod_op_to_non_mod(expr->binary_expr.operator)))); - return false; - } - // 5. Convert any compile time values to runtime - if (!cast_implicitly_to_runtime(context, right)) return false; + // 6. Convert any compile time values to runtime + if (!cast_implicitly_to_runtime(right)) return false; - // 6. Finally, check that the right side is indeed an integer. + // 7. Finally, check that the right side is indeed an integer. if (!type_is_integer(right->type->canonical)) { SEMA_ERROR(right, "The right side was '%s' but only integers are valid on the right side of %s when the left side is a pointer.", @@ -3141,31 +3145,40 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr return true; } - // 5. Otherwise we cast rhs to lhs - if (!cast_implicit(context, right, left->type)) return false; + // 8. Otherwise we cast rhs to lhs + if (!cast_implicit(right, left->type)) return false; - // 6. We expect a numeric type on both left and right + // 9. We expect a numeric type on both left and right if (!type_is_numeric(left->type)) { SEMA_ERROR(left, "Expected a numeric type here."); return false; } - // 7. Prevent +%= and -%= on non integers - if (is_mod && !type_is_integer(left->type->canonical)) - { - SEMA_ERROR(expr, "%s can only be used for integer arithmetics, for other cases use %s instead.", - token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), - token_type_to_string(binaryop_to_token(binary_mod_op_to_non_mod(expr->binary_expr.operator)))); - return false; - } - return true; } +static Type *numeric_arithmetic_promotion(Type *type) +{ + if (!type) return NULL; + switch (type->type_kind) + { + case ALL_SIGNED_INTS: + case ALL_UNSIGNED_INTS: + if (type->builtin.bitsize < build_target.width_c_int) return type_c_int->canonical; + return type; + case TYPE_F16: + // Promote F16 to a real type. + return type_float; + default: + return type; + } +} + static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *right, Type *left_type, Type *right_type, Expr *parent, const char *error_message) { - Type *max = type_find_max_type(left_type, right_type); + + Type *max = numeric_arithmetic_promotion(type_find_max_type(left_type, right_type)); if (!max || !type_is_numeric(max)) { if (!error_message) @@ -3175,7 +3188,20 @@ static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *righ SEMA_ERROR(parent, error_message, type_to_error_string(left_type), type_to_error_string(right_type)); return false; } - return cast_implicit(context, left, max) && cast_implicit(context, right, max); + return cast_implicit(left, max) & cast_implicit(right, max); +} + +static bool sema_check_int_type_fit(Context *context, Expr *expr, Type *target_type) +{ + if (!target_type) return true; + Type *type = expr->type->canonical; + if (!type_is_any_integer(target_type->canonical) || !type_is_any_integer(type)) return true; + if (type_size(type) > type_size(target_type)) + { + SEMA_ERROR(expr, "A '%s' cannot implicitly convert into '%s'.", type_to_error_string(expr->type), type_to_error_string(target_type)); + return false; + } + return true; } /** @@ -3184,12 +3210,8 @@ static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *righ */ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - // TODO enums - - bool is_mod = expr->binary_expr.operator == BINARYOP_SUB_MOD; - - // 1. Analyse a and b. Do not push down if this is a -% - if (!sema_expr_analyse_binary_sub_expr(context, is_mod ? NULL : to, left, right)) return false; + // 1. Analyse a and b. + if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; Type *left_type = left->type->canonical; Type *right_type = right->type->canonical; @@ -3197,45 +3219,49 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * // 2. Handle the ptr - x and ptr - other_pointer if (left_type->type_kind == TYPE_POINTER) { - // 3. Is this -%? That's not ok for pointer maths. - if (is_mod) - { - SEMA_ERROR(expr, "'-%%' is not valid for pointer maths, use '-' instead."); - return false; - } - - // 4. ptr - other pointer + // 3. ptr - other pointer if (right_type->type_kind == TYPE_POINTER) { - // 5. Require that both types are the same. + // 3a. Require that both types are the same. if (left_type != right_type) { SEMA_ERROR(expr, "'%s' - '%s' is not allowed. Subtracting pointers of different types from each other is not possible.", type_to_error_string(left_type), type_to_error_string(right_type)); return false; } - // 5. usize only if that is the recipient - if (to && to->canonical->type_kind == type_usize->canonical->type_kind) - { - expr->type = to; - return true; - } - expr->type = type_isize; - return true; + + // 3b. Set the type + expr_set_type(expr, type_iptrdiff); + + // 3c. Set all other properties + expr_unify_binary_properties(expr, left, right); + + // 3d. Otherwise check against assigned type so for example short x = &p - &q is an error. + return sema_check_int_type_fit(context, expr, to); } - // 5. Cast any compile time int into runtime version if we have a compile time constant. - if (!cast_implicitly_to_runtime(context, right)) return false; - right_type = right->type->canonical; - - // 6. No need for further casts, just it is an integer. - if (!type_is_integer(right_type)) + + // 4. Check that the right hand side is an integer. + if (!type_is_any_integer(right_type)) { SEMA_ERROR(expr, "Cannot subtract '%s' from '%s'", type_to_error_string(right_type), type_to_error_string(left_type)); return false; } - expr->type = left->type; + // 5. Make sure that the integer does not exceed iptrdiff in size. + if (type_size(right_type) > type_size(type_iptrdiff)) + { + SEMA_ERROR(expr, "Cannot subtract a '%s' from a pointer, please first cast it to '%s'.", type_to_error_string(right_type), type_to_error_string(type_iptrdiff)); + return false; + } + + // 6. Convert to iptrdiff + if (!cast_implicit(right, type_iptrdiff)) return true; + + // 7. Assign the type of the left side. + expr_copy_types(expr, left); + expr_unify_binary_properties(expr, left, right); + return true; } @@ -3247,30 +3273,20 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * left_type = left->type->canonical; + expr_unify_binary(expr, left, right); + // 8. Handle constant folding. if (both_const(left, right)) { expr->expr_kind = EXPR_CONST; expr->const_expr.kind = left_type->type_kind; + expr_copy_types(expr, left); switch (left_type->type_kind) { case ALL_INTS: - if (is_mod && left_type != type_compint) - { - bigint_sub_wrap(&expr->const_expr.i, - &left->const_expr.i, - &right->const_expr.i, - left_type->builtin.bitsize, - type_is_signed(left_type)); - } - else - { - bigint_sub(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); - } - if (!expr_const_int_valid(expr, left_type)) return false; + bigint_sub(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); break; case ALL_FLOATS: - // IMPROVE precision. expr->const_expr.f = left->const_expr.f - right->const_expr.f; break; default: @@ -3278,38 +3294,23 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * } } - // 9. Is this -%? That's not ok unless we are adding integers. - if (is_mod && !type_is_any_integer(left->type->canonical)) - { - SEMA_ERROR(expr, "'-%%' is only valid for integer subtraction, use '-' instead."); - return false; - } - - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; - expr->type = left->type; return true; } /** - * Analyse a + b / a +% b + * Analyse a + b * @return true if it succeeds. */ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - // TODO enums - - bool is_mod = expr->binary_expr.operator == BINARYOP_ADD_MOD; - // 1. Promote everything to the recipient type – if possible // this is safe in the pointer case actually. - if (!sema_expr_analyse_binary_sub_expr(context, is_mod ? NULL : to, left, right)) return false; + if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; Type *left_type = left->type->canonical; Type *right_type = right->type->canonical; - // 2. To detect pointer additions, reorder if needed if (right_type->type_kind == TYPE_POINTER && left_type->type_kind != TYPE_POINTER) { @@ -3320,11 +3321,11 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * left_type = left->type->canonical; } - // 4. The "left" will now always be the pointer. + // 3. The "left" will now always be the pointer. // so check if we want to do the normal pointer add special handling. if (left_type->type_kind == TYPE_POINTER) { - // 4a. Check that the other side is an integer of some sort. + // 3a. Check that the other side is an integer of some sort. if (!type_is_any_integer(right_type)) { SEMA_ERROR(right, "A value of type '%s' cannot be added to '%s', an integer was expected here.", @@ -3333,50 +3334,34 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * return false; } - // 4b. Cast it to usize or isize depending on underlying type. + // 3b. Cast it to usize or isize depending on underlying type. // Either is fine, but it looks a bit nicer if we actually do this and keep the sign. - bool success = cast_implicit(context, right, type_is_unsigned(right_type) ? type_usize : type_isize); + bool success = cast_implicit(right, type_iptrdiff); + // No need to check the cast we just ensured it was an integer. assert(success && "This should always work"); - // 4c. Set the type. - expr->type = left->type; - - // 4d. Is this +%? That's not ok for pointers! - if (is_mod) - { - SEMA_ERROR(expr, "You cannot use '+%%' with pointer addition, use '+' instead."); - return false; - } + // 3c. Set the type and other properties. + expr_copy_types(expr, left); + expr_unify_binary_properties(expr, left, right); return true; } - // 5. Do the binary arithmetic promotion (finding a common super type) - // If none can be find, send an error. + // 4. Do an binary arithmetic promotion if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot add '%s' to '%s'")) { return false; } - left_type = left->type->canonical; - - // 6. Handle the "both const" case. We should only see ints and floats at this point. + // 5. Handle the "both const" case. We should only see ints and floats at this point. if (both_const(left, right)) { expr->expr_kind = EXPR_CONST; - expr->const_expr.kind = left_type->type_kind; + expr->const_expr.kind = left->type->canonical->type_kind; switch (left->const_expr.kind) { case ALL_INTS: - if (is_mod && left_type != type_compint) - { - bigint_add_wrap(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i, left_type->builtin.bitsize, type_is_signed(left_type)); - } - else - { - bigint_add(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); - } - if (!expr_const_int_valid(expr, left_type)) return false; + bigint_add(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); break; case ALL_FLOATS: expr->const_expr.f = left->const_expr.f + right->const_expr.f; @@ -3386,37 +3371,25 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * } } - // 7. Is this +%? That's not ok unless we are adding integers. - if (is_mod && !type_is_any_integer(left->type->canonical)) - { - SEMA_ERROR(expr, "'+%%' is only valid for integer addition, use '+' instead."); - return false; - } - // 7. Set the type - expr->type = left->type; - - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; + // 6. Set the type & other properties. + expr_unify_binary(expr, left, right); return true; } /** - * Analyse a * b and a *% b + * Analyse a * b * - * Will analyse a and b and convert them to the "to" type if possible. + * Will analyse a and b and then use arithmetic promotion on each. * It will then try to promote both to a common type, - * check that *% is only used on an integer and then perform constant folding. * * @return true if analysis worked. */ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - bool is_mod = expr->binary_expr.operator == BINARYOP_MULT_MOD; - // 1. Analyse the sub expressions. if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; @@ -3429,42 +3402,16 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr return false; } - // 3. Set the type. - expr->type = left->type; - - // Might have changed - left_type = left->type->canonical; - - // 4. Prevent *% use on non-integers. - if (is_mod && !type_is_any_integer(left_type)) - { - SEMA_ERROR(expr, "*%% can only be used with integer types, try * instead."); - return false; - } - - // 5. Handle constant folding. + // 3. Handle constant folding. if (both_const(left, right)) { expr->expr_kind = EXPR_CONST; - expr->const_expr.kind = left_type->type_kind; + expr->const_expr.kind = left->type->canonical->type_kind; switch (left->const_expr.kind) { case ALL_INTS: - // 5a. Do mod mult if applicable. - if (is_mod && left_type != type_compint) - { - bigint_mul_wrap(&expr->const_expr.i, - &left->const_expr.i, - &right->const_expr.i, - left_type->builtin.bitsize, - type_is_signed(left_type)); - } - else - { - bigint_mul(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); - } - if (!expr_const_int_valid(expr, left_type)) return false; + bigint_mul(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); break; case ALL_FLOATS: expr->const_expr.f = left->const_expr.f * right->const_expr.f; @@ -3474,9 +3421,9 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr } } - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; - // 6. All done. + // 4. Update failable / pure / type etc. + expr_unify_binary(expr, left, right); + return true; } @@ -3498,8 +3445,6 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr * return false; } - expr->type = left->type; - // 3. Check for a constant 0 on the right hand side. if (is_const(right)) { @@ -3542,8 +3487,7 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr * } // 5. Done. - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; + expr_unify_binary(expr, left, right); return true; @@ -3582,9 +3526,7 @@ static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr * bigint_rem(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); } - expr->type = left->type; - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; + expr_unify_binary(expr, left, right); return true; } @@ -3635,9 +3577,7 @@ static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr * } // 5. Assign the type - expr->type = left->type; - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; + expr_unify_binary(expr, left, right); return true; } @@ -3647,22 +3587,29 @@ static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr * */ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - // 1. Analyze the two sub lhs & rhs *without coercion* - if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false; + // 1. Analyze lhs with target type. + if (!sema_analyse_expr(context, to, left)) return false; - // 2. Only integers may be shifted. + // 2. Analyse rhs without target type. + if (!sema_analyse_expr(context, NULL, right)) return false; + + // 3. Only integers may be shifted. if (!both_any_integer(left, right)) { return sema_type_error_on_binop(context, expr); } + // 4. Promote lhs using the usual numeric promotion. + if (!cast_implicit(left, numeric_arithmetic_promotion(left->type))) return false; + expr->pure = left->pure & right->pure; expr->constant = left->constant & right->constant; + expr->failable = left->failable | right->failable; - // 3. For a constant right hand side we will make a series of checks. + // 5. For a constant right hand side we will make a series of checks. if (is_const(right)) { - // 3a. Make sure the value does not exceed the bitsize of + // 5a. Make sure the value does not exceed the bitsize of // the left hand side. We ignore this check for lhs being a constant. if (left->type->canonical->type_kind != TYPE_IXX) { @@ -3674,24 +3621,24 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr return false; } } - // 3b. Make sure that the right hand side is positive. + // 5b. Make sure that the right hand side is positive. if (bigint_cmp_zero(&right->const_expr.i) == CMP_LT) { SEMA_ERROR(right, "A shift must be a positive number."); return false; } - // 4. Fold constant expressions. + // 6. Fold constant expressions. if (is_const(left)) { - // 4a. For >> this is always an arithmetic shift. + // 6a. For >> this is always an arithmetic shift. if (expr->binary_expr.operator == BINARYOP_SHR) { expr_replace(expr, left); bigint_shr(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); return true; } - // 4b. The << case needs to behave differently for bigints and fixed bit integers. + // 6b. The << case needs to behave differently for bigints and fixed bit integers. expr_replace(expr, left); if (left->const_expr.kind == TYPE_IXX) { @@ -3707,20 +3654,24 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr } } - // 5. We might have the case 2 << x. In that case we will to cast the left hand side to the receiving type. - if (!cast_implicit(context, left, to)) return false; - - // 6. As a last out, we make sure that a comptime int has a real type by casting to the right side (which must be non constant) + // 7. In the case of 2 >> x, we will want to cast to the target type if available, otherwise we use a ct->runtime promotion. if (type_is_ct(left->type)) { - assert(!type_is_ct(right->type)); - cast(context, left, right->type, CAST_TYPE_EXPLICIT); + if (to) + { + // 7a. The target type exists, convert to this type after arithmetic promotion. + if (!cast_implicit(left, numeric_arithmetic_promotion(to))) return false; + left->original_type = to; + } + else + { + // 7b. Otherwise, use runtime promotion. + if (!cast_implicitly_to_runtime(left)) return false; + } } - // 7. On LLVM, left and right types must match. - cast(context, right, left->type, CAST_TYPE_EXPLICIT); + expr_copy_types(expr, left); - expr->type = left->type; return true; } @@ -3730,12 +3681,14 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr */ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *left, Expr *right) { - expr->pure = false; - expr->constant = false; // 1. Analyze the two sub lhs & rhs *without coercion* if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false; + expr->pure = false; + expr->constant = false; + expr->failable = left->failable | right->failable; + // 2. Ensure the left hand side is assignable if (!expr_is_ltype(left)) { @@ -3743,13 +3696,13 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l return false; } - // 2. Only integers may be shifted. + // 3. Only integers may be shifted. if (!both_any_integer(left, right)) return sema_type_error_on_binop(context, expr); - // 3. For a constant right hand side we will make a series of checks. + // 4. For a constant right hand side we will make a series of checks. if (is_const(right)) { - // 3a. Make sure the value does not exceed the bitsize of + // 4a. Make sure the value does not exceed the bitsize of // the left hand side. BigInt bitsize; bigint_init_unsigned(&bitsize, left->type->canonical->builtin.bitsize); @@ -3759,7 +3712,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l return false; } - // 3b. Make sure that the right hand side is positive. + // 4b. Make sure that the right hand side is positive. if (bigint_cmp_zero(&right->const_expr.i) == CMP_LT) { SEMA_ERROR(right, "A shift must be a positive number."); @@ -3767,11 +3720,8 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l } } - // 4. Set the type - expr->type = left->type; - - // 5. This is already checked as ok - cast(context, right, left->type, CAST_TYPE_EXPLICIT); + // 5. Set the type using the left hand side. + expr_copy_types(expr, left); return true; } @@ -3780,32 +3730,30 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right) { if (!sema_analyse_expr(context, type_bool, left) & sema_analyse_expr(context, type_bool, right)) return false; - if (!cast_implicit(context, left, type_bool) || !cast_implicit(context, right, type_bool)) return false; + if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; - expr->type = type_bool; + expr_set_type(expr, type_bool); if (both_const(left, right)) { expr_replace(expr, left); expr->const_expr.b &= right->const_expr.b; } - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; + expr_unify_binary_properties(expr, left, right); return true; } static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) { if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false; - if (!cast_implicit(context, left, type_bool) || !cast_implicit(context, right, type_bool)) return false; + if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; if (both_const(left, right)) { expr_replace(expr, left); expr->const_expr.b |= right->const_expr.b; } - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; - expr->type = type_bool; + expr_unify_binary_properties(expr, left, right); + expr_set_type(expr, type_bool); return true; } @@ -3822,14 +3770,14 @@ static void cast_to_max_bit_size(Context *context, Expr *left, Expr *right, Type Type *to = left->type->type_kind < TYPE_U8 ? type_int_signed_by_bitsize(bit_size_right) : type_int_unsigned_by_bitsize(bit_size_right); - bool success = cast_implicit(context, left, to); + bool success = cast_implicit(left, to); assert(success); return; } Type *to = right->type->type_kind < TYPE_U8 ? type_int_signed_by_bitsize(bit_size_right) : type_int_unsigned_by_bitsize(bit_size_right); - bool success = cast_implicit(context, right, to); + bool success = cast_implicit(right, to); assert(success); } @@ -3896,7 +3844,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp case TYPE_STRUCT: case TYPE_UNION: case TYPE_ERR_UNION: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_ARRAY: case TYPE_VARARRAY: case TYPE_SUBARRAY: @@ -3923,8 +3871,8 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp } // 6. Do the implicit cast. - if (!cast_implicit(context, left, max)) goto ERR; - if (!cast_implicit(context, right, max)) goto ERR; + if (!cast_implicit(left, max)) goto ERR; + if (!cast_implicit(right, max)) goto ERR; } // 7. Do constant folding. @@ -3936,9 +3884,8 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp } // 8. Set the type to bool - expr->type = type_bool; - expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; + expr_unify_binary_properties(expr, left, right); + expr_set_type(expr, type_bool); return true; ERR: @@ -3970,9 +3917,8 @@ static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner) Type *deref_type = inner->type->type_kind != TYPE_POINTER ? inner->type : canonical; // 4. And... set the type. - expr->type = deref_type->pointer; - expr->constant = inner->constant; - expr->pure = inner->pure; + expr_set_type(expr, deref_type->pointer); + expr_copy_properties(expr, inner); return true; } @@ -4102,9 +4048,10 @@ static bool sema_expr_analyse_addr(Context *context, Type *to, Expr *expr, Expr if (!sema_take_addr_of(inner, &is_constant)) return expr_poison(expr); // 3. Get the pointer of the underlying type. - expr->type = type_get_ptr(inner->type); + expr_set_type(expr, type_get_ptr(inner->type)); expr->constant = is_constant; expr->pure = inner->pure; + expr->failable = inner->failable; return true; } @@ -4117,39 +4064,22 @@ static bool sema_expr_analyse_neg(Context *context, Type *to, Expr *expr, Expr * SEMA_ERROR(expr, "Cannot negate %s.", type_to_error_string(inner->type)); return false; } - expr->constant = inner->constant; - expr->pure = inner->pure; + expr_copy_properties(expr, inner); if (inner->expr_kind != EXPR_CONST) { - expr->type = inner->type; + expr_copy_types(expr, inner); return true; } - bool is_negmod = expr->unary_expr.operator == UNARYOP_NEGMOD; expr_replace(expr, inner); switch (expr->const_expr.kind) { case ALL_INTS: - if (is_negmod) - { - if (canonical->type_kind != TYPE_IXX) - { - SEMA_ERROR(expr, "Cannot use –% on compile time integers, you need to first cast it to an integer type e.g. -%cast(-128, char)."); - - // Continue parsing, pretending this is a - - bigint_negate(&expr->const_expr.i, &inner->const_expr.i); - return true; - } - bigint_negate_wrap(&expr->const_expr.i, - &inner->const_expr.i, - inner->type->canonical->builtin.bitsize); - return true; - } bigint_negate(&expr->const_expr.i, &inner->const_expr.i); if (expr_const_int_overflowed(&expr->const_expr)) { - SEMA_ERROR(expr, "Negating %s overflows '%s'.", expr_const_to_error_string(&expr->const_expr), type_to_error_string(expr->type)); + SEMA_ERROR(expr, "%s does not fit in '%s'.", expr_const_to_error_string(&expr->const_expr), type_to_error_string(expr->type)); return false; } return true; @@ -4169,11 +4099,15 @@ static bool sema_expr_analyse_neg(Context *context, Type *to, Expr *expr, Expr * */ static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Expr *inner) { - expr->constant = inner->constant; - expr->pure = inner->pure; + expr_copy_properties(expr, inner); Type *canonical = inner->type->canonical; - if (!type_is_integer(canonical) && canonical != type_bool) + if (canonical->type_kind == TYPE_IXX) + { + SEMA_ERROR(expr, "Cannot bit negate an untyped integer literal, please first cast it to a concrete type.", type_to_error_string(inner->type)); + return false; + } + if (!type_is_any_integer(canonical) && canonical != type_bool) { SEMA_ERROR(expr, "Cannot bit negate '%s'.", type_to_error_string(inner->type)); return false; @@ -4181,7 +4115,7 @@ static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Ex // The simple case, non-const. if (inner->expr_kind != EXPR_CONST) { - expr->type = inner->type; + expr_copy_types(expr, inner); return true; } @@ -4197,18 +4131,18 @@ static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Ex case TYPE_BOOL: expr->const_expr.b = !expr->const_expr.b; break; + case TYPE_IXX: default: UNREACHABLE } return true; } -static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *inner) +static bool sema_expr_analyse_not(Expr *expr, Expr *inner) { - expr->constant = inner->constant; - expr->pure = inner->pure; + expr_copy_properties(expr, inner); + expr_set_type(expr, type_bool); - expr->type = type_bool; if (inner->expr_kind == EXPR_CONST) { switch (expr->const_expr.kind) @@ -4222,7 +4156,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * case ALL_FLOATS: expr->const_expr.b = inner->const_expr.f == 0.0; break; - case TYPE_CTSTR: + case TYPE_STRLIT: expr->const_expr.b = !inner->const_expr.string.len; break; case TYPE_ERRTYPE: @@ -4261,7 +4195,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * case TYPE_STRUCT: case TYPE_UNION: case TYPE_VOID: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_ENUM: case TYPE_ERRTYPE: case TYPE_TYPEID: @@ -4321,6 +4255,7 @@ static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr * { expr->constant = false; expr->pure = false; + expr->failable = inner->failable; if (!expr_is_ltype(inner)) { @@ -4332,12 +4267,14 @@ static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr * return sema_expr_analyse_ct_incdec(context, expr, inner); } - if (!type_is_numeric(inner->type->canonical) && inner->type->canonical->type_kind != TYPE_POINTER) + Type *type = type_flatten(inner->type); + + if (!type_is_numeric(type) && type->type_kind != TYPE_POINTER) { SEMA_ERROR(inner, "Expression must be a number or a pointer."); return false; } - expr->type = inner->type; + expr_copy_types(expr, inner); return true; } @@ -4351,9 +4288,8 @@ static inline bool sema_expr_analyse_taddr(Context *context, Type *to, Expr *exp if (!sema_analyse_expr(context, inferred_type, inner)) return false; - expr->constant = inner->constant; - expr->pure = inner->pure; - expr->type = type_get_ptr(inner->type); + expr_copy_properties(expr, inner); + expr_set_type(expr, type_get_ptr(inner->type)); return true; } @@ -4370,25 +4306,19 @@ static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *ex case BINARYOP_ASSIGN: return sema_expr_analyse_assign(context, expr, left, right); case BINARYOP_MULT: - case BINARYOP_MULT_MOD: return sema_expr_analyse_mult(context, to, expr, left, right); case BINARYOP_ADD: - case BINARYOP_ADD_MOD: return sema_expr_analyse_add(context, to, expr, left, right); case BINARYOP_ADD_ASSIGN: - case BINARYOP_ADD_MOD_ASSIGN: case BINARYOP_SUB_ASSIGN: - case BINARYOP_SUB_MOD_ASSIGN: return sema_expr_analyse_add_sub_assign(context, expr, left, right); case BINARYOP_SUB: - case BINARYOP_SUB_MOD: return sema_expr_analyse_sub(context, to, expr, left, right); case BINARYOP_DIV: return sema_expr_analyse_div(context, to, expr, left, right); case BINARYOP_MULT_ASSIGN: case BINARYOP_DIV_ASSIGN: return sema_expr_analyse_common_assign(context, expr, left, right, false); - case BINARYOP_MULT_MOD_ASSIGN: case BINARYOP_BIT_AND_ASSIGN: case BINARYOP_BIT_OR_ASSIGN: case BINARYOP_BIT_XOR_ASSIGN: @@ -4435,15 +4365,14 @@ static inline bool sema_expr_analyse_unary(Context *context, Type *to, Expr *exp case UNARYOP_ADDR: return sema_expr_analyse_addr(context, to, expr, inner); case UNARYOP_NEG: - case UNARYOP_NEGMOD: - if (!sema_analyse_expr(context, NULL, inner)) return false; + if (!sema_analyse_expr(context, to, inner)) return false; return sema_expr_analyse_neg(context, to, expr, inner); case UNARYOP_BITNEG: if (!sema_analyse_expr(context, to, inner)) return false; return sema_expr_analyse_bit_not(context, to, expr, inner); case UNARYOP_NOT: if (!sema_analyse_expr(context, NULL, inner)) return false; - return sema_expr_analyse_not(context, to, expr, inner); + return sema_expr_analyse_not(expr, inner); case UNARYOP_DEC: case UNARYOP_INC: if (!sema_analyse_expr_value(context, NULL, inner)) return false; @@ -4479,7 +4408,7 @@ static inline bool sema_expr_analyse_try(Context *context, Expr *expr) SEMA_ERROR(expr->trycatch_expr, "Expected a failable expression to 'try'."); return false; } - expr->type = type_bool; + expr_set_type(expr, type_bool); return true; } @@ -4495,7 +4424,7 @@ static inline bool sema_expr_analyse_catch(Context *context, Expr *expr) SEMA_ERROR(expr->trycatch_expr, "Expected a failable expression to 'catch'."); return false; } - expr->type = type_bool; + expr_set_type(expr, type_bool); return true; } @@ -4517,7 +4446,7 @@ static inline bool sema_expr_analyse_else(Context *context, Type *to, Expr *expr { expr->pure = false; if (!sema_analyse_statement(context, expr->else_expr.else_stmt)) return false; - expr->type = type; + expr_copy_types(expr, inner); return true; } @@ -4526,10 +4455,12 @@ static inline bool sema_expr_analyse_else(Context *context, Type *to, Expr *expr expr->pure &= expr->else_expr.else_expr->pure; // Here we might need to insert casts. Type *common = type_find_max_type(type, expr->else_expr.else_expr->type); - if (!cast_implicit(context, expr->else_expr.else_expr, common)) return false; + if (!cast_implicit(expr->else_expr.else_expr, common)) return false; expr->type = common; - return cast_implicit(context, expr->else_expr.expr, common); + expr->original_type = type_find_max_type(inner->original_type, expr->else_expr.else_expr->original_type); + + return cast_implicit(expr->else_expr.expr, common); } static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *expr) @@ -4538,7 +4469,7 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp bool success = sema_analyse_expr(context, to, inner); expr->guard_expr.defer = context->current_scope->defer_last; if (!success) return false; - expr->type = inner->type; + expr_copy_types(expr, inner); expr->pure = false; expr->constant = false; if (!inner->failable) @@ -4554,6 +4485,13 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp return true; } +static inline bool sema_expr_analyse_const(Type *to, Expr *expr) +{ + expr->constant = true; + expr->pure = true; + return true; +} + static Ast *ast_shallow_copy(Ast *source) { return COPY(source); @@ -4995,7 +4933,7 @@ static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr { return expr_poison(expr); } - expr->type = type_typeid; + expr_set_type(expr, type_typeid); return true; } @@ -5007,7 +4945,7 @@ static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr *expr) { bool success = true; - expr->type = type_void; + expr_set_type(expr, type_void); bool saved_expr_failable_return = context->expr_failable_return; Type *prev_expected_block_type = context->expected_block_type; Ast **saved_returns = context_push_returns(context); @@ -5039,7 +4977,7 @@ static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr success = false; goto EXIT; } - expr->type = left_canonical; + expr_set_type(expr, left_canonical); EXIT: context_pop_scope(context); context_pop_returns(context, saved_returns); @@ -5069,7 +5007,7 @@ static inline bool sema_expr_analyse_typeof(Context *context, Expr *expr) Type *type = expr->typeof_expr->type->canonical; expr->expr_kind = EXPR_TYPEID; expr->typeid_expr = type_info_new_base(type, expr->typeof_expr->span); - expr->type = type_typeid; + expr_set_type(expr, type_typeid); return true; } @@ -5091,7 +5029,7 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr * inner->expr_kind = EXPR_COMPOUND_LITERAL; inner->expr_compound_literal.type_info = inner_type_info; inner->expr_compound_literal.initializer = NULL; - inner->type = inner_type_info->type; + expr_set_type(inner, inner_type_info->type); } if (inner->failable) { @@ -5110,11 +5048,11 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr * } if (!to) { - expr->type = type_void; + expr_set_type(expr, type_void); return true; } expr->failable = true; - expr->type = to; + expr_set_type(expr, to); return true; } @@ -5133,7 +5071,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * return sema_expr_analyse_hash_identifier(context, to, expr); case EXPR_MACRO_CT_IDENTIFIER: case EXPR_CT_IDENT: - return sema_expr_analyse_ct_identifier(context, to, expr); + return sema_expr_analyse_ct_identifier(context, expr); case EXPR_FAILABLE: return sema_expr_analyse_failable(context, to, expr); case EXPR_POISONED: @@ -5164,9 +5102,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * case EXPR_GUARD: return sema_expr_analyse_guard(context, to, expr); case EXPR_CONST: - expr->constant = true; - expr->pure = true; - return true; + return sema_expr_analyse_const(to, expr); case EXPR_BINARY: if (!sema_expr_analyse_binary(context, to, expr)) return false; if (expr->expr_kind == EXPR_BINARY) @@ -5218,7 +5154,7 @@ bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, SEMA_ERROR(expr, "'%s!' cannot be converted into '%s'.", type_to_error_string(expr->type), type_to_error_string(to)); return false; } - return cast_implicit(context, expr, to); + return to ? cast_implicit(expr, to) : true; } @@ -5239,9 +5175,9 @@ static inline bool sema_cast_rvalue(Context *context, Type *to, Expr *expr) case EXPR_MEMBER_ACCESS: if (expr->access_expr.ref->decl_kind == DECL_ENUM_CONSTANT) { - Type *original_type = expr->type; + Type *original_type = expr->access_expr.ref->type; expr_replace(expr, expr->access_expr.ref->enum_constant.expr); - expr->type = original_type; + expr->original_type = original_type; return true; } SEMA_ERROR(expr, "A member must be followed by '.' plus a property like 'sizeof'."); @@ -5274,7 +5210,7 @@ static inline bool sema_cast_rvalue(Context *context, Type *to, Expr *expr) default: break; } - return to ? cast(context, expr, to, CAST_TYPE_OPTIONAL_IMPLICIT) : true; + return true; } bool sema_analyse_expr_value(Context *context, Type *to, Expr *expr) diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 40a75e2eb..b68450e80 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -87,7 +87,7 @@ static Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr) context_pop_defers_to(context, &defers); if (defers.end == defers.start) return expr; Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span); - wrap->type = expr->type; + expr_copy_types(wrap, expr); wrap->resolve_status = RESOLVE_DONE; wrap->expr_scope.expr = expr; wrap->expr_scope.defers = defers; @@ -206,17 +206,17 @@ static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr) } if (entries == 0) { - expr->type = type_void; + expr_set_type(expr, type_void); return true; } Ast *last = dexprs[entries - 1]; switch (last->ast_kind) { case AST_DECLARE_STMT: - expr->type = last->declare_stmt->type; + expr_set_type(expr, last->declare_stmt->type); break; case AST_EXPR_STMT: - expr->type = last->expr_stmt->type; + expr_copy_types(expr, last->expr_stmt); break; default: UNREACHABLE @@ -249,7 +249,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ } if (cast_to_bool) { - if (!cast_implicit(context, last->expr_stmt, type_bool)) return false; + if (!cast_implicit(last->expr_stmt, type_bool)) return false; } return true; case AST_DECLARE_STMT: @@ -267,8 +267,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ type_to_error_string(last->expr_stmt->type), cast_to_bool ? "bool" : type_to_error_string(init->type)); } - if (!decl->var.unwrap && cast_to_bool && init->type->type_kind != TYPE_BOOL && - cast_to_bool_kind(decl->var.type_info->type) == CAST_ERROR) + if (!decl->var.unwrap && cast_to_bool && cast_to_bool_kind(decl->var.type_info->type) == CAST_ERROR) { SEMA_ERROR(last->declare_stmt->var.init_expr, "The expression needs to be convertible to a boolean."); return false; @@ -379,6 +378,11 @@ static inline bool sema_analyse_local_decl(Context *context, Decl *decl) } if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, decl->var.failable || decl->var.unwrap ? FAILABLE_YES : FAILABLE_NO)) return decl_poison(decl); + if (decl->type) + { + expr_set_type(decl->var.init_expr, decl->type); + } + if (type_is_inferred) { Type *right_side_type = init->type->canonical; @@ -702,8 +706,8 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) if (var->type != expected_var_type) { // This is hackish, replace when cast is refactored. - Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type }; - if (!cast_implicit(context, &dummy, var->type)) goto EXIT_FAIL; + Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type, .original_type = expected_var_type }; + if (!cast_implicit(&dummy, var->type)) goto EXIT_FAIL; assert(dummy.expr_kind == EXPR_CAST); statement->foreach_stmt.cast = dummy.cast_expr.kind; } @@ -1003,7 +1007,7 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) if (!sema_analyse_expr(context, parent->switch_stmt.cond->type, target)) return false; - if (!cast_implicit(context, target, parent->switch_stmt.cond->type)) return false; + if (!cast_implicit(target, parent->switch_stmt.cond->type)) return false; if (target->expr_kind == EXPR_CONST) { @@ -1140,7 +1144,7 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st return false; } - Type *case_type = case_expr->type->canonical; + Type *case_type = case_expr->original_type->canonical; Type *to_type_canonical = to_type->canonical; // 3. If we already have the same type we're done. @@ -1148,12 +1152,12 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st // 4. Otherwise check if we have an enum receiving type and a number on // in the case. In that case we do an implicit conversion. - if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_expr->type)) + if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_type)) { - return cast(context, case_expr, to_type, CAST_TYPE_EXPLICIT); + return cast(case_expr, to_type); } - return cast_implicit(context, case_expr, to_type); + return cast_implicit(case_expr, to_type); } @@ -1627,7 +1631,7 @@ bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement) if (message) { if (!sema_analyse_expr(context, type_compstr, message)) return false; - if (message->type->type_kind != TYPE_CTSTR) + if (message->type->type_kind != TYPE_STRLIT) { SEMA_ERROR(message, "Expected a string as the error message."); } @@ -1658,7 +1662,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement) if (message) { if (!sema_analyse_expr(context, type_compstr, message)) return false; - if (message->type->type_kind != TYPE_CTSTR) + if (message->type->type_kind != TYPE_STRLIT) { SEMA_ERROR(message, "Expected a string as the error message."); } diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index a50dbf6a2..30ee4e0b5 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -43,7 +43,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type) SEMA_ERROR(type->array.len, "Expected a constant value as array size."); return type_info_poison(type); } - if (!type_is_integer(type->array.len->type->canonical)) + if (!type_is_any_integer(type->array.len->type->canonical)) { SEMA_ERROR(type->array.len, "Expected an integer size."); return type_info_poison(type); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 4e11ae624..593cd7ad4 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -96,14 +96,10 @@ const char *token_type_to_string(TokenType type) return "{|"; case TOKEN_MINUS_ASSIGN: return "-="; - case TOKEN_MINUS_MOD: - return "-%"; case TOKEN_MINUSMINUS: return "--"; case TOKEN_MULT_ASSIGN: return "*="; - case TOKEN_MULT_MOD: - return "*%"; case TOKEN_MOD_ASSIGN: return "%="; case TOKEN_NOT_EQUAL: @@ -112,8 +108,6 @@ const char *token_type_to_string(TokenType type) return "||"; case TOKEN_PLUS_ASSIGN: return "+="; - case TOKEN_PLUS_MOD: - return "+%"; case TOKEN_PLUSPLUS: return "++"; case TOKEN_RBRAPIPE: @@ -130,16 +124,10 @@ const char *token_type_to_string(TokenType type) // Three character tokens case TOKEN_ELLIPSIS: return "..."; - case TOKEN_MULT_MOD_ASSIGN: - return "*%="; - case TOKEN_PLUS_MOD_ASSIGN: - return "+%="; case TOKEN_SHL_ASSIGN: return "<<="; case TOKEN_SHR_ASSIGN: return ">>="; - case TOKEN_MINUS_MOD_ASSIGN: - return "-%="; // Identifiers case TOKEN_IDENT: @@ -304,27 +292,17 @@ const char *token_type_to_string(TokenType type) return "isize"; case TOKEN_USIZE: return "usize"; + case TOKEN_IPTR: + return "iptr"; + case TOKEN_UPTR: + return "uptr"; + case TOKEN_IPTRDIFF: + return "iptrdiff"; + case TOKEN_UPTRDIFF: + return "uptrdiff"; case TOKEN_HALF: return "half"; - case TOKEN_C_SHORT: - return "c_short"; - case TOKEN_C_INT: - return "c_int"; - case TOKEN_C_LONG: - return "c_long"; - case TOKEN_C_LONGLONG: - return "c_longlong"; - case TOKEN_C_USHORT: - return "c_ushort"; - case TOKEN_C_UINT: - return "c_uint"; - case TOKEN_C_ULONG: - return "c_ulong"; - case TOKEN_C_ULONGLONG: - return "c_ulonglong"; - - case TOKEN_DOCS_EOL: return "EOL"; case TOKEN_DOCS_START: @@ -380,10 +358,10 @@ bool token_is_symbol(TokenType type) bool token_is_type(TokenType type) { - return type >= TOKEN_VOID && type <= TOKEN_C_ULONGLONG; + return type >= TOKEN_VOID && type <= TOKEN_TYPEID; } bool token_is_any_type(TokenType type) { - return (type >= TOKEN_VOID && type <= TOKEN_C_ULONGLONG) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT; + return (type >= TOKEN_VOID && type <= TOKEN_TYPEID) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT; } diff --git a/src/compiler/types.c b/src/compiler/types.c index ac7ab9850..cb5652632 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -7,7 +7,7 @@ static Type t_u0, t_str, t_u1, t_i8, t_i16, t_i32, t_i64, t_i128, t_ixx; static Type t_u8, t_u16, t_u32, t_u64, t_u128; static Type t_f16, t_f32, t_f64, t_f128, t_fxx; -static Type t_usz, t_isz; +static Type t_usz, t_isz, t_uptr, t_iptr, t_uptrdiff, t_iptrdiff; static Type t_cus, t_cui, t_cul, t_cull; static Type t_cs, t_ci, t_cl, t_cll; static Type t_voidstar, t_typeid, t_error, t_typeinfo; @@ -27,12 +27,16 @@ Type *type_short = &t_i16; Type *type_int = &t_i32; Type *type_long = &t_i64; Type *type_i128 = &t_i128; +Type *type_iptr = &t_iptr; +Type *type_iptrdiff = &t_iptrdiff; Type *type_isize = &t_isz; Type *type_char = &t_u8; Type *type_ushort = &t_u16; Type *type_uint = &t_u32; Type *type_ulong = &t_u64; Type *type_u128 = &t_u128; +Type *type_uptr = &t_uptr; +Type *type_uptrdiff = &t_uptrdiff; Type *type_usize = &t_usz; Type *type_compint = &t_ixx; Type *type_compfloat = &t_fxx; @@ -83,6 +87,17 @@ Type *type_int_unsigned_by_bitsize(unsigned bytesize) } } +const char *type_quoted_error_string(Type *type) +{ + char *buffer = NULL; + if (type->canonical != type) + { + asprintf(&buffer, "'%s' (%s)", type_to_error_string(type), type_to_error_string(type->canonical)); + return buffer; + } + asprintf(&buffer, "'%s'", type_to_error_string(type)); + return buffer; +} const char *type_to_error_string(Type *type) { char *buffer = NULL; @@ -129,7 +144,7 @@ const char *type_to_error_string(Type *type) } asprintf(&buffer, "%s*", type_to_error_string(type->pointer)); return buffer; - case TYPE_CTSTR: + case TYPE_STRLIT: return "compile time string"; case TYPE_ARRAY: asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len); @@ -208,7 +223,7 @@ ByteSize type_size(Type *type) case ALL_FLOATS: case TYPE_ERR_UNION: return type->builtin.bytesize; - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: @@ -338,7 +353,7 @@ bool type_is_abi_aggregate(Type *type) case TYPE_POINTER: case TYPE_ENUM: case TYPE_FUNC: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_VECTOR: return false; case TYPE_ERRTYPE: @@ -484,7 +499,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) case TYPE_MEMBER: case TYPE_TYPEID: case TYPE_FUNC: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_SUBARRAY: case TYPE_INFERRED_ARRAY: return false; @@ -644,7 +659,7 @@ AlignSize type_abi_alignment(Type *type) case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: - case TYPE_CTSTR: + case TYPE_STRLIT: return t_usz.canonical->builtin.abi_alignment; case TYPE_ARRAY: return type_abi_alignment(type->array.base); @@ -788,6 +803,98 @@ Type *type_get_vararray(Type *arr_type) return type_generate_subarray(arr_type, false); } +static inline bool array_structurally_equivalent_to_struct(Type *array, Type *type) +{ + assert(array->type_kind == TYPE_ARRAY); + + ByteSize len = array->array.len; + if (!len) return type_size(type) == 0; + + Type *base = array->array.base; + + if (len == 1 && type_is_structurally_equivalent(base, type)) return true; + + assert(type->type_kind != TYPE_UNION && "Does not work on unions"); + + if (!type_is_structlike(type)) return false; + + Decl **members = type->decl->strukt.members; + + // For structs / errors, all members must match. + ArrayIndex offset = 0; + AlignSize align_size = type_abi_alignment(array); + Type *array_base = array->array.base; + VECEACH(members, i) + { + if (!type_is_structurally_equivalent(array_base, members[i]->type)) return false; + if (members[i]->offset != offset) return false; + offset += align_size; + } + return true; +} + +bool type_is_structurally_equivalent(Type *type1, Type *type2) +{ + type1 = type_flatten(type1); + type2 = type_flatten(type2); + + if (type1 == type2) return true; + + if (type_size(type1) != type_size(type2)) return false; + + // If the other type is a union, we check against every member + // noting that there is only structural equivalence if it fills out the + if (type2->type_kind == TYPE_UNION) + { + Decl **members = type2->decl->strukt.members; + // If any member is structurally equivalent, then + // the cast is valid. + VECEACH(members, i) + { + if (type_is_structurally_equivalent(type1, members[i]->type)) return true; + } + // In this case we can't get a match. + return false; + } + + if (type1->type_kind == TYPE_ARRAY) + { + return array_structurally_equivalent_to_struct(type1, type2); + } + + if (type2->type_kind == TYPE_ARRAY) + { + return array_structurally_equivalent_to_struct(type2, type1); + } + + if (!type_is_structlike(type1)) return false; + + Decl **members = type1->decl->strukt.members; + if (type1->type_kind == TYPE_UNION) + { + // If any member is structurally equivalent, then + // the cast is valid. + VECEACH(members, i) + { + if (type_is_structurally_equivalent(members[i]->type, type2)) return true; + } + return false; + } + + // The only thing we have left is to check against another structlike. + if (!type_is_structlike(type2)) return false; + + Decl **other_members = type2->decl->strukt.members; + + // For structs / errors, all members must match. + VECEACH(members, i) + { + if (!type_is_structurally_equivalent(members[i]->type, other_members[i]->type)) return false; + if (members[i]->offset != other_members[i]->offset) return false; + } + return true; +} + bool type_is_user_defined(Type *type) { switch (type->type_kind) @@ -816,7 +923,7 @@ Type *type_get_indexed_type(Type *type) case TYPE_SUBARRAY: case TYPE_INFERRED_ARRAY: return type->array.base; - case TYPE_CTSTR: + case TYPE_STRLIT: return type_char; case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; @@ -941,7 +1048,7 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target- DEF_TYPE(u128, t_u128, TYPE_U128, 128, i128); DEF_TYPE(void, t_u0, TYPE_VOID, 8, byte); - DEF_TYPE(string, t_str, TYPE_CTSTR, target->width_pointer, pointer); + DEF_TYPE(string, t_str, TYPE_STRLIT, target->width_pointer, pointer); #undef DEF_TYPE @@ -951,12 +1058,18 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target- create_type_cache(type_void); type_void->type_cache[0] = &t_voidstar; t_voidstar.pointer = type_void; - type_create("compint", &t_ixx, TYPE_IXX, 32, 0, 0); - type_create("compfloat", &t_fxx, TYPE_FXX, 64, 0, 0); + type_create("compint", &t_ixx, TYPE_IXX, 0, 0, 0); + type_create("compfloat", &t_fxx, TYPE_FXX, 0, 0, 0); type_create_alias("usize", &t_usz, type_int_unsigned_by_bitsize(target->width_pointer)); type_create_alias("isize", &t_isz, type_int_signed_by_bitsize(target->width_pointer)); + type_create_alias("uptr", &t_uptr, type_int_unsigned_by_bitsize(target->width_pointer)); + type_create_alias("iptr", &t_iptr, type_int_signed_by_bitsize(target->width_pointer)); + + type_create_alias("uptrdiff", &t_uptrdiff, type_int_unsigned_by_bitsize(target->width_pointer)); + type_create_alias("iptrdiff", &t_iptrdiff, type_int_signed_by_bitsize(target->width_pointer)); + type_create_alias("c_ushort", &t_cus, type_int_unsigned_by_bitsize(target->width_c_short)); type_create_alias("c_uint", &t_cui, type_int_unsigned_by_bitsize(target->width_c_int)); type_create_alias("c_ulong", &t_cul, type_int_unsigned_by_bitsize(target->width_c_long)); @@ -993,7 +1106,7 @@ bool type_is_scalar(Type *type) case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: - case TYPE_CTSTR: + case TYPE_STRLIT: case TYPE_TYPEID: case TYPE_POINTER: case TYPE_ENUM: @@ -1050,52 +1163,58 @@ bool type_may_have_sub_elements(Type *type) } } -typedef enum -{ - L, - R, - FL, - X, -} MaxType; - Type *type_find_max_num_type(Type *num_type, Type *other_num) { TypeKind kind = num_type->type_kind; TypeKind other_kind = other_num->type_kind; + assert(kind <= other_kind && "Expected ordering"); + assert(kind != other_kind); + + // 1. The only conversions need to happen if the other type is a number. if (other_kind < TYPE_I8 || other_kind > TYPE_FXX) return NULL; - static MaxType max_conv[TYPE_FXX - TYPE_I8 + 1][TYPE_FXX - TYPE_I8 + 1] = { - // I8 I16 I32 I64 I128 U8 U16 U32 U64 U128 IXX F16 F32 F64 F128 FXX - { L, R, R, R, R, X, X, X, X, X, L, R, R, R, R, FL }, // I8 - { L, L, R, R, R, L, X, X, X, X, L, R, R, R, R, FL }, // I16 - { L, L, L, R, R, L, L, X, X, X, L, R, R, R, R, FL }, // I32 - { L, L, L, L, R, L, L, L, X, X, L, R, R, R, R, FL }, // I64 - { L, L, L, L, L, L, L, L, X, X, L, R, R, R, R, FL }, // I128 - { X, R, R, R, R, L, R, R, R, R, L, R, R, R, R, FL }, // U8 - { X, X, R, R, R, L, L, R, R, R, L, R, R, R, R, FL }, // U16 - { X, X, X, R, R, L, L, L, R, R, L, R, R, R, R, FL }, // U32 - { X, X, X, X, R, L, L, L, L, R, L, R, R, R, R, FL }, // U64 - { X, X, X, X, X, L, L, L, L, L, L, R, R, R, R, FL }, // U128 - { R, R, R, R, R, R, R, R, R, R, L, R, R, R, R, R }, // IXX - { L, L, L, L, L, L, L, L, L, L, L, L, R, R, R, L }, // F16 - { L, L, L, L, L, L, L, L, L, L, L, L, L, R, R, L }, // F32 - { L, L, L, L, L, L, L, L, L, L, L, L, L, L, R, L }, // F64 - { L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L }, // F128 - { FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, R, R, R, R, L }, // FXX - }; - MaxType conversion = max_conv[num_type->type_kind - TYPE_I8][other_num->type_kind - TYPE_I8]; - switch (conversion) + + // 2. First check the float case. + if (other_kind >= TYPE_F16 && other_kind <= TYPE_FXX) { - case X: - return NULL; - case L: - return num_type; - case R: - return other_num; - case FL: - return type_double; - default: - UNREACHABLE + switch (other_kind) + { + case TYPE_FXX: + return kind <= TYPE_IXX ? type_double : other_num; + case TYPE_F16: + case TYPE_F32: + case TYPE_F64: + case TYPE_F128: + // Pick the biggest, which will be in other_num due to ordering. + return other_num; + default: + UNREACHABLE + } } + + // Handle integer <=> integer conversions. + assert(type_kind_is_any_integer(other_kind) && type_is_integer(num_type)); + + // 3. If the other type is IXX, return the current type. + if (other_kind == TYPE_IXX) return num_type; + + // 4. Check the bit sizes. + unsigned other_bit_size = other_num->builtin.bitsize; + unsigned bit_size = num_type->builtin.bitsize; + + // 5. The other type is unsigned + if (type_kind_is_unsigned(other_kind)) + { + if (type_kind_is_signed(kind)) + { + // 5a. Signed + Unsigned -> Signed + return bit_size >= other_bit_size ? num_type : NULL; + } + // 5b. Unsigned + Unsigned -> return other_num which is the bigger due to ordering. + return other_num; + } + + // 6. The other type is signed, then pick other_num which is bigger due to ordering. + return other_num; } /** @@ -1234,7 +1353,7 @@ Type *type_find_max_type(Type *type, Type *other) TODO case TYPE_TYPEDEF: UNREACHABLE - case TYPE_CTSTR: + case TYPE_STRLIT: if (other->type_kind == TYPE_DISTINCT) { // In this case we only react to the flattened type. diff --git a/src/compiler_tests/tests.c b/src/compiler_tests/tests.c index da454c55b..6864ec05b 100644 --- a/src/compiler_tests/tests.c +++ b/src/compiler_tests/tests.c @@ -18,7 +18,7 @@ static void test_lexer(void) printf("Begin lexer testing.\n"); printf("-- Check number of keywords...\n"); int tokens_found = 0; - const int EXPECTED_TOKENS = TOKEN_CT_SWITCH - TOKEN_ALIAS + 1 + TOKEN_C_ULONGLONG - TOKEN_VOID + 1; + const int EXPECTED_TOKENS = TOKEN_CT_SWITCH - TOKEN_ALIAS + 1 + TOKEN_TYPEID - TOKEN_VOID + 1; const char* tokens[TOKEN_EOF]; int len[TOKEN_EOF]; Lexer lexer; diff --git a/test/test_suite/arrays/array_invalid_casts.c3 b/test/test_suite/arrays/array_invalid_casts.c3 index 38e43a4cf..3835f84b3 100644 --- a/test/test_suite/arrays/array_invalid_casts.c3 +++ b/test/test_suite/arrays/array_invalid_casts.c3 @@ -8,5 +8,5 @@ func void test() func void test2() { int[3] x; - double[] z = &x; // #error: Cannot cast 'int[3]*' to 'double[]' + double[] z = &x; // #error: Cannot implicitly cast 'int[3]*' to 'double[]' } \ No newline at end of file diff --git a/test/test_suite/arrays/negative_array.c3 b/test/test_suite/arrays/negative_array.c3 index c3abb03db..e2fc1d88c 100644 --- a/test/test_suite/arrays/negative_array.c3 +++ b/test/test_suite/arrays/negative_array.c3 @@ -1,4 +1,3 @@ -usize z = -1; // #error: Negative number '-1' -int[-1] a; // #error: Negative number '-1' -int[10-20] b; // #error: '-10' underflows type 'ulong' \ No newline at end of file +int[-1] a; // #error: An array may not have a negative size +int[10-20] b; // #error: An array may not have a negative size \ No newline at end of file diff --git a/test/test_suite/assert/unreachable.c3t b/test/test_suite/assert/unreachable.c3t index 2422a83b9..e7d585f1e 100644 --- a/test/test_suite/assert/unreachable.c3t +++ b/test/test_suite/assert/unreachable.c3t @@ -31,6 +31,6 @@ if.exit: unreachable_block: %2 = load i32, i32* %x - %add = add nsw i32 %2, 1 + %add = add i32 %2, 1 store i32 %add, i32* %x ret void diff --git a/test/test_suite/cast/cast_struct.c3 b/test/test_suite/cast/cast_struct.c3 new file mode 100644 index 000000000..9089a6c10 --- /dev/null +++ b/test/test_suite/cast/cast_struct.c3 @@ -0,0 +1,37 @@ +struct Foo +{ + int a; + float b; +} + +struct Bar +{ + int b; + float c; +} + +struct Baz +{ + int b; + int c; +} + +struct BazTwo +{ + int[1] d; + int e; +} + +func void test() +{ + Foo x; + Bar y = cast(x as Bar); + + Baz z; + int[2] w = cast(z as int[2]); + z = cast(w as Baz); + BazTwo v = cast(z as BazTwo); + v = cast(w as BazTwo); + z = cast(v as Baz); + w = cast(v as int[2]); +} diff --git a/test/test_suite/cast/cast_struct_fails.c3 b/test/test_suite/cast/cast_struct_fails.c3 new file mode 100644 index 000000000..efdc0a544 --- /dev/null +++ b/test/test_suite/cast/cast_struct_fails.c3 @@ -0,0 +1,34 @@ +struct Foo +{ + int a; + float b; +} + +struct Bar +{ + int b; + float c; +} + +struct Baz +{ + int b; + int c; +} + +struct BazTwo +{ + int[2] d; + int e; +} + +func void test1() +{ + Foo x; + Bar z = cast(x as Baz); // #error: Cannot cast 'Foo' to 'Baz' +} +func void test2() +{ + Baz x; + BazTwo z = cast(x as BazTwo); // #error: Cannot cast 'Baz' to 'BazTwo' +} diff --git a/test/test_suite/constants/constants.c3t b/test/test_suite/constants/constants.c3t index 688e25c19..177bba937 100644 --- a/test/test_suite/constants/constants.c3t +++ b/test/test_suite/constants/constants.c3t @@ -1,20 +1,20 @@ -const char AA = ~0; +const char AA = ~cast(0 as char); const char BB = 200 ; -const uint CC = ~0; +const uint CC = ~cast(0 as uint); const uint DD = FOO; -const FOO = ~0; +const FOO = ~cast(0 as uint); uint x = AA; uint z = CC; -char w = FOO; -ushort v = FOO; +char w = cast(FOO as char); +ushort v = cast(FOO as ushort); uint z2 = DD; func void test() { int xx = FOO; - int* yy = &&FOO; + uint* yy = &&FOO; } // #expect: constants.ll diff --git a/test/test_suite/distinct/distinct_invalid.c3 b/test/test_suite/distinct/distinct_invalid.c3 new file mode 100644 index 000000000..a82c4a9bf --- /dev/null +++ b/test/test_suite/distinct/distinct_invalid.c3 @@ -0,0 +1,10 @@ +error Error +{} + +typedef Error as distinct Foo1; // #error: You cannot create a distinct type from an error + +typedef error as distinct Foo2; // #error: You cannot create a distinct type from an error union + +typedef void as distinct Foo3; // #error: create a distinct type from 'void' + +typedef typeid as distinct Foo4; // #error: create a distinct type from 'typeid' diff --git a/test/test_suite/expressions/arithmetics.c3 b/test/test_suite/expressions/arithmetics.c3 index b84381f71..28d331b4c 100644 --- a/test/test_suite/expressions/arithmetics.c3 +++ b/test/test_suite/expressions/arithmetics.c3 @@ -3,30 +3,21 @@ module arithmetics; func void testAdd(int a, int b) { a = a + b; - a = a +% b; - a +%= b; a += b; a += 1; - a +%= 1; } func void testSub(int a, int b) { a = a - b; - a = a -% b; - a -%= b; a -= b; - a -%= 1; a -= 1; } func void testMult(int a, int b) { a = a * b; - a = a *% b; - a *%= b; a *= b; - a *%= 1; a *= 1; } diff --git a/test/test_suite/expressions/arithmetics_sema_fail.c3 b/test/test_suite/expressions/arithmetics_sema_fail.c3 index ac0f3c69e..0f798d4dc 100644 --- a/test/test_suite/expressions/arithmetics_sema_fail.c3 +++ b/test/test_suite/expressions/arithmetics_sema_fail.c3 @@ -1,35 +1,3 @@ -func void test1() -{ - double x = 2.3 +% 2; // #error: only valid for integer addition -} - -func void test2() -{ - double x = 0; - int y = x +% 4; // #error: only valid for integer addition -} - -func void test3() -{ - double x = 2.3 -% 2; // #error: only valid for integer subtraction -} - -func void test4() -{ - double x = 0; - int y = x -% 4; // #error: only valid for integer subtraction -} - -func void test5() -{ - double x = 2.3 *% 2; // #error: try * instead -} - -func void test6() -{ - double x = 0; - int y = x *% 4; // #error: try * instead -} func void test7() { @@ -83,34 +51,34 @@ func void test16() uint b = 2; ushort c = 3; a = a + c; - int g = a + b; // #error: Cannot add 'int' to 'uint' + int g = a + b; } func void test17() { - char a = 100 + 300; // #error: '300' does not fit in type 'char' + char a = 100 + 300; // #error: '400' is out of range for 'char' } func void test18() { - char b = 100 + 156; // #error: Cannot fit '256' into type 'char' + char b = 100 + 156; // #error: '256' is out of range for 'char' } func void test19() { - ichar b = (-40) - 126; // #error: Cannot fit '-166' into type 'ichar' + ichar b = (-40) - 126; // #error: '-166' is out of range for 'ichar' } func void test20() { - ichar d = ((-128 - 10) + 10) - 2; // #error: Cannot fit '-130' into type 'ichar' - ichar c = 100 * 100; // #error: Cannot fit '10000' into type 'ichar' + ichar d = ((-128 - 10) + 10) - 2; // #error: '-130' is out of range for 'ichar' + ichar c = 100 * 100; // #error: '10000' is out of range for 'ichar' ichar e = (-138 + 30); - ichar f = -138 + 30; // #error: '-138' does not fit in type 'ichar' + ichar f = -138 + 30; ichar g = -(128); - check(128); // #error: '128' does not fit in type 'ichar' + check(128); // #error: '128' is out of range for 'ichar' } func void check(ichar x) {} @@ -118,6 +86,6 @@ func void check(ichar x) {} func char test22() { - return 300; // #error: '300' does not fit in type 'char' + return 300; // #error: '300' is out of range for 'char' } diff --git a/test/test_suite/expressions/call_arg_types.c3 b/test/test_suite/expressions/call_arg_types.c3 index 30fe2fac2..089161e72 100644 --- a/test/test_suite/expressions/call_arg_types.c3 +++ b/test/test_suite/expressions/call_arg_types.c3 @@ -14,6 +14,6 @@ func void test1() const int X = 120; test2(X); // #error: Cannot implicitly cast 'int' to 'ichar'. - test2(100 + 100); // #error: Cannot fit '200' into type 'ichar'. + test2(100 + 100); // #error: '200' is out of range for 'ichar' } diff --git a/test/test_suite/expressions/casts/cast_enum_to_various.c3 b/test/test_suite/expressions/casts/cast_enum_to_various.c3 index 6764e7a2c..d98cca7dc 100644 --- a/test/test_suite/expressions/casts/cast_enum_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_enum_to_various.c3 @@ -24,16 +24,16 @@ func void test1(Enum e) char b = cast(e as char); uint c = cast(e as uint); float d = cast(e as float); - uint* f = cast(e as uint*); + uint* f = cast(e as uint*); // #error: cast 'Enum' to 'uint*' } func void test2(Enum e) { - Struct* g = cast(e as Struct*); + Struct* g = cast(e as Struct*); // #error: cast 'Enum' to 'Struct*' } func void test3(Enum e) { - //EnumB h = cast(e as EnumB); - //Func i = cast(e as Func); + EnumB h = cast(e as EnumB); + Func i = cast(e as Func); // #error: cast 'Enum' to 'Func' } 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 3e5926c62..23a3d3093 100644 --- a/test/test_suite/expressions/casts/cast_func_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_func_to_various.c3 @@ -3,7 +3,7 @@ struct Struct int x; } -enum Enum : uint +enum Enum : uptr { A, B } @@ -18,16 +18,17 @@ typedef func void(int) as FuncSame; func void test1(Func arg) { bool a = cast(arg as bool); + bool b = arg; } func void test2(Func arg) { - ichar b = cast(arg as ichar); + ichar b = cast(arg as ichar); // #error: Cannot cast 'Func' (func void()) to 'ichar'. } func void test3(Func arg) { - uint c = cast(arg as uint); + uint c = cast(arg as uint); // #error: Cannot cast 'Func' (func void()) to 'uint'. } func void test4(Func arg) @@ -40,7 +41,7 @@ func void test7(Func arg) usize g = cast(arg as usize); FuncOther k = cast(arg as FuncOther); FuncSame l = cast(arg as FuncSame); - FuncOther ke = arg; // #error: Cannot implicitly cast 'Func' (func void()) to 'FuncOther' ('func bool()') + FuncOther ke = arg; // #error: Cannot implicitly cast 'Func' (func void()) to 'FuncOther' (func bool()) FuncSame fe = arg; Enum j = cast(arg as Enum); // #error: Cannot cast 'Func' (func void()) to 'Enum'. } diff --git a/test/test_suite/expressions/incdec.c3t b/test/test_suite/expressions/incdec.c3t index b724bb459..72bb7227d 100644 --- a/test/test_suite/expressions/incdec.c3t +++ b/test/test_suite/expressions/incdec.c3t @@ -25,10 +25,10 @@ func void test(int* foo) store i32* %ptrincdec1, i32** %foo, align 8 store i32 10, i32* %y, align 4 %3 = load i32, i32* %y, align 4 - %add = add nsw i32 %3, 1 + %add = add i32 %3, 1 store i32 %add, i32* %y, align 4 %4 = load i32, i32* %y, align 4 - %sub = sub nsw i32 %4, 1 + %sub = sub i32 %4, 1 store i32 %sub, i32* %y, align 4 store float 2.000000e+00, float* %z, align 4 %5 = load float, float* %z, align 4 diff --git a/test/test_suite/expressions/pointer_arith.c3 b/test/test_suite/expressions/pointer_arith.c3 index 2a6afa99d..1c13fa504 100644 --- a/test/test_suite/expressions/pointer_arith.c3 +++ b/test/test_suite/expressions/pointer_arith.c3 @@ -9,4 +9,10 @@ func void test1(ichar* cp) cp3 += 10; cp3 += a; ichar* cp4 = cp - a; + cp2 - cp3; +} +func void test2(ichar* cp) +{ + cp + 1; + cp * 1.0; // #error: Cannot multiply 'ichar*' by 'compfloat' } \ 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 48cd6c47b..2e825d59d 100644 --- a/test/test_suite/expressions/pointer_conv_error.c3 +++ b/test/test_suite/expressions/pointer_conv_error.c3 @@ -13,6 +13,6 @@ func void test2() func void test3() { uint myUInt = 1; - int* p2 = cast(myUInt as int*); + int* p2 = cast(myUInt as int*); // #error: Cannot cast 'uint' to 'int*'. } diff --git a/test/test_suite/functions/assorted_tests.c3t b/test/test_suite/functions/assorted_tests.c3t index 91e1cfca5..187914a71 100644 --- a/test/test_suite/functions/assorted_tests.c3t +++ b/test/test_suite/functions/assorted_tests.c3t @@ -56,8 +56,8 @@ func void denormalize(InternalFPF* ptr) %1 = load i8*, i8** %pp, align 8 %2 = load i8, i8* %1, align 8 %uiuiext = zext i8 %2 to i32 - %uadd = add nuw i32 %0, %uiuiext - store i32 %uadd, i32* %w_cnt, align 4 + %add = add i32 %0, %uiuiext + store i32 %add, i32* %w_cnt, align 4 %3 = load i32, i32* %w_cnt, align 4 ret i32 %3 @@ -89,7 +89,7 @@ cond.phi: if.then: %3 = load i32, i32* %lls, align 4 %4 = load i32, i32* %asa, align 4 - %add = add nsw i32 %3, %4 + %add = add i32 %3, %4 store i32 %add, i32* %asa, align 4 br label %if.exit @@ -97,7 +97,7 @@ if.exit: %5 = load i32, i32* %asa, align 4 %6 = load double, double* %val, align 8 %fpui = fptoui double %6 to i32 - %add1 = add nsw i32 %5, %fpui + %add1 = add i32 %5, %fpui ret i32 %add1 diff --git a/test/test_suite/globals/global_init.c3 b/test/test_suite/globals/global_init.c3 index 6246ca70b..fe177f375 100644 --- a/test/test_suite/globals/global_init.c3 +++ b/test/test_suite/globals/global_init.c3 @@ -17,8 +17,8 @@ ichar cb = 1; ichar cc = 127; ichar cd = -128; -ichar ce = 128; // #error: '128' does not fit -ichar cf = -129; // #error: '-129' does not fit +ichar ce = 128; // #error: The value '128' is out of range for 'ichar' +ichar cf = -129; // #error: The value '-129' is out of range for 'ichar' -ichar cg = 70000; // #error: '70000' does not fit -ichar ch = -70000; // #error: '-70000' does not fit \ No newline at end of file +ichar cg = 70000; // #error: The value '70000' is out of range for 'ichar' +ichar ch = -70000; // #error: The value '-70000' is out of range for 'ichar' \ No newline at end of file diff --git a/test/test_suite/statements/defer_return.c3t b/test/test_suite/statements/defer_return.c3t index 9228a32bc..77f76ea45 100644 --- a/test/test_suite/statements/defer_return.c3t +++ b/test/test_suite/statements/defer_return.c3t @@ -48,7 +48,7 @@ while.body: if.then: %3 = load i32, i32* %a %4 = load i32, i32* %argc - %add = add nsw i32 %3, %4 + %add = add i32 %3, %4 call void @test.test2() br label %exit exit: @@ -77,7 +77,7 @@ while.body6: br i1 %eq7, label %if.then8, label %if.exit13 if.then8: %7 = load i32, i32* %a - %add9 = add nsw i32 %7, 2 + %add9 = add i32 %7, 2 call void @test.test6() br label %exit10 exit10: @@ -105,7 +105,7 @@ exit17: ret i32 4 while.exit21: %8 = load i32, i32* %argc - %add22 = add nsw i32 0, %8 + %add22 = add i32 0, %8 call void @test.test5() br label %exit23 exit23: diff --git a/test/test_suite/statements/foreach_break.c3t b/test/test_suite/statements/foreach_break.c3t index 5e8b23308..9bc658f26 100644 --- a/test/test_suite/statements/foreach_break.c3t +++ b/test/test_suite/statements/foreach_break.c3t @@ -40,7 +40,7 @@ if.then1: if.exit2: %6 = load i32, i32* %g, align 4 %7 = load i32, i32* %z, align 4 - %add = add nsw i32 %6, %7 + %add = add i32 %6, %7 store i32 %add, i32* %g, align 4 br label %foreach.inc foreach.inc: diff --git a/test/test_suite/statements/foreach_with_error.c3t b/test/test_suite/statements/foreach_with_error.c3t index cf5a465da..58334a31c 100644 --- a/test/test_suite/statements/foreach_with_error.c3t +++ b/test/test_suite/statements/foreach_with_error.c3t @@ -43,7 +43,7 @@ foreach.body: store i32 %5, i32* %z, align 4 %6 = load i32, i32* %g, align 4 %7 = load i32, i32* %z, align 4 - %add = add nsw i32 %6, %7 + %add = add i32 %6, %7 store i32 %add, i32* %g, align 4 %8 = load { i64, i64 }, { i64, i64 }* %x1, align 8 %9 = extractvalue { i64, i64 } %8, 0 diff --git a/test/test_suite/statements/if_tests.c3t b/test/test_suite/statements/if_tests.c3t index d751af9c6..c5dc5a0f4 100644 --- a/test/test_suite/statements/if_tests.c3t +++ b/test/test_suite/statements/if_tests.c3t @@ -35,7 +35,7 @@ func void test3(int x) br i1 %gt, label %if.then, label %if.exit if.then: %2 = load i32, i32* %x, align 4 - %add = add nsw i32 %2, 1 + %add = add i32 %2, 1 store i32 %add, i32* %x, align 4 br label %exit exit: @@ -58,7 +58,7 @@ define void @iftest.test3(i32 %0) br i1 %gt, label %if.exit, label %if.else if.else: %2 = load i32, i32* %x, align 4 - %add = add nsw i32 %2, 1 + %add = add i32 %2, 1 store i32 %add, i32* %x, align 4 br label %if.exit if.exit: diff --git a/test/test_suite/statements/labelled_continue_for.c3t b/test/test_suite/statements/labelled_continue_for.c3t index 4b5e7b71b..a7c5af692 100644 --- a/test/test_suite/statements/labelled_continue_for.c3t +++ b/test/test_suite/statements/labelled_continue_for.c3t @@ -29,7 +29,7 @@ for.cond: for.inc8: %4 = load i32, i32* %i - %add9 = add nsw i32 %4, 1 + %add9 = add i32 %4, 1 store i32 %add9, i32* %i br label %for.cond diff --git a/test/test_suite/struct/struct_pack_and_align.c3t b/test/test_suite/struct/struct_pack_and_align.c3t index 441519313..81ff0d39a 100644 --- a/test/test_suite/struct/struct_pack_and_align.c3t +++ b/test/test_suite/struct/struct_pack_and_align.c3t @@ -98,5 +98,5 @@ entry: %sisiext = sext i8 %5 to i32 %6 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 0 %7 = load i32, i32* %6, align 16 - %add = add nsw i32 %sisiext, %7 + %add = add i32 %sisiext, %7 ret i32 %add diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 index ba588b419..30438c237 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -82,7 +82,7 @@ enum Enum : int func void test11() { int a = Enum.A; - ichar b = Enum.B; // #error: Cannot implicitly convert 'Enum' with underlying type of 'int' to 'ichar' + ichar b = Enum.B; // #error: Cannot implicitly cast 'Enum' to 'ichar' } func void test12() @@ -100,7 +100,7 @@ func void test13() func void test14() { char a = 1; - ichar b = a; // #error: cast 'char' to 'ichar' + ichar b = a; } func void test15() @@ -137,7 +137,7 @@ func void test18() func void test19() { uint a = 1; - int b = a; // #error: cast 'uint' to 'int' + int b = a; } /* @@ -150,7 +150,7 @@ func void test1() { func void test21() { int a = 1; - uint b = a; // #error: cast 'int' to 'uint' + uint b = a; } func void foo() {} diff --git a/test/test_suite/types/enum_inference.c3 b/test/test_suite/types/enum_inference.c3 index 08ee23508..7e1804bc0 100644 --- a/test/test_suite/types/enum_inference.c3 +++ b/test/test_suite/types/enum_inference.c3 @@ -26,7 +26,7 @@ func void enumInferenceTest() Inf2 z = C; if (z == Inf2.A) return; if (z == 1) return; - z = 2; + z = cast(2 as Inf2); switch (z) { case Inf2.A: diff --git a/test/test_suite/types/enum_overflow.c3 b/test/test_suite/types/enum_overflow.c3 index d6a085cc4..4631356d9 100644 --- a/test/test_suite/types/enum_overflow.c3 +++ b/test/test_suite/types/enum_overflow.c3 @@ -1,4 +1,4 @@ enum EnumTestOverflow { - VALUE = 0x80000000, // #error: does not fit in type 'int' + VALUE = 0x80000000, // #error: The value '2147483648' is out of range for 'int' } \ No newline at end of file