Removed original_type, pure, removed bigint, added i128 type, lots of fixes to $Foo, reassigning ct type, catch/macro, "!", removed type inference.

This commit is contained in:
Christoffer Lerno
2021-10-08 10:07:40 +02:00
committed by Christoffer Lerno
parent 1b086e06f1
commit b4df56db54
84 changed files with 4820 additions and 4173 deletions

2
.gitattributes vendored
View File

@@ -1,4 +1,4 @@
$ cat .gitattributes $ cat .gitattributes
* text=auto * text=lf
*.c3 linguist-language=C *.c3 linguist-language=C
*.c3t linguist-language=C *.c3t linguist-language=C

View File

@@ -130,6 +130,7 @@ add_executable(c3c
src/compiler/sema_types.c src/compiler/sema_types.c
src/compiler/sema_stmts.c src/compiler/sema_stmts.c
src/compiler/number.c src/compiler/number.c
src/compiler/float.c
src/compiler/linker.c src/compiler/linker.c
src/utils/vmem.c src/utils/vmem.c
src/utils/vmem.h src/utils/vmem.h

View File

@@ -50,7 +50,7 @@ const DOUBLE_MIN_10_EXP = -307;
const DOUBLE_MAX_EXP = 1024; const DOUBLE_MAX_EXP = 1024;
const DOUBLE_MIN_EXP = -1021; const DOUBLE_MIN_EXP = -1021;
const DOUBLE_EPSILON = 2.22044604925031308085e-16; const DOUBLE_EPSILON = 2.22044604925031308085e-16;
/*
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932; const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932; const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966; const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
@@ -62,7 +62,7 @@ const QUAD_MIN_10_EXP = -4931;
const QUAD_MAX_EXP = 16384; const QUAD_MAX_EXP = 16384;
const QUAD_MIN_EXP = -16481; const QUAD_MIN_EXP = -16481;
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34; const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
*/
private union DoubleLong private union DoubleLong
{ {
double f; double f;
@@ -107,13 +107,13 @@ func double log10(double x)
hx += 0x3ff00000 - 0x3fe6a09e; hx += 0x3ff00000 - 0x3fe6a09e;
k += (int)(hx >> 20) - 0x3ff; k += (int)(hx >> 20) - 0x3ff;
hx = (hx & 0x000fffff) + 0x3fe6a09e; hx = (hx & 0x000fffff) + 0x3fe6a09e;
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff); u.i = (ulong)(hx << 32) | (u.i & 0xffffffffu64);
x = u.f; x = u.f;
hx += 0x3ff00000 - 0x3fe6a09e; hx += 0x3ff00000 - 0x3fe6a09e;
k += (int)(hx >> 20) - 0x3ff; k += (int)(hx >> 20) - 0x3ff;
hx = (hx & 0x000fffff) + 0x3fe6a09e; hx = (hx & 0x000fffff) + 0x3fe6a09e;
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff); u.i = (ulong)(hx << 32) | (u.i & 0xffffffffu64);
x = u.f; x = u.f;
@@ -131,7 +131,7 @@ func double log10(double x)
double hi = f - hfsq; double hi = f - hfsq;
u.f = hi; u.f = hi;
// u.i &= (ulong)(-1) << 32; // u.i &= (ulong)(-1) << 32;
u.i &= 0xFFFFFFFF00000000; u.i &= 0xFFFFFFFF00000000u64;
hi = u.f; hi = u.f;
double lo = f - hi - hfsq + s * (hfsq + r); double lo = f - hi - hfsq + s * (hfsq + r);

View File

@@ -223,7 +223,7 @@ Expr *expr_new(ExprKind kind, SourceSpan start)
Expr *expr = expr_calloc(); Expr *expr = expr_calloc();
expr->expr_kind = kind; expr->expr_kind = kind;
expr->span = start; expr->span = start;
expr->type = expr->original_type = NULL; expr->type = NULL;
return expr; return expr;
} }
@@ -293,10 +293,6 @@ UnaryOp unary_op[TOKEN_LAST + 1] = {
}; };
PostUnaryOp post_unary_op[TOKEN_LAST + 1] = {
[TOKEN_PLUSPLUS] = POSTUNARYOP_INC,
[TOKEN_MINUSMINUS] = POSTUNARYOP_DEC,
};
@@ -319,11 +315,6 @@ UnaryOp unaryop_from_token(TokenType type)
return unary_op[type]; return unary_op[type];
} }
PostUnaryOp post_unaryop_from_token(TokenType type)
{
return post_unary_op[type];
}
static Ast poison_ast = { .ast_kind = AST_POISONED }; static Ast poison_ast = { .ast_kind = AST_POISONED };
Ast *poisoned_ast = &poison_ast; Ast *poisoned_ast = &poison_ast;

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,8 @@ typedef struct
unsigned float_regs; unsigned float_regs;
} Regs; } Regs;
ABIArgInfo *c_abi_classify_return_type_default(Type *type); ABIArgInfo *c_abi_classify_return_type_default(Type *type);
ABIArgInfo *c_abi_classify_argument_type_default(Type *type); ABIArgInfo *c_abi_classify_argument_type_default(Type *type);
void c_abi_func_create_win64(FunctionSignature *signature); void c_abi_func_create_win64(FunctionSignature *signature);
@@ -49,6 +51,7 @@ void c_abi_func_create_aarch64(FunctionSignature *signature);
void c_abi_func_create_riscv(FunctionSignature *signature); void c_abi_func_create_riscv(FunctionSignature *signature);
void c_abi_func_create_wasm(FunctionSignature *signature); void c_abi_func_create_wasm(FunctionSignature *signature);
// Implementation // Implementation
static inline ABIArgInfo *abi_arg_by_reg_attr(ABIArgInfo *info) static inline ABIArgInfo *abi_arg_by_reg_attr(ABIArgInfo *info)
{ {

View File

@@ -242,13 +242,19 @@ static void add_global_define(const char *name, Expr *value)
stable_set(&dec->module->symbols, dec->name, dec); stable_set(&dec->module->symbols, dec->name, dec);
} }
static void setup_int_define(const char *id, uint64_t i) static void setup_int_define(const char *id, uint64_t i, Type *type)
{ {
TokenType token_type = TOKEN_CONST_IDENT; TokenType token_type = TOKEN_CONST_IDENT;
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type); id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
expr_const_set_int(&expr->const_expr, i, TYPE_IXX); assert(type_is_integer(type));
expr->original_type = expr->type = type_compint; expr_const_set_int(&expr->const_expr, i, type->type_kind);
if (expr_const_will_overflow(&expr->const_expr, type->type_kind))
{
error_exit("Integer define %s overflow.", id);
}
expr->type = type;
expr->const_expr.narrowable = true;
expr->span = INVALID_RANGE; expr->span = INVALID_RANGE;
expr->resolve_status = RESOLVE_NOT_DONE; expr->resolve_status = RESOLVE_NOT_DONE;
void *previous = stable_set(&global_context.compiler_defines, id, expr); void *previous = stable_set(&global_context.compiler_defines, id, expr);
@@ -264,7 +270,7 @@ static void setup_bool_define(const char *id, bool value)
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type); id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
expr_const_set_bool(&expr->const_expr, value); expr_const_set_bool(&expr->const_expr, value);
expr->original_type = expr->type = type_bool; expr->type = type_bool;
expr->span = INVALID_RANGE; expr->span = INVALID_RANGE;
expr->resolve_status = RESOLVE_NOT_DONE; expr->resolve_status = RESOLVE_NOT_DONE;
void *previous = stable_set(&global_context.compiler_defines, id, expr); void *previous = stable_set(&global_context.compiler_defines, id, expr);
@@ -275,15 +281,15 @@ static void setup_bool_define(const char *id, bool value)
} }
void compiler_compile(void) void compiler_compile(void)
{ {
setup_int_define("C_SHORT_SIZE", platform_target.width_c_short); setup_int_define("C_SHORT_SIZE", platform_target.width_c_short, type_long);
setup_int_define("C_INT_SIZE", platform_target.width_c_int); setup_int_define("C_INT_SIZE", platform_target.width_c_int, type_long);
setup_int_define("C_LONG_SIZE", platform_target.width_c_long); setup_int_define("C_LONG_SIZE", platform_target.width_c_long, type_long);
setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long); setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long, type_long);
setup_bool_define("C_CHAR_IS_SIGNED", platform_target.signed_c_char); setup_bool_define("C_CHAR_IS_SIGNED", platform_target.signed_c_char);
setup_bool_define("PLATFORM_BIG_ENDIAN", platform_target.big_endian); setup_bool_define("PLATFORM_BIG_ENDIAN", platform_target.big_endian);
setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128); setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128);
setup_int_define("COMPILER_OPT_LEVEL", (int)active_target.optimization_level); setup_int_define("COMPILER_OPT_LEVEL", (int)active_target.optimization_level, type_int);
setup_int_define("COMPILER_SIZE_OPT_LEVEL", (int)active_target.size_optimization_level); setup_int_define("COMPILER_SIZE_OPT_LEVEL", (int)active_target.size_optimization_level, type_int);
setup_bool_define("COMPILER_SAFE_MODE", active_target.feature.safe_mode); setup_bool_define("COMPILER_SAFE_MODE", active_target.feature.safe_mode);
global_context_clear_errors(); global_context_clear_errors();

View File

@@ -12,17 +12,8 @@
#include "utils/malloc.h" #include "utils/malloc.h"
#include <float.h> #include <float.h>
#if DBL_DIG == LDBL_DIG
#define LONG_DOUBLE 0
#else
#define LONG_DOUBLE 1
#endif
#if LONG_DOUBLE
typedef long double Real;
#else
typedef double Real; typedef double Real;
#endif
#define MAX_ARRAYINDEX INT64_MAX #define MAX_ARRAYINDEX INT64_MAX
typedef uint64_t ByteSize; typedef uint64_t ByteSize;
@@ -69,16 +60,27 @@ typedef struct Type_ Type;
typedef unsigned AstId; typedef unsigned AstId;
typedef struct BigInt_ typedef struct Int128_
{ {
unsigned digit_count; uint64_t high;
bool is_negative; uint64_t low;
union { } Int128;
uint64_t digit;
uint64_t *digits;
};
} BigInt;
typedef struct
{
Int128 i;
TypeKind type;
} Int;
typedef struct
{
Real f;
TypeKind type;
} Float;
#define UINT128_MAX ((Int128) { UINT64_MAX, UINT64_MAX })
#define INT128_MAX ((Int128) { INT64_MAX, UINT64_MAX })
#define INT128_MIN ((Int128) { (uint64_t)INT64_MIN, 0 })
typedef enum typedef enum
{ {
@@ -125,19 +127,12 @@ typedef struct ConstInitializer_
typedef struct typedef struct
{ {
ConstKind const_kind; ConstKind const_kind : 8;
bool narrowable : 1;
union union
{ {
struct Float fxx;
{ Int ixx;
Real f;
TypeKind float_type;
};
struct
{
BigInt i;
TypeKind int_type;
};
bool b; bool b;
struct struct
{ {
@@ -266,7 +261,7 @@ typedef struct
struct Type_ struct Type_
{ {
TypeKind type_kind : 8; TypeKind type_kind;
Type *canonical; Type *canonical;
const char *name; const char *name;
Type **type_cache; Type **type_cache;
@@ -288,6 +283,8 @@ struct Type_
Type *pointer; Type *pointer;
// Type[<123>] or Type<[123]> // Type[<123>] or Type<[123]>
TypeVector vector; TypeVector vector;
// Failable
Type *failable;
}; };
}; };
@@ -295,6 +292,7 @@ struct TypeInfo_
{ {
ResolveStatus resolve_status : 3; ResolveStatus resolve_status : 3;
bool virtual_type : 1; bool virtual_type : 1;
bool failable : 1;
Type *type; Type *type;
TypeInfoKind kind; TypeInfoKind kind;
SourceSpan span; SourceSpan span;
@@ -349,7 +347,6 @@ typedef struct VarDecl_
{ {
VarDeclKind kind : 4; VarDeclKind kind : 4;
bool constant : 1; bool constant : 1;
bool failable : 1;
bool unwrap : 1; bool unwrap : 1;
bool vararg : 1; bool vararg : 1;
bool is_static : 1; bool is_static : 1;
@@ -420,7 +417,6 @@ typedef struct FunctionSignature_
CallABI call_abi : 4; CallABI call_abi : 4;
Variadic variadic : 3; Variadic variadic : 3;
bool has_default : 1; bool has_default : 1;
bool failable : 1;
bool use_win64 : 1; bool use_win64 : 1;
TypeInfo *rtype; TypeInfo *rtype;
struct ABIArgInfo_ *ret_abi_info; struct ABIArgInfo_ *ret_abi_info;
@@ -493,7 +489,6 @@ typedef struct
typedef struct typedef struct
{ {
bool failable : 1;
Decl **parameters; Decl **parameters;
TypeInfo *type_parent; // May be null TypeInfo *type_parent; // May be null
TypeInfo *rtype; // May be null! TypeInfo *rtype; // May be null!
@@ -663,12 +658,6 @@ typedef struct
} ExprUnary; } ExprUnary;
typedef struct
{
Expr* expr;
PostUnaryOp operator;
} ExprPostUnary;
@@ -797,6 +786,7 @@ typedef struct
typedef struct typedef struct
{ {
CastKind kind; CastKind kind;
bool implicit;
Expr *expr; Expr *expr;
TypeInfo *type_info; TypeInfo *type_info;
union union
@@ -919,12 +909,9 @@ typedef struct
struct Expr_ struct Expr_
{ {
ExprKind expr_kind : 8; ExprKind expr_kind : 8;
ResolveStatus resolve_status : 3; ResolveStatus resolve_status : 4;
bool failable : 1;
bool pure : 1;
SourceSpan span; SourceSpan span;
Type *type; Type *type;
Type *original_type;
union { union {
Expr *group_expr; Expr *group_expr;
ExprLen len_expr; ExprLen len_expr;
@@ -943,7 +930,6 @@ struct Expr_
ExprTernary ternary_expr; ExprTernary ternary_expr;
ExprUnary unary_expr; ExprUnary unary_expr;
Expr** try_unwrap_chain_expr; Expr** try_unwrap_chain_expr;
ExprPostUnary post_expr;
ExprTryUnwrap try_unwrap_expr; ExprTryUnwrap try_unwrap_expr;
ExprCall call_expr; ExprCall call_expr;
ExprSlice slice_expr; ExprSlice slice_expr;
@@ -1329,7 +1315,7 @@ typedef union
const char *string; const char *string;
size_t strlen; size_t strlen;
}; };
Real value; Float value;
struct struct
{ {
bool is_base64 : 1; bool is_base64 : 1;
@@ -1412,7 +1398,6 @@ typedef struct Context_
Ast **returns_cache; Ast **returns_cache;
}; };
Type *rtype; Type *rtype;
bool failable_return;
int in_volatile_section; int in_volatile_section;
MacroScope macro_scope; MacroScope macro_scope;
struct { struct {
@@ -1550,10 +1535,10 @@ 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_char, *type_ushort, *type_uint, *type_ulong, *type_usize;
extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff; extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff;
extern Type *type_u128, *type_i128; extern Type *type_u128, *type_i128;
extern Type *type_compint, *type_compfloat;
extern Type *type_typeid, *type_anyerr, *type_typeinfo; extern Type *type_typeid, *type_anyerr, *type_typeinfo;
extern Type *type_virtual, *type_virtual_generic; extern Type *type_virtual, *type_virtual_generic;
extern Type *type_complist; extern Type *type_complist;
extern Type *type_anyfail;
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES]; extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
@@ -1624,64 +1609,131 @@ static inline Ast *extend_ast_with_prev_token(Context *context, Ast *ast)
typedef enum CmpRes_ typedef enum CmpRes_
{ {
CMP_LT, CMP_LT = -1,
CMP_GT, CMP_EQ = 0,
CMP_EQ, CMP_GT = 1,
} CmpRes; } CmpRes;
void bigint_init_unsigned(BigInt *big_int, uint64_t value); typedef enum
void bigint_init_signed(BigInt *big_int, int64_t value); {
void bigint_init_bigint(BigInt *dest, const BigInt *src); FLOAT_NAN,
void bigint_init_data(BigInt *dest, const uint64_t *digits, unsigned int digit_count, bool is_negative); FLOAT_INFINITY,
void bigint_negate(BigInt *dest, const BigInt *source); FLOAT_NORMAL,
size_t bigint_clz(const BigInt *big_int, size_t bit_count); FLOAT_ZERO
size_t bigint_ctz(const BigInt *big_int, size_t bit_count); } FloatCategory;
bool bigint_fits_in_bits(const BigInt *big_int, size_t bit_count, bool is_signed);
void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); typedef enum
void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, bool is_signed); {
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); ROUNDING_TOWARD_ZERO,
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); ROUNDING_NEAREST_TIES_TO_EVEN,
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); ROUNDING_TOWARD_POSITIVE,
void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); ROUNDING_TOWARD_NEGATIVE,
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2); ROUNDING_NEAREST_TIES_TO_AWAY
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); } FloatRounding;
void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2); typedef struct FloatXX
void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); {
void bigint_shl_int(BigInt *dest, const BigInt *op1, uint64_t shift); union
void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); {
void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); double f64;
void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2); float f32;
void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2); };
void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2); TypeKind type;
void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); } FloatXX;
void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);
void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
bool bigint_eql(BigInt a, BigInt b);
CmpRes bigint_cmp(const BigInt *op1, const BigInt *op2);
CmpRes bigint_cmp_zero(const BigInt *op);
uint32_t bigint_hash(BigInt x);
const char *bigint_to_error_string(const BigInt *bigint, uint64_t base);
void bigint_print(BigInt *bigint, uint64_t base);
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base);
uint64_t bigint_as_unsigned(const BigInt *bigint);
int64_t bigint_as_signed(const BigInt *bigint);
Real bigint_as_float(const BigInt *bigint);
void bigint_truncate(BigInt *dst, const BigInt *op, size_t bit_count, bool is_signed);
void bigint_incr(BigInt *x);
size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count);
size_t bigint_popcount_unsigned(const BigInt *big_int);
void type_setup(PlatformTarget *target); void type_setup(PlatformTarget *target);
Float float_add(Float op1, Float op2);
Float float_sub(Float op1, Float op2);
Float float_mul(Float op1, Float op2);
Float float_div(Float op1, Float op2);
Float float_neg(Float op);
Float float_from_string(const char *string, char **error);
Float float_from_hex(const char *string, char **error);
Int128 i128_from_double(double x);
bool int_ucomp(Int op1, uint64_t op2, BinaryOp op);
bool int_icomp(Int op1, int64_t op2, BinaryOp op);
bool int_comp(Int op1, Int op2, BinaryOp op);
uint64_t int_to_u64(Int op);
int64_t int_to_i64(Int op);
bool int_is_zero(Int op);
bool int_fits(Int op1, TypeKind kind);
Int int_conv(Int op, TypeKind to_type);
Int int_div(Int op1, Int op2);
Int int_mul(Int op1, Int op2);
Int int_sub(Int op1, Int op2);
Int int_sub64(Int op1, uint64_t op2);
Int int_add(Int op1, Int op2);
Int int_add64(Int op1, uint64_t op2);
Int int_rem(Int op1, Int op2);
Int int_and(Int op1, Int op2);
Int int_or(Int op1, Int op2);
Int int_xor(Int op1, Int op2);
Int int_neg(Int op);
Int int_not(Int op);
bool int_is_neg(Int op);
Int int_shr64(Int op, uint64_t);
Int int_shl64(Int op, uint64_t);
Real int_to_real(Int op);
Int int_from_real(Real d, TypeKind type);
char *int_to_str(Int i, int radix);
bool i128_can_convert_from_double(double x);
bool i128_can_convert_from_double_signed(double x);
Int128 i128_from_double(double x);
Int128 i128_from_double_signed(double x);
Int128 i128_extend(Int128 op, TypeKind type);
Int128 i128_add(Int128 op1, Int128 op2);
Int128 i128_add64(Int128 op1, uint64_t op2);
Int128 i128_add_swrap64(Int128 op1, int64_t op2, bool *wrapped);
Int128 i128_add_uwrap64(Int128 op1, uint64_t op2, bool *wrapped);
Int128 i128_sub(Int128 op1, Int128 op2);
Int128 i128_sub64(Int128 op1, uint64_t op2);
Int128 i128_and(Int128 op1, Int128 op2);
Int128 i128_or(Int128 op1, Int128 op2);
Int128 i128_xor(Int128 op1, Int128 op2);
Int128 i128_neg(Int128 op1);
Int128 i128_not(Int128 op1);
Int128 i128_mult(Int128 op1, Int128 op2);
Int128 i128_mult64(Int128 op1, uint64_t op2);
Int128 i128_from_str(const char *str);
char *i128_to_string(Int128 op, uint64_t base, bool is_signed);
bool i128_is_neg(Int128 op);
CmpRes i128_ucomp(Int128 op1, Int128 op2);
CmpRes i128_scomp(Int128 op1, Int128 op2);
CmpRes i128_comp(Int128 op1, Int128 op2, Type *type);
Int128 i128_shl64(Int128 op1, uint64_t amount);
Int128 i128_shl(Int128 op1, Int128 op);
Int128 i128_ashr64(Int128 op1, uint64_t amount);
Int128 i128_ashr(Int128 op1, Int128 op2);
Int128 i128_lshr64(Int128 op1, uint64_t amount);
Int128 i128_lshr(Int128 op1, Int128 op2);
Int128 i128_udiv(Int128 op1, Int128 op2);
Int128 i128_sdiv(Int128 op1, Int128 op2);
Int128 i128_urem(Int128 op1, Int128 op2);
Int128 i128_srem(Int128 op1, Int128 op2);
void i128_udivrem(Int128 op1, Int128 op2, Int128 *div, Int128 *rem);
Real i128_to_float(Int128 op);
Real i128_to_float_signed(Int128 op);
bool i128_is_zero(Int128 op);
uint32_t i128_clz(const Int128 *op);
uint32_t i128_ctz(const Int128 *op);
int i128_lsb(const Int128 *op);
int i128_msb(const Int128 *op);
Int128 i128_from_float_signed(Real d);
Int128 i128_from_float_unsigned(Real d);
Int128 i128_from_signed(int64_t i);
Int128 i128_from_unsigned(uint64_t i);
bool i128_get_bit(const Int128 *op, int bit);
static inline bool type_may_negate(Type *type) static inline bool type_may_negate(Type *type)
{ {
RETRY: RETRY:
switch (type->type_kind) switch (type->type_kind)
{ {
case ALL_FLOATS:
case ALL_SIGNED_INTS:
case TYPE_VECTOR: case TYPE_VECTOR:
case TYPE_IXX: type = type->vector.base;
goto RETRY;
case ALL_FLOATS:
case ALL_INTS:
return true; return true;
case TYPE_DISTINCT: case TYPE_DISTINCT:
type = type->decl->distinct_decl.base_type; type = type->decl->distinct_decl.base_type;
@@ -1689,12 +1741,16 @@ static inline bool type_may_negate(Type *type)
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
type = type->canonical; type = type->canonical;
goto RETRY; goto RETRY;
case TYPE_FAILABLE:
type = type->failable;
goto RETRY;
default: default:
return false; return false;
} }
} }
bool cast_implicit_ignore_failable(Expr *expr, Type *to_type);
bool cast_implicit(Expr *expr, Type *to_type); bool cast_implicit(Expr *expr, Type *to_type);
bool cast(Expr *expr, Type *to_type); bool cast(Expr *expr, Type *to_type);
@@ -1704,8 +1760,6 @@ bool cast_implicit_bit_width(Expr *expr, Type *to_type);
CastKind cast_to_bool_kind(Type *type); CastKind cast_to_bool_kind(Type *type);
bool cast_implicitly_to_runtime(Expr *expr);
const char *llvm_codegen(void *context); const char *llvm_codegen(void *context);
void *llvm_gen(Module *module); void *llvm_gen(Module *module);
void llvm_codegen_setup(); void llvm_codegen_setup();
@@ -1792,14 +1846,12 @@ static inline void expr_replace(Expr *expr, Expr *replacement)
*expr = *replacement; *expr = *replacement;
expr->span = loc; 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_int(ExprConst *expr, uint64_t v, TypeKind kind);
void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind); void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind);
void expr_const_set_bool(ExprConst *expr, bool b); void expr_const_set_bool(ExprConst *expr, bool b);
void expr_const_set_null(ExprConst *expr); void expr_const_set_null(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_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind); bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
ByteSize expr_const_list_size(const ConstInitializer *list); ByteSize expr_const_list_size(const ConstInitializer *list);
@@ -1820,12 +1872,6 @@ static inline bool expr_is_init_list(Expr *expr)
ExprKind kind = expr->expr_kind; ExprKind kind = expr->expr_kind;
return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST; return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST;
} }
static inline void expr_set_type(Expr *expr, Type *type)
{
assert(type);
expr->type = type;
expr->original_type = type;
}
#pragma mark --- Lexer functions #pragma mark --- Lexer functions
@@ -1883,15 +1929,20 @@ bool sema_unwrap_var(Context *context, Decl *decl);
bool sema_rewrap_var(Context *context, Decl *decl); bool sema_rewrap_var(Context *context, Decl *decl);
bool sema_erase_var(Context *context, Decl *decl); bool sema_erase_var(Context *context, Decl *decl);
bool sema_erase_unwrapped(Context *context, Decl *decl); bool sema_erase_unwrapped(Context *context, Decl *decl);
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, bool may_be_failable); bool sema_analyse_cond_expr(Context *context, Expr *expr);
bool sema_analyse_assigned_expr(Context *context, Type *to, Expr *expr, bool may_be_failable);
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr);
ArrayIndex sema_get_initializer_const_array_size(Context *context, Expr *initializer, bool *may_be_array, bool *is_const_size); ArrayIndex sema_get_initializer_const_array_size(Context *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
bool sema_analyse_expr(Context *context, Type *to, Expr *expr); bool sema_analyse_expr(Context *context, Expr *expr);
bool sema_analyse_inferred_expr(Context *context, Type *to, Expr *expr);
bool sema_analyse_decl(Context *context, Decl *decl); bool sema_analyse_decl(Context *context, Decl *decl);
bool sema_analyse_var_decl(Context *context, Decl *decl); bool sema_analyse_var_decl(Context *context, Decl *decl);
bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement); bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement);
bool sema_analyse_statement(Context *context, Ast *statement); bool sema_analyse_statement(Context *context, Ast *statement);
bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, ExprFailableStatus lhs_is_failable); bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var);
bool sema_expr_analyse_general_call(Context *context, Type *to, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro);
bool sema_expr_analyse_general_call(Context *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable);
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol); Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol);
Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path); Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path);
Decl *sema_resolve_method(Context *context, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref); Decl *sema_resolve_method(Context *context, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
@@ -1980,9 +2031,10 @@ bool type_is_valid_for_vector(Type *type);
Type *type_get_array(Type *arr_type, ByteSize len); Type *type_get_array(Type *arr_type, ByteSize len);
Type *type_get_indexed_type(Type *type); Type *type_get_indexed_type(Type *type);
Type *type_get_ptr(Type *ptr_type); Type *type_get_ptr(Type *ptr_type);
Type *type_get_ptr_recurse(Type *ptr_type);
Type *type_get_subarray(Type *arr_type); Type *type_get_subarray(Type *arr_type);
Type *type_get_inferred_array(Type *arr_type); Type *type_get_inferred_array(Type *arr_type);
Type *type_get_failable(Type *failable_type);
Type *type_get_vector(Type *vector_type, unsigned len); Type *type_get_vector(Type *vector_type, unsigned len);
Type *type_get_vector_bool(Type *original_type); Type *type_get_vector_bool(Type *original_type);
Type *type_cint(void); Type *type_cint(void);
@@ -1990,9 +2042,7 @@ Type *type_cuint(void);
Type *type_int_signed_by_bitsize(unsigned bitsize); Type *type_int_signed_by_bitsize(unsigned bitsize);
Type *type_int_unsigned_by_bitsize(unsigned bytesize); Type *type_int_unsigned_by_bitsize(unsigned bytesize);
bool type_is_abi_aggregate(Type *type); bool type_is_abi_aggregate(Type *type);
static inline bool type_is_any_integer(Type *type);
static inline bool type_is_builtin(TypeKind kind); static inline bool type_is_builtin(TypeKind kind);
static inline bool type_is_ct(Type *type);
bool type_is_empty_record(Type *type, bool allow_array); bool type_is_empty_record(Type *type, bool allow_array);
bool type_is_empty_field(Type *type, bool allow_array); bool type_is_empty_field(Type *type, bool allow_array);
static inline bool type_is_float(Type *type); static inline bool type_is_float(Type *type);
@@ -2002,7 +2052,7 @@ Type *type_find_function_type(FunctionSignature *signature);
static inline bool type_is_integer(Type *type); static inline bool type_is_integer(Type *type);
static inline bool type_is_integer_unsigned(Type *type); static inline bool type_is_integer_unsigned(Type *type);
static inline bool type_is_integer_signed(Type *type); static inline bool type_is_integer_signed(Type *type);
static inline bool type_is_integer_kind(Type *type); static inline bool type_is_integer_or_bool_kind(Type *type);
static inline bool type_is_numeric(Type *type); static inline bool type_is_numeric(Type *type);
static inline bool type_underlying_is_numeric(Type *type); static inline bool type_underlying_is_numeric(Type *type);
static inline bool type_is_pointer(Type *type); static inline bool type_is_pointer(Type *type);
@@ -2024,7 +2074,6 @@ static inline Type *type_reduced_from_expr(Expr *expr);
ByteSize type_size(Type *type); ByteSize type_size(Type *type);
const char *type_to_error_string(Type *type); const char *type_to_error_string(Type *type);
const char *type_quoted_error_string(Type *type); const char *type_quoted_error_string(Type *type);
bool type_may_convert_to_boolean(Type *type);
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span); static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span); static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span);
@@ -2043,6 +2092,10 @@ static inline Type *type_reduced_from_expr(Expr *expr)
return type_lowering(expr->type); return type_lowering(expr->type);
} }
static inline Type *type_no_fail(Type *type)
{
return type && type->type_kind == TYPE_FAILABLE ? type->failable : type;
}
static inline bool type_is_pointer_sized_or_more(Type *type) static inline bool type_is_pointer_sized_or_more(Type *type)
{ {
@@ -2054,35 +2107,48 @@ static inline bool type_is_pointer_sized(Type *type)
return type_is_integer(type) && type_size(type) == type_size(type_iptr); return type_is_integer(type) && type_size(type) == type_size(type_iptr);
} }
#define DECL_TYPE_KIND_REAL(k_, t_) \
TypeKind k_ = (t_)->type_kind; \
if (k_ == TYPE_TYPEDEF) k_ = (t_)->canonical->type_kind;
#define IS_FAILABLE(element_) ((element_)->type->type_kind == TYPE_FAILABLE)
#define TYPE_IS_FAILABLE(type_) (type_->type_kind == TYPE_FAILABLE)
static inline Type *type_with_added_failability(Expr *expr, bool add_failable)
{
Type *type = expr->type;
if (!add_failable || type->type_kind == TYPE_FAILABLE) return type;
return type_get_failable(type);
}
static inline Type *type_get_opt_fail(Type *type, bool add_failable)
{
if (!add_failable || type->type_kind == TYPE_FAILABLE) return type;
return type_get_failable(type);
}
static inline bool type_is_integer(Type *type) static inline bool type_is_integer(Type *type)
{ {
assert(type == type->canonical); DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_IXX; return kind >= TYPE_INTEGER_FIRST && type->type_kind <= TYPE_INTEGER_LAST;
}
static inline bool type_is_any_integer(Type *type)
{
assert(type == type->canonical);
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX;
} }
static inline bool type_is_integer_signed(Type *type) static inline bool type_is_integer_signed(Type *type)
{ {
assert(type == type->canonical); DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; return kind >= TYPE_INT_FIRST && type->type_kind <= TYPE_INT_LAST;
} }
static inline bool type_is_integer_kind(Type *type) static inline bool type_is_integer_or_bool_kind(Type *type)
{ {
assert(type == type->canonical); DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind >= TYPE_BOOL && type->type_kind < TYPE_IXX; return kind >= TYPE_BOOL && kind <= TYPE_U128;
} }
static inline bool type_is_integer_unsigned(Type *type) static inline bool type_is_integer_unsigned(Type *type)
{ {
assert(type == type->canonical); DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX; return kind >= TYPE_UINT_FIRST && type->type_kind <= TYPE_UINT_LAST;
} }
static inline bool type_info_poison(TypeInfo *type) static inline bool type_info_poison(TypeInfo *type)
@@ -2092,26 +2158,11 @@ static inline bool type_info_poison(TypeInfo *type)
return false; return false;
} }
static inline bool type_is_ct(Type *type)
{
RETRY:
switch (type->type_kind)
{
case TYPE_FXX:
case TYPE_IXX:
return true;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
default:
return false;
}
}
static inline bool type_is_pointer(Type *type) static inline bool type_is_pointer(Type *type)
{ {
type = type->canonical; DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind == TYPE_POINTER; return kind == TYPE_POINTER;
} }
static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment) static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment)
@@ -2121,14 +2172,14 @@ static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment)
static inline bool type_is_substruct(Type *type) static inline bool type_is_substruct(Type *type)
{ {
assert(type == type->canonical); DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind == TYPE_STRUCT && type->decl->is_substruct; return kind == TYPE_STRUCT && type->decl->is_substruct;
} }
static inline bool type_is_float(Type *type) static inline bool type_is_float(Type *type)
{ {
assert(type == type->canonical); DECL_TYPE_KIND_REAL(kind, type);
return type->type_kind >= TYPE_F16 && type->type_kind <= TYPE_FXX; return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
} }
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span) static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
@@ -2171,7 +2222,6 @@ static inline bool type_convert_will_trunc(Type *destination, Type *source)
UnaryOp unaryop_from_token(TokenType type); UnaryOp unaryop_from_token(TokenType type);
PostUnaryOp post_unaryop_from_token(TokenType type);
BinaryOp binaryop_from_token(TokenType type); BinaryOp binaryop_from_token(TokenType type);
BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op); BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op);
TokenType binaryop_to_token(BinaryOp type); TokenType binaryop_to_token(BinaryOp type);
@@ -2233,6 +2283,12 @@ static inline Type *type_flatten(Type *type)
type = type->decl->enums.type_info->type; type = type->decl->enums.type_info->type;
continue; continue;
} }
if (type->type_kind == TYPE_FAILABLE)
{
type = type->failable;
if (!type) type = type_void;
continue;
}
return type; return type;
} }
} }
@@ -2245,19 +2301,19 @@ static Type *type_vector_type(Type *type)
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; } 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_U8; } 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_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U128; }
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; } static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_U128; }
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; } 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_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U128; }
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; } 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; } static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
int type_kind_bitsize(TypeKind kind);
bool type_is_scalar(Type *type); bool type_is_scalar(Type *type);
static inline bool type_is_numeric(Type *type) static inline bool type_is_numeric(Type *type)
{ {
TypeKind kind = type->type_kind; TypeKind kind = type->type_kind;
return (kind >= TYPE_I8 && kind <= TYPE_FXX) || kind == TYPE_VECTOR; return (kind >= TYPE_I8 && kind <= TYPE_FLOAT_LAST) || kind == TYPE_VECTOR;
} }
static inline bool type_underlying_is_numeric(Type *type) static inline bool type_underlying_is_numeric(Type *type)
@@ -2305,6 +2361,10 @@ static inline Type *type_lowering(Type *type)
static inline Decl *decl_raw(Decl *decl) static inline Decl *decl_raw(Decl *decl)
{ {
while (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind == DEFINE_IDENT_ALIAS)
{
decl = decl->define_decl.alias;
}
if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED) return decl; if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED) return decl;
decl = decl->var.alias; decl = decl->var.alias;
assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED); assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED);
@@ -2346,7 +2406,7 @@ static inline DeclKind decl_from_token(TokenType type)
static inline bool type_is_promotable_integer(Type *type) static inline bool type_is_promotable_integer(Type *type)
{ {
// If we support other architectures, update this. // If we support other architectures, update this.
return type_is_integer_kind(type) && type->builtin.bitsize < platform_target.width_c_int; return type_is_integer_or_bool_kind(type) && type->builtin.bitsize < platform_target.width_c_int;
} }
static inline bool type_is_promotable_float(Type *type) static inline bool type_is_promotable_float(Type *type)
@@ -2394,3 +2454,15 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
#define ASSIGN_TYPE_ELSE(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = TEMP(_type) #define ASSIGN_TYPE_ELSE(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = TEMP(_type)
#define ASSIGN_DECL_ELSE(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl) #define ASSIGN_DECL_ELSE(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl)
static inline Type *abi_rtype(FunctionSignature *signature)
{
Type *type = signature->rtype->type;
if (type->type_kind == TYPE_FAILABLE) return type->failable;
return type;
}
static inline Type *abi_returntype(FunctionSignature *signature)
{
Type *type = signature->rtype->type;
return type->type_kind == TYPE_FAILABLE ? type_anyerr : type;
}

View File

@@ -162,10 +162,6 @@ Expr *copy_expr(Expr *source_expr)
MACRO_COPY_EXPR(expr->guard_expr.inner); MACRO_COPY_EXPR(expr->guard_expr.inner);
return expr; return expr;
case EXPR_CONST: case EXPR_CONST:
if (expr->const_expr.const_kind == CONST_INTEGER && expr->const_expr.i.digit_count > 1)
{
bigint_init_bigint(&expr->const_expr.i, &source_expr->const_expr.i);
}
return expr; return expr;
case EXPR_BINARY: case EXPR_BINARY:
MACRO_COPY_EXPR(expr->binary_expr.left); MACRO_COPY_EXPR(expr->binary_expr.left);
@@ -177,10 +173,8 @@ Expr *copy_expr(Expr *source_expr)
MACRO_COPY_EXPR(expr->ternary_expr.else_expr); MACRO_COPY_EXPR(expr->ternary_expr.else_expr);
return expr; return expr;
case EXPR_UNARY: case EXPR_UNARY:
MACRO_COPY_EXPR(expr->unary_expr.expr);
return expr;
case EXPR_POST_UNARY: case EXPR_POST_UNARY:
MACRO_COPY_EXPR(expr->post_expr.expr); MACRO_COPY_EXPR(expr->unary_expr.expr);
return expr; return expr;
case EXPR_TYPEID: case EXPR_TYPEID:
MACRO_COPY_TYPE(expr->typeid_expr); MACRO_COPY_TYPE(expr->typeid_expr);
@@ -301,7 +295,7 @@ Ast *copy_ast(Ast *source)
case AST_DEFAULT_STMT: case AST_DEFAULT_STMT:
MACRO_COPY_AST(ast->case_stmt.body); MACRO_COPY_AST(ast->case_stmt.body);
return ast; return ast;
case AST_DEFINE_STMT: case AST_VAR_STMT:
ast->var_stmt = copy_decl(ast->var_stmt); ast->var_stmt = copy_decl(ast->var_stmt);
return ast; return ast;
case AST_DEFER_STMT: case AST_DEFER_STMT:

View File

@@ -50,7 +50,7 @@ typedef enum
AST_CASE_STMT, AST_CASE_STMT,
AST_COMPOUND_STMT, AST_COMPOUND_STMT,
AST_CONTINUE_STMT, AST_CONTINUE_STMT,
AST_DEFINE_STMT, AST_VAR_STMT,
AST_CT_ASSERT, AST_CT_ASSERT,
AST_CT_COMPOUND_STMT, AST_CT_COMPOUND_STMT,
AST_CT_IF_STMT, AST_CT_IF_STMT,
@@ -245,12 +245,6 @@ typedef enum
DESIGNATOR_RANGE DESIGNATOR_RANGE
} DesignatorType; } DesignatorType;
typedef enum
{
FAILABLE_NO,
FAILABLE_YES,
FAILABLE_UNWRAPPED
} ExprFailableStatus;
typedef enum typedef enum
@@ -523,21 +517,27 @@ typedef enum
TYPE_VOID, TYPE_VOID,
TYPE_BOOL, TYPE_BOOL,
TYPE_I8, TYPE_I8,
TYPE_INTEGER_FIRST = TYPE_I8,
TYPE_INT_FIRST = TYPE_I8,
TYPE_I16, TYPE_I16,
TYPE_I32, TYPE_I32,
TYPE_I64, TYPE_I64,
TYPE_I128, TYPE_I128,
TYPE_INT_LAST = TYPE_I128,
TYPE_U8, TYPE_U8,
TYPE_UINT_FIRST = TYPE_U8,
TYPE_U16, TYPE_U16,
TYPE_U32, TYPE_U32,
TYPE_U64, TYPE_U64,
TYPE_U128, TYPE_U128,
TYPE_IXX, TYPE_UINT_LAST = TYPE_U128,
TYPE_INTEGER_LAST = TYPE_U128,
TYPE_F16, TYPE_F16,
TYPE_FLOAT_FIRST = TYPE_F16,
TYPE_F32, TYPE_F32,
TYPE_F64, TYPE_F64,
TYPE_F128, TYPE_F128,
TYPE_FXX, TYPE_FLOAT_LAST = TYPE_F128,
TYPE_TYPEID, TYPE_TYPEID,
TYPE_POINTER, TYPE_POINTER,
TYPE_ENUM, TYPE_ENUM,
@@ -554,6 +554,7 @@ typedef enum
TYPE_SUBARRAY, TYPE_SUBARRAY,
TYPE_INFERRED_ARRAY, TYPE_INFERRED_ARRAY,
TYPE_UNTYPED_LIST, TYPE_UNTYPED_LIST,
TYPE_FAILABLE,
TYPE_TYPEINFO, TYPE_TYPEINFO,
TYPE_VECTOR, TYPE_VECTOR,
TYPE_VIRTUAL, TYPE_VIRTUAL,
@@ -563,11 +564,10 @@ typedef enum
#define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_UNTYPED_LIST: case TYPE_POISONED #define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_UNTYPED_LIST: case TYPE_POISONED
#define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \ #define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \
case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128: case TYPE_IXX case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
#define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128 #define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128
#define ALL_UNSIGNED_INTS TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128 #define ALL_UNSIGNED_INTS TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
#define ALL_REAL_FLOATS TYPE_F16: case TYPE_F32: case TYPE_F64: case TYPE_F128 #define ALL_FLOATS TYPE_F16: case TYPE_F32: case TYPE_F64: case TYPE_F128
#define ALL_FLOATS ALL_REAL_FLOATS: case TYPE_FXX
#define TYPE_KINDS (TYPE_LAST + 1) #define TYPE_KINDS (TYPE_LAST + 1)
@@ -585,12 +585,6 @@ typedef enum
UNARYOP_LAST = UNARYOP_DEC UNARYOP_LAST = UNARYOP_DEC
} UnaryOp; } UnaryOp;
typedef enum
{
POSTUNARYOP_INC,
POSTUNARYOP_DEC,
} PostUnaryOp;
typedef enum typedef enum
{ {
VARDECL_CONST = 0, VARDECL_CONST = 0,

266
src/compiler/float.c Normal file
View File

@@ -0,0 +1,266 @@
#include "compiler_internal.h"
#include <math.h>
#include <errno.h>
static int precision_bits(TypeKind kind)
{
switch (kind)
{
case TYPE_F16:
return 11;
/*case TYPE_BF16:
return 8;*/
case TYPE_F32:
return 24;
case TYPE_F64:
return 53;
case TYPE_F128:
return 113;
default:
UNREACHABLE
}
}
static int max_exponent(TypeKind kind)
{
switch (kind)
{
case TYPE_F16:
return 15;
/*case TYPE_BF16:
return 127;*/
case TYPE_F32:
return 127;
case TYPE_F64:
return 1023;
case TYPE_F128:
return 16383;
default:
UNREACHABLE
}
}
static int min_exponent(TypeKind kind)
{
switch (kind)
{
case TYPE_F16:
return -14;
/*case TYPE_BF16:
return -126;*/
case TYPE_F32:
return -126;
case TYPE_F64:
return -1022;
case TYPE_F128:
return -16382;
default:
UNREACHABLE
}
}
Float float_add(Float op1, Float op2)
{
assert(op1.type == op2.type);
return (Float){ op1.f + op2.f, op1.type };
}
Float float_sub(Float op1, Float op2)
{
assert(op1.type == op2.type);
return (Float){ op1.f - op2.f, op1.type };
}
Float float_mul(Float op1, Float op2)
{
assert(op1.type == op2.type);
return (Float){ op1.f * op2.f, op1.type };
}
Float float_div(Float op1, Float op2)
{
assert(op1.type == op2.type);
return (Float){ op1.f / op2.f, op1.type };
}
Float float_neg(Float op)
{
op.f = -op.f;
return op;
}
static char *err_invalid_float_width = "The float width is not valid, it must be one of 16, 32, 64 and 128.";
static char *err_float_out_of_range = "The float value is out of range.";
static char *err_float_format_invalid = "The float format is invalid.";
Float float_from_string(const char *string, char **error)
{
const char *index = string;
char c;
scratch_buffer_clear();
while ((c = *(index++)) && (c == '_' || (c >= '0' && c <= '9')))
{
if (c == '_') continue;
scratch_buffer_append_char(c);
}
if (c == '.')
{
scratch_buffer_append_char(c);
while ((c = *(index++)) && (c == '_' || (c >= '0' && c <= '9')))
{
if (c == '_') continue;
scratch_buffer_append_char(c);
}
}
if (c == 'e' || c == 'E')
{
scratch_buffer_append_char(c);
if (*index == '-')
{
scratch_buffer_append_char('-');
index++;
}
else if (*index == '+') index++;
while ((c = *(index++)) && (c >= '0' && c <= '9'))
{
scratch_buffer_append_char(c);
}
}
TypeKind kind = TYPE_F64;
if (c == 'f')
{
int i = 0;
while ((c = *(index++)) && (c >= '0' && c <= '9'))
{
if (i > 100)
{
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
i = i * 10 + c - '0';
}
switch (i)
{
case 32:
kind = TYPE_F32;
break;
case 16:
kind = TYPE_F16;
break;
case 64:
case 0:
kind = TYPE_F64;
break;
case 128:
kind = TYPE_F128;
break;
default:
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
}
const char *str = scratch_buffer_to_string();
char *end = NULL;
errno = 0;
double d = strtod(str, &end);
if (d == HUGE_VAL && errno == ERANGE)
{
if (error) *error = err_float_out_of_range;
return (Float){ .type = TYPE_POISONED };
}
char *expected_end = global_context.scratch_buffer + global_context.scratch_buffer_len;
if (d == 0 && end != expected_end)
{
if (error) *error = err_float_format_invalid;
return (Float){ .type = TYPE_POISONED };
}
return (Float){ d, kind };
}
Float float_from_hex(const char *string, char **error)
{
const char *index = string + 2;
char c;
scratch_buffer_clear();
scratch_buffer_append("0x");
while ((c = *(index++)) && (c == '_' || is_hex(c)))
{
if (c == '_') continue;
scratch_buffer_append_char(c);
}
if (c == '.')
{
scratch_buffer_append_char(c);
while ((c = *(index++)) && (c == '_' || is_hex(c)))
{
if (c == '_') continue;
scratch_buffer_append_char(c);
}
}
if (c == 'p' || c == 'P')
{
scratch_buffer_append_char(c);
if (*index == '-')
{
scratch_buffer_append_char('-');
index++;
}
else if (*index == '+') index++;
while ((c = *(index++)) && (c >= '0' && c <= '9'))
{
scratch_buffer_append_char(c);
}
}
TypeKind kind = TYPE_F64;
if (c == 'f')
{
int i = 0;
while ((c = *(index++)) && (c >= '0' && c <= '9'))
{
if (i > 100)
{
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
i = i * 10 + c - '0';
}
switch (i)
{
case 32:
kind = TYPE_F32;
break;
case 16:
kind = TYPE_F16;
break;
case 0:
case 64:
kind = TYPE_F64;
break;
case 128:
kind = TYPE_F128;
break;
default:
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
}
const char *str = scratch_buffer_to_string();
char *end = NULL;
errno = 0;
double d = strtod(str, &end);
if (d == HUGE_VAL && errno == ERANGE)
{
if (error) *error = err_float_out_of_range;
return (Float){ .type = TYPE_POISONED };
}
if (d == 0 && end != global_context.scratch_buffer + global_context.scratch_buffer_len)
{
if (error) *error = err_float_format_invalid;
return (Float){ .type = TYPE_POISONED };
}
return (Float){ d, kind };
}

View File

@@ -34,6 +34,9 @@ static void header_print_type(FILE *file, Type *type)
UNREACHABLE UNREACHABLE
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
TODO TODO
case TYPE_FAILABLE:
// If this is reachable then we are not doing the proper lowering.
UNREACHABLE
case TYPE_VOID: case TYPE_VOID:
OUTPUT("void"); OUTPUT("void");
return; return;
@@ -50,7 +53,6 @@ static void header_print_type(FILE *file, Type *type)
OUTPUT("int32_t"); OUTPUT("int32_t");
return; return;
case TYPE_I64: case TYPE_I64:
case TYPE_IXX:
OUTPUT("int64_t"); OUTPUT("int64_t");
return; return;
case TYPE_I128: case TYPE_I128:
@@ -78,7 +80,6 @@ static void header_print_type(FILE *file, Type *type)
OUTPUT("float"); OUTPUT("float");
return; return;
case TYPE_F64: case TYPE_F64:
case TYPE_FXX:
OUTPUT("double"); OUTPUT("double");
return; return;
case TYPE_F128: case TYPE_F128:

View File

@@ -352,6 +352,36 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to
#pragma mark --- Number scanning #pragma mark --- Number scanning
static bool scan_number_suffix(Lexer *lexer, bool *is_float)
{
if (!is_alphanum_(peek(lexer))) return true;
switch (peek(lexer))
{
case 'u':
case 'U':
case 'I':
case 'i':
if (*is_float)
{
return add_error_token(lexer, "Integer suffix '%x' is not valid for a floating point literal.", peek(lexer));
}
next(lexer);
while (is_number(peek(lexer))) next(lexer);
break;
case 'f':
*is_float = true;
next(lexer);
while (is_number(peek(lexer))) next(lexer);
break;
default:
break;
}
if (is_alphanum_(peek(lexer)))
{
return add_error_token(lexer, "This doesn't seem to be a valid literal.");
}
return true;
}
/** /**
* Parsing octals. Here we depart from the (error prone) C style octals with initial zero e.g. 0231 * Parsing octals. Here we depart from the (error prone) C style octals with initial zero e.g. 0231
* Instead we only support 0o prefix like 0o231. Note that lexing here doesn't actually parse the * Instead we only support 0o prefix like 0o231. Note that lexing here doesn't actually parse the
@@ -362,6 +392,12 @@ static bool scan_oct(Lexer *lexer)
char o = next(lexer); // Skip the o char o = next(lexer); // Skip the o
if (!is_oct(next(lexer))) return add_error_token(lexer, "An expression starting with '0%c' would expect to be followed by octal numbers (0-7).", o); if (!is_oct(next(lexer))) return add_error_token(lexer, "An expression starting with '0%c' would expect to be followed by octal numbers (0-7).", o);
while (is_oct_or_(peek(lexer))) next(lexer); while (is_oct_or_(peek(lexer))) next(lexer);
bool is_float = false;
if (!scan_number_suffix(lexer, &is_float)) return false;
if (is_float)
{
return add_error_token(lexer, "Octal literals cannot have a floating point suffix.");
}
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
} }
@@ -377,6 +413,12 @@ static bool scan_binary(Lexer *lexer)
"did you try to write a hex value but forgot the '0x'?"); "did you try to write a hex value but forgot the '0x'?");
} }
while (is_binary_or_(peek(lexer))) next(lexer); while (is_binary_or_(peek(lexer))) next(lexer);
bool is_float = false;
if (!scan_number_suffix(lexer, &is_float)) return false;
if (is_float)
{
return add_error_token(lexer, "Binary literals cannot have a floating point suffix.");
}
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
} }
@@ -434,6 +476,8 @@ static inline bool scan_hex(Lexer *lexer)
if (!scan_exponent(lexer)) return false; if (!scan_exponent(lexer)) return false;
} }
if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits."); if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits.");
// TODO this does not currently work.
if (!scan_number_suffix(lexer, &is_float)) return false;
if (is_float) if (is_float)
{ {
// IMPROVE // IMPROVE
@@ -441,26 +485,17 @@ static inline bool scan_hex(Lexer *lexer)
// this is not ideal, we should try to use f128 if possible for example. // this is not ideal, we should try to use f128 if possible for example.
// Possibly we should move to a BigDecimal implementation or at least a soft float 256 // Possibly we should move to a BigDecimal implementation or at least a soft float 256
// implementation for the constants. // implementation for the constants.
char *end = NULL; char *err = NULL;
errno = 0; Float f = float_from_hex(lexer->lexing_start, &err);
#if LONG_DOUBLE if (f.type == TYPE_POISONED)
Real fval = strtold(lexer->lexing_start, &end);
#else
Real fval = strtod(lexer->lexing_start, &end);
#endif
if (errno == ERANGE)
{ {
return add_error_token(lexer, "The float value is out of range."); return add_error_token(lexer, err);
}
if (end != lexer->current)
{
return add_error_token(lexer, "Invalid float value.");
} }
add_generic_token(lexer, TOKEN_REAL); add_generic_token(lexer, TOKEN_REAL);
lexer->latest_token_data->value = fval; lexer->latest_token_data->value = f;
return true; return true;
} }
return add_token(lexer, is_float ? TOKEN_REAL : TOKEN_INTEGER, lexer->lexing_start); return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
} }
/** /**
@@ -502,7 +537,8 @@ static inline bool scan_dec(Lexer *lexer)
} }
if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits."); if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits.");
// TODO this does not currently work.
if (!scan_number_suffix(lexer, &is_float)) return false;
if (is_float) if (is_float)
{ {
// IMPROVE // IMPROVE
@@ -510,18 +546,14 @@ static inline bool scan_dec(Lexer *lexer)
// this is not ideal, we should try to use f128 if possible for example. // this is not ideal, we should try to use f128 if possible for example.
// Possibly we should move to a BigDecimal implementation or at least a soft float 256 // Possibly we should move to a BigDecimal implementation or at least a soft float 256
// implementation for the constants. // implementation for the constants.
char *end = NULL; char *err = NULL;
#if LONG_DOUBLE Float f = float_from_string(lexer->lexing_start, &err);
Real fval = strtold(lexer->lexing_start, &end); if (f.type == TYPE_POISONED)
#else
Real fval = strtod(lexer->lexing_start, &end);
#endif
if (end != lexer->current)
{ {
return add_error_token(lexer, "Invalid float value."); return add_error_token(lexer, err);
} }
add_generic_token(lexer, TOKEN_REAL); add_generic_token(lexer, TOKEN_REAL);
lexer->latest_token_data->value = fval; lexer->latest_token_data->value = f;
return true; return true;
} }
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);

View File

@@ -262,7 +262,7 @@ static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl
{ {
decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal"); decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal");
} }
if (decl->var.failable) if (IS_FAILABLE(decl))
{ {
scratch_buffer_clear(); scratch_buffer_clear();
scratch_buffer_append(decl->external_name); scratch_buffer_append(decl->external_name);
@@ -312,7 +312,8 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
LLVMValueRef init_value; LLVMValueRef init_value;
ByteSize alignment = type_alloca_alignment(decl->type); Type *var_type = type_lowering(decl->type);
ByteSize alignment = type_alloca_alignment(var_type);
Expr *init_expr = decl->var.init_expr; Expr *init_expr = decl->var.init_expr;
if (init_expr) if (init_expr)
@@ -341,7 +342,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
} }
else else
{ {
init_value = LLVMConstNull(llvm_get_type(c, decl->type)); init_value = LLVMConstNull(llvm_get_type(c, var_type));
} }
@@ -359,7 +360,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
{ {
llvm_set_alignment(failable_ref, type_alloca_alignment(type_anyerr)); llvm_set_alignment(failable_ref, type_alloca_alignment(type_anyerr));
} }
if (decl->var.init_expr && decl->var.init_expr->failable) if (init_expr && IS_FAILABLE(init_expr) && init_expr->expr_kind == EXPR_FAILABLE)
{ {
UNREACHABLE UNREACHABLE
} }
@@ -395,9 +396,9 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
break; break;
} }
if (init_value && LLVMTypeOf(init_value) != llvm_get_type(c, decl->type)) if (init_value && LLVMTypeOf(init_value) != llvm_get_type(c, var_type))
{ {
decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, decl->type)); decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, var_type));
} }
LLVMReplaceAllUsesWith(old, decl->backend_ref); LLVMReplaceAllUsesWith(old, decl->backend_ref);
LLVMDeleteGlobal(old); LLVMDeleteGlobal(old);
@@ -467,12 +468,9 @@ LLVMValueRef llvm_emit_alloca_aligned(GenContext *c, Type *type, const char *nam
void llvm_emit_and_set_decl_alloca(GenContext *c, Decl *decl) void llvm_emit_and_set_decl_alloca(GenContext *c, Decl *decl)
{ {
if (decl->type == type_void) Type *type = type_lowering(decl->type);
{ if (type == type_void) return;
return; decl->backend_ref = llvm_emit_alloca(c, llvm_get_type(c, type), decl->alignment, decl->name ? decl->name : "anon");
}
LLVMTypeRef type = llvm_get_type(c, decl->type);
decl->backend_ref = llvm_emit_alloca(c, type, decl->alignment, decl->name ? decl->name : "anon");
} }
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl) void llvm_emit_local_var_alloca(GenContext *c, Decl *decl)
@@ -789,7 +787,7 @@ void llvm_value_set_decl_address(BEValue *value, Decl *decl)
llvm_value_set_address(value, decl_ref(decl), decl->type); llvm_value_set_address(value, decl_ref(decl), decl->type);
value->alignment = decl->alignment; value->alignment = decl->alignment;
if (decl->decl_kind == DECL_VAR && decl->var.failable) if (decl->decl_kind == DECL_VAR && IS_FAILABLE(decl))
{ {
value->kind = BE_ADDRESS_FAILABLE; value->kind = BE_ADDRESS_FAILABLE;
value->failable = decl->var.failable_ref; value->failable = decl->var.failable_ref;

View File

@@ -237,3 +237,4 @@ ABIArgInfo *c_abi_classify_argument_type_default(Type *type)
// No, then do a direct pass. // No, then do a direct pass.
return abi_arg_new_direct(); return abi_arg_new_direct();
} }

View File

@@ -140,17 +140,18 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic)
void c_abi_func_create_aarch64(FunctionSignature *signature) void c_abi_func_create_aarch64(FunctionSignature *signature)
{ {
if (signature->failable) Type *rtype = abi_rtype(signature);
if (IS_FAILABLE(signature->rtype))
{ {
signature->failable_abi_info = aarch64_classify_return_type(signature->rtype->type, signature->variadic == VARIADIC_RAW); signature->failable_abi_info = aarch64_classify_return_type(rtype, signature->variadic == VARIADIC_RAW);
if (signature->rtype->type->type_kind != TYPE_VOID) if (rtype->type_kind != TYPE_VOID)
{ {
signature->ret_abi_info = aarch64_classify_argument_type(type_get_ptr(type_lowering(signature->rtype->type))); signature->ret_abi_info = aarch64_classify_argument_type(type_get_ptr(type_lowering(rtype)));
} }
} }
else else
{ {
signature->ret_abi_info = aarch64_classify_return_type(signature->rtype->type, signature->variadic == VARIADIC_RAW); signature->ret_abi_info = aarch64_classify_return_type(rtype, signature->variadic == VARIADIC_RAW);
} }
Decl **params = signature->params; Decl **params = signature->params;
VECEACH(params, i) VECEACH(params, i)

View File

@@ -259,10 +259,12 @@ void c_abi_func_create_riscv(FunctionSignature *signature)
unsigned gpr = 8; unsigned gpr = 8;
unsigned fpr = 8; unsigned fpr = 8;
Type *return_type = signature->failable ? type_anyerr : signature->rtype->type; bool failable = IS_FAILABLE(signature->rtype);
Type *rtype = abi_rtype(signature);
Type *return_type = abi_returntype(signature);
return_type = type_lowering(return_type); return_type = type_lowering(return_type);
ABIArgInfo *return_abi = riscv_classify_return(return_type); ABIArgInfo *return_abi = riscv_classify_return(return_type);
if (signature->failable) if (failable)
{ {
signature->failable_abi_info = return_abi; signature->failable_abi_info = return_abi;
} }
@@ -291,9 +293,9 @@ void c_abi_func_create_riscv(FunctionSignature *signature)
unsigned arg_fprs_left = platform_target.riscv.flen ? fpr : 0; unsigned arg_fprs_left = platform_target.riscv.flen ? fpr : 0;
// If we have a failable, then the return type is a parameter. // If we have a failable, then the return type is a parameter.
if (signature->failable && signature->rtype->type->type_kind != TYPE_VOID) if (IS_FAILABLE(signature->rtype) && rtype != type_void)
{ {
signature->ret_abi_info = riscv_classify_argument_type(type_get_ptr(type_lowering(signature->rtype->type)), signature->ret_abi_info = riscv_classify_argument_type(type_get_ptr(type_lowering(rtype)),
true, &arg_gprs_left, &arg_fprs_left); true, &arg_gprs_left, &arg_fprs_left);
} }

View File

@@ -58,19 +58,21 @@ static ABIArgInfo *wasm_classify_return(Type *type)
void c_abi_func_create_wasm(FunctionSignature *signature) void c_abi_func_create_wasm(FunctionSignature *signature)
{ {
if (signature->failable) Type *rtype = abi_rtype(signature);
Type *return_type = abi_returntype(signature);
if (IS_FAILABLE(signature->rtype))
{ {
signature->failable_abi_info = wasm_classify_return(type_lowering(type_anyerr)); signature->failable_abi_info = wasm_classify_return(type_lowering(type_anyerr));
} }
else else
{ {
signature->ret_abi_info = wasm_classify_return(type_lowering(signature->rtype->type)); signature->ret_abi_info = wasm_classify_return(type_lowering(rtype));
} }
// If we have a failable, then the return type is a parameter. // If we have a failable, then the return type is a parameter.
if (signature->failable && signature->rtype->type->type_kind != TYPE_VOID) if (IS_FAILABLE(signature->rtype) && rtype->type_kind != TYPE_VOID)
{ {
signature->ret_abi_info = wasm_classify_argument_type(type_get_ptr(type_lowering(signature->rtype->type))); signature->ret_abi_info = wasm_classify_argument_type(type_get_ptr(type_lowering(rtype)));
} }
Decl **params = signature->params; Decl **params = signature->params;

View File

@@ -160,17 +160,18 @@ void c_abi_func_create_win64(FunctionSignature *signature)
break; break;
} }
if (signature->failable) Type *rtype = abi_rtype(signature);
if (IS_FAILABLE(signature->rtype))
{ {
signature->failable_abi_info = win64_classify(&regs, type_anyerr, true, is_vector_call, is_reg_call); signature->failable_abi_info = win64_classify(&regs, type_anyerr, true, is_vector_call, is_reg_call);
if (signature->rtype->type->type_kind != TYPE_VOID) if (rtype->type_kind != TYPE_VOID)
{ {
signature->ret_abi_info = win64_classify(&regs, type_get_ptr(type_lowering(signature->rtype->type)), false, is_vector_call, is_reg_call); signature->ret_abi_info = win64_classify(&regs, type_get_ptr(type_lowering(rtype)), false, is_vector_call, is_reg_call);
} }
} }
else else
{ {
signature->ret_abi_info = win64_classify(&regs, signature->rtype->type, true, is_vector_call, is_reg_call); signature->ret_abi_info = win64_classify(&regs, rtype, true, is_vector_call, is_reg_call);
} }
// Set up parameter registers. // Set up parameter registers.

View File

@@ -395,8 +395,6 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
{ {
case TYPE_ENUM: case TYPE_ENUM:
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
case TYPE_FXX:
case TYPE_IXX:
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_FUNC: case TYPE_FUNC:
case TYPE_DISTINCT: case TYPE_DISTINCT:
@@ -404,6 +402,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
case TYPE_ANYERR: case TYPE_ANYERR:
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
case TYPE_FAILABLE:
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
case TYPE_VOID: case TYPE_VOID:
@@ -589,8 +588,6 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
return x64_get_int_type_at_offset(element, offset - element_offset, source_type, source_offset); return x64_get_int_type_at_offset(element, offset - element_offset, source_type, source_offset);
} }
case TYPE_VOID: case TYPE_VOID:
case TYPE_FXX:
case TYPE_IXX:
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_ENUM: case TYPE_ENUM:
case TYPE_FUNC: case TYPE_FUNC:
@@ -600,6 +597,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
case TYPE_ANYERR: case TYPE_ANYERR:
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
case TYPE_FAILABLE:
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
case TYPE_I128: case TYPE_I128:
@@ -914,21 +912,22 @@ void c_abi_func_create_x64(FunctionSignature *signature)
.sse_registers = is_regcall ? 16 : 8 .sse_registers = is_regcall ? 16 : 8
}; };
if (signature->failable) Type *rtype = abi_rtype(signature);
if (IS_FAILABLE(signature->rtype))
{ {
signature->failable_abi_info = x64_classify_return_type(type_anyerr, &available_registers, is_regcall); signature->failable_abi_info = x64_classify_return_type(type_anyerr, &available_registers, is_regcall);
if (abi_arg_is_indirect(signature->failable_abi_info)) if (abi_arg_is_indirect(signature->failable_abi_info))
{ {
available_registers.int_registers--; available_registers.int_registers--;
} }
if (signature->rtype->type->type_kind != TYPE_VOID) if (rtype->type_kind != TYPE_VOID)
{ {
signature->ret_abi_info = x64_classify_parameter(type_get_ptr(type_lowering(signature->rtype->type)), &available_registers, is_regcall, NAMED); signature->ret_abi_info = x64_classify_parameter(type_get_ptr(type_lowering(rtype)), &available_registers, is_regcall, NAMED);
} }
} }
else else
{ {
signature->ret_abi_info = x64_classify_return_type(signature->rtype->type, &available_registers, is_regcall); signature->ret_abi_info = x64_classify_return_type(rtype, &available_registers, is_regcall);
if (abi_arg_is_indirect(signature->ret_abi_info)) if (abi_arg_is_indirect(signature->ret_abi_info))
{ {
available_registers.int_registers--; available_registers.int_registers--;

View File

@@ -92,7 +92,7 @@ static ABIArgInfo *create_indirect_return_x86(Type *type, Regs *regs)
static bool x86_should_return_type_in_reg(Type *type) static bool x86_should_return_type_in_reg(Type *type)
{ {
type = type->canonical; assert(type->canonical == type);
unsigned size = type_size(type); unsigned size = type_size(type);
if (size > 8) return false; if (size > 8) return false;
@@ -119,6 +119,7 @@ static bool x86_should_return_type_in_reg(Type *type)
case TYPE_ANYERR: case TYPE_ANYERR:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
case CT_TYPES: case CT_TYPES:
case TYPE_FAILABLE:
UNREACHABLE UNREACHABLE
case ALL_INTS: case ALL_INTS:
case ALL_FLOATS: case ALL_FLOATS:
@@ -384,7 +385,7 @@ static bool x86_try_put_primitive_in_reg(CallABI call, Regs *regs, Type *type)
case CALL_X86_VECTOR: case CALL_X86_VECTOR:
case CALL_X86_REG: case CALL_X86_REG:
if (type_size(type) > 4) return false; if (type_size(type) > 4) return false;
return type_is_integer_kind(type) || type_is_pointer(type); return type_is_integer_or_bool_kind(type) || type_is_pointer(type);
default: default:
return true; return true;
} }
@@ -594,6 +595,7 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
case TYPE_STRLIT: case TYPE_STRLIT:
case TYPE_FAILABLE:
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
case ALL_FLOATS: case ALL_FLOATS:
@@ -655,17 +657,18 @@ void c_abi_func_create_x86(FunctionSignature *signature)
// 4. Classify the return type. In the case of failable, we need to classify the failable itself as the // 4. Classify the return type. In the case of failable, we need to classify the failable itself as the
// return type. // return type.
if (signature->failable) Type *rtype = abi_rtype(signature);
if (IS_FAILABLE(signature->rtype))
{ {
signature->failable_abi_info = x86_classify_return(signature->call_abi, &regs, type_anyerr); signature->failable_abi_info = x86_classify_return(signature->call_abi, &regs, type_anyerr);
if (signature->rtype->type->type_kind != TYPE_VOID) if (rtype->type_kind != TYPE_VOID)
{ {
signature->ret_abi_info = x86_classify_argument(signature->call_abi, &regs, type_get_ptr(type_lowering(signature->rtype->type))); signature->ret_abi_info = x86_classify_argument(signature->call_abi, &regs, type_get_ptr(type_lowering(rtype)));
} }
} }
else else
{ {
signature->ret_abi_info = x86_classify_return(signature->call_abi, &regs, signature->rtype->type); signature->ret_abi_info = x86_classify_return(signature->call_abi, &regs, rtype);
} }
/* /*

View File

@@ -289,9 +289,7 @@ static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetad
VECEACH(enums, i) VECEACH(enums, i)
{ {
Decl *enum_constant = enums[i]; Decl *enum_constant = enums[i];
uint64_t val = is_unsigned uint64_t val = int_to_u64(enum_constant->enum_constant.expr->const_expr.ixx);
? bigint_as_unsigned(&enum_constant->enum_constant.expr->const_expr.i)
: (uint64_t)bigint_as_signed(&enum_constant->enum_constant.expr->const_expr.i);
LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator( LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator(
c->debug.builder, c->debug.builder,
enum_constant->name, TOKLEN(enum_constant->name_token), enum_constant->name, TOKLEN(enum_constant->name_token),
@@ -481,12 +479,13 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
// Consider special handling of UTF8 arrays. // Consider special handling of UTF8 arrays.
switch (type->type_kind) switch (type->type_kind)
{ {
case TYPE_IXX:
case TYPE_FXX:
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_STRLIT: case TYPE_STRLIT:
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
case TYPE_FAILABLE:
// If this is reachable then we're not doing the proper lowering.
UNREACHABLE
case TYPE_BOOL: case TYPE_BOOL:
return llvm_debug_simple_type(c, type, DW_ATE_boolean); return llvm_debug_simple_type(c, type, DW_ATE_boolean);
case TYPE_I8: case TYPE_I8:

View File

@@ -1342,9 +1342,9 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator); FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
case UNARYOP_NOT: case UNARYOP_NOT:
llvm_emit_expr(c, value, inner); llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
if (type_is_vector(type)) if (type_is_vector(type))
{ {
llvm_value_rvalue(c, value);
Type *vec_type = type_vector_type(type); Type *vec_type = type_vector_type(type);
if (type_is_float(vec_type)) if (type_is_float(vec_type))
{ {
@@ -1359,17 +1359,37 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
llvm_value_set(value, llvm_value, res_type); llvm_value_set(value, llvm_value, res_type);
return; return;
} }
if (type_is_float(type)) switch (type->type_kind)
{ {
llvm_value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, type), "not"); case ALL_FLOATS:
} llvm_value_rvalue(c, value);
else if (type->type_kind == TYPE_BOOL) llvm_value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, type), "not");
{ break;
llvm_value = LLVMBuildNot(c->builder, value->value, "not"); case TYPE_BOOL:
} llvm_value_rvalue(c, value);
else llvm_value = LLVMBuildNot(c->builder, value->value, "not");
{ break;
llvm_value = LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, type), "not"); case TYPE_SUBARRAY:
if (value->kind != BE_VALUE)
{
llvm_emit_len_for_expr(c, value, value);
llvm_value_rvalue(c, value);
llvm_value = value->value;
}
else
{
llvm_value = LLVMBuildExtractValue(c->builder, value->value, 1, "len");
}
llvm_value = LLVMBuildIsNull(c->builder, llvm_value, "not");
break;
case ALL_INTS:
case TYPE_POINTER:
llvm_value_rvalue(c, value);
llvm_value = LLVMBuildIsNull(c->builder, value->value, "not");
break;
default:
DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type));
UNREACHABLE
} }
llvm_value_set_bool(value, llvm_value); llvm_value_set_bool(value, llvm_value);
return; return;
@@ -1474,7 +1494,7 @@ static void llvm_emit_trap_zero(GenContext *c, Type *type, LLVMValueRef value, c
if (!active_target.feature.safe_mode) return; if (!active_target.feature.safe_mode) return;
LLVMValueRef zero = llvm_get_zero(c, type); LLVMValueRef zero = llvm_get_zero(c, type);
LLVMValueRef ok = type_is_any_integer(type) ? LLVMBuildICmp(c->builder, LLVMIntEQ, value, zero, "zero") : LLVMBuildFCmp(c->builder, LLVMRealUEQ, value, zero, "zero"); LLVMValueRef ok = type_is_integer(type) ? LLVMBuildICmp(c->builder, LLVMIntEQ, value, zero, "zero") : LLVMBuildFCmp(c->builder, LLVMRealUEQ, value, zero, "zero");
llvm_emit_panic_on_true(c, ok, error, loc); llvm_emit_panic_on_true(c, ok, error, loc);
} }
@@ -1809,6 +1829,8 @@ void llvm_emit_int_comp_zero(GenContext *c, BEValue *result, BEValue *lhs, Binar
void llvm_emit_int_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) void llvm_emit_int_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
{ {
llvm_value_rvalue(c, lhs);
llvm_value_rvalue(c, rhs);
llvm_emit_int_comp(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op); llvm_emit_int_comp(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op);
} }
void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op) void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op)
@@ -1858,6 +1880,30 @@ void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rh
rhs_signed = false; rhs_signed = false;
} }
} }
if (lhs_signed && !rhs_signed && !vector_type && LLVMIsConstant(lhs_value) && type_size(lhs_type) <= 64)
{
long long val = LLVMConstIntGetSExtValue(lhs_value);
if (val < 0)
{
switch (binary_op)
{
case BINARYOP_EQ:
case BINARYOP_GE:
case BINARYOP_GT:
llvm_value_set(result, llvm_const_int(c, type_bool, 0), type_bool);
return;
case BINARYOP_NE:
case BINARYOP_LE:
case BINARYOP_LT:
llvm_value_set(result, llvm_const_int(c, type_bool, 1), type_bool);
return;
default:
UNREACHABLE
}
}
lhs_signed = false;
}
if (!lhs_signed) if (!lhs_signed)
{ {
assert(lhs_signed == rhs_signed); assert(lhs_signed == rhs_signed);
@@ -1895,9 +1941,11 @@ void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rh
return; return;
} }
// Left side is signed. // Left side is signed.
LLVMValueRef comp_value; LLVMValueRef comp_value;
LLVMValueRef check_value; LLVMValueRef check_value;
switch (binary_op) switch (binary_op)
{ {
case BINARYOP_EQ: case BINARYOP_EQ:
@@ -2378,8 +2426,8 @@ static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Ex
llvm_emit_post_inc_dec(context, llvm_emit_post_inc_dec(context,
be_value, be_value,
expr->post_expr.expr, expr->unary_expr.expr,
expr->post_expr.operator == POSTUNARYOP_INC ? 1 : -1, expr->unary_expr.operator == UNARYOP_INC ? 1 : -1,
false); false);
} }
@@ -2474,9 +2522,39 @@ void llvm_emit_try_assign_expr(GenContext *c, BEValue *be_value, Expr *expr)
} }
} }
static inline void llvm_emit_catch_expr(GenContext *c, BEValue *value, Expr *expr)
{
LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "noerr_block");
// Store catch/error var
PUSH_ERROR();
LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyerr, "error_var");
llvm_value_set_address(value, error_var, type_anyerr);
llvm_store_bevalue_raw(c, value, llvm_get_zero(c, type_anyerr));
c->error_var = error_var;
c->catch_block = end_block;
BEValue expr_value;
llvm_emit_expr(c, &expr_value, expr->try_expr.expr);
llvm_value_fold_failable(c, &expr_value);
// Restore.
POP_ERROR();
// Emit success and jump to end block.
llvm_emit_br(c, end_block);
llvm_emit_block(c, end_block);
}
void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr) void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
{ {
if (!expr->try_expr.is_try)
{
llvm_emit_catch_expr(c, value, expr);
return;
}
LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block"); LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block");
LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block"); LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block");
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block"); LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block");
@@ -2505,9 +2583,9 @@ void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_block(c, phi_block); llvm_emit_block(c, phi_block);
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val"); LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
LLVMValueRef lhs = llvm_const_int(c, type_bool, expr->try_expr.is_try ? 1 : 0); LLVMValueRef lhs = llvm_const_int(c, type_bool, 1);
LLVMValueRef rhs = llvm_const_int(c, type_bool, expr->try_expr.is_try ? 0 : 1); LLVMValueRef rhs = llvm_const_int(c, type_bool, 0);
LLVMValueRef logic_values[2] = { lhs, rhs }; LLVMValueRef logic_values[2] = { lhs, rhs };
LLVMBasicBlockRef blocks[2] = { no_err_block, error_block }; LLVMBasicBlockRef blocks[2] = { no_err_block, error_block };
@@ -2832,21 +2910,21 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, phi, expr->type); llvm_value_set(value, phi, expr->type);
} }
static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Real f) static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Float f)
{ {
if (isnan(f)) if (isnan(f.f))
{ {
return LLVMConstRealOfString(type, "nan"); return LLVMConstRealOfString(type, "nan");
} }
if (isinf(f)) if (isinf(f.f))
{ {
return LLVMConstRealOfString(type, f < 0 ? "-inf" : "inf"); return LLVMConstRealOfString(type, f.f < 0 ? "-inf" : "inf");
} }
scratch_buffer_clear(); scratch_buffer_clear();
#if LONG_DOUBLE #if LONG_DOUBLE
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%La", f); global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%La", f.f);
#else #else
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%a", f); global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%a", f.f);
#endif #endif
return LLVMConstRealOfStringAndSize(type, global_context.scratch_buffer, global_context.scratch_buffer_len); return LLVMConstRealOfStringAndSize(type, global_context.scratch_buffer, global_context.scratch_buffer_len);
} }
@@ -2884,20 +2962,30 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
return; return;
} }
case CONST_INTEGER: case CONST_INTEGER:
if (type_is_unsigned(type)) {
LLVMValueRef value;
Int128 i = expr->const_expr.ixx.i;
switch (expr->const_expr.ixx.type)
{ {
llvm_value_set(be_value, llvm_const_int(c, type, bigint_as_unsigned(&expr->const_expr.i)), type); case TYPE_I128:
} case TYPE_U128:
else {
{ uint64_t words[2] = { i.low, i.high };
llvm_value_set(be_value, llvm_const_int(c, type, bigint_as_signed(&expr->const_expr.i)), type); value = LLVMConstIntOfArbitraryPrecision(llvm_get_type(c, type), 2, words);
break;
}
default:
value = llvm_const_int(c, type, i.low);
break;
} }
llvm_value_set(be_value, value, type);
return; return;
}
case CONST_LIST: case CONST_LIST:
llvm_emit_const_initializer_list_expr(c, be_value, expr); llvm_emit_const_initializer_list_expr(c, be_value, expr);
return; return;
case CONST_FLOAT: case CONST_FLOAT:
llvm_value_set(be_value, llvm_emit_real(llvm_get_type(c, type), expr->const_expr.f), type); llvm_value_set(be_value, llvm_emit_real(llvm_get_type(c, type), expr->const_expr.fxx), type);
return; return;
case CONST_POINTER: case CONST_POINTER:
llvm_value_set(be_value, LLVMConstNull(llvm_get_type(c, type)), type); llvm_value_set(be_value, LLVMConstNull(llvm_get_type(c, type)), type);
@@ -2987,8 +3075,6 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
switch (type_lowering(param_type)->type_kind) switch (type_lowering(param_type)->type_kind)
{ {
case TYPE_VOID: case TYPE_VOID:
case TYPE_IXX:
case TYPE_FXX:
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_FUNC: case TYPE_FUNC:
case TYPE_DISTINCT: case TYPE_DISTINCT:
@@ -2997,13 +3083,13 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
case TYPE_ANYERR: case TYPE_ANYERR:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
case TYPE_FAILABLE:
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
break; break;
case TYPE_BOOL: case TYPE_BOOL:
case ALL_SIGNED_INTS: case ALL_INTS:
case ALL_UNSIGNED_INTS: case ALL_FLOATS:
case ALL_REAL_FLOATS:
case TYPE_POINTER: case TYPE_POINTER:
vec_add(*values, LLVMBuildLoad2(context->builder, llvm_get_type(context, param_type), expand_ptr, "loadexpanded")); vec_add(*values, LLVMBuildLoad2(context->builder, llvm_get_type(context, param_type), expand_ptr, "loadexpanded"));
return; return;
@@ -3312,14 +3398,14 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
// 4. Prepare the return abi data. // 4. Prepare the return abi data.
ABIArgInfo *ret_info = signature->ret_abi_info; ABIArgInfo *ret_info = signature->ret_abi_info;
Type *return_type = signature->rtype->type->canonical; Type *return_type = abi_returntype(signature);
bool is_failable = IS_FAILABLE(signature->rtype);
// 5. In the case of a failable, the error is replacing the regular return abi. // 5. In the case of a failable, the error is replacing the regular return abi.
LLVMValueRef error_var = NULL; LLVMValueRef error_var = NULL;
if (signature->failable) if (is_failable)
{ {
ret_info = signature->failable_abi_info; ret_info = signature->failable_abi_info;
return_type = type_anyerr;
} }
*result_value = (BEValue){ .kind = BE_VALUE, .value = NULL }; *result_value = (BEValue){ .kind = BE_VALUE, .value = NULL };
@@ -3328,7 +3414,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
{ {
case ABI_ARG_INDIRECT: case ABI_ARG_INDIRECT:
// 6a. We can use the stored error var if there is no redirect. // 6a. We can use the stored error var if there is no redirect.
if (signature->failable && c->error_var && !ret_info->attributes.realign) if (is_failable && c->error_var && !ret_info->attributes.realign)
{ {
error_var = c->error_var; error_var = c->error_var;
vec_add(values, error_var); vec_add(values, error_var);
@@ -3355,7 +3441,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
// 7. We might have a failable indirect return and a normal return. // 7. We might have a failable indirect return and a normal return.
// In this case we need to add it by hand. // In this case we need to add it by hand.
BEValue synthetic_return_param = { 0 }; BEValue synthetic_return_param = { 0 };
if (signature->failable && signature->ret_abi_info) if (is_failable && signature->ret_abi_info)
{ {
// 7b. Create the address to hold the return. // 7b. Create the address to hold the return.
Type *actual_return_type = type_lowering(signature->rtype->type); Type *actual_return_type = type_lowering(signature->rtype->type);
@@ -3494,7 +3580,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
case ABI_ARG_IGNORE: case ABI_ARG_IGNORE:
// 12. Basically void returns or empty structs. // 12. Basically void returns or empty structs.
// Here we know we don't have a failable or any return value that can be used. // Here we know we don't have a failable or any return value that can be used.
assert(!signature->failable && "Failable should have produced a return value."); assert(!is_failable && "Failable should have produced a return value.");
*result_value = (BEValue) { .type = type_void, .kind = BE_VALUE }; *result_value = (BEValue) { .type = type_void, .kind = BE_VALUE };
return; return;
case ABI_ARG_INDIRECT: case ABI_ARG_INDIRECT:
@@ -3602,7 +3688,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
} }
// 17. Handle failables. // 17. Handle failables.
if (signature->failable) if (is_failable)
{ {
BEValue no_err; BEValue no_err;
@@ -3668,7 +3754,7 @@ static inline void gencontext_emit_expression_list_expr(GenContext *context, BEV
static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, Ast **stmts) static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, Ast **stmts)
{ {
Type *type_lowered = type_lowering(type);
LLVMValueRef old_ret_out = context->return_out; LLVMValueRef old_ret_out = context->return_out;
LLVMBasicBlockRef saved_block_return_exit = context->block_return_exit; LLVMBasicBlockRef saved_block_return_exit = context->block_return_exit;
LLVMBasicBlockRef saved_block_failable_exit = context->block_failable_exit; LLVMBasicBlockRef saved_block_failable_exit = context->block_failable_exit;
@@ -3682,9 +3768,9 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
LLVMValueRef error_out = context->error_var; LLVMValueRef error_out = context->error_var;
LLVMBasicBlockRef error_block = context->catch_block; LLVMBasicBlockRef error_block = context->catch_block;
if (type != type_void) if (type_lowered != type_void)
{ {
return_out = llvm_emit_alloca_aligned(context, type, "blockret"); return_out = llvm_emit_alloca_aligned(context, type_lowered, "blockret");
} }
context->block_error_var = error_out; context->block_error_var = error_out;
context->block_failable_exit = error_block; context->block_failable_exit = error_block;
@@ -3711,7 +3797,7 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
if (return_out) if (return_out)
{ {
llvm_value_set_address(be_value, return_out, type); llvm_value_set_address(be_value, return_out, type_lowered);
} }
else else
{ {
@@ -3783,7 +3869,7 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
if (failable) if (failable)
{ {
if (expr->failable) if (IS_FAILABLE(expr))
{ {
assign_block = llvm_basic_block_new(c, "after_assign"); assign_block = llvm_basic_block_new(c, "after_assign");
c->error_var = failable; c->error_var = failable;
@@ -3823,7 +3909,7 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
} }
POP_ERROR(); POP_ERROR();
if (failable && expr->failable) if (failable && IS_FAILABLE(expr))
{ {
llvm_emit_br(c, assign_block); llvm_emit_br(c, assign_block);
llvm_emit_block(c, assign_block); llvm_emit_block(c, assign_block);
@@ -3848,12 +3934,13 @@ static inline void gencontext_emit_failable(GenContext *context, BEValue *be_val
llvm_emit_br(context, context->catch_block); llvm_emit_br(context, context->catch_block);
LLVMBasicBlockRef ignored_block = llvm_basic_block_new(context, "postfailed"); LLVMBasicBlockRef ignored_block = llvm_basic_block_new(context, "postfailed");
llvm_emit_block(context, ignored_block); llvm_emit_block(context, ignored_block);
if (expr->type->canonical == type_void) Type *type = type_no_fail(expr->type);
if (type->canonical == type_void)
{ {
llvm_value_set(be_value, NULL, type_void); llvm_value_set(be_value, NULL, type_void);
return; return;
} }
llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(context, expr->type)), expr->type); llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(context, type)), type);
} }
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, ArrayIndex index, bool *is_const) static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, ArrayIndex index, bool *is_const)
@@ -3931,12 +4018,14 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
static inline void llvm_emit_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr) static inline void llvm_emit_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr)
{ {
if (type_is_vector(expr->type)) Type *type = type_lowering(expr->type);
if (type_is_vector(type))
{ {
llvm_emit_vector_initializer_list(c, value, expr); llvm_emit_vector_initializer_list(c, value, expr);
return; return;
} }
llvm_value_set_address(value, llvm_emit_alloca_aligned(c, expr->type, "literal"), expr->type); assert(!IS_FAILABLE(expr) || c->catch_block);
llvm_value_set_address(value, llvm_emit_alloca_aligned(c, type, "literal"), type);
llvm_emit_initialize_reference(c, value, expr); llvm_emit_initialize_reference(c, value, expr);
} }
@@ -4127,6 +4216,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_try_assign_expr(c, value, expr); llvm_emit_try_assign_expr(c, value, expr);
return; return;
case EXPR_NOP: case EXPR_NOP:
llvm_value_set(value, NULL, type_void);
return; return;
case EXPR_ELSE: case EXPR_ELSE:
gencontext_emit_else_expr(c, value, expr); gencontext_emit_else_expr(c, value, expr);

View File

@@ -250,12 +250,14 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
// If we have a failable it's always the return argument, so we need to copy // If we have a failable it's always the return argument, so we need to copy
// the return value into the return value holder. // the return value into the return value holder.
LLVMValueRef return_out = c->return_out; LLVMValueRef return_out = c->return_out;
bool is_failable = IS_FAILABLE(signature->rtype);
Type *return_type = signature->rtype->type; Type *return_type = signature->rtype->type;
if (is_failable) return_type = return_type->failable;
BEValue no_fail; BEValue no_fail;
// In this case we use the failable as the actual return. // In this case we use the failable as the actual return.
if (signature->failable) if (is_failable)
{ {
if (return_value && return_value->value) if (return_value && return_value->value)
{ {
@@ -346,18 +348,19 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
void llvm_emit_return_implicit(GenContext *c) void llvm_emit_return_implicit(GenContext *c)
{ {
if (c->cur_func_decl->func_decl.function_signature.rtype->type != type_void) Type *rtype_real = c->cur_func_decl->func_decl.function_signature.rtype->type;
if (type_lowering(type_no_fail(rtype_real)) != type_void)
{ {
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);
return; return;
} }
if (!c->cur_func_decl->func_decl.function_signature.failable) if (rtype_real->type_kind == TYPE_FAILABLE)
{ {
llvm_emit_return_abi(c, NULL, NULL); llvm_emit_return_abi(c, NULL, NULL);
return; return;
} }
BEValue value; BEValue value;
llvm_value_set(&value, LLVMConstNull(llvm_get_type(c, type_anyerr)), type_anyerr); llvm_value_set(&value, llvm_get_zero(c, type_anyerr), type_anyerr);
llvm_emit_return_abi(c, NULL, &value); llvm_emit_return_abi(c, NULL, &value);
} }
@@ -400,7 +403,8 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
llvm_debug_scope_push(context, context->debug.function); llvm_debug_scope_push(context, context->debug.function);
} }
if (signature->failable && signature->failable_abi_info->kind == ABI_ARG_INDIRECT) bool is_failable = IS_FAILABLE(signature->rtype);
if (is_failable && signature->failable_abi_info->kind == ABI_ARG_INDIRECT)
{ {
context->failable_out = LLVMGetParam(context->function, arg++); context->failable_out = LLVMGetParam(context->function, arg++);
} }
@@ -415,7 +419,7 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
else else
{ {
context->return_out = NULL; context->return_out = NULL;
if (signature->ret_abi_info && signature->failable) if (signature->ret_abi_info && is_failable)
{ {
context->return_out = LLVMGetParam(context->function, arg++); context->return_out = LLVMGetParam(context->function, arg++);
} }

View File

@@ -307,7 +307,7 @@ static inline LLVMValueRef decl_failable_ref(Decl *decl)
{ {
assert(decl->decl_kind == DECL_VAR); assert(decl->decl_kind == DECL_VAR);
if (decl->var.kind == VARDECL_UNWRAPPED) return decl_failable_ref(decl->var.alias); if (decl->var.kind == VARDECL_UNWRAPPED) return decl_failable_ref(decl->var.alias);
if (!decl->var.failable) return NULL; if (decl->type->type_kind != TYPE_FAILABLE) return NULL;
return decl->var.failable_ref; return decl->var.failable_ref;
} }
@@ -411,7 +411,7 @@ static inline LLVMValueRef llvm_get_zero(GenContext *c, Type *type)
static inline LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t val) static inline LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t val)
{ {
type = type_lowering(type); type = type_lowering(type);
assert(type_is_any_integer(type) || type->type_kind == TYPE_BOOL); assert(type_is_integer(type) || type->type_kind == TYPE_BOOL);
return LLVMConstInt(llvm_get_type(c, type), val, type_is_integer_signed(type)); return LLVMConstInt(llvm_get_type(c, type), val, type_is_integer_signed(type));
} }
@@ -438,3 +438,4 @@ static inline bool abi_info_should_flatten(ABIArgInfo *info)
{ {
return info->kind == ABI_ARG_DIRECT_COERCE && info->direct_coerce.elements > 1U && !info->direct_coerce.prevent_flatten; return info->kind == ABI_ARG_DIRECT_COERCE && info->direct_coerce.elements > 1U && !info->direct_coerce.prevent_flatten;
} }

View File

@@ -48,7 +48,8 @@ void gencontext_emit_ct_compound_stmt(GenContext *context, Ast *ast)
LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
{ {
// 1. Get the declaration and the LLVM type. // 1. Get the declaration and the LLVM type.
LLVMTypeRef alloc_type = llvm_get_type(c, type_lowering(decl->type)); Type *var_type = type_lowering(type_no_fail(decl->type));
LLVMTypeRef alloc_type = llvm_get_type(c, var_type);
// 2. In the case we have a static variable, // 2. In the case we have a static variable,
// then we essentially treat this as a global. // then we essentially treat this as a global.
@@ -56,8 +57,8 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
{ {
void *builder = c->builder; void *builder = c->builder;
c->builder = NULL; c->builder = NULL;
decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal"); decl->backend_ref = LLVMAddGlobal(c->module, alloc_type, "tempglobal");
if (decl->var.failable) if (IS_FAILABLE(decl))
{ {
scratch_buffer_clear(); scratch_buffer_clear();
scratch_buffer_append(decl->external_name); scratch_buffer_append(decl->external_name);
@@ -69,14 +70,14 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
return decl->backend_ref; return decl->backend_ref;
} }
llvm_emit_local_var_alloca(c, decl); llvm_emit_local_var_alloca(c, decl);
if (decl->var.failable) if (IS_FAILABLE(decl))
{ {
scratch_buffer_clear(); scratch_buffer_clear();
scratch_buffer_append(decl->name); scratch_buffer_append(decl->name);
scratch_buffer_append(".f"); scratch_buffer_append(".f");
decl->var.failable_ref = llvm_emit_alloca_aligned(c, type_anyerr, scratch_buffer_to_string()); decl->var.failable_ref = llvm_emit_alloca_aligned(c, type_anyerr, scratch_buffer_to_string());
// Only clear out the result if the assignment isn't a failable. // Only clear out the result if the assignment isn't a failable.
if (!decl->var.init_expr || !decl->var.init_expr->failable) if (!decl->var.init_expr || !IS_FAILABLE(decl->var.init_expr))
{ {
LLVMBuildStore(c->builder, LLVMConstNull(llvm_get_type(c, type_anyerr)), decl->var.failable_ref); LLVMBuildStore(c->builder, LLVMConstNull(llvm_get_type(c, type_anyerr)), decl->var.failable_ref);
} }
@@ -178,7 +179,7 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast)
c->error_var = c->block_error_var; c->error_var = c->block_error_var;
c->catch_block = c->block_failable_exit; c->catch_block = c->block_failable_exit;
} }
else if (c->cur_func_decl->func_decl.function_signature.failable) else if (IS_FAILABLE(c->cur_func_decl->func_decl.function_signature.rtype))
{ {
error_return_block = llvm_basic_block_new(c, "err_retblock"); error_return_block = llvm_basic_block_new(c, "err_retblock");
error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr"); error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr");
@@ -962,6 +963,96 @@ void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast)
llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end); llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
} }
static bool expr_is_pure(Expr *expr)
{
if (!expr) return true;
switch (expr->expr_kind)
{
case EXPR_CONST:
case EXPR_CONST_IDENTIFIER:
case EXPR_IDENTIFIER:
case EXPR_NOP:
return true;
case EXPR_BINARY:
if (expr->binary_expr.operator >= BINARYOP_ASSIGN) return false;
return expr_is_pure(expr->binary_expr.right) && expr_is_pure(expr->binary_expr.left);
case EXPR_UNARY:
switch (expr->unary_expr.operator)
{
case UNARYOP_INC:
case UNARYOP_DEC:
case UNARYOP_TADDR:
return false;
default:
return expr_is_pure(expr->unary_expr.expr);
}
break;
case EXPR_ACCESS:
return expr_is_pure(expr->access_expr.parent);
case EXPR_POISONED:
case EXPR_CT_IDENT:
case EXPR_TYPEID:
case EXPR_CT_CALL:
case EXPR_TYPEOF:
UNREACHABLE
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_CALL:
case EXPR_CATCH_UNWRAP:
case EXPR_COMPOUND_LITERAL:
case EXPR_COND:
case EXPR_DESIGNATOR:
case EXPR_DECL:
case EXPR_ELSE:
case EXPR_EXPR_BLOCK:
case EXPR_FAILABLE:
case EXPR_GUARD:
case EXPR_HASH_IDENT:
case EXPR_MACRO_BLOCK:
case EXPR_MACRO_EXPANSION:
case EXPR_FLATPATH:
case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_PLACEHOLDER:
case EXPR_POST_UNARY:
case EXPR_SCOPED_EXPR:
case EXPR_SLICE_ASSIGN:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TRY_ASSIGN:
case EXPR_UNDEF:
case EXPR_TYPEINFO:
return false;
case EXPR_CAST:
return expr_is_pure(expr->cast_expr.expr);
case EXPR_EXPRESSION_LIST:
{
VECEACH(expr->expression_list, i)
{
if (!expr_is_pure(expr->expression_list[i])) return false;
}
return true;
}
break;
case EXPR_GROUP:
return expr_is_pure(expr->group_expr);
case EXPR_LEN:
return expr_is_pure(expr->len_expr.inner);
case EXPR_SLICE:
return expr_is_pure(expr->slice_expr.expr)
&& expr_is_pure(expr->slice_expr.start)
&& expr_is_pure(expr->slice_expr.end);
case EXPR_SUBSCRIPT:
return expr_is_pure(expr->subscript_expr.expr)
&& expr_is_pure(expr->subscript_expr.index);
case EXPR_TERNARY:
return expr_is_pure(expr->ternary_expr.cond)
&& expr_is_pure(expr->ternary_expr.else_expr)
&& expr_is_pure(expr->ternary_expr.then_expr);
case EXPR_TRY:
return expr_is_pure(expr->try_expr.expr);
}
UNREACHABLE
}
static inline void llvm_emit_assume(GenContext *c, Expr *expr) static inline void llvm_emit_assume(GenContext *c, Expr *expr)
{ {
@@ -994,7 +1085,7 @@ static inline void llvm_emit_assume(GenContext *c, Expr *expr)
} }
// 3. Check if pure, if so we emit the assume. // 3. Check if pure, if so we emit the assume.
if (expr->pure) if (expr_is_pure(expr))
{ {
BEValue value; BEValue value;
llvm_emit_expr(c, &value, expr); llvm_emit_expr(c, &value, expr);
@@ -1092,7 +1183,7 @@ static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *as
void gencontext_emit_expr_stmt(GenContext *c, Ast *ast) void gencontext_emit_expr_stmt(GenContext *c, Ast *ast)
{ {
BEValue value; BEValue value;
if (ast->expr_stmt->failable) if (IS_FAILABLE(ast->expr_stmt))
{ {
PUSH_ERROR(); PUSH_ERROR();
LLVMBasicBlockRef discard_fail = llvm_basic_block_new(c, "voiderr"); LLVMBasicBlockRef discard_fail = llvm_basic_block_new(c, "voiderr");
@@ -1279,7 +1370,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
case AST_DOCS: case AST_DOCS:
case AST_DOC_DIRECTIVE: case AST_DOC_DIRECTIVE:
case AST_POISONED: case AST_POISONED:
case AST_DEFINE_STMT: case AST_VAR_STMT:
case AST_IF_CATCH_SWITCH_STMT: case AST_IF_CATCH_SWITCH_STMT:
UNREACHABLE UNREACHABLE
case AST_SCOPED_STMT: case AST_SCOPED_STMT:

View File

@@ -232,8 +232,11 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type)
LLVMTypeRef return_type = NULL; LLVMTypeRef return_type = NULL;
Type *real_return_type = signature->failable ? type_anyerr : signature->rtype->type->canonical; Type *rtype = signature->rtype->type;
ABIArgInfo *ret_arg_info = signature->failable ? signature->failable_abi_info : signature->ret_abi_info; bool is_failable = rtype->type_kind == TYPE_FAILABLE;
if (is_failable) rtype = rtype->failable;
Type *real_return_type = is_failable ? type_anyerr : rtype;
ABIArgInfo *ret_arg_info = is_failable ? signature->failable_abi_info : signature->ret_abi_info;
ret_arg_info->param_index_end = 0; ret_arg_info->param_index_end = 0;
ret_arg_info->param_index_start = 0; ret_arg_info->param_index_start = 0;
@@ -276,9 +279,9 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type)
} }
// If it's failable and it's not void (meaning ret_abi_info will be NULL) // If it's failable and it's not void (meaning ret_abi_info will be NULL)
if (signature->failable && signature->ret_abi_info) if (is_failable && signature->ret_abi_info)
{ {
add_func_type_param(context, type_get_ptr(signature->rtype->type), signature->ret_abi_info, &params); add_func_type_param(context, type_get_ptr(rtype), signature->ret_abi_info, &params);
} }
// Add in all of the required arguments. // Add in all of the required arguments.
@@ -310,6 +313,9 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
{ {
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
case TYPE_FAILABLE:
// If this is reachable, then we're not doing the proper lowering.
UNREACHABLE
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_ANYERR: case TYPE_ANYERR:
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
@@ -329,7 +335,6 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
case TYPE_VOID: case TYPE_VOID:
return any_type->backend_type = LLVMVoidTypeInContext(c->context); return any_type->backend_type = LLVMVoidTypeInContext(c->context);
case TYPE_F64: case TYPE_F64:
case TYPE_FXX:
return any_type->backend_type = LLVMDoubleTypeInContext(c->context); return any_type->backend_type = LLVMDoubleTypeInContext(c->context);
case TYPE_F16: case TYPE_F16:
return any_type->backend_type = LLVMHalfTypeInContext(c->context); return any_type->backend_type = LLVMHalfTypeInContext(c->context);
@@ -340,8 +345,6 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
case ALL_SIGNED_INTS: case ALL_SIGNED_INTS:
case ALL_UNSIGNED_INTS: case ALL_UNSIGNED_INTS:
return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize); return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize);
case TYPE_IXX:
return any_type->backend_type = LLVMIntTypeInContext(c->context, 32U);
case TYPE_BOOL: case TYPE_BOOL:
return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U); return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U);
case TYPE_POINTER: case TYPE_POINTER:

View File

@@ -7,16 +7,14 @@
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind) void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind)
{ {
expr->ixx.i.high = 0;
if (type_kind_is_signed(kind)) if (type_kind_is_signed(kind))
{ {
bigint_init_signed(&expr->i, (int64_t)v); if (v > (uint64_t)INT64_MAX) expr->ixx.i.high = UINT64_MAX;
}
else
{
bigint_init_unsigned(&expr->i, v);
} }
expr->ixx.i.low = v;
expr->ixx.type = kind;
expr->const_kind = CONST_INTEGER; expr->const_kind = CONST_INTEGER;
expr->int_type = kind;
} }
void expr_const_set_bool(ExprConst *expr, bool b) void expr_const_set_bool(ExprConst *expr, bool b)
@@ -27,8 +25,7 @@ void expr_const_set_bool(ExprConst *expr, bool b)
void expr_const_set_null(ExprConst *expr) void expr_const_set_null(ExprConst *expr)
{ {
expr->i.digit_count = 0; expr->ixx = (Int) { .i = (Int128) { 0, 0 }, .type = type_iptr->canonical->type_kind };
expr->i.digit = 0;
expr->const_kind = CONST_POINTER; expr->const_kind = CONST_POINTER;
} }
@@ -52,29 +49,6 @@ static inline bool compare_bool(bool left, bool right, BinaryOp op)
UNREACHABLE UNREACHABLE
} }
} }
static inline bool compare_ints(const BigInt *left, const BigInt *right, BinaryOp op)
{
CmpRes res = bigint_cmp(left, right);
switch (op)
{
case BINARYOP_GE:
return res != CMP_LT;
case BINARYOP_LE:
return res != CMP_GT;
case BINARYOP_NE:
return res != CMP_EQ;
case BINARYOP_GT:
return res == CMP_GT;
case BINARYOP_LT:
return res == CMP_LT;
case BINARYOP_EQ:
return res == CMP_EQ;
default:
UNREACHABLE
}
}
static inline bool compare_fps(Real left, Real right, BinaryOp op) static inline bool compare_fps(Real left, Real right, BinaryOp op)
{ {
switch (op) switch (op)
@@ -104,9 +78,9 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
case CONST_BOOL: case CONST_BOOL:
return compare_bool(left->b, right->b, op); return compare_bool(left->b, right->b, op);
case CONST_INTEGER: case CONST_INTEGER:
return compare_ints(&left->i, &right->i, op); return int_comp(left->ixx, right->ixx, op);
case CONST_FLOAT: case CONST_FLOAT:
return compare_fps(left->f, right->f, op); return compare_fps(left->fxx.f, right->fxx.f, op);
case CONST_POINTER: case CONST_POINTER:
return true; return true;
case CONST_STRING: case CONST_STRING:
@@ -190,29 +164,14 @@ bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind)
{ {
switch (kind) switch (kind)
{ {
case TYPE_I8: case ALL_INTS:
return !bigint_fits_in_bits(&expr->i, 8, true); return !int_fits(expr->ixx, kind);
case TYPE_I16:
return !bigint_fits_in_bits(&expr->i, 16, true);
case TYPE_I32:
return !bigint_fits_in_bits(&expr->i, 32, true);
case TYPE_I64:
return !bigint_fits_in_bits(&expr->i, 64, true);
case TYPE_U8:
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 8, false);
case TYPE_U16:
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 16, false);
case TYPE_U32:
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 32, false);
case TYPE_U64:
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 64, false);
case TYPE_F16: case TYPE_F16:
return !bigint_fits_in_bits(&expr->i, 17, false); REMINDER("Check f16 narrowing");
case TYPE_IXX: FALLTHROUGH;
case TYPE_F32: case TYPE_F32:
case TYPE_F64: case TYPE_F64:
case TYPE_F128: case TYPE_F128:
case TYPE_FXX:
case TYPE_BOOL: case TYPE_BOOL:
return false; return false;
default: default:
@@ -220,10 +179,6 @@ bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind)
} }
} }
bool expr_const_int_overflowed(const ExprConst *expr)
{
return expr_const_will_overflow(expr, expr->int_type);
}
const char *expr_const_to_error_string(const ExprConst *expr) const char *expr_const_to_error_string(const ExprConst *expr)
{ {
char *buff = NULL; char *buff = NULL;
@@ -234,12 +189,12 @@ const char *expr_const_to_error_string(const ExprConst *expr)
case CONST_BOOL: case CONST_BOOL:
return expr->b ? "true" : "false"; return expr->b ? "true" : "false";
case CONST_INTEGER: case CONST_INTEGER:
return bigint_to_error_string(&expr->i, 10); return int_to_str(expr->ixx, 10);
case CONST_FLOAT: case CONST_FLOAT:
#if LONG_DOUBLE #if LONG_DOUBLE
asprintf(&buff, "%Lg", expr->f); asprintf(&buff, "%Lg", expr->fxx.f);
#else #else
asprintf(&buff, "%g", expr->f); asprintf(&buff, "%g", expr->fxx.f);
#endif #endif
return buff; return buff;
case CONST_STRING: case CONST_STRING:
@@ -265,16 +220,16 @@ void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind)
switch (kind) switch (kind)
{ {
case TYPE_F32: case TYPE_F32:
expr->f = (float)d; expr->fxx = (Float) { (float)d, TYPE_F32 };
break; break;
case TYPE_F64: case TYPE_F64:
expr->f = (double)d; expr->fxx = (Float) { (double)d, TYPE_F64 };
break; break;
default: default:
expr->f = d; expr->fxx = (Float) { d, kind };
break;
} }
expr->const_kind = CONST_FLOAT; expr->const_kind = CONST_FLOAT;
expr->float_type = kind;
} }
ByteSize expr_const_list_size(const ConstInitializer *list) ByteSize expr_const_list_size(const ConstInitializer *list)

View File

@@ -410,8 +410,8 @@ static Expr *parse_post_unary(Context *context, Expr *left)
{ {
assert(expr_ok(left)); assert(expr_ok(left));
Expr *unary = EXPR_NEW_TOKEN(EXPR_POST_UNARY, context->tok); Expr *unary = EXPR_NEW_TOKEN(EXPR_POST_UNARY, context->tok);
unary->post_expr.expr = left; unary->unary_expr.expr = left;
unary->post_expr.operator = post_unaryop_from_token(context->tok.type); unary->unary_expr.operator = unaryop_from_token(context->tok.type);
unary->span.loc = left->span.loc; unary->span.loc = left->span.loc;
advance(context); advance(context);
return unary; return unary;
@@ -666,7 +666,7 @@ static Expr *parse_subscript_expr(Context *context, Expr *left)
else else
{ {
index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
expr_set_type(index, type_uint); index->type = type_uint;
index->resolve_status = RESOLVE_DONE; index->resolve_status = RESOLVE_DONE;
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind); expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
} }
@@ -759,22 +759,20 @@ static Expr *parse_ct_call(Context *context, Expr *left)
SEMA_TOKEN_ERROR(context->tok, "Expected an integer index."); SEMA_TOKEN_ERROR(context->tok, "Expected an integer index.");
return poisoned_expr; return poisoned_expr;
} }
BigInt *value = &int_expr->const_expr.i; Int value = int_expr->const_expr.ixx;
BigInt limit; if (!int_fits(value, TYPE_I64))
bigint_init_unsigned(&limit, MAX_ARRAYINDEX);
if (bigint_cmp(value, &limit) == CMP_GT)
{ {
SEMA_ERROR(int_expr, "Array index out of range."); SEMA_ERROR(int_expr, "Array index out of range.");
return poisoned_expr; return poisoned_expr;
} }
if (bigint_cmp_zero(value) == CMP_LT) if (int_is_neg(value))
{ {
SEMA_ERROR(int_expr, "Array index must be zero or greater."); SEMA_ERROR(int_expr, "Array index must be zero or greater.");
return poisoned_expr; return poisoned_expr;
} }
TRY_CONSUME_OR(TOKEN_RBRACKET, "Expected a ']' after the number.", poisoned_expr); TRY_CONSUME_OR(TOKEN_RBRACKET, "Expected a ']' after the number.", poisoned_expr);
flat_element.array = true; flat_element.array = true;
flat_element.index = (ArrayIndex)bigint_as_unsigned(value); flat_element.index = value.i.low;
} }
else if (try_consume(context, TOKEN_DOT)) else if (try_consume(context, TOKEN_DOT))
{ {
@@ -922,6 +920,18 @@ static Expr *parse_placeholder(Context *context, Expr *left)
return expr; return expr;
} }
static int read_num_type(const char *string, const char *end)
{
REMINDER("Limit num type reader");
int i = 0;
while (string < end)
{
i *= 10;
i += *(string++) - '0';
}
return i;
}
static Expr *parse_integer(Context *context, Expr *left) static Expr *parse_integer(Context *context, Expr *left)
{ {
assert(!left && "Had left hand side"); assert(!left && "Had left hand side");
@@ -929,73 +939,178 @@ static Expr *parse_integer(Context *context, Expr *left)
const char *string = TOKSTR(context->tok); const char *string = TOKSTR(context->tok);
const char *end = string + TOKLEN(context->tok); const char *end = string + TOKLEN(context->tok);
BigInt *i = &expr_int->const_expr.i; Int128 i = { 0, 0 };
bigint_init_unsigned(i, 0); bool is_unsigned = false;
BigInt diff; uint64_t type_bits = 0;
bigint_init_unsigned(&diff, 0); int hex_characters = 0;
BigInt ten; int oct_characters = 0;
bigint_init_unsigned(&ten, 10); int binary_characters = 0;
BigInt res; bool wrapped = false;
uint64_t max;
switch (TOKLEN(context->tok) > 2 ? string[1] : '0') switch (TOKLEN(context->tok) > 2 ? string[1] : '0')
{ {
case 'x': case 'x':
string += 2; string += 2;
is_unsigned = true;
max = UINT64_MAX >> 4;
while (string < end) while (string < end)
{ {
char c = *(string++); char c = *(string++);
if (c == 'u' || c == 'U')
{
type_bits = read_num_type(string, end);
break;
}
if (c == 'i' || c == 'I')
{
is_unsigned = false;
type_bits = read_num_type(string, end);
break;
}
if (c == '_') continue; if (c == '_') continue;
bigint_shl_int(&res, i, 4); if (i.high > max) wrapped = true;
if (c < 'A') i = i128_shl64(i, 4);
{ i = i128_add64(i, hex_nibble(c));
bigint_init_unsigned(&diff, c - '0'); hex_characters++;
}
else if (c < 'a')
{
bigint_init_unsigned(&diff, c - 'A' + 10);
}
else
{
bigint_init_unsigned(&diff, c - 'a' + 10);
}
bigint_add(i, &res, &diff);
} }
break; break;
case 'o': case 'o':
string += 2; string += 2;
is_unsigned = true;
max = UINT64_MAX >> 3;
while (string < end) while (string < end)
{ {
char c = *(string++); char c = *(string++);
if (c == 'i' || c == 'I')
{
is_unsigned = false;
type_bits = read_num_type(string, end);
break;
}
if (c == 'u' || c == 'U')
{
type_bits = read_num_type(string, end);
break;
}
if (c == '_') continue; if (c == '_') continue;
bigint_shl_int(&res, i, 4); if (i.high > max) wrapped = true;
bigint_init_unsigned(&diff, c - '0'); i = i128_shl64(i, 3);
bigint_add(i, &res, &diff); i = i128_add64(i, c - '0');
oct_characters++;
} }
break; break;
case 'b': case 'b':
string += 2; string += 2;
max = UINT64_MAX >> 1;
while (string < end) while (string < end)
{ {
char c = *(string++); char c = *(string++);
if (c == '_') continue; if (c == '_') continue;
bigint_shl_int(&res, i, 1); binary_characters++;
bigint_init_unsigned(&diff, c - '0'); if (i.high > max) wrapped = true;
bigint_add(i, &res, &diff); i = i128_shl64(i, 1);
i = i128_add64(i, c - '0');
} }
break; break;
default: default:
while (string < end) while (string < end)
{ {
char c = *(string++); char c = *(string++);
if (c == 'i' || c == 'I')
{
is_unsigned = false;
type_bits = read_num_type(string, end);
break;
}
if (c == 'u' || c == 'U')
{
is_unsigned = true;
type_bits = read_num_type(string, end);
break;
}
if (c == '_') continue; if (c == '_') continue;
bigint_mul(&res, i, &ten); uint64_t old_top = i.high;
bigint_init_unsigned(&diff, c - '0'); i = i128_mult64(i, 10);
bigint_add(i, &res, &diff); i = i128_add64(i, c - '0');
if (!wrapped && old_top > i.high) wrapped = true;
} }
break; break;
} }
if (wrapped)
{
SEMA_TOKEN_ERROR(context->tok, "Integer size exceeded 128 bits, max 128 bits are supported.");
return poisoned_expr;
}
expr_int->const_expr.const_kind = CONST_INTEGER; expr_int->const_expr.const_kind = CONST_INTEGER;
expr_int->const_expr.int_type = TYPE_IXX; Type *type = is_unsigned ? type_cuint() : type_cint();
expr_set_type(expr_int, type_compint); expr_int->const_expr.narrowable = !type_bits;
if (type_bits)
{
if (!is_power_of_two(type_bits) || type_bits > 128)
{
SEMA_TOKEN_ERROR(context->tok, "Integer width should be 8, 16, 32, 64 or 128.");
return poisoned_expr;
}
}
else
{
if (hex_characters)
{
type_bits = 4 * hex_characters;
if (type_bits > 128)
{
SEMA_TOKEN_ERROR(context->tok, "%d hex digits indicates a bit width over 128, which is not supported.", hex_characters);
return poisoned_expr;
}
}
if (oct_characters)
{
type_bits = 3 * oct_characters;
if (type_bits > 128)
{
SEMA_TOKEN_ERROR(context->tok, "%d octal digits indicates a bit width over 128, which is not supported.", oct_characters);
return poisoned_expr;
}
}
if (binary_characters)
{
type_bits = binary_characters;
if (type_bits > 128)
{
SEMA_TOKEN_ERROR(context->tok, "%d binary digits indicates a bit width over 128, which is not supported.", binary_characters);
return poisoned_expr;
}
}
if (type_bits && !is_power_of_two(type_bits)) type_bits = next_highest_power_of_2(type_bits);
}
if (!type_bits)
{
type_bits = type_size(type) * 8;
}
if (type_bits)
{
type = is_unsigned ? type_int_unsigned_by_bitsize(type_bits) : type_int_signed_by_bitsize(type_bits);
}
expr_int->const_expr.ixx = (Int) { i, type->type_kind };
if (!int_fits(expr_int->const_expr.ixx, type->type_kind))
{
int radix = 10;
if (hex_characters) radix = 16;
if (oct_characters) radix = 8;
if (binary_characters) radix = 2;
if (type_bits)
{
SEMA_TOKEN_ERROR(context->tok, "'%s' does not fit in a '%c%d' literal.",
i128_to_string(i, radix, true), is_unsigned ? 'u' : 'i', type_bits);
}
else
{
SEMA_TOKEN_ERROR(context->tok, "'%s' does not fit in an %s literal.",
i128_to_string(i, radix, true), is_unsigned ? "unsigned int" : "int");
}
return poisoned_expr;
}
expr_int->type = type;
advance(context); advance(context);
return expr_int; return expr_int;
} }
@@ -1100,7 +1215,8 @@ static Expr *parse_bytes_expr(Context *context, Expr *left)
expr_bytes->const_expr.bytes.ptr = data; expr_bytes->const_expr.bytes.ptr = data;
expr_bytes->const_expr.bytes.len = len; expr_bytes->const_expr.bytes.len = len;
expr_bytes->const_expr.const_kind = CONST_BYTES; expr_bytes->const_expr.const_kind = CONST_BYTES;
expr_set_type(expr_bytes, type_get_array(type_char, len)); Type *type = type_get_array(type_char, len);
expr_bytes->type = type;
assert(data + len == data_current); assert(data + len == data_current);
return expr_bytes; return expr_bytes;
} }
@@ -1109,24 +1225,25 @@ static Expr *parse_char_lit(Context *context, Expr *left)
{ {
assert(!left && "Had left hand side"); assert(!left && "Had left hand side");
Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
expr_int->const_expr.narrowable = true;
TokenData *data = tokendata_from_id(context->tok.id); TokenData *data = tokendata_from_id(context->tok.id);
switch (data->width) switch (data->width)
{ {
case 1: case 1:
expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_IXX); expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_U8);
expr_set_type(expr_int, type_compint); expr_int->type = type_char;
break; break;
case 2: case 2:
expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_IXX); expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_U16);
expr_set_type(expr_int, type_compint); expr_int->type = type_ushort;
break; break;
case 4: case 4:
expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_IXX); expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_U32);
expr_set_type(expr_int, type_compint); expr_int->type = type_uint;
break; break;
case 8: case 8:
expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64); expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64);
expr_set_type(expr_int, type_compint); expr_int->type = type_ulong;
break; break;
default: default:
UNREACHABLE UNREACHABLE
@@ -1141,10 +1258,26 @@ static Expr *parse_double(Context *context, Expr *left)
{ {
assert(!left && "Had left hand side"); assert(!left && "Had left hand side");
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
number->const_expr.f = TOKREAL(context->tok.id); number->const_expr.fxx = TOKREAL(context->tok.id);
expr_set_type(number, type_compfloat); switch (number->const_expr.fxx.type)
number->const_expr.float_type = TYPE_FXX; {
case TYPE_F128:
number->type = type_quad;
break;
case TYPE_F64:
number->type = type_double;
break;
case TYPE_F32:
number->type = type_float;
break;
case TYPE_F16:
number->type = type_half;
break;
default:
UNREACHABLE
}
number->const_expr.const_kind = CONST_FLOAT; number->const_expr.const_kind = CONST_FLOAT;
number->const_expr.narrowable = true;
advance(context); advance(context);
return number; return number;
} }
@@ -1226,7 +1359,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
{ {
assert(!left && "Had left hand side"); assert(!left && "Had left hand side");
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
expr_set_type(expr_string, type_compstr); expr_string->type = type_compstr;
TokenData *data = TOKDATA(context->tok); TokenData *data = TOKDATA(context->tok);
const char *str = data->string; const char *str = data->string;
@@ -1255,7 +1388,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
assert(str); assert(str);
expr_string->const_expr.string.chars = str; expr_string->const_expr.string.chars = str;
expr_string->const_expr.string.len = (uint32_t)len; expr_string->const_expr.string.len = (uint32_t)len;
expr_set_type(expr_string, type_compstr); expr_string->type = type_compstr;
expr_string->const_expr.const_kind = CONST_STRING; expr_string->const_expr.const_kind = CONST_STRING;
return expr_string; return expr_string;
} }
@@ -1265,7 +1398,7 @@ static Expr *parse_bool(Context *context, Expr *left)
assert(!left && "Had left hand side"); assert(!left && "Had left hand side");
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .const_kind = CONST_BOOL }; number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .const_kind = CONST_BOOL };
expr_set_type(number, type_bool); number->type = type_bool;
advance(context); advance(context);
return number; return number;
} }
@@ -1275,7 +1408,7 @@ static Expr *parse_null(Context *context, Expr *left)
assert(!left && "Had left hand side"); assert(!left && "Had left hand side");
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
number->const_expr.const_kind = CONST_POINTER; number->const_expr.const_kind = CONST_POINTER;
expr_set_type(number, type_voidptr); number->type = type_voidptr;
advance(context); advance(context);
return number; return number;
} }
@@ -1309,10 +1442,11 @@ Expr *parse_type_expression_with_path(Context *context, Path *path)
advance_and_verify(context, TOKEN_TYPE_IDENT); advance_and_verify(context, TOKEN_TYPE_IDENT);
RANGE_EXTEND_PREV(type); RANGE_EXTEND_PREV(type);
ASSIGN_TYPE_ELSE(type, parse_type_with_base(context, type), poisoned_expr); ASSIGN_TYPE_ELSE(type, parse_type_with_base(context, type), poisoned_expr);
type->failable = try_consume(context, TOKEN_BANG);
} }
else else
{ {
ASSIGN_TYPE_ELSE(type, parse_type(context), poisoned_expr); ASSIGN_TYPE_ELSE(type, parse_failable_type(context), poisoned_expr);
} }
if (!type->virtual_type && TOKEN_IS(TOKEN_LBRACE)) if (!type->virtual_type && TOKEN_IS(TOKEN_LBRACE))
{ {

View File

@@ -737,6 +737,23 @@ TypeInfo *parse_type(Context *context)
return parse_type_with_base(context, base); return parse_type_with_base(context, base);
} }
TypeInfo *parse_failable_type(Context *context)
{
ASSIGN_TYPE_ELSE(TypeInfo *info, parse_base_type(context), poisoned_type_info);
ASSIGN_TYPE_ELSE(info, parse_type_with_base(context, info), poisoned_type_info);
if (try_consume(context, TOKEN_BANG))
{
assert(!info->failable);
info->failable = true;
if (info->resolve_status == RESOLVE_DONE)
{
info->type = type_get_failable(info->type);
}
RANGE_EXTEND_PREV(info);
}
return info;
}
#pragma mark --- Decl parsing #pragma mark --- Decl parsing
@@ -754,13 +771,13 @@ Decl *parse_decl_after_type(Context *context, TypeInfo *type)
return poisoned_decl; return poisoned_decl;
} }
EXPECT_IDENT_FOR_OR("variable name", poisoned_decl); EXPECT_IDENT_FOR_OR("variable name", poisoned_decl);
TokenId name = context->tok.id; TokenId name = context->tok.id;
advance(context); advance(context);
Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, VISIBLE_LOCAL); Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, VISIBLE_LOCAL);
if (!parse_attributes(context, &decl->attributes)) return poisoned_decl;
if (TOKEN_IS(TOKEN_EQ)) if (TOKEN_IS(TOKEN_EQ))
{ {
if (!decl) if (!decl)
@@ -789,17 +806,14 @@ Decl *parse_decl(Context *context)
bool is_static = try_consume(context, TOKEN_STATIC); bool is_static = try_consume(context, TOKEN_STATIC);
ASSIGN_TYPE_ELSE(TypeInfo *type, parse_type(context), poisoned_decl); ASSIGN_TYPE_ELSE(TypeInfo *type, parse_failable_type(context), poisoned_decl);
bool failable = try_consume(context, TOKEN_BANG);
ASSIGN_DECL_ELSE(Decl *decl, parse_decl_after_type(context, type), poisoned_decl); ASSIGN_DECL_ELSE(Decl *decl, parse_decl_after_type(context, type), poisoned_decl);
if (failable && decl->var.unwrap) if (type->failable && decl->var.unwrap)
{ {
SEMA_ERROR(decl, "You cannot use unwrap with a failable variable."); SEMA_ERROR(decl, "You cannot use unwrap with a failable variable.");
return poisoned_decl; return poisoned_decl;
} }
decl->var.failable = failable;
decl->var.is_static = is_static; decl->var.is_static = is_static;
return decl; return decl;
} }
@@ -1004,14 +1018,10 @@ bool parse_attributes(Context *context, Attr ***attributes_ref)
*/ */
static inline Decl *parse_global_declaration(Context *context, Visibility visibility) static inline Decl *parse_global_declaration(Context *context, Visibility visibility)
{ {
ASSIGN_TYPE_ELSE(TypeInfo *type, parse_type(context), poisoned_decl); ASSIGN_TYPE_ELSE(TypeInfo *type, parse_failable_type(context), poisoned_decl);
bool failable = try_consume(context, TOKEN_BANG);
Decl *decl = decl_new_var(context->tok.id, type, VARDECL_GLOBAL, visibility); Decl *decl = decl_new_var(context->tok.id, type, VARDECL_GLOBAL, visibility);
decl->var.failable = failable;
if (TOKEN_IS(TOKEN_CONST_IDENT)) if (TOKEN_IS(TOKEN_CONST_IDENT))
{ {
SEMA_TOKEN_ERROR(context->tok, "This looks like a constant variable, did you forget 'const'?"); SEMA_TOKEN_ERROR(context->tok, "This looks like a constant variable, did you forget 'const'?");
@@ -1533,12 +1543,8 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility)
decl->span.loc = start; decl->span.loc = start;
decl->typedef_decl.is_func = true; decl->typedef_decl.is_func = true;
decl->typedef_decl.is_distinct = distinct; decl->typedef_decl.is_distinct = distinct;
ASSIGN_TYPE_ELSE(TypeInfo *type_info, parse_type(context), poisoned_decl); ASSIGN_TYPE_ELSE(TypeInfo *type_info, parse_failable_type(context), poisoned_decl);
decl->typedef_decl.function_signature.rtype = type_info; decl->typedef_decl.function_signature.rtype = type_info;
if (try_consume(context, TOKEN_BANG))
{
decl->typedef_decl.function_signature.failable = true;
}
if (!parse_parameter_list(context, decl->visibility, &(decl->typedef_decl.function_signature), true)) if (!parse_parameter_list(context, decl->visibility, &(decl->typedef_decl.function_signature), true))
{ {
return poisoned_decl; return poisoned_decl;
@@ -1684,11 +1690,12 @@ static inline Decl *parse_define(Context *context, Visibility visibility)
* func_header ::= type '!'? (type '.')? IDENT * func_header ::= type '!'? (type '.')? IDENT
* macro_header ::= (type '!'?)? (type '.')? IDENT * macro_header ::= (type '!'?)? (type '.')? IDENT
*/ */
static inline bool parse_func_macro_header(Context *context, bool rtype_is_optional, TypeInfo **rtype_ref, bool *failable_ref, TypeInfo **method_type_ref, TokenId *name_ref) static inline bool
parse_func_macro_header(Context *context, bool rtype_is_optional, TypeInfo **rtype_ref, TypeInfo **method_type_ref,
TokenId *name_ref)
{ {
TypeInfo *rtype = NULL; TypeInfo *rtype = NULL;
TypeInfo *method_type = NULL; TypeInfo *method_type = NULL;
bool failable = false;
// 1. We have a macro with just a name, if so, then we set the name and we're done. // 1. We have a macro with just a name, if so, then we set the name and we're done.
if (rtype_is_optional && !context_next_is_type_and_not_ident(context)) if (rtype_is_optional && !context_next_is_type_and_not_ident(context))
@@ -1697,10 +1704,7 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
} }
// 2. Now we must have a type - either that is the return type or the method type. // 2. Now we must have a type - either that is the return type or the method type.
ASSIGN_TYPE_ELSE(rtype, parse_type(context), false); ASSIGN_TYPE_ELSE(rtype, parse_failable_type(context), false);
// 3. We possibly have a failable return at this point.
failable = try_consume(context, TOKEN_BANG);
// 4. We might have a type here, if so then we read it. // 4. We might have a type here, if so then we read it.
if (!TOKEN_IS(TOKEN_DOT) && context_next_is_type_and_not_ident(context)) if (!TOKEN_IS(TOKEN_DOT) && context_next_is_type_and_not_ident(context))
@@ -1715,7 +1719,7 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
if (!method_type) if (!method_type)
{ {
// 5b. If the rtype is not optional or the return type was a failable, then this is an error. // 5b. If the rtype is not optional or the return type was a failable, then this is an error.
if (!rtype_is_optional || failable) if (!rtype_is_optional || rtype->failable)
{ {
SEMA_TOKID_ERROR(context->prev_tok, SEMA_TOKID_ERROR(context->prev_tok,
"This looks like you are declaring a method without a return type?"); "This looks like you are declaring a method without a return type?");
@@ -1733,7 +1737,6 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
} }
RESULT: RESULT:
TRY_CONSUME_OR(TOKEN_IDENT, "Expected a name here.", false); TRY_CONSUME_OR(TOKEN_IDENT, "Expected a name here.", false);
*failable_ref = failable;
*name_ref = context->prev_tok; *name_ref = context->prev_tok;
*rtype_ref = rtype; *rtype_ref = rtype;
*method_type_ref = method_type; *method_type_ref = method_type;
@@ -1752,11 +1755,9 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
Decl *decl = decl_new(kind, context->tok.id, visibility); Decl *decl = decl_new(kind, context->tok.id, visibility);
TypeInfo **rtype_ref = &decl->macro_decl.rtype; TypeInfo **rtype_ref = &decl->macro_decl.rtype;
TypeInfo **method_type_ref = &decl->macro_decl.type_parent; TypeInfo **method_type_ref = &decl->macro_decl.type_parent;
bool failable;
TokenId name; TokenId name;
if (!parse_func_macro_header(context, true, rtype_ref, &failable, method_type_ref, &name)) return poisoned_decl; if (!parse_func_macro_header(context, true, rtype_ref, method_type_ref, &name)) return poisoned_decl;
decl->macro_decl.failable = failable;
decl->name = TOKSTR(name); decl->name = TOKSTR(name);
decl->name_token = name; decl->name_token = name;
@@ -1965,10 +1966,8 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
advance_and_verify(context, TOKEN_FUNC); advance_and_verify(context, TOKEN_FUNC);
TypeInfo **rtype_ref = &func->func_decl.function_signature.rtype; TypeInfo **rtype_ref = &func->func_decl.function_signature.rtype;
TypeInfo **method_type_ref = &func->func_decl.type_parent; TypeInfo **method_type_ref = &func->func_decl.type_parent;
bool failable;
TokenId name; TokenId name;
if (!parse_func_macro_header(context, false, rtype_ref, &failable, method_type_ref, &name)) return poisoned_decl; if (!parse_func_macro_header(context, false, rtype_ref, method_type_ref, &name)) return poisoned_decl;
func->func_decl.function_signature.failable = failable;
func->name = TOKSTR(name); func->name = TOKSTR(name);
func->name_token = name; func->name_token = name;
RANGE_EXTEND_PREV(func); RANGE_EXTEND_PREV(func);
@@ -2396,4 +2395,5 @@ Decl *parse_top_level_statement(Context *context)
assert(decl); assert(decl);
decl->docs = docs; decl->docs = docs;
return decl; return decl;
} }

View File

@@ -439,9 +439,8 @@ static inline bool parse_foreach_var(Context *context, Ast *foreach)
// If we don't get foreach (foo ... or foreach (*foo ... then a type is expected. // If we don't get foreach (foo ... or foreach (*foo ... then a type is expected.
if (!TOKEN_IS(TOKEN_IDENT) && !TOKEN_IS(TOKEN_AMP)) if (!TOKEN_IS(TOKEN_IDENT) && !TOKEN_IS(TOKEN_AMP))
{ {
ASSIGN_TYPE_ELSE(type, parse_type(context), false); ASSIGN_TYPE_ELSE(type, parse_failable_type(context), false);
failable = try_consume(context, TOKEN_BANG);
// Add the failable to the type for nicer error reporting. // Add the failable to the type for nicer error reporting.
RANGE_EXTEND_PREV(type); RANGE_EXTEND_PREV(type);
} }
@@ -460,7 +459,6 @@ static inline bool parse_foreach_var(Context *context, Ast *foreach)
return false; return false;
} }
Decl *var = decl_new_var(context->prev_tok, type, VARDECL_LOCAL, VISIBLE_LOCAL); Decl *var = decl_new_var(context->prev_tok, type, VARDECL_LOCAL, VISIBLE_LOCAL);
var->var.failable = failable;
foreach->foreach_stmt.variable = var; foreach->foreach_stmt.variable = var;
return true; return true;
} }
@@ -586,14 +584,13 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context)
// If so we need to unwrap this. // If so we need to unwrap this.
if (expr->expr_kind == EXPR_FAILABLE && expr->failable_expr->expr_kind == EXPR_TYPEINFO) if (expr->expr_kind == EXPR_FAILABLE && expr->failable_expr->expr_kind == EXPR_TYPEINFO)
{ {
failable = true; UNREACHABLE
expr_replace(expr, expr->failable_expr); expr_replace(expr, expr->failable_expr);
} }
if (expr->expr_kind == EXPR_TYPEINFO) if (expr->expr_kind == EXPR_TYPEINFO)
{ {
ast->ast_kind = AST_DECLARE_STMT; ast->ast_kind = AST_DECLARE_STMT;
ASSIGN_DECL_ELSE(ast->declare_stmt, parse_decl_after_type(context, expr->type_expr), poisoned_ast); ASSIGN_DECL_ELSE(ast->declare_stmt, parse_decl_after_type(context, expr->type_expr), poisoned_ast);
ast->declare_stmt->var.failable = failable;
} }
else else
{ {
@@ -612,7 +609,7 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context)
*/ */
static inline Ast *parse_var_stmt(Context *context) static inline Ast *parse_var_stmt(Context *context)
{ {
Ast *ast = AST_NEW_TOKEN(AST_DEFINE_STMT, context->tok); Ast *ast = AST_NEW_TOKEN(AST_VAR_STMT, context->tok);
TokenId start = context->tok.id; TokenId start = context->tok.id;
advance_and_verify(context, TOKEN_VAR); advance_and_verify(context, TOKEN_VAR);
Decl *decl; Decl *decl;
@@ -631,7 +628,7 @@ static inline Ast *parse_var_stmt(Context *context)
advance(context); advance(context);
if (try_consume(context, TOKEN_EQ)) if (try_consume(context, TOKEN_EQ))
{ {
ASSIGN_TYPE_ELSE(decl->var.type_info, parse_type(context), poisoned_ast); ASSIGN_EXPR_ELSE(decl->var.init_expr, parse_expr(context), poisoned_ast);
} }
break; break;
default: default:

View File

@@ -37,6 +37,7 @@ Expr *parse_expr(Context *context);
bool consume_ident(Context *context, const char* name); bool consume_ident(Context *context, const char* name);
Expr *parse_try_expr_after_try(Context *context, bool is_try); Expr *parse_try_expr_after_try(Context *context, bool is_try);
TypeInfo *parse_type(Context *context); TypeInfo *parse_type(Context *context);
TypeInfo *parse_failable_type(Context *context);
TypeInfo *parse_type_with_base(Context *context, TypeInfo *type_info); TypeInfo *parse_type_with_base(Context *context, TypeInfo *type_info);
Expr* parse_constant_expr(Context *context); Expr* parse_constant_expr(Context *context);
Expr *parse_initializer(Context *context); Expr *parse_initializer(Context *context);

File diff suppressed because it is too large Load Diff

View File

@@ -497,7 +497,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
if (param->var.init_expr) if (param->var.init_expr)
{ {
Expr *expr = param->var.init_expr; Expr *expr = param->var.init_expr;
if (!sema_analyse_expr_of_required_type(context, param->type, expr, false)) return false; if (!sema_analyse_assigned_expr(context, param->type, expr, false)) return false;
Expr *inner = expr; Expr *inner = expr;
while (inner->expr_kind == EXPR_CAST) inner = expr->cast_expr.expr; while (inner->expr_kind == EXPR_CAST) inner = expr->cast_expr.expr;
if (inner->expr_kind != EXPR_CONST) if (inner->expr_kind != EXPR_CONST)
@@ -587,14 +587,15 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
switch (base->type_kind) switch (base->type_kind)
{ {
case TYPE_STRLIT: case TYPE_STRLIT:
case TYPE_IXX:
case TYPE_FXX:
case TYPE_FUNC: case TYPE_FUNC:
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
case TYPE_DISTINCT: case TYPE_DISTINCT:
case CT_TYPES: case CT_TYPES:
UNREACHABLE UNREACHABLE
return false; return false;
case TYPE_FAILABLE:
SEMA_ERROR(decl, "You cannot create a distinct type from a failable.");
return false;
case TYPE_VIRTUAL_ANY: case TYPE_VIRTUAL_ANY:
case TYPE_VIRTUAL: case TYPE_VIRTUAL:
SEMA_ERROR(decl, "You cannot create a distinct type from a virtual type."); SEMA_ERROR(decl, "You cannot create a distinct type from a virtual type.");
@@ -609,9 +610,8 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
case TYPE_TYPEID: case TYPE_TYPEID:
SEMA_ERROR(decl, "Cannot create a distinct type from %s.", type_quoted_error_string(base)); SEMA_ERROR(decl, "Cannot create a distinct type from %s.", type_quoted_error_string(base));
case TYPE_BOOL: case TYPE_BOOL:
case ALL_SIGNED_INTS: case ALL_INTS:
case ALL_UNSIGNED_INTS: case ALL_FLOATS:
case ALL_REAL_FLOATS:
case TYPE_POINTER: case TYPE_POINTER:
case TYPE_ENUM: case TYPE_ENUM:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
@@ -644,10 +644,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
DEBUG_LOG("* Enum type resolved to %s.", type->name); DEBUG_LOG("* Enum type resolved to %s.", type->name);
bool success = true; bool success = true;
unsigned enums = vec_size(decl->enums.values); unsigned enums = vec_size(decl->enums.values);
BigInt value; Int128 value = { 0, 0 };
BigInt add;
bigint_init_unsigned(&add, 1);
bigint_init_unsigned(&value, 0);
for (unsigned i = 0; i < enums; i++) for (unsigned i = 0; i < enums; i++)
{ {
@@ -668,23 +665,24 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
if (!expr) if (!expr)
{ {
expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token)); expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token));
expr_set_type(expr, type); expr->type = type;
expr->resolve_status = RESOLVE_NOT_DONE; expr->resolve_status = RESOLVE_NOT_DONE;
bigint_init_bigint(&expr->const_expr.i, &value); REMINDER("Do range check");
expr->const_expr.int_type = TYPE_IXX; expr->const_expr.ixx = (Int) { value, canonical->type_kind };
expr->const_expr.const_kind = CONST_INTEGER; expr->const_expr.const_kind = CONST_INTEGER;
expr_set_type(expr, type_compint); expr->const_expr.narrowable = true;
expr->type = canonical;
enum_value->enum_constant.expr = expr; enum_value->enum_constant.expr = expr;
} }
// We try to convert to the desired type. // We try to convert to the desired type.
if (!sema_analyse_expr_of_required_type(context, type, expr, false)) if (!sema_analyse_expr_of_required_type(context, type, expr))
{ {
success = false; success = false;
enum_value->resolve_status = RESOLVE_DONE; enum_value->resolve_status = RESOLVE_DONE;
decl_poison(enum_value); decl_poison(enum_value);
// Reset! // Reset!
bigint_init_unsigned(&value, 0); value = (Int128) { 0, 0 };
continue; continue;
} }
@@ -701,7 +699,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
} }
// Update the value // Update the value
bigint_add(&value, &expr->const_expr.i, &add); value = i128_add64(value, 1);
DEBUG_LOG("* Value: %s", expr_const_to_error_string(&expr->const_expr)); DEBUG_LOG("* Value: %s", expr_const_to_error_string(&expr->const_expr));
enum_value->resolve_status = RESOLVE_DONE; enum_value->resolve_status = RESOLVE_DONE;
} }
@@ -897,26 +895,24 @@ AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDoma
SEMA_TOKID_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8)."); SEMA_TOKID_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8).");
return ATTRIBUTE_NONE; return ATTRIBUTE_NONE;
} }
if (!sema_analyse_expr(context, type_usize, attr->expr)) return false; if (!sema_analyse_expr(context, attr->expr)) return false;
if (attr->expr->expr_kind != EXPR_CONST || !type_is_any_integer(attr->expr->type->canonical)) if (attr->expr->expr_kind != EXPR_CONST || !type_is_integer(attr->expr->type->canonical))
{ {
SEMA_ERROR(attr->expr, "Expected a constant integer value as argument."); SEMA_ERROR(attr->expr, "Expected a constant integer value as argument.");
return ATTRIBUTE_NONE; return ATTRIBUTE_NONE;
} }
{ {
BigInt comp; if (int_ucomp(attr->expr->const_expr.ixx, MAX_ALIGNMENT, BINARYOP_GT))
bigint_init_unsigned(&comp, MAX_ALIGNMENT);
if (bigint_cmp(&attr->expr->const_expr.i, &comp) == CMP_GT)
{ {
SEMA_ERROR(attr->expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT); SEMA_ERROR(attr->expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT);
return ATTRIBUTE_NONE; return ATTRIBUTE_NONE;
} }
if (bigint_cmp_zero(&attr->expr->const_expr.i) != CMP_GT) if (int_ucomp(attr->expr->const_expr.ixx, 0, BINARYOP_LE))
{ {
SEMA_ERROR(attr->expr, "Alignment must be greater than zero."); SEMA_ERROR(attr->expr, "Alignment must be greater than zero.");
return ATTRIBUTE_NONE; return ATTRIBUTE_NONE;
} }
uint64_t align = bigint_as_unsigned(&attr->expr->const_expr.i); uint64_t align = int_to_u64(attr->expr->const_expr.ixx);
if (!is_power_of_two(align)) if (!is_power_of_two(align))
{ {
SEMA_ERROR(attr->expr, "Alignment must be a power of two."); SEMA_ERROR(attr->expr, "Alignment must be a power of two.");
@@ -938,7 +934,7 @@ AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDoma
SEMA_TOKID_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", TOKSTR(attr->name), TOKSTR(attr->name)); SEMA_TOKID_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", TOKSTR(attr->name), TOKSTR(attr->name));
return ATTRIBUTE_NONE; return ATTRIBUTE_NONE;
} }
if (!sema_analyse_expr(context, NULL, attr->expr)) return false; if (!sema_analyse_expr(context, attr->expr)) return false;
if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_compstr) if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_compstr)
{ {
SEMA_ERROR(attr->expr, "Expected a constant string value as argument."); SEMA_ERROR(attr->expr, "Expected a constant string value as argument.");
@@ -1333,7 +1329,7 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
} }
if (!decl->var.type_info) if (!decl->var.type_info)
{ {
if (!sema_analyse_expr(context, NULL, init_expr)) return false; if (!sema_analyse_expr(context, init_expr)) return false;
decl->type = init_expr->type; decl->type = init_expr->type;
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
@@ -1358,7 +1354,6 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
{ {
bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY; bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY;
Expr *init = decl->var.init_expr; Expr *init = decl->var.init_expr;
// Handle explicit undef // Handle explicit undef
if (init->expr_kind == EXPR_UNDEF) if (init->expr_kind == EXPR_UNDEF)
{ {
@@ -1376,7 +1371,8 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
decl->resolve_status = RESOLVE_DONE; decl->resolve_status = RESOLVE_DONE;
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
} }
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 (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) return decl_poison(decl);
if (type_is_inferred) if (type_is_inferred)
{ {
@@ -1386,13 +1382,13 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
} }
else if (decl->type) else if (decl->type)
{ {
expr_set_type(decl->var.init_expr, decl->type); decl->var.init_expr->type = decl->type;
} }
Expr *init_expr = decl->var.init_expr; Expr *init_expr = decl->var.init_expr;
// 1. Check type. // 1. Check type.
if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false; if (!sema_analyse_assigned_expr(context, decl->type, init_expr, false)) return false;
// 2. Check const-ness // 2. Check const-ness
if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY)) if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY))
@@ -1401,12 +1397,13 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
} }
else else
{ {
if (decl->var.unwrap && !init->failable) if (decl->var.unwrap && init->type->type_kind != TYPE_FAILABLE)
{ {
SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here."); SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here.");
return decl_poison(decl); return decl_poison(decl);
} }
} }
if (init_expr->expr_kind == EXPR_CONST) init_expr->const_expr.narrowable = false;
} }
EXIT_OK: EXIT_OK:
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);

File diff suppressed because it is too large Load Diff

View File

@@ -54,5 +54,5 @@ void context_change_scope_with_flags(Context *context, ScopeFlags flags);
void c_abi_func_create(FunctionSignature *signature); void c_abi_func_create(FunctionSignature *signature);
AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDomain domain); AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDomain domain);
bool expr_is_ltype(Expr *expr); bool expr_is_ltype(Expr *expr);
bool sema_analyse_expr_value(Context *context, Type *to, Expr *expr);
bool sema_analyse_expr_lvalue(Context *context, Expr *expr);

View File

@@ -475,14 +475,14 @@ bool sema_unwrap_var(Context *context, Decl *decl)
Decl *alias = decl_copy(decl); Decl *alias = decl_copy(decl);
alias->var.kind = VARDECL_UNWRAPPED; alias->var.kind = VARDECL_UNWRAPPED;
alias->var.alias = decl; alias->var.alias = decl;
alias->var.failable = false; alias->type = alias->type->failable;
alias->resolve_status = RESOLVE_DONE; alias->resolve_status = RESOLVE_DONE;
return sema_append_local(context, alias); return sema_append_local(context, alias);
} }
bool sema_rewrap_var(Context *context, Decl *decl) bool sema_rewrap_var(Context *context, Decl *decl)
{ {
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED && decl->var.alias->var.failable); assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED && decl->var.alias->type->type_kind == TYPE_FAILABLE);
return sema_append_local(context, decl->var.alias); return sema_append_local(context, decl->var.alias);
} }
@@ -497,11 +497,11 @@ bool sema_erase_var(Context *context, Decl *decl)
bool sema_erase_unwrapped(Context *context, Decl *decl) bool sema_erase_unwrapped(Context *context, Decl *decl)
{ {
assert(decl->var.failable); assert(IS_FAILABLE(decl));
Decl *rewrapped = decl_copy(decl); Decl *rewrapped = decl_copy(decl);
rewrapped->var.kind = VARDECL_REWRAPPED; rewrapped->var.kind = VARDECL_REWRAPPED;
rewrapped->var.alias = decl; rewrapped->var.alias = decl;
rewrapped->var.failable = true; rewrapped->type = decl->type;
rewrapped->resolve_status = RESOLVE_DONE; rewrapped->resolve_status = RESOLVE_DONE;
return sema_append_local(context, rewrapped); return sema_append_local(context, rewrapped);
} }

View File

@@ -27,7 +27,7 @@ static void sema_unwrappable_from_catch_in_else(Context *c, Expr *cond)
if (expr->expr_kind != EXPR_IDENTIFIER) continue; if (expr->expr_kind != EXPR_IDENTIFIER) continue;
Decl *decl = expr->identifier_expr.decl; Decl *decl = expr->identifier_expr.decl;
if (decl->decl_kind != DECL_VAR) continue; if (decl->decl_kind != DECL_VAR) continue;
assert(decl->var.failable && "The variable should always be failable at this point."); assert(decl->type->type_kind == TYPE_FAILABLE && "The variable should always be failable at this point.");
// 5. Locals and globals may be unwrapped // 5. Locals and globals may be unwrapped
switch (decl->var.kind) switch (decl->var.kind)
@@ -54,10 +54,10 @@ static inline bool sema_analyse_block_return_stmt(Context *context, Ast *stateme
context->active_scope.jump_end = true; context->active_scope.jump_end = true;
if (statement->return_stmt.expr) if (statement->return_stmt.expr)
{ {
if (!sema_analyse_expr_of_required_type(context, if (!sema_analyse_expr(context, statement->return_stmt.expr))
context->expected_block_type, {
statement->return_stmt.expr, true)) return false; return false;
context->expr_failable_return |= statement->return_stmt.expr->failable; }
} }
vec_add(context->returns, statement); vec_add(context->returns, statement);
return true; return true;
@@ -94,7 +94,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
// 2. First handle the plain return. // 2. First handle the plain return.
if (return_expr == NULL) if (return_expr == NULL)
{ {
if (expected_rtype->canonical != type_void) if (type_no_fail(expected_rtype)->canonical != type_void)
{ {
SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype)); SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype));
return false; return false;
@@ -103,9 +103,9 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
} }
// 3. Evaluate the return value to be the expected return type. // 3. Evaluate the return value to be the expected return type.
if (!sema_analyse_expr_of_required_type(context, expected_rtype, return_expr, context->failable_return)) return false; if (!sema_analyse_expr_of_required_type(context, expected_rtype, return_expr)) return false;
assert(statement->return_stmt.expr->type->canonical == expected_rtype->canonical); assert(type_no_fail(statement->return_stmt.expr->type)->canonical == type_no_fail(expected_rtype)->canonical);
return true; return true;
} }
@@ -125,7 +125,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
// Case A. Unwrapping a single variable. // Case A. Unwrapping a single variable.
if (!failable) if (!failable)
{ {
if (!sema_analyse_expr(context, NULL, ident)) return false; if (!sema_analyse_expr(context, ident)) return false;
if (ident->expr_kind != EXPR_IDENTIFIER) if (ident->expr_kind != EXPR_IDENTIFIER)
{ {
SEMA_ERROR(ident, "Only single identifiers may be unwrapped using 'try var', maybe you wanted 'try (expr)' instead?"); SEMA_ERROR(ident, "Only single identifiers may be unwrapped using 'try var', maybe you wanted 'try (expr)' instead?");
@@ -137,7 +137,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
SEMA_ERROR(ident, "Expected this to be the name of a failable variable, but it isn't. Did you mistype?"); SEMA_ERROR(ident, "Expected this to be the name of a failable variable, but it isn't. Did you mistype?");
return false; return false;
} }
if (!decl->var.failable) if (!IS_FAILABLE(decl))
{ {
if (decl->var.kind == VARDECL_UNWRAPPED) if (decl->var.kind == VARDECL_UNWRAPPED)
{ {
@@ -148,7 +148,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
return false; return false;
} }
expr->try_unwrap_expr.decl = decl; expr->try_unwrap_expr.decl = decl;
expr_set_type(expr, type_bool); expr->type = type_bool;
sema_unwrap_var(context, decl); sema_unwrap_var(context, decl);
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; return true;
@@ -166,13 +166,21 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
} }
// 2. If we have a type for the variable, resolve it. // 2. If we have a type for the variable, resolve it.
if (var_type && !sema_resolve_type_info(context, var_type)) return false; if (var_type)
{
if (!sema_resolve_type_info(context, var_type)) return false;
if (IS_FAILABLE(var_type))
{
SEMA_ERROR(var_type, "Only non-failable types may be used as types for 'try', please remove the '!'.");
return false;
}
}
// 3. We interpret this as an assignment to an existing variable. // 3. We interpret this as an assignment to an existing variable.
if (!var_type && !implicit_declaration) if (!var_type && !implicit_declaration)
{ {
// 3a. Resolve the identifier. // 3a. Resolve the identifier.
if (!sema_analyse_expr_value(context, NULL, ident)) return false; if (!sema_analyse_expr_lvalue(context, ident)) return false;
// 3b. Make sure it's assignable // 3b. Make sure it's assignable
if (!expr_is_ltype(ident)) if (!expr_is_ltype(ident))
@@ -182,7 +190,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
} }
// 3c. It can't be failable either. // 3c. It can't be failable either.
if (ident->failable) if (IS_FAILABLE(ident))
{ {
if (ident->expr_kind == EXPR_IDENTIFIER) if (ident->expr_kind == EXPR_IDENTIFIER)
{ {
@@ -196,7 +204,15 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
} }
// 3d. We can now analyse the expression using the variable type. // 3d. We can now analyse the expression using the variable type.
if (!sema_analyse_expr_of_required_type(context, ident->type, failable, true)) return false; if (!sema_analyse_expr(context, failable)) return false;
if (!IS_FAILABLE(failable))
{
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
return false;
}
if (!cast_implicit_ignore_failable(failable, ident->type)) return false;
expr->try_unwrap_expr.assign_existing = true; expr->try_unwrap_expr.assign_existing = true;
expr->try_unwrap_expr.lhs = ident; expr->try_unwrap_expr.lhs = ident;
@@ -226,16 +242,24 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
return false; return false;
} }
// 4a. Type may be assigned or inferred.
Type *type = var_type ? var_type->type : NULL;
// 4b. Evaluate the expression // 4b. Evaluate the expression
if (!sema_analyse_expr_of_required_type(context, type, failable, true)) return false; if (!sema_analyse_expr(context, failable)) return false;
if (!IS_FAILABLE(failable))
{
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
return false;
}
if (var_type)
{
if (!cast_implicit_ignore_failable(failable, var_type->type)) return false;
}
// 4c. Create a type_info if needed. // 4c. Create a type_info if needed.
if (!var_type) if (!var_type)
{ {
var_type = type_info_new_base(failable->type, failable->span); var_type = type_info_new_base(failable->type->failable, failable->span);
} }
// 4d. A new declaration is created. // 4d. A new declaration is created.
@@ -247,14 +271,8 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
expr->try_unwrap_expr.decl = decl; expr->try_unwrap_expr.decl = decl;
} }
if (!failable->failable)
{
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
return false;
}
expr->try_unwrap_expr.failable = failable; expr->try_unwrap_expr.failable = failable;
expr_set_type(expr, type_bool); expr->type = type_bool;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; return true;
} }
@@ -269,9 +287,9 @@ static inline bool sema_analyse_try_unwrap_chain(Context *context, Expr *expr)
if (!sema_analyse_try_unwrap(context, chain)) return false; if (!sema_analyse_try_unwrap(context, chain)) return false;
continue; continue;
} }
if (!sema_analyse_expr_of_required_type(context, type_bool, chain, false)) return false; if (!sema_analyse_cond_expr(context, chain)) return false;
} }
expr_set_type(expr, type_bool); expr->type = type_bool;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; return true;
} }
@@ -296,7 +314,7 @@ static inline bool sema_analyse_catch_unwrap(Context *context, Expr *expr)
if (!type && !implicit_declaration) if (!type && !implicit_declaration)
{ {
if (!sema_analyse_expr_value(context, NULL, ident)) return false; if (!sema_analyse_expr_lvalue(context, ident)) return false;
if (!expr_is_ltype(ident)) if (!expr_is_ltype(ident))
{ {
@@ -361,14 +379,14 @@ RESOLVE_EXPRS:;
VECEACH(exprs, i) VECEACH(exprs, i)
{ {
Expr *fail = exprs[i]; Expr *fail = exprs[i];
if (!sema_analyse_expr(context, NULL, fail)) return false; if (!sema_analyse_expr(context, fail)) return false;
if (!fail->failable) if (fail->type->type_kind != TYPE_FAILABLE)
{ {
SEMA_ERROR(fail, "This expression is not failable, did you add it by mistake?"); SEMA_ERROR(fail, "This expression is not failable, did you add it by mistake?");
return false; return false;
} }
} }
expr_set_type(expr, type_anyerr); expr->type = type_anyerr;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; return true;
} }
@@ -414,7 +432,7 @@ static inline bool sema_analyse_last_cond(Context *context, Expr *expr, bool may
} }
return sema_analyse_catch_unwrap(context, expr); return sema_analyse_catch_unwrap(context, expr);
default: default:
return sema_analyse_expr(context, NULL, expr); return sema_analyse_expr(context, expr);
} }
} }
/** /**
@@ -435,19 +453,19 @@ static inline bool sema_analyse_cond_list(Context *context, Expr *expr, bool may
// 1. Special case, there are no entries, so the type is void // 1. Special case, there are no entries, so the type is void
if (entries == 0) if (entries == 0)
{ {
expr_set_type(expr, type_void); expr->type = type_void;
return true; return true;
} }
// 2. Walk through each of our declarations / expressions as if they were regular expressions. // 2. Walk through each of our declarations / expressions as if they were regular expressions.
for (unsigned i = 0; i < entries - 1; i++) for (unsigned i = 0; i < entries - 1; i++)
{ {
if (!sema_analyse_expr(context, NULL, dexprs[i])) return false; if (!sema_analyse_expr(context, dexprs[i])) return false;
} }
if (!sema_analyse_last_cond(context, dexprs[entries - 1], may_unwrap)) return false; if (!sema_analyse_last_cond(context, dexprs[entries - 1], may_unwrap)) return false;
expr_set_type(expr, dexprs[entries - 1]->type); expr->type = dexprs[entries - 1]->type;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; return true;
} }
@@ -495,11 +513,12 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
return false; return false;
} }
// 3e. Expect that it isn't a failable // 3e. Expect that it isn't a failable
if (init->failable && !decl->var.unwrap) if (IS_FAILABLE(init) && !decl->var.unwrap)
{ {
SEMA_ERROR(last, "'%s!' cannot be converted into '%s'.", SEMA_ERROR(last, "%s cannot be converted to %s.",
type_to_error_string(last->type), type_quoted_error_string(last->type),
cast_to_bool ? "bool" : type_to_error_string(init->type)); cast_to_bool ? "'bool'" : type_quoted_error_string(init->type));
return false;
} }
// TODO document // TODO document
if (!decl->var.unwrap && cast_to_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)
@@ -510,11 +529,12 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
return true; return true;
} }
// 3a. Check for failables in case of an expression. // 3a. Check for failables in case of an expression.
if (last->failable) if (IS_FAILABLE(last))
{ {
SEMA_ERROR(last, "'%s!' cannot be converted into '%s'.", SEMA_ERROR(last, "%s cannot be converted to %s.",
type_to_error_string(last->type), type_quoted_error_string(last->type),
cast_to_bool ? "bool" : type_to_error_string(last->type)); cast_to_bool ? "'bool'" : type_quoted_error_string(type_no_fail(last->type)));
return false;
} }
// 3b. Cast to bool if that is needed // 3b. Cast to bool if that is needed
if (cast_to_bool) if (cast_to_bool)
@@ -618,7 +638,7 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
SCOPE_START SCOPE_START
// 10. Try to evaluate and implicitly cast to boolean. // 10. Try to evaluate and implicitly cast to boolean.
if (!sema_analyse_expr_of_required_type(context, type_bool, expr, false)) if (!sema_analyse_cond_expr(context, expr))
{ {
// 10a. On failure, pop and return false. // 10a. On failure, pop and return false.
return SCOPE_POP_ERROR(); return SCOPE_POP_ERROR();
@@ -669,7 +689,7 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
} }
if (!decl->var.type_info) if (!decl->var.type_info)
{ {
if (!sema_analyse_expr(context, NULL, init_expr)) return false; if (!sema_analyse_expr(context, init_expr)) return false;
decl->type = init_expr->type; decl->type = init_expr->type;
// Skip further evaluation. // Skip further evaluation.
goto EXIT_OK; goto EXIT_OK;
@@ -692,7 +712,7 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
goto EXIT_OK; goto EXIT_OK;
} }
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 (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) return decl_poison(decl);
if (type_is_inferred) if (type_is_inferred)
{ {
@@ -700,18 +720,13 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
assert(right_side_type->type_kind == TYPE_ARRAY); assert(right_side_type->type_kind == TYPE_ARRAY);
decl->type = type_get_array(decl->type->array.base, right_side_type->array.len); decl->type = type_get_array(decl->type->array.base, right_side_type->array.len);
} }
else if (decl->type)
{
expr_set_type(decl->var.init_expr, decl->type);
}
if (decl->var.unwrap && init->type->type_kind != TYPE_FAILABLE)
if (decl->var.unwrap && !init->failable)
{ {
SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here."); SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here.");
return decl_poison(decl); return decl_poison(decl);
} }
if (init->expr_kind == EXPR_CONST) init->const_expr.narrowable = false;
} }
EXIT_OK: EXIT_OK:
if (decl->var.is_static) if (decl->var.is_static)
@@ -739,15 +754,37 @@ static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
return sema_analyse_local_decl(context, statement->declare_stmt); return sema_analyse_local_decl(context, statement->declare_stmt);
} }
static inline bool sema_analyse_define_stmt(Context *context, Ast *statement) /**
* Check "var $foo = ... " and "var $Foo = ..."
*/
static inline bool sema_analyse_var_stmt(Context *context, Ast *statement)
{ {
Decl *decl = statement->declare_stmt; // 1. Pick the declaration.
Decl *decl = statement->var_stmt;
// 2. Convert it to a NOP early
statement->ast_kind = AST_NOP_STMT; statement->ast_kind = AST_NOP_STMT;
assert(decl->decl_kind == DECL_VAR); assert(decl->decl_kind == DECL_VAR);
switch (decl->var.kind) switch (decl->var.kind)
{ {
case VARDECL_LOCAL_CT_TYPE: case VARDECL_LOCAL_CT_TYPE:
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false; // Locally declared compile time type.
if (decl->var.type_info)
{
SEMA_ERROR(decl->var.type_info, "Compile time type variables may not have a type.");
return false;
}
Expr *init = decl->var.init_expr;
if (init)
{
if (!sema_analyse_expr_lvalue(context, init)) return false;
if (init->expr_kind != EXPR_TYPEINFO)
{
SEMA_ERROR(decl->var.init_expr, "Expected a type assigned to %s.", decl->name);
return false;
}
}
break; break;
case VARDECL_LOCAL_CT: case VARDECL_LOCAL_CT:
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false; if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false;
@@ -761,7 +798,7 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
} }
if (decl->var.init_expr) if (decl->var.init_expr)
{ {
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false; if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr)) return false;
if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY)) if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY))
{ {
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name); SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
@@ -779,7 +816,7 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
Expr *init = decl->var.init_expr; Expr *init = decl->var.init_expr;
if (init) if (init)
{ {
if (!sema_analyse_expr(context, NULL, init)) return false; if (!sema_analyse_expr(context, init)) return false;
if (!expr_is_constant_eval(init, CONSTANT_EVAL_ANY)) if (!expr_is_constant_eval(init, CONSTANT_EVAL_ANY))
{ {
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name); SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
@@ -803,7 +840,7 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement) static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
{ {
if (!sema_analyse_expr(context, NULL, statement->expr_stmt)) return false; if (!sema_analyse_expr(context, statement->expr_stmt)) return false;
return true; return true;
} }
@@ -860,7 +897,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
// Conditional scope start // Conditional scope start
SCOPE_START SCOPE_START
Expr *cond = statement->for_stmt.cond; Expr *cond = statement->for_stmt.cond;
success = sema_analyse_expr_of_required_type(context, type_bool, cond, false); success = sema_analyse_cond_expr(context, cond);
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond); statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
// If this is const true, then set this to infinite and remove the expression. // If this is const true, then set this to infinite and remove the expression.
if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b) if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b)
@@ -876,7 +913,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
// Incr scope start // Incr scope start
SCOPE_START SCOPE_START
Expr *incr = statement->for_stmt.incr; Expr *incr = statement->for_stmt.incr;
success = sema_analyse_expr(context, NULL, incr); success = sema_analyse_expr(context, incr);
statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr); statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr);
// Incr scope end // Incr scope end
SCOPE_END; SCOPE_END;
@@ -919,7 +956,8 @@ static inline bool sema_inline_default_iterator(Context *context, Expr *expr, De
expr->call_expr = (ExprCall) { expr->call_expr = (ExprCall) {
.is_type_method = true, .is_type_method = true,
}; };
return sema_expr_analyse_general_call(context, NULL, expr, decl, inner, decl->decl_kind == DECL_MACRO); REMINDER("Failability");
return sema_expr_analyse_general_call(context, expr, decl, inner, decl->decl_kind == DECL_MACRO, false);
} }
static Decl *find_iterator(Context *context, Expr *enumerator) static Decl *find_iterator(Context *context, Expr *enumerator)
@@ -1085,7 +1123,7 @@ static bool sema_rewrite_foreach_to_for(Context *context, Ast *statement, Expr *
expr->decl_expr = iterator; expr->decl_expr = iterator;
vec_add(init_expr->cond_expr, expr); vec_add(init_expr->cond_expr, expr);
init_expr->resolve_status = RESOLVE_DONE; init_expr->resolve_status = RESOLVE_DONE;
expr_set_type(init_expr, iterator->type); init_expr->type = iterator->type;
// Generate "next": it.next(&value) // Generate "next": it.next(&value)
Expr *call = expr_new(EXPR_CALL, enumerator->span); Expr *call = expr_new(EXPR_CALL, enumerator->span);
@@ -1101,7 +1139,12 @@ static bool sema_rewrite_foreach_to_for(Context *context, Ast *statement, Expr *
Expr *iterator_access = expr_variable(iterator); Expr *iterator_access = expr_variable(iterator);
expr_insert_addr(iterator_access); expr_insert_addr(iterator_access);
if (!sema_expr_analyse_general_call(context, NULL, call, next_method, iterator_access, next_method->decl_kind == DECL_MACRO)) return false; REMINDER("Failability");
if (!sema_expr_analyse_general_call(context,
call,
next_method,
iterator_access,
next_method->decl_kind == DECL_MACRO, false)) return false;
call->resolve_status = RESOLVE_DONE; call->resolve_status = RESOLVE_DONE;
statement->for_stmt = (AstForStmt){ .init = init_expr, statement->for_stmt = (AstForStmt){ .init = init_expr,
@@ -1179,7 +1222,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
} }
// because we don't want the index + variable to move into the internal scope // because we don't want the index + variable to move into the internal scope
if (!sema_analyse_expr(context, inferred_type, enumerator)) if (!sema_analyse_inferred_expr(context, inferred_type, enumerator))
{ {
// Exit early here, because semantic checking might be messed up otherwise. // Exit early here, because semantic checking might be messed up otherwise.
return SCOPE_POP_ERROR(); return SCOPE_POP_ERROR();
@@ -1242,6 +1285,12 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
// Analyse the declaration. // Analyse the declaration.
if (!sema_analyse_local_decl(context, index)) return SCOPE_POP_ERROR(); if (!sema_analyse_local_decl(context, index)) return SCOPE_POP_ERROR();
if (index->type->type_kind == TYPE_FAILABLE)
{
SEMA_ERROR(index->var.type_info, "The index may not be a failable.");
return SCOPE_POP_ERROR();
}
// Make sure that the index is an integer. // Make sure that the index is an integer.
if (!type_is_integer(type_flatten(index->type))) if (!type_is_integer(type_flatten(index->type)))
{ {
@@ -1250,11 +1299,6 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
type_to_error_string(index->type)); type_to_error_string(index->type));
return SCOPE_POP_ERROR(); return SCOPE_POP_ERROR();
} }
if (index->var.failable)
{
SEMA_ERROR(index->var.type_info, "The index may not be a failable.");
return SCOPE_POP_ERROR();
}
} }
// Find the expected type for the value. // Find the expected type for the value.
@@ -1272,7 +1316,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
// Analyse the value declaration. // Analyse the value declaration.
if (!sema_analyse_local_decl(context, var)) return SCOPE_POP_ERROR(); if (!sema_analyse_local_decl(context, var)) return SCOPE_POP_ERROR();
if (var->var.failable) if (IS_FAILABLE(var))
{ {
SEMA_ERROR(var->var.type_info, "The variable may not be a failable."); SEMA_ERROR(var->var.type_info, "The variable may not be a failable.");
return SCOPE_POP_ERROR(); return SCOPE_POP_ERROR();
@@ -1287,7 +1331,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
{ {
// This is hackish, replace when cast is refactored. // This is hackish, replace when cast is refactored.
Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, 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 }; var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type };
if (!cast_implicit(&dummy, var->type)) return SCOPE_POP_ERROR(); if (!cast_implicit(&dummy, var->type)) return SCOPE_POP_ERROR();
assert(dummy.expr_kind == EXPR_CAST); assert(dummy.expr_kind == EXPR_CAST);
@@ -1418,7 +1462,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
static bool sema_analyse_asm_stmt(Context *context, Ast *stmt) static bool sema_analyse_asm_stmt(Context *context, Ast *stmt)
{ {
if (!sema_analyse_expr(context, NULL, stmt->asm_stmt.body)) return false; if (!sema_analyse_expr(context, stmt->asm_stmt.body)) return false;
if (stmt->asm_stmt.body->expr_kind != EXPR_CONST if (stmt->asm_stmt.body->expr_kind != EXPR_CONST
|| stmt->asm_stmt.body->const_expr.const_kind != CONST_STRING) || stmt->asm_stmt.body->const_expr.const_kind != CONST_STRING)
{ {
@@ -1594,7 +1638,7 @@ static bool sema_analyse_nextcase_stmt(Context *context, Ast *statement)
Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? parent->switch_stmt.cond->type : type_anyerr; Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? parent->switch_stmt.cond->type : type_anyerr;
if (!sema_analyse_expr_of_required_type(context, expected_type, target, false)) return false; if (!sema_analyse_expr_of_required_type(context, expected_type, target)) return false;
if (target->expr_kind == EXPR_CONST) if (target->expr_kind == EXPR_CONST)
{ {
@@ -1720,9 +1764,9 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st
Expr *case_expr = case_stmt->case_stmt.expr; Expr *case_expr = case_stmt->case_stmt.expr;
// 1. Try to do implicit conversion to the correct type. // 1. Try to do implicit conversion to the correct type.
if (!sema_analyse_expr(context, to_type, case_expr)) return false; if (!sema_analyse_inferred_expr(context, to_type, case_expr)) return false;
Type *case_type = case_expr->original_type->canonical; Type *case_type = case_expr->type->canonical;
Type *to_type_canonical = to_type->canonical; Type *to_type_canonical = to_type->canonical;
// 3. If we already have the same type we're done. // 3. If we already have the same type we're done.
@@ -1730,7 +1774,7 @@ 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 // 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. // in the case. In that case we do an implicit conversion.
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_type)) if (to_type_canonical->type_kind == TYPE_ENUM && type_is_integer(case_type))
{ {
return cast(case_expr, to_type); return cast(case_expr, to_type);
} }
@@ -1758,7 +1802,7 @@ static inline bool sema_analyse_compound_statement_no_scope(Context *context, As
static inline bool sema_check_type_case(Context *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index) static inline bool sema_check_type_case(Context *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index)
{ {
Expr *expr = case_stmt->case_stmt.expr; Expr *expr = case_stmt->case_stmt.expr;
if (!sema_analyse_expr_of_required_type(context, type_typeid, expr, false)) return false; if (!sema_analyse_expr_of_required_type(context, type_typeid, expr)) return false;
if (expr->expr_kind == EXPR_CONST) if (expr->expr_kind == EXPR_CONST)
{ {
@@ -1810,7 +1854,7 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa
return false; return false;
} }
// We need an if chain if this isn't an integer type. // We need an if chain if this isn't an integer type.
bool if_chain = !type_is_any_integer(type_flatten(switch_type)); bool if_chain = !type_is_integer(type_flatten(switch_type));
Ast *default_case = NULL; Ast *default_case = NULL;
assert(context->active_scope.defer_start == context->active_scope.defer_last); assert(context->active_scope.defer_start == context->active_scope.defer_last);
@@ -1895,7 +1939,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement)
if (use_type_id) if (use_type_id)
{ {
Expr *expr = stmt->case_stmt.expr; Expr *expr = stmt->case_stmt.expr;
if (!sema_analyse_expr_value(context, NULL, expr)) return false; if (!sema_analyse_expr_lvalue(context, expr)) return false;
if (stmt->case_stmt.expr->expr_kind != EXPR_TYPEINFO) if (stmt->case_stmt.expr->expr_kind != EXPR_TYPEINFO)
{ {
SEMA_ERROR(stmt, "Unexpectedly encountered a value rather than a type in the $case"); SEMA_ERROR(stmt, "Unexpectedly encountered a value rather than a type in the $case");
@@ -1921,8 +1965,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement)
{ {
if (!sema_analyse_expr_of_required_type(context, if (!sema_analyse_expr_of_required_type(context,
cond->type, cond->type,
stmt->case_stmt.expr, stmt->case_stmt.expr))
false))
{ {
return false; return false;
} }
@@ -1956,7 +1999,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement)
static bool sema_analyse_ct_switch_stmt(Context *context, Ast *statement) static bool sema_analyse_ct_switch_stmt(Context *context, Ast *statement)
{ {
Expr *cond = statement->ct_switch_stmt.cond; Expr *cond = statement->ct_switch_stmt.cond;
if (!sema_analyse_expr(context, NULL, cond)) return false; if (!sema_analyse_expr(context, cond)) return false;
if (cond->expr_kind != EXPR_CONST && cond->expr_kind != EXPR_TYPEID) if (cond->expr_kind != EXPR_CONST && cond->expr_kind != EXPR_TYPEID)
{ {
SEMA_ERROR(cond, "A compile time $switch must be over a constant value."); SEMA_ERROR(cond, "A compile time $switch must be over a constant value.");
@@ -2018,7 +2061,7 @@ bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement)
Expr *message = statement->ct_assert_stmt.message; Expr *message = statement->ct_assert_stmt.message;
if (message) if (message)
{ {
if (!sema_analyse_expr(context, type_compstr, message)) return false; if (!sema_analyse_expr(context, message)) return false;
if (message->type->type_kind != TYPE_STRLIT) if (message->type->type_kind != TYPE_STRLIT)
{ {
SEMA_ERROR(message, "Expected a string as the error message."); SEMA_ERROR(message, "Expected a string as the error message.");
@@ -2049,7 +2092,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement)
Expr *message = statement->assert_stmt.message; Expr *message = statement->assert_stmt.message;
if (message) if (message)
{ {
if (!sema_analyse_expr(context, type_compstr, message)) return false; if (!sema_analyse_expr(context, message)) return false;
if (message->type->type_kind != TYPE_STRLIT) if (message->type->type_kind != TYPE_STRLIT)
{ {
SEMA_ERROR(message, "Expected a string as the error message."); SEMA_ERROR(message, "Expected a string as the error message.");
@@ -2061,7 +2104,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement)
} }
else else
{ {
if (!sema_analyse_expr_of_required_type(context, type_bool, expr, false)) return false; if (!sema_analyse_assigned_expr(context, type_bool, expr, false)) return false;
} }
return true; return true;
} }
@@ -2144,8 +2187,8 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
return false; return false;
case AST_DEFER_STMT: case AST_DEFER_STMT:
return sema_analyse_defer_stmt(context, statement); return sema_analyse_defer_stmt(context, statement);
case AST_DEFINE_STMT: case AST_VAR_STMT:
return sema_analyse_define_stmt(context, statement); return sema_analyse_var_stmt(context, statement);
case AST_DO_STMT: case AST_DO_STMT:
return sema_analyse_do_stmt(context, statement); return sema_analyse_do_stmt(context, statement);
case AST_EXPR_STMT: case AST_EXPR_STMT:
@@ -2219,7 +2262,7 @@ static bool sema_analyse_requires(Context *context, Ast *docs, Ast ***asserts)
SEMA_ERROR(expr, "Only expressions are allowed."); SEMA_ERROR(expr, "Only expressions are allowed.");
return false; return false;
} }
if (!sema_analyse_expr_of_required_type(context, type_bool, expr, false)) return false; if (!sema_analyse_cond_expr(context, expr)) return false;
Ast *assert = new_ast(AST_ASSERT_STMT, expr->span); Ast *assert = new_ast(AST_ASSERT_STMT, expr->span);
assert->assert_stmt.expr = expr; assert->assert_stmt.expr = expr;
assert->assert_stmt.message = comment; assert->assert_stmt.message = comment;
@@ -2243,12 +2286,10 @@ bool sema_analyse_function_body(Context *context, Decl *func)
.current_local = &context->locals[0] .current_local = &context->locals[0]
}; };
context->macro_scope = (MacroScope) { 0 }; context->macro_scope = (MacroScope) { 0 };
context->failable_return = signature->failable;
// Clear returns // Clear returns
vec_resize(context->returns, 0); vec_resize(context->returns, 0);
context->scope_id = 0; context->scope_id = 0;
context->expected_block_type = NULL;
context->in_volatile_section = 0; context->in_volatile_section = 0;
context->continue_target = 0; context->continue_target = 0;
context->next_target = 0; context->next_target = 0;
@@ -2283,11 +2324,11 @@ bool sema_analyse_function_body(Context *context, Decl *func)
assert(context->active_scope.depth == 1); assert(context->active_scope.depth == 1);
if (!context->active_scope.jump_end) if (!context->active_scope.jump_end)
{ {
Type *canonical_rtype = signature->rtype->type->canonical; Type *canonical_rtype = type_no_fail(signature->rtype->type)->canonical;
if (canonical_rtype != type_void) if (canonical_rtype != type_void)
{ {
// IMPROVE better pointer to end. // IMPROVE better pointer to end.
SEMA_ERROR(func, "Missing return statement at the end of the function."); SEMA_TOKID_ERROR(func->name_token, "Missing return statement at the end of the function.");
return false; return false;
} }
} }

View File

@@ -18,40 +18,34 @@ static inline bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info)
bool sema_resolve_array_like_len(Context *context, TypeInfo *type_info, ArrayIndex *len_ref) bool sema_resolve_array_like_len(Context *context, TypeInfo *type_info, ArrayIndex *len_ref)
{ {
Expr *len_expr = type_info->array.len; Expr *len_expr = type_info->array.len;
if (!sema_analyse_expr(context, type_usize, len_expr)) return type_info_poison(type_info); if (!sema_analyse_expr(context, len_expr)) return type_info_poison(type_info);
if (len_expr->expr_kind != EXPR_CONST) if (len_expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(len_expr, "Expected a constant value as size."); SEMA_ERROR(len_expr, "Expected a constant value as size.");
return type_info_poison(type_info); return type_info_poison(type_info);
} }
if (!type_is_any_integer(len_expr->type->canonical)) if (!type_is_integer(len_expr->type->canonical))
{ {
SEMA_ERROR(len_expr, "Expected an integer size."); SEMA_ERROR(len_expr, "Expected an integer size.");
return type_info_poison(type_info); return type_info_poison(type_info);
} }
BigInt *big_len = &len_expr->const_expr.i;
bool is_vector = type_info->kind == TYPE_INFO_VECTOR; bool is_vector = type_info->kind == TYPE_INFO_VECTOR;
switch (bigint_cmp_zero(big_len)) Int len = len_expr->const_expr.ixx;
if (int_is_neg(len))
{ {
case CMP_LT: SEMA_ERROR(len_expr,
SEMA_ERROR(len_expr, is_vector ? "A vector may not have a negative width." :
is_vector ? "A vector may not have a negative width." : "An array may not have a negative size.");
"An array may not have a negative size."); return type_info_poison(type_info);
return type_info_poison(type_info);
case CMP_EQ:
if (is_vector)
{
SEMA_ERROR(len_expr, "A vector may not have a zero width.");
return type_info_poison(type_info);
}
break;
case CMP_GT:
break;
} }
BigInt max; if (is_vector && int_is_zero(len))
bigint_init_unsigned(&max, is_vector ? MAX_VECTOR_WIDTH : MAX_ARRAY_SIZE); {
if (bigint_cmp(big_len, &max) == CMP_GT) SEMA_ERROR(len_expr, "A vector may not have a zero width.");
return type_info_poison(type_info);
}
if (int_icomp(len, is_vector ? MAX_VECTOR_WIDTH : MAX_ARRAY_SIZE, BINARYOP_GT))
{ {
if (is_vector) if (is_vector)
{ {
@@ -63,7 +57,7 @@ bool sema_resolve_array_like_len(Context *context, TypeInfo *type_info, ArrayInd
} }
return type_info_poison(type_info); return type_info_poison(type_info);
} }
*len_ref = bigint_as_signed(big_len); *len_ref = len.i.low;
return true; return true;
} }
@@ -148,6 +142,11 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_VAR: case DECL_VAR:
if (decl->var.kind == VARDECL_PARAM_CT_TYPE || decl->var.kind == VARDECL_LOCAL_CT_TYPE) if (decl->var.kind == VARDECL_PARAM_CT_TYPE || decl->var.kind == VARDECL_LOCAL_CT_TYPE)
{ {
if (!decl->var.init_expr)
{
SEMA_ERROR(type_info, "The variable '%s' is not defined yet.", decl->name);
return false;
}
assert(decl->var.init_expr->expr_kind == EXPR_TYPEINFO); assert(decl->var.init_expr->expr_kind == EXPR_TYPEINFO);
assert(decl->var.init_expr->resolve_status == RESOLVE_DONE); assert(decl->var.init_expr->resolve_status == RESOLVE_DONE);
*type_info = *decl->var.init_expr->type_expr; *type_info = *decl->var.init_expr->type_expr;
@@ -213,6 +212,8 @@ bool sema_resolve_type(Context *context, Type *type)
return sema_resolve_type(context, type->array.base); return sema_resolve_type(context, type->array.base);
case TYPE_VIRTUAL: case TYPE_VIRTUAL:
TODO; TODO;
case TYPE_FAILABLE:
return sema_resolve_type(context, type->failable);
} }
return sema_analyse_decl(context, type->decl); return sema_analyse_decl(context, type->decl);
} }
@@ -243,17 +244,13 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow
case TYPE_INFO_EXPRESSION: case TYPE_INFO_EXPRESSION:
{ {
Expr *expr = type_info->unresolved_type_expr; Expr *expr = type_info->unresolved_type_expr;
if (!sema_analyse_expr(context, NULL, expr)) if (!sema_analyse_expr(context, expr))
{ {
return type_info_poison(type_info); return type_info_poison(type_info);
} }
if (!cast_implicitly_to_runtime(expr))
{
SEMA_ERROR(expr, "The expression does not fit any runtime type.");
return false;
}
type_info->type = expr->type; type_info->type = expr->type;
type_info->resolve_status = RESOLVE_DONE; type_info->resolve_status = RESOLVE_DONE;
assert(!type_info->failable);
return true; return true;
} }
case TYPE_INFO_INFERRED_ARRAY: case TYPE_INFO_INFERRED_ARRAY:
@@ -272,6 +269,10 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow
if (!sema_resolve_ptr_type(context, type_info)) return false; if (!sema_resolve_ptr_type(context, type_info)) return false;
break; break;
} }
if (type_info->failable)
{
type_info->type = type_get_failable(type_info->type);
}
return true; return true;
} }

View File

@@ -13,7 +13,7 @@ void sema_shadow_error(Decl *decl, Decl *old)
bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type) bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type)
{ {
if (!sema_resolve_type_shallow(context, type_info, allow_inferred_type, false)) return false; if (!sema_resolve_type_shallow(context, type_info, allow_inferred_type, false)) return false;
Type *type = type_info->type; Type *type = type_no_fail(type_info->type);
// usize and similar typedefs will not have a decl. // usize and similar typedefs will not have a decl.
if (type->type_kind == TYPE_TYPEDEF && type->decl == NULL) return true; if (type->type_kind == TYPE_TYPEDEF && type->decl == NULL) return true;
if (!type_is_user_defined(type)) return true; if (!type_is_user_defined(type)) return true;
@@ -95,7 +95,7 @@ Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr)
context_pop_defers_to(context, &defers); context_pop_defers_to(context, &defers);
if (defers.end == defers.start) return expr; if (defers.end == defers.start) return expr;
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span); Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
expr_copy_types(wrap, expr); wrap->type = expr->type;
wrap->resolve_status = RESOLVE_DONE; wrap->resolve_status = RESOLVE_DONE;
wrap->expr_scope.expr = expr; wrap->expr_scope.expr = expr;
wrap->expr_scope.defers = defers; wrap->expr_scope.defers = defers;

View File

@@ -12,7 +12,7 @@ static struct
Type f16, f32, f64, f128, fxx; Type f16, f32, f64, f128, fxx;
Type usz, isz, uptr, iptr, uptrdiff, iptrdiff; Type usz, isz, uptr, iptr, uptrdiff, iptrdiff;
Type voidstar, typeid, anyerr, typeinfo, ctlist; Type voidstar, typeid, anyerr, typeinfo, ctlist;
Type str, virtual, virtual_generic; Type str, virtual, virtual_generic, anyfail;
} t; } t;
Type *type_bool = &t.u1; Type *type_bool = &t.u1;
@@ -47,6 +47,7 @@ Type *type_compfloat = &t.fxx;
Type *type_compstr = &t.str; Type *type_compstr = &t.str;
Type *type_anyerr = &t.anyerr; Type *type_anyerr = &t.anyerr;
Type *type_complist = &t.ctlist; Type *type_complist = &t.ctlist;
Type *type_anyfail = &t.anyfail;
static unsigned size_subarray; static unsigned size_subarray;
static AlignSize alignment_subarray; static AlignSize alignment_subarray;
@@ -57,7 +58,8 @@ static AlignSize max_alignment_vector;
#define PTR_OFFSET 0 #define PTR_OFFSET 0
#define INFERRED_ARRAY_OFFSET 1 #define INFERRED_ARRAY_OFFSET 1
#define SUB_ARRAY_OFFSET 2 #define SUB_ARRAY_OFFSET 2
#define ARRAY_OFFSET 3 #define FAILABLE_OFFSET 3
#define ARRAY_OFFSET 4
Type *type_cint(void) Type *type_cint(void)
{ {
@@ -144,6 +146,10 @@ const char *type_to_error_string(Type *type)
} }
asprintf(&buffer, "%s*", type_to_error_string(type->pointer)); asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
return buffer; return buffer;
case TYPE_FAILABLE:
if (!type->failable) return "void!";
asprintf(&buffer, "%s!", type_to_error_string(type->failable));
return buffer;
case TYPE_STRLIT: case TYPE_STRLIT:
return "string literal"; return "string literal";
case TYPE_ARRAY: case TYPE_ARRAY:
@@ -187,12 +193,15 @@ void type_append_signature_name(Type *type, char *dst, size_t *offset)
ByteSize type_size(Type *type) ByteSize type_size(Type *type)
{ {
RETRY:
switch (type->type_kind) switch (type->type_kind)
{ {
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
return type_size(type->decl->bitstruct.base_type->type); type = type->decl->bitstruct.base_type->type;
goto RETRY;
case TYPE_DISTINCT: case TYPE_DISTINCT:
return type_size(type->decl->distinct_decl.base_type); type = type->decl->distinct_decl.base_type;
goto RETRY;
case TYPE_VECTOR: case TYPE_VECTOR:
{ {
ByteSize width = type_size(type->vector.base) * type->vector.len; ByteSize width = type_size(type->vector.base) * type->vector.len;
@@ -205,10 +214,16 @@ ByteSize type_size(Type *type)
} }
case CT_TYPES: case CT_TYPES:
UNREACHABLE; UNREACHABLE;
case TYPE_FAILABLE:
type = type->failable;
if (!type) return 1;
goto RETRY;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
return type_size(type->canonical); type = type->canonical;
goto RETRY;
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
return type_size(type_usize->canonical); type = type_iptr->canonical;
goto RETRY;
case TYPE_ENUM: case TYPE_ENUM:
return type->decl->enums.type_info->type->canonical->builtin.bytesize; return type->decl->enums.type_info->type->canonical->builtin.bytesize;
case TYPE_STRUCT: case TYPE_STRUCT:
@@ -229,7 +244,7 @@ ByteSize type_size(Type *type)
case TYPE_STRLIT: case TYPE_STRLIT:
case TYPE_FUNC: case TYPE_FUNC:
case TYPE_POINTER: case TYPE_POINTER:
return t.usz.canonical->builtin.bytesize; return t.iptr.canonical->builtin.bytesize;
case TYPE_ARRAY: case TYPE_ARRAY:
return type_size(type->array.base) * type->array.len; return type_size(type->array.base) * type->array.len;
case TYPE_SUBARRAY: case TYPE_SUBARRAY:
@@ -332,16 +347,22 @@ Type *type_abi_find_single_struct_element(Type *type)
bool type_is_abi_aggregate(Type *type) bool type_is_abi_aggregate(Type *type)
{ {
RETRY:
switch (type->type_kind) switch (type->type_kind)
{ {
case TYPE_POISONED: case TYPE_POISONED:
return false; return false;
case TYPE_FAILABLE:
type = type->failable;
if (!type) return false;
goto RETRY;
case TYPE_DISTINCT: case TYPE_DISTINCT:
return type_is_abi_aggregate(type->decl->distinct_decl.base_type); type = type->decl->distinct_decl.base_type;
goto RETRY;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
return type_is_abi_aggregate(type->canonical); type = type->canonical;
goto RETRY;
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
return type_is_abi_aggregate(type->decl->bitstruct.base_type->type);
case ALL_FLOATS: case ALL_FLOATS:
case TYPE_VOID: case TYPE_VOID:
case ALL_INTS: case ALL_INTS:
@@ -495,14 +516,16 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
RETRY: RETRY:
switch (type->type_kind) switch (type->type_kind)
{ {
case TYPE_FAILABLE:
type = type->failable;
if (!type) return false;
goto RETRY;
case TYPE_DISTINCT: case TYPE_DISTINCT:
type = type->decl->distinct_decl.base_type; type = type->decl->distinct_decl.base_type;
goto RETRY; goto RETRY;
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
type = type->decl->bitstruct.base_type->type; type = type->decl->bitstruct.base_type->type;
goto RETRY; goto RETRY;
case TYPE_FXX:
case TYPE_IXX:
case TYPE_VOID: case TYPE_VOID:
case TYPE_TYPEID: case TYPE_TYPEID:
case TYPE_FUNC: case TYPE_FUNC:
@@ -584,7 +607,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
type = type_int_unsigned_by_bitsize(type->builtin.bitsize); type = type_int_unsigned_by_bitsize(type->builtin.bitsize);
break; break;
case ALL_UNSIGNED_INTS: case ALL_UNSIGNED_INTS:
case ALL_REAL_FLOATS: case ALL_FLOATS:
case TYPE_VECTOR: case TYPE_VECTOR:
break; break;
case TYPE_POINTER: case TYPE_POINTER:
@@ -700,6 +723,7 @@ bool type_is_comparable(Type *type)
AlignSize type_abi_alignment(Type *type) AlignSize type_abi_alignment(Type *type)
{ {
RETRY:
switch (type->type_kind) switch (type->type_kind)
{ {
case TYPE_POISONED: case TYPE_POISONED:
@@ -707,7 +731,8 @@ AlignSize type_abi_alignment(Type *type)
case TYPE_UNTYPED_LIST: case TYPE_UNTYPED_LIST:
UNREACHABLE; UNREACHABLE;
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
return type_abi_alignment(type->decl->bitstruct.base_type->type); type = type->decl->bitstruct.base_type->type;
goto RETRY;
case TYPE_VECTOR: case TYPE_VECTOR:
{ {
ByteSize width = type_size(type->vector.base) * type->vector.len; ByteSize width = type_size(type->vector.base) * type->vector.len;
@@ -721,10 +746,16 @@ AlignSize type_abi_alignment(Type *type)
} }
case TYPE_VOID: case TYPE_VOID:
return 1; return 1;
case TYPE_FAILABLE:
type = type->failable;
if (!type) return 1;
goto RETRY;
case TYPE_DISTINCT: case TYPE_DISTINCT:
return type_abi_alignment(type->decl->distinct_decl.base_type); type = type->decl->distinct_decl.base_type;
goto RETRY;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
return type_abi_alignment(type->canonical); type = type->canonical;
goto RETRY;
case TYPE_ENUM: case TYPE_ENUM:
return type->decl->enums.type_info->type->canonical->builtin.abi_alignment; return type->decl->enums.type_info->type->canonical->builtin.abi_alignment;
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
@@ -732,8 +763,6 @@ AlignSize type_abi_alignment(Type *type)
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_UNION: case TYPE_UNION:
return type->decl->alignment; return type->decl->alignment;
case TYPE_TYPEID:
return type_abi_alignment(type_usize);
case TYPE_BOOL: case TYPE_BOOL:
case ALL_INTS: case ALL_INTS:
case ALL_FLOATS: case ALL_FLOATS:
@@ -745,10 +774,12 @@ AlignSize type_abi_alignment(Type *type)
case TYPE_FUNC: case TYPE_FUNC:
case TYPE_POINTER: case TYPE_POINTER:
case TYPE_STRLIT: case TYPE_STRLIT:
case TYPE_TYPEID:
return t.iptr.canonical->builtin.abi_alignment; return t.iptr.canonical->builtin.abi_alignment;
case TYPE_ARRAY: case TYPE_ARRAY:
case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_ARRAY:
return type_abi_alignment(type->array.base); type = type->array.base;
goto RETRY;
case TYPE_SUBARRAY: case TYPE_SUBARRAY:
return alignment_subarray; return alignment_subarray;
} }
@@ -789,6 +820,30 @@ static Type *type_generate_ptr(Type *ptr_type, bool canonical)
return ptr; return ptr;
} }
static Type *type_generate_failable(Type *failable_type, bool canonical)
{
if (canonical) failable_type = failable_type->canonical;
if (!failable_type->type_cache)
{
create_type_cache(failable_type);
}
Type *failable = failable_type->type_cache[FAILABLE_OFFSET];
if (failable == NULL)
{
failable = type_new(TYPE_FAILABLE, strformat("%s!", failable_type->name));
failable->pointer = failable_type;
failable_type->type_cache[FAILABLE_OFFSET] = failable;
if (failable_type == failable_type->canonical)
{
failable->canonical = failable;
}
else
{
failable->canonical = type_generate_failable(failable_type->canonical, true);
}
}
return failable;
}
static Type *type_generate_subarray(Type *arr_type, bool canonical) static Type *type_generate_subarray(Type *arr_type, bool canonical)
{ {
@@ -843,12 +898,28 @@ static Type *type_generate_inferred_array(Type *arr_type, bool canonical)
} }
Type *type_get_ptr_recurse(Type *ptr_type)
{
if (ptr_type->type_kind == TYPE_FAILABLE)
{
ptr_type = ptr_type->failable;
return type_get_failable(type_get_ptr(ptr_type));
}
return type_get_ptr(ptr_type);
}
Type *type_get_ptr(Type *ptr_type) Type *type_get_ptr(Type *ptr_type)
{ {
assert(ptr_type->type_kind != TYPE_FAILABLE);
return type_generate_ptr(ptr_type, false); return type_generate_ptr(ptr_type, false);
} }
Type *type_get_failable(Type *failable_type)
{
assert(failable_type->type_kind != TYPE_FAILABLE);
return type_generate_failable(failable_type, false);
}
Type *type_get_subarray(Type *arr_type) Type *type_get_subarray(Type *arr_type)
{ {
return type_generate_subarray(arr_type, false); return type_generate_subarray(arr_type, false);
@@ -1050,9 +1121,8 @@ bool type_is_valid_for_vector(Type *type)
RETRY: RETRY:
switch (type->type_kind) switch (type->type_kind)
{ {
case ALL_SIGNED_INTS: case ALL_INTS:
case ALL_UNSIGNED_INTS: case ALL_FLOATS:
case ALL_REAL_FLOATS:
case TYPE_BOOL: case TYPE_BOOL:
return true; return true;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
@@ -1143,6 +1213,17 @@ static void type_append_name_to_scratch(Type *type)
type_append_name_to_scratch(type->pointer); type_append_name_to_scratch(type->pointer);
scratch_buffer_append_char('*'); scratch_buffer_append_char('*');
break; break;
case TYPE_FAILABLE:
if (type->failable)
{
type_append_name_to_scratch(type->failable);
}
else
{
scratch_buffer_append("void");
}
scratch_buffer_append_char('!');
break;
case TYPE_SUBARRAY: case TYPE_SUBARRAY:
type_append_name_to_scratch(type->pointer); type_append_name_to_scratch(type->pointer);
scratch_buffer_append("[]"); scratch_buffer_append("[]");
@@ -1168,8 +1249,6 @@ static void type_append_name_to_scratch(Type *type)
case TYPE_VECTOR: case TYPE_VECTOR:
scratch_buffer_append(type->name); scratch_buffer_append(type->name);
break; break;
case TYPE_IXX:
case TYPE_FXX:
case TYPE_STRLIT: case TYPE_STRLIT:
case TYPE_UNTYPED_LIST: case TYPE_UNTYPED_LIST:
case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_ARRAY:
@@ -1191,7 +1270,6 @@ Type *type_find_function_type(FunctionSignature *signature)
{ {
scratch_buffer_clear(); scratch_buffer_clear();
type_append_name_to_scratch(signature->rtype->type); type_append_name_to_scratch(signature->rtype->type);
if (signature->failable) scratch_buffer_append_char('!');
scratch_buffer_append_char('('); scratch_buffer_append_char('(');
unsigned elements = vec_size(signature->params); unsigned elements = vec_size(signature->params);
for (unsigned i = 0; i < elements; i++) for (unsigned i = 0; i < elements; i++)
@@ -1267,6 +1345,7 @@ void type_setup(PlatformTarget *target)
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1); type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1); type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1);
t.anyfail = (Type){ .type_kind = TYPE_FAILABLE, .failable = type_void };
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer); type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer); type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);
@@ -1276,8 +1355,6 @@ void type_setup(PlatformTarget *target)
type_init("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer); type_init("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer);
type_init("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer); type_init("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer);
type_create("compint", &t.ixx, TYPE_IXX, 1, 1, 1);
type_create("compfloat", &t.fxx, TYPE_FXX, 1, 1, 1);
type_create_alias("usize", &t.usz, type_int_unsigned_by_bitsize(target->width_pointer)); 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("isize", &t.isz, type_int_signed_by_bitsize(target->width_pointer));
@@ -1293,6 +1370,33 @@ void type_setup(PlatformTarget *target)
type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer); type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer);
} }
int type_kind_bitsize(TypeKind kind)
{
switch (kind)
{
case TYPE_I8:
case TYPE_U8:
return 8;
case TYPE_I16:
case TYPE_U16:
case TYPE_F16:
return 16;
case TYPE_I32:
case TYPE_U32:
case TYPE_F32:
return 32;
case TYPE_I64:
case TYPE_U64:
case TYPE_F64:
return 64;
case TYPE_I128:
case TYPE_U128:
case TYPE_F128:
return 128;
default:
UNREACHABLE;
}
}
bool type_is_scalar(Type *type) bool type_is_scalar(Type *type)
{ {
RETRY: RETRY:
@@ -1326,6 +1430,10 @@ bool type_is_scalar(Type *type)
case TYPE_DISTINCT: case TYPE_DISTINCT:
type = type->decl->distinct_decl.base_type; type = type->decl->distinct_decl.base_type;
goto RETRY; goto RETRY;
case TYPE_FAILABLE:
type = type->failable;
if (!type) return false;
goto RETRY;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
type = type->canonical; type = type->canonical;
goto RETRY; goto RETRY;
@@ -1412,46 +1520,6 @@ Type *type_from_token(TokenType type)
} }
} }
bool type_may_convert_to_boolean(Type *type)
{
RETRY:
switch (type->type_kind)
{
case TYPE_POISONED:
return false;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
case TYPE_DISTINCT:
type = type->decl->distinct_decl.base_type;
goto RETRY;
case ALL_INTS:
case ALL_FLOATS:
case TYPE_POINTER:
case TYPE_VIRTUAL:
case TYPE_VIRTUAL_ANY:
case TYPE_BOOL:
case TYPE_SUBARRAY:
case TYPE_ENUM:
case TYPE_ANYERR:
case TYPE_ERRTYPE:
case TYPE_STRLIT:
case TYPE_UNTYPED_LIST:
return true;
case TYPE_FUNC:
case TYPE_ARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_BITSTRUCT:
case TYPE_VECTOR:
case TYPE_STRUCT:
case TYPE_TYPEID:
case TYPE_TYPEINFO:
case TYPE_UNION:
case TYPE_VOID:
return false;
}
UNREACHABLE
}
bool type_may_have_sub_elements(Type *type) bool type_may_have_sub_elements(Type *type)
{ {
// An alias is not ok. // An alias is not ok.
@@ -1476,15 +1544,13 @@ Type *type_find_max_num_type(Type *num_type, Type *other_num)
assert(kind != other_kind); assert(kind != other_kind);
// 1. The only conversions need to happen if the other type is a number. // 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; if (other_kind < TYPE_INTEGER_FIRST || other_kind > TYPE_FLOAT_LAST) return NULL;
// 2. First check the float case. // 2. First check the float case.
if (other_kind >= TYPE_F16 && other_kind <= TYPE_FXX) if (other_kind >= TYPE_FLOAT_FIRST && other_kind <= TYPE_FLOAT_LAST)
{ {
switch (other_kind) switch (other_kind)
{ {
case TYPE_FXX:
return kind <= TYPE_IXX ? type_double : num_type;
case TYPE_F16: case TYPE_F16:
case TYPE_F32: case TYPE_F32:
case TYPE_F64: case TYPE_F64:
@@ -1499,9 +1565,6 @@ Type *type_find_max_num_type(Type *num_type, Type *other_num)
// Handle integer <=> integer conversions. // Handle integer <=> integer conversions.
assert(type_kind_is_any_integer(other_kind) && type_is_integer(num_type)); 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. // 4. Check the bit sizes.
unsigned other_bit_size = other_num->builtin.bitsize; unsigned other_bit_size = other_num->builtin.bitsize;
unsigned bit_size = num_type->builtin.bitsize; unsigned bit_size = num_type->builtin.bitsize;
@@ -1574,8 +1637,20 @@ static inline Type *type_find_max_ptr_type(Type *type, Type *other)
Type *type_find_max_type(Type *type, Type *other) Type *type_find_max_type(Type *type, Type *other)
{ {
assert(type->canonical == type); if (type == type_anyfail)
assert(other->canonical == other); {
return type_get_opt_fail(other, true);
}
if (other == type_anyfail)
{
return type_get_failable(type);
}
type = type->canonical;
other = other->canonical;
assert(type->type_kind != TYPE_FAILABLE && other->type_kind != TYPE_FAILABLE);
if (type == other) return type; if (type == other) return type;
// Sort types // Sort types
@@ -1590,6 +1665,7 @@ Type *type_find_max_type(Type *type, Type *other)
{ {
case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_ARRAY:
case TYPE_POISONED: case TYPE_POISONED:
case TYPE_FAILABLE:
UNREACHABLE UNREACHABLE
case TYPE_VOID: case TYPE_VOID:
case TYPE_BOOL: case TYPE_BOOL:
@@ -1598,17 +1674,12 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_VIRTUAL_ANY: case TYPE_VIRTUAL_ANY:
case TYPE_BITSTRUCT: case TYPE_BITSTRUCT:
return NULL; return NULL;
case TYPE_IXX: case ALL_INTS:
if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other; if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other;
FALLTHROUGH;
case ALL_SIGNED_INTS:
case ALL_UNSIGNED_INTS:
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical); if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
return type_find_max_num_type(type, other); return type_find_max_num_type(type, other);
case TYPE_FXX: case ALL_FLOATS:
if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other; if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other;
FALLTHROUGH;
case ALL_REAL_FLOATS:
return type_find_max_num_type(type, other); return type_find_max_num_type(type, other);
case TYPE_POINTER: case TYPE_POINTER:
return type_find_max_ptr_type(type, other); return type_find_max_ptr_type(type, other);
@@ -1664,7 +1735,7 @@ Type *type_find_common_ancestor(Type *left, Type *right)
if (left->type_kind == TYPE_POINTER) if (left->type_kind == TYPE_POINTER)
{ {
Type *common = type_find_common_ancestor(left->pointer, right->pointer); Type *common = type_find_common_ancestor(left->pointer, right->pointer);
return common ? type_generate_ptr(common, true) : NULL; return common ? type_get_ptr(common) : NULL;
} }
if (left->type_kind != TYPE_STRUCT) return NULL; if (left->type_kind != TYPE_STRUCT) return NULL;

View File

@@ -10,7 +10,6 @@
#include "benchmark.h" #include "benchmark.h"
void test_file(void) void test_file(void)
{ {
File file; File file;
@@ -37,12 +36,160 @@ void test_file(void)
TEST_ASSERT(source_file_find_position_in_file(&file, 21).line == 3, "Expected third line"); TEST_ASSERT(source_file_find_position_in_file(&file, 21).line == 3, "Expected third line");
TEST_ASSERT(source_file_find_position_in_file(&file, 25).line == 3, "Expected third line"); TEST_ASSERT(source_file_find_position_in_file(&file, 25).line == 3, "Expected third line");
TEST_ASSERT(source_file_find_position_in_file(&file, 31).line == 4, "Expected fourth line"); TEST_ASSERT(source_file_find_position_in_file(&file, 31).line == 4, "Expected fourth line");
}
#define i128(x_, y_) ((Int128){x_, y_})
void test128()
{
printf("Begin i128 testing.\n");
Int128 addres = i128_add(i128(0x123, 0x123), i128(0x222, 0x333));
TEST_ASSERTF(addres.high == 0x345 && addres.low == 0x456, "i128 add failed with small numbers was %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_add(i128(0x123, UINT64_MAX), i128(0x222, 0x1));
TEST_ASSERT(addres.high == 0x346 && addres.low == 0, "i128 add failed with simple overflow");
addres = i128_add(i128(0x123, UINT64_MAX), i128(0x222, UINT64_MAX));
TEST_ASSERT(addres.high == 0x346 && addres.low == UINT64_MAX - 1, "i128 add failed with simple overflow2");
addres = i128_add(i128(UINT64_MAX, UINT64_MAX), i128(0x0, 0x1));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "i128 add failed with wrap");
addres = i128_add(i128(UINT64_MAX, UINT64_MAX), i128(UINT64_MAX, UINT64_MAX));
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX - 1, "i128 add failed overflow with wrap");
printf("-- i128 Add - Ok.\n");
addres = i128_sub(i128(0x345, 0x457), i128(0x222, 0x333));
TEST_ASSERTF(addres.high == 0x123 && addres.low == 0x124, "i128 sub failed with small numbers was %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_sub(i128(0x346, 0), i128(0x222, 0x1));
TEST_ASSERTF(addres.high == 0x123 && addres.low == UINT64_MAX, "i128 sub failed with simple overflow %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_sub(i128(0x346, UINT64_MAX - 1), i128(0x222, UINT64_MAX));
TEST_ASSERT(addres.high == 0x123 && addres.low == UINT64_MAX, "i128 sub failed with simple overflow2");
addres = i128_sub(i128(0, 0), i128(0x0, 0x1));
TEST_ASSERTF(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "i128 sub failed with wrap %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_sub(i128(UINT64_MAX, UINT64_MAX - 1), i128(UINT64_MAX, UINT64_MAX));
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "i128 sub failed overflow with wrap");
printf("-- i128 Sub - Ok.\n");
addres = i128_and(i128(0x0, 0x0), i128(UINT64_MAX, UINT64_MAX));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "And failed");
addres = i128_and(i128(0x123, 0x123456789abcdef1), i128(UINT64_MAX, UINT64_MAX));
TEST_ASSERT(addres.high == 0x123 && addres.low == 0x123456789abcdef1, "And failed");
addres = i128_and(i128(0xabcdef2233, 0x123456789A), i128(0x0F0F0F0F0F0F, 0xF0F0F0F0F0F0));
TEST_ASSERT(addres.high == 0x0b0d0f0203 && addres.low == 0x1030507090, "And failed");
printf("-- i128 And - Ok.\n");
addres = i128_or(i128(0x0, 0x0), i128(UINT64_MAX, UINT64_MAX));
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "Or failed");
addres = i128_or(i128(0x123, 0x123456789abcdef1), i128(0x123203, 0x0));
TEST_ASSERT(addres.high == 0x123323 && addres.low == 0x123456789abcdef1, "Or failed");
addres = i128_or(i128(0xabcdef2233, 0x123456789A), i128(0x0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0));
TEST_ASSERTF(addres.high == 0x0FAFCFEF2F3F && addres.low == 0xF0F0F2F4F6F8FA, "Or failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Or - Ok.\n");
addres = i128_xor(i128(0x0, 0x0), i128(UINT64_MAX, UINT64_MAX));
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "Xor failed");
addres = i128_xor(i128(0x123, 0x123456789abcdef1), i128(0x123223, 0x0));
TEST_ASSERT(addres.high == 0x123300 && addres.low == 0x123456789abcdef1, "Xor failed");
addres = i128_xor(i128(0xabcdef2233, 0x123456789A), i128(0x0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0));
TEST_ASSERTF(addres.high == 0x0FA4C2E02d3c && addres.low == 0xF0F0e2c4a6886A, "Xor failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Xor - Ok.\n");
addres = i128_neg(i128(0x0, 0x0));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "Neg failed");
addres = i128_neg(i128(0x123, 0x123456789abcdef1));
TEST_ASSERT(addres.high == ~((uint64_t)0x123) && addres.low == ~(uint64_t)0x123456789abcdef0, "Neg failed");
addres = i128_neg(i128(0xabcdef2233, 0x123456789A));
TEST_ASSERTF(addres.high == ~(uint64_t)0xabcdef2233 && addres.low == ~(uint64_t)0x1234567899, "Neg failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Neg - Ok.\n");
addres = i128_from_str("1123");
TEST_ASSERT(addres.high == 0 && addres.low == 1123, "Init failed");
addres = i128_from_str("10000000000000000000012344434232");
TEST_ASSERT(addres.high == 0x7e37be2022 && addres.low == 0xc0914b295fc91e38, "Init failed");
addres = i128_mult(i128(0x111, 0x222), i128(0, 2));
TEST_ASSERTF(addres.high == 0x222 && addres.low == 0x444, "Mult failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_mult(i128(0x111, 0x222), i128(2, 0));
TEST_ASSERTF(addres.high == 0x444 && addres.low == 0, "Mult failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_mult(i128_from_str("523871293871232000123"), i128_from_str("283712312938293299"));
TEST_ASSERTF(i128_ucomp(i128_from_str("148628736466183585621117368965778075777"), addres) == CMP_EQ, "Mult failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Mult ok.\n");
TEST_ASSERTF(i128_ucomp(i128_from_str("123"), i128_from_str("123")) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128_from_str("123"), i128_from_str("124")) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128_from_str("123"), i128_from_str("121")) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128(0x222, 0x111), i128(0x111, 0x222)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128(0x111, 0x222), i128(0x222, 0x111)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128(0x222, 0x111), i128(0x222, 0x111)) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128(UINT64_MAX, 0x111), i128(0x111, 0x222)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_ucomp(i128(0x111, 0x222), i128(UINT64_MAX, 0x111)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Ucomp ok.\n");
TEST_ASSERTF(i128_scomp(i128_from_str("123"), i128_from_str("123")) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128_from_str("123"), i128_from_str("124")) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128_from_str("123"), i128_from_str("121")) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128(0x222, 0x111), i128(0x111, 0x222)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128(0x111, 0x222), i128(0x222, 0x111)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128(0x222, 0x111), i128(0x222, 0x111)) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128(UINT64_MAX, 0x111), i128(0x111, 0x222)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
TEST_ASSERTF(i128_scomp(i128(0x111, 0x222), i128(UINT64_MAX, 0x111)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Scomp ok.\n");
addres = i128_shl(i128(0x234, 0x123456), i128(0, 0x4));
TEST_ASSERT(addres.high == 0x2340 && addres.low == 0x1234560, "shl failed");
addres = i128_shl(i128(0x234, 0x1234561), i128(0, 128));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "shl failed");
addres = i128_shl(i128(0x234, 0x1234561), i128(1, 1));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "shl failed");
addres = i128_shl(i128(0x234, 0x1234561), i128(0, 64));
TEST_ASSERT(addres.high == 0x1234561 && addres.low == 0, "shl failed");
printf("-- i128 Shl ok.\n");
addres = i128_lshr(i128(0x234, 0x123456), i128(0, 0x4));
TEST_ASSERTF(addres.high == 0x23 && addres.low == 0x4000000000012345, "lshr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_lshr(i128(0x234, 0x1234561), i128(0, 128));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "lshr failed");
addres = i128_lshr(i128(0x234, 0x1234561), i128(1, 1));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "lshr failed");
addres = i128_lshr(i128(0x234, 0x1234561), i128(0, 64));
TEST_ASSERTF(addres.high == 0 && addres.low == 0x234, "lshr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Lshr ok.\n");
addres = i128_ashr(i128(0x234, 0x123456), i128(0, 0x4));
TEST_ASSERTF(addres.high == 0x23 && addres.low == 0x4000000000012345, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_ashr(i128(0xF000000000000234, 0x123456), i128(0, 0x4));
TEST_ASSERTF(addres.high == 0xFF00000000000023 && addres.low == 0x4000000000012345, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_ashr(i128(0x234, 0x1234561), i128(0, 128));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "ashr failed");
addres = i128_ashr(i128(0xF000000000000234, 0x1234561), i128(0, 128));
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "ashr failed");
addres = i128_ashr(i128(0x234, 0x1234561), i128(1, 1));
TEST_ASSERT(addres.high == 0 && addres.low == 0, "ashr failed");
addres = i128_ashr(i128(0xF000000000000234, 0x1234561), i128(1, 1));
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "ashr failed");
addres = i128_ashr(i128(0x234, 0x1234561), i128(0, 64));
TEST_ASSERTF(addres.high == 0 && addres.low == 0x234, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
addres = i128_ashr(i128(0xF000000000000234, 0x1234561), i128(0, 64));
TEST_ASSERTF(addres.high == UINT64_MAX && addres.low == 0xF000000000000234, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Ashr ok.\n");
TEST_ASSERT(i128_ucomp(i128_udiv(i128_from_str("123"), i128_from_str("123")), i128_from_str("1")) == CMP_EQ, "Div failed");
TEST_ASSERT(i128_ucomp(i128_udiv(i128_from_str("123"), i128_from_str("124")), i128_from_str("0")) == CMP_EQ, "Div failed");
TEST_ASSERT(i128_ucomp(i128_udiv(i128_from_str("245"), i128_from_str("123")), i128_from_str("1")) == CMP_EQ, "Div failed");
addres = i128_udiv(i128(0x12345, UINT64_MAX), i128(1, 0));
TEST_ASSERT(addres.low == 0x12345 && addres.high == 0, "Div failed");
addres = i128_sdiv(i128(0x12345, UINT64_MAX), i128(1, 0));
TEST_ASSERT(addres.low == 0x12345 && addres.high == 0, "Div failed");
addres = i128_udiv(i128(UINT64_MAX, 0), i128(1, 0));
TEST_ASSERT(addres.low == UINT64_MAX && addres.high == 0, "Div failed");
addres = i128_sdiv(i128(UINT64_MAX - 1, UINT64_MAX - 1), i128(1, 0));
TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed %s", i128_to_string(addres, 10, true));
addres = i128_sdiv(i128(2, 0), i128(UINT64_MAX - 1, UINT64_MAX - 1));
printf("-- i128 Div okfefe %x.\n", (unsigned)-2);
TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed: %s %llx, %llx", i128_to_string(addres, 10, true), (unsigned long long)addres.high, (unsigned long long)addres.low);
printf("-- i128 Div ok.\n");
} }
void compiler_tests(void) void compiler_tests(void)
{ {
symtab_init(0x100000); symtab_init(0x100000);
test_file(); test_file();
test128();
run_arena_allocator_tests(); run_arena_allocator_tests();
exit(0); exit(0);

View File

@@ -43,7 +43,8 @@
#define TODO FATAL_ERROR("TODO reached"); #define TODO FATAL_ERROR("TODO reached");
#define TEST_ASSERT(_condition, _string, ...) while (!(_condition)) { FATAL_ERROR(_string, ##__VA_ARGS__); } #define TEST_ASSERT(condition_, string_) while (!(condition_)) { FATAL_ERROR(string_); }
#define TEST_ASSERTF(condition_, string_, ...) while (!(condition_)) { char* str_; asprintf(&str_, string_, __VA_ARGS__); FATAL_ERROR(str_); }
#define EXPECT(_string, _value, _expected) \ #define EXPECT(_string, _value, _expected) \
do { long long __tempval1 = _value; long long __tempval2 = _expected; \ do { long long __tempval1 = _value; long long __tempval2 = _expected; \

View File

@@ -250,6 +250,17 @@ static inline bool is_hex(char c)
} }
} }
static inline int hex_nibble(char c)
{
static int conv[256] = {
['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4,
['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15,
['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15,
};
return conv[(unsigned char)c];
}
static inline bool is_whitespace(char c) static inline bool is_whitespace(char c)
{ {
switch (c) switch (c)

View File

@@ -1 +1 @@
#define COMPILER_VERSION "A238" #define COMPILER_VERSION "A239"

View File

@@ -294,6 +294,7 @@ def main():
else: else:
print("Error: Invalid path to tests: " + filepath) print("Error: Invalid path to tests: " + filepath)
usage() usage()
print("Found %d tests: %d / %d passed (%d skipped)." % (conf.numtests, conf.numsuccess, conf.numtests - conf.numskipped, conf.numskipped))
print("Found %d tests: %.1f%% (%d / %d) passed (%d skipped)." % (conf.numtests, 100 * conf.numsuccess / max(1, conf.numtests - conf.numskipped), conf.numsuccess, conf.numtests - conf.numskipped, conf.numskipped))
main() main()

View File

@@ -0,0 +1,6 @@
func void test()
{
for (int a @align(16) @align(16) = 0 ; a < 10; a++) // #error: Repeat of attribute 'align'
{
}
}

View File

@@ -0,0 +1,15 @@
// #target: x64-darwin
module reassign;
func void test()
{
var $Foo = double;
$Foo = int;
$Foo hello;
}
// #expect: reassign.ll
%hello = alloca i32, align 4
store i32 0, i32* %hello, align 4
ret void

View File

@@ -0,0 +1,17 @@
macro foo($Foo)
{
$Foo a;
return a;
}
func void test1()
{
var $Bar;
@foo($Bar); // #error: '$Bar' is not defined yet
}
func void test2()
{
var $Bar;
$Bar z; // #error: '$Bar' is not defined yet
}

View File

@@ -2,13 +2,13 @@ module foo;
func void a() func void a()
{ {
$typeof(9146744073709551615) ef; $typeof(9146744073709551615i64) ef;
int fffx = ef; // #error: 'long' to 'int' int fffx = ef; // #error: 'long' to 'int'
} }
func void b() func void b()
{ {
$typeof(9223372036854775809) ef; $typeof(9223372036854775809u64) ef;
int fffx = ef; // #error: 'ulong' to 'int' int fffx = ef; // #error: 'ulong' to 'int'
} }

View File

@@ -0,0 +1,23 @@
// #target: x64-darwin
enum HelloEnum
{
HELLO,
WORLD,
ELLOWORLD,
}
func void test()
{
HelloEnum h = WORLD;
h = ELLOWORLD;
}
/* #expect: simple_inference.ll
define void @simple_inference.test() #0 {
entry:
%h = alloca i32, align 4
store i32 1, i32* %h, align 4
store i32 2, i32* %h, align 4
ret void
}

View File

@@ -0,0 +1,5 @@
func void test()
{
int! x = 0;
int! z = x << 100; // #error: shift exceeds bitsize of 'int'
}

View File

@@ -0,0 +1,124 @@
// #target: x64-darwin
module test;
struct Foo
{
int x, y;
}
errtype MyErr
{
FOO
}
extern func int printf(char *c, ...);
func void main()
{
int! z = 2;
Foo*! w = &&Foo{ z, 0 };
printf("%d\n", w.x);
z = MyErr.FOO!;
w = &&Foo{ z, 0 };
printf("Not visible: %d\n", w.x);
}
/* #expect: test.ll
%Foo = type { i32, i32 }
@Foo = linkonce_odr constant i8 1
@"test.MyErr$elements" = linkonce_odr constant [1 x i8*] zeroinitializer
@MyErr = linkonce_odr constant i8 1
@.str = private constant [4 x i8] c"%d\0A\00", align 1
@.str.1 = private constant [17 x i8] c"Not visible: %d\0A\00", align 1
; Function Attrs: nounwind
declare i32 @printf(i8*, ...) #0
; Function Attrs: nounwind
define void @main() #0 {
entry:
%z = alloca i32, align 4
%z.f = alloca i64, align 8
%w = alloca %Foo*, align 8
%w.f = alloca i64, align 8
%literal = alloca %Foo, align 4
%literal5 = alloca %Foo, align 4
store i64 0, i64* %z.f, align 8
store i32 2, i32* %z, align 4
store i64 0, i64* %z.f, align 8
%0 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 0
%1 = load i64, i64* %z.f, align 8
%not_err = icmp eq i64 %1, 0
br i1 %not_err, label %after_check, label %error
error: ; preds = %entry
store i64 %1, i64* %w.f, align 8
br label %after_assign
after_check: ; preds = %entry
%2 = load i32, i32* %z, align 4
store i32 %2, i32* %0, align 4
%3 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 1
store i32 0, i32* %3, align 4
store %Foo* %literal, %Foo** %w, align 8
store i64 0, i64* %w.f, align 8
br label %after_assign
after_assign: ; preds = %after_check, %error
%4 = load i64, i64* %w.f, align 8
%not_err1 = icmp eq i64 %4, 0
br i1 %not_err1, label %after_check2, label %voiderr
after_check2: ; preds = %after_assign
%5 = load %Foo*, %Foo** %w, align 8
%6 = getelementptr inbounds %Foo, %Foo* %5, i32 0, i32 0
%7 = load i32, i32* %6, align 8
%8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %7)
br label %voiderr
voiderr: ; preds = %after_check2, %after_assign
store i64 ptrtoint ([1 x i8*]* @"test.MyErr$elements" to i64), i64* %z.f, align 8
br label %after_assign3
after_assign3: ; preds = %voiderr
br label %voiderr4
voiderr4: ; preds = %after_assign3
%9 = getelementptr inbounds %Foo, %Foo* %literal5, i32 0, i32 0
%10 = load i64, i64* %z.f, align 8
%not_err6 = icmp eq i64 %10, 0
br i1 %not_err6, label %after_check8, label %error7
error7: ; preds = %voiderr4
store i64 %10, i64* %w.f, align 8
br label %after_assign9
after_check8: ; preds = %voiderr4
%11 = load i32, i32* %z, align 4
store i32 %11, i32* %9, align 4
%12 = getelementptr inbounds %Foo, %Foo* %literal5, i32 0, i32 1
store i32 0, i32* %12, align 4
store %Foo* %literal5, %Foo** %w, align 8
store i64 0, i64* %w.f, align 8
br label %after_assign9
after_assign9: ; preds = %after_check8, %error7
br label %voiderr10
voiderr10: ; preds = %after_assign9
%13 = load i64, i64* %w.f, align 8
%not_err11 = icmp eq i64 %13, 0
br i1 %not_err11, label %after_check12, label %voiderr13
after_check12: ; preds = %voiderr10
%14 = load %Foo*, %Foo** %w, align 8
%15 = getelementptr inbounds %Foo, %Foo* %14, i32 0, i32 0
%16 = load i32, i32* %15, align 8
%17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 %16)
br label %voiderr13
voiderr13: ; preds = %after_check12, %voiderr10
ret void
}

View File

@@ -0,0 +1,24 @@
module test;
struct Foo
{
int x, y;
}
errtype MyErr
{
FOO
}
extern func int printf(char *c, ...);
func void main()
{
int! z = 2;
Foo*! w = &&{ z, 0 }; // #error: casting 'int[2]*' to 'Foo*' is not permitted
}
func void test()
{
int! z = 2;
Foo*! w = &&Foo!{ z, 0 }; // #error: please remove the '!'
}

View File

@@ -1,12 +1,12 @@
func void syntaxErrors() func void syntaxErrors()
{ {
int! i = 0; int! i = 0;
while (i + 1) {} // #error: 'int!' cannot be converted into 'bool' while (i + 1) {} // #error: 'int!' cannot be converted to 'bool'
if (i + 1) {} // #error: 'int!' cannot be converted into 'bool' if (i + 1) {} // #error: 'int!' cannot be converted to 'bool'
for (int x = i;;) {} // #error: 'int!' cannot be converted into 'int'. for (int x = i;;) {} // #error: 'int!' cannot be converted to 'int'.
for (int x = 0; x < i + 1;) {} // #error: 'bool!' cannot be converted into 'bool' for (int x = 0; x < i + 1;) {} // #error: 'bool!' cannot be converted to 'bool'
for (int x = 0; x < 10; x += i + 1) {} // #error: 'int!' cannot be converted into 'int' for (int x = 0; x < 10; x += i + 1) {} // #error: 'int!' cannot be converted to 'int'
switch (i + 1) // #error: 'int!' cannot be converted into 'int' switch (i + 1) // #error: 'int!' cannot be converted to 'int'
{ {
default: default:
i + 1; i + 1;

View File

@@ -50,7 +50,6 @@ entry:
%a.f = alloca i64, align 8 %a.f = alloca i64, align 8
%err = alloca i64, align 8 %err = alloca i64, align 8
%retparam = alloca i32, align 4 %retparam = alloca i32, align 4
store i64 0, i64* %a.f, align 8
store i32 123, i32* %a, align 4 store i32 123, i32* %a, align 4
store i64 0, i64* %a.f, align 8 store i64 0, i64* %a.f, align 8
br label %testblock br label %testblock

View File

@@ -88,6 +88,6 @@ func void test10()
} }
else else
{ {
int g = a; // #error: 'int!' cannot be converted into 'int' int g = a; // #error: 'int!' cannot be converted to 'int'
} }
} }

View File

@@ -0,0 +1,145 @@
// #target: x64-darwin
module test;
extern func void printf(char*, ...);
func void main()
{
test();
test2();
test3();
}
func void test()
{
int f = 3;
int* x = &(((f)));
int* h = &&(f++);
printf("x = %d (4), h = %d (3)\n", *x, *h);
}
const int XX = 314;
func void test2()
{
int* w = &XX;
printf("w = %d (314)\n", *w);
}
struct Foo
{
int x;
int y;
}
func void test3()
{
Foo h = { 345, 555 };
int* zx = &h.x;
int* zy = &h.y;
int[3] arr = { 333, 444, 999 };
printf("zx = %d (345) zy = %d (555)\n", *zx, *zy);
arr[0]--;
arr[1]--;
arr[2]--;
int* d = &arr[2];
int[]* e = &&arr[1..2];
printf("d = %d (998) e = %d (443)\n", *d, (*e)[0]);
}
/* #expect: test.ll
define void @main() #0 {
entry:
call void @test.test()
call void @test.test2()
call void @test.test3()
ret void
}
; Function Attrs: nounwind
define void @test.test() #0 {
entry:
%f = alloca i32, align 4
%x = alloca i32*, align 8
%h = alloca i32*, align 8
%taddr = alloca i32, align 4
store i32 3, i32* %f, align 4
store i32* %f, i32** %x, align 8
%0 = load i32, i32* %f, align 4
%add = add i32 %0, 1
store i32 %add, i32* %f, align 4
store i32 %0, i32* %taddr, align 4
store i32* %taddr, i32** %h, align 8
%1 = load i32*, i32** %x, align 8
%2 = load i32, i32* %1, align 8
%3 = load i32*, i32** %h, align 8
%4 = load i32, i32* %3, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str, i32 0, i32 0), i32 %2, i32 %4)
ret void
}
; Function Attrs: nounwind
define void @test.test2() #0 {
entry:
%w = alloca i32*, align 8
store i32* @test.XX, i32** %w, align 8
%0 = load i32*, i32** %w, align 8
%1 = load i32, i32* %0, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.1, i32 0, i32 0), i32 %1)
ret void
}
; Function Attrs: nounwind
define void @test.test3() #0 {
entry:
%h = alloca %Foo, align 4
%zx = alloca i32*, align 8
%zy = alloca i32*, align 8
%arr = alloca [3 x i32], align 4
%d = alloca i32*, align 8
%e = alloca %"int[]"*, align 8
%taddr = alloca %"int[]", align 8
%0 = bitcast %Foo* %h to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Foo* @.__const to i8*), i32 8, i1 false)
%1 = getelementptr inbounds %Foo, %Foo* %h, i32 0, i32 0
store i32* %1, i32** %zx, align 8
%2 = getelementptr inbounds %Foo, %Foo* %h, i32 0, i32 1
store i32* %2, i32** %zy, align 8
%3 = bitcast [3 x i32]* %arr to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %3, i8* align 4 bitcast ([3 x i32]* @.__const.2 to i8*), i32 12, i1 false)
%4 = load i32*, i32** %zx, align 8
%5 = load i32, i32* %4, align 8
%6 = load i32*, i32** %zy, align 8
%7 = load i32, i32* %6, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @.str.3, i32 0, i32 0), i32 %5, i32 %7)
%arridx = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 0
%8 = load i32, i32* %arridx, align 4
%sub = sub i32 %8, 1
store i32 %sub, i32* %arridx, align 4
%arridx1 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 1
%9 = load i32, i32* %arridx1, align 4
%sub2 = sub i32 %9, 1
store i32 %sub2, i32* %arridx1, align 4
%arridx3 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2
%10 = load i32, i32* %arridx3, align 4
%sub4 = sub i32 %10, 1
store i32 %sub4, i32* %arridx3, align 4
%arridx5 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2
store i32* %arridx5, i32** %d, align 8
%11 = bitcast [3 x i32]* %arr to i32*
%offset = getelementptr inbounds i32, i32* %11, i64 1
%12 = insertvalue %"int[]" undef, i32* %offset, 0
%13 = insertvalue %"int[]" %12, i64 2, 1
store %"int[]" %13, %"int[]"* %taddr, align 8
store %"int[]"* %taddr, %"int[]"** %e, align 8
%14 = load i32*, i32** %d, align 8
%15 = load i32, i32* %14, align 8
%16 = load %"int[]"*, %"int[]"** %e, align 8
%subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %16, i32 0, i32 0
%saptr = load i32*, i32** %subarrayptr, align 8
%sarridx = getelementptr inbounds i32, i32* %saptr, i64 0
%17 = load i32, i32* %sarridx, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.4, i32 0, i32 0), i32 %15, i32 %17)
ret void
}

View File

@@ -0,0 +1,78 @@
func void test()
{
int f;
int* x = &(((f)));
int* h = &&(f++);
int* z = &(f++); // #error: To take the address of a temporary value, use '&&' instead of '&'
}
func void test2()
{
int f;
var $foo;
int* x = &$foo; // #error: It's not possible to take the address of a compile time value
}
int he;
macro int hello()
{
return he;
}
func void test3()
{
int* x = &@hello(); // #error: To take the address of a temporary value, use '&&' instead of '&'
}
func void test3b()
{
int* x = &hello; // #error: It is not possible to take the address of a macro.
}
const X = 2;
const int XX = 3;
func void test4()
{
int* w = &XX;
}
func void test5()
{
int* z = &X; // #error: The constant is not typed, either type it or use && to take the reference to a temporary.
}
struct Foo
{
int x;
int y;
}
define heh = he;
func void test6()
{
int* hee = &heh;
Foo h;
int* z = &h.x;
int[3] arr;
int* d = &arr[2];
int[]* e = &arr[1..2]; // #error: To take the address of a temporary value, use '&&' instead of '&'
}
define Baz = Foo;
define Bar = distinct int;
errtype Err { FOO }
union Un { int x; }
enum MyEnum { BAR }
func void test7()
{
&Baz; // #error: It is not possible to take the address of a type.
&Bar; // #error: It is not possible to take the address of a type.
&Err; // #error: It is not possible to take the address of a type.
&Un; // #error: It is not possible to take the address of a type.
&Err.FOO; // #error: To take the address of a temporary value, use '&&' instead of '&'
&MyEnum; // #error: It is not possible to take the address of a type.
&MyEnum.BAR; // #error: To take the address of a temporary value, use '&&' instead of '&'
}

View File

@@ -5,5 +5,5 @@ struct Struct
func void test1() func void test1()
{ {
int a = (Struct)(200); // #error: Cannot cast 'compint' to 'Struct' int a = (Struct)(200); // #error: Cannot cast 'int' to 'Struct'
} }

View File

@@ -0,0 +1,41 @@
func void test1()
{
short! a = 1;
try(-a);
short b = -a; // #error: 'int!' cannot be converted to 'short'.
}
func void test2()
{
int! a = 1;
try(-a);
int b = -a; // #error: 'int!' cannot be converted to 'int'
}
func void test3()
{
long! a = 1;
try(-a);
long b = -a; // #error: 'long!' cannot be converted to 'long'
}
func void test4()
{
short! a = 1;
try(~a);
short b = ~a; // #error: 'short!' cannot be converted to 'short'
}
func void test5()
{
int! a = 1;
try(~a);
int b = ~a; // #error: 'int!' cannot be converted to 'int'
}
func void test6()
{
long! a = 1;
try(~a);
long b = ~a; // #error: 'long!' cannot be converted to 'long'
}

View File

@@ -14,5 +14,5 @@ func void test1(ichar* cp)
func void test2(ichar* cp) func void test2(ichar* cp)
{ {
cp + 1; cp + 1;
cp * 1.0; // #error: Cannot multiply 'ichar*' by 'compfloat' cp * 1.0; // #error: 'ichar*' by 'double'
} }

View File

@@ -0,0 +1,16 @@
macro void hello($bar)
{
$bar;
}
const FOO = 1 + 2;
func void test()
{
var $Foo = int;
var $Bar = $Foo;
$Bar x;
@hello(1);
var $foo = 1;
$foo;
FOO;
}

View File

@@ -0,0 +1,189 @@
// #target: x64-darwin
errtype MyErr
{
TEST
}
macro foo(int x)
{
if (x) return x;
return MyErr.TEST!;
}
extern func void printf(char*, ...);
func void main()
{
int! a = @foo(1);
int! b = @foo((a + 3) ?? 2);
int! c = @foo(0);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
if (catch(c)) printf("c had error\n");
c = 3;
printf("c = %d\n", c);
}
// #expect: failable_catch.ll
define void @main() #0 {
entry:
%a = alloca i32, align 4
%a.f = alloca i64, align 8
%x = alloca i32, align 4
%blockret = alloca i32, align 4
%b = alloca i32, align 4
%b.f = alloca i64, align 8
%x1 = alloca i32, align 4
%blockret2 = alloca i32, align 4
%c = alloca i32, align 4
%c.f = alloca i64, align 8
%x8 = alloca i32, align 4
%blockret9 = alloca i32, align 4
%error_var = alloca i64, align 8
store i32 1, i32* %x, align 4
%0 = load i32, i32* %x, align 4
%intbool = icmp ne i32 %0, 0
br i1 %intbool, label %if.then, label %if.exit
if.then: ; preds = %entry
%1 = load i32, i32* %x, align 4
store i32 %1, i32* %blockret, align 4
br label %expr_block.exit
if.exit: ; preds = %entry
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %a.f, align 8
br label %after_assign
expr_block.exit: ; preds = %if.then
%2 = load i32, i32* %blockret, align 4
store i32 %2, i32* %a, align 4
store i64 0, i64* %a.f, align 8
br label %after_assign
after_assign: ; preds = %expr_block.exit, %if.exit
%3 = load i64, i64* %a.f, align 8
%not_err = icmp eq i64 %3, 0
br i1 %not_err, label %after_check, label %else_block
after_check: ; preds = %after_assign
%4 = load i32, i32* %a, align 4
%add = add i32 %4, 3
br label %phi_block
else_block: ; preds = %after_assign
br label %phi_block
phi_block: ; preds = %else_block, %after_check
%val = phi i32 [ %add, %after_check ], [ 2, %else_block ]
store i32 %val, i32* %x1, align 4
%5 = load i32, i32* %x1, align 4
%intbool3 = icmp ne i32 %5, 0
br i1 %intbool3, label %if.then4, label %if.exit5
if.then4: ; preds = %phi_block
%6 = load i32, i32* %x1, align 4
store i32 %6, i32* %blockret2, align 4
br label %expr_block.exit6
if.exit5: ; preds = %phi_block
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %b.f, align 8
br label %after_assign7
expr_block.exit6: ; preds = %if.then4
%7 = load i32, i32* %blockret2, align 4
store i32 %7, i32* %b, align 4
store i64 0, i64* %b.f, align 8
br label %after_assign7
after_assign7: ; preds = %expr_block.exit6, %if.exit5
store i32 0, i32* %x8, align 4
%8 = load i32, i32* %x8, align 4
%intbool10 = icmp ne i32 %8, 0
br i1 %intbool10, label %if.then11, label %if.exit12
if.then11: ; preds = %after_assign7
%9 = load i32, i32* %x8, align 4
store i32 %9, i32* %blockret9, align 4
br label %expr_block.exit13
if.exit12: ; preds = %after_assign7
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %c.f, align 8
br label %after_assign14
expr_block.exit13: ; preds = %if.then11
%10 = load i32, i32* %blockret9, align 4
store i32 %10, i32* %c, align 4
store i64 0, i64* %c.f, align 8
br label %after_assign14
after_assign14: ; preds = %expr_block.exit13, %if.exit12
%11 = load i64, i64* %a.f, align 8
%not_err15 = icmp eq i64 %11, 0
br i1 %not_err15, label %after_check16, label %voiderr
after_check16: ; preds = %after_assign14
%12 = load i32, i32* %a, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %12)
br label %voiderr
voiderr: ; preds = %after_check16, %after_assign14
%13 = load i64, i64* %b.f, align 8
%not_err17 = icmp eq i64 %13, 0
br i1 %not_err17, label %after_check18, label %voiderr19
after_check18: ; preds = %voiderr
%14 = load i32, i32* %b, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %14)
br label %voiderr19
voiderr19: ; preds = %after_check18, %voiderr
%15 = load i64, i64* %c.f, align 8
%not_err20 = icmp eq i64 %15, 0
br i1 %not_err20, label %after_check21, label %voiderr22
after_check21: ; preds = %voiderr19
%16 = load i32, i32* %c, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i32 %16)
br label %voiderr22
voiderr22: ; preds = %after_check21, %voiderr19
store i64 0, i64* %error_var, align 8
%17 = load i64, i64* %c.f, align 8
%not_err23 = icmp eq i64 %17, 0
br i1 %not_err23, label %after_check24, label %error
error: ; preds = %voiderr22
store i64 %17, i64* %error_var, align 8
br label %noerr_block
after_check24: ; preds = %voiderr22
br label %noerr_block
noerr_block: ; preds = %after_check24, %error
%18 = load i64, i64* %error_var, align 8
%neq = icmp ne i64 %18, 0
br i1 %neq, label %if.then25, label %if.exit26
if.then25: ; preds = %noerr_block
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0))
br label %if.exit26
if.exit26: ; preds = %if.then25, %noerr_block
store i32 3, i32* %c, align 4
store i64 0, i64* %c.f, align 8
%19 = load i64, i64* %c.f, align 8
%not_err27 = icmp eq i64 %19, 0
br i1 %not_err27, label %after_check28, label %voiderr29
after_check28: ; preds = %if.exit26
%20 = load i32, i32* %c, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.4, i32 0, i32 0), i32 %20)
br label %voiderr29
voiderr29: ; preds = %after_check28, %if.exit26
ret void
}

View File

@@ -1,4 +1,4 @@
func void test() func void test()
{ {
float x = 0x7FFFFFFFFFFF.0p+400; // #error: The value '3.63419e+134' is out of range for 'float', so you need an explicit cast to truncate the value float x = 0x7FFFFFFFFFFF.0p+400; // #error: The value '3.63419e+134' is out of range for 'float'
} }

View File

@@ -140,7 +140,7 @@ func void main()
} }
list.free(); list.free();
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, MyEnum.elements); printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, (int)(MyEnum.elements));
int max = MyEnum.max; int max = MyEnum.max;
int min = MyEnum.min; int min = MyEnum.min;
@@ -245,7 +245,7 @@ func Type getValue(Blob blob)
return blob.a; return blob.a;
} }
// #expect: test.ll /* #expect: test.ll
%Blob = type { i32 } %Blob = type { i32 }
%Blob.0 = type { double } %Blob.0 = type { double }
@@ -364,7 +364,7 @@ entry:
store i32 0, i32* %sum, align 4 store i32 0, i32* %sum, align 4
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
%2 = load i64, i64* %len, align 8 %2 = load i64, i64* %len, align 8
%eq = icmp eq i64 %2, 0 %eq = icmp eq i64 0, %2
br i1 %eq, label %if.then, label %if.exit br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %entry if.then: ; preds = %entry

View File

@@ -140,7 +140,7 @@ func void main()
} }
list.free(); list.free();
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, MyEnum.elements); printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, (int)(MyEnum.elements));
int max = MyEnum.max; int max = MyEnum.max;
int min = MyEnum.min; int min = MyEnum.min;
@@ -358,7 +358,7 @@ entry:
store i32 0, i32* %sum, align 4 store i32 0, i32* %sum, align 4
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
%3 = load i64, i64* %len, align 8 %3 = load i64, i64* %len, align 8
%eq = icmp eq i64 %3, 0 %eq = icmp eq i64 0, %3
br i1 %eq, label %if.then, label %if.exit br i1 %eq, label %if.then, label %if.exit
if.then: if.then:

View File

@@ -5,7 +5,7 @@ char[] str3 = "hello";
int[2] a1 = { 1, 2 }; int[2] a1 = { 1, 2 };
int[2] a2 = 30; // #error: 'compint' into 'int[2]' int[2] a2 = 30; // #error: 'int' into 'int[2]'
// TODO int[2] a3 = a1; // TODO int[2] a3 = a1;
ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers

View File

@@ -1,9 +1,10 @@
// #target: x64-darwin
module fasta; module fasta;
const IM = 139968; const IM = 139968u;
const IA = 3877; const IA = 3877u;
const IC = 29573; const IC = 29573u;
const SEED = 42; const SEED = 42u;
uint seed = SEED; uint seed = SEED;
@@ -108,10 +109,10 @@ func void main(int argc, char **argv)
%"char[]" = type { i8*, i64 } %"char[]" = type { i8*, i64 }
%"double[]" = type { double*, i64 } %"double[]" = type { double*, i64 }
@fasta.IM = constant i32 139968, align 1 @fasta.IM = constant i32 139968, align 4
@fasta.IA = constant i32 3877, align 1 @fasta.IA = constant i32 3877, align 4
@fasta.IC = constant i32 29573, align 1 @fasta.IC = constant i32 29573, align 4
@fasta.SEED = constant i32 42, align 1 @fasta.SEED = constant i32 42, align 4
@fasta.seed = global i32 42, align 4 @fasta.seed = global i32 42, align 4
@.str = private constant [288 x i8] c"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA\00", align 1 @.str = private constant [288 x i8] c"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA\00", align 1
@fasta.alu = protected global %"char[]" { i8* getelementptr inbounds ([288 x i8], [288 x i8]* @.str, i32 0, i32 0), i64 287 }, align 8 @fasta.alu = protected global %"char[]" { i8* getelementptr inbounds ([288 x i8], [288 x i8]* @.str, i32 0, i32 0), i64 287 }, align 8
@@ -123,7 +124,7 @@ func void main(int argc, char **argv)
@fasta.homosapiens = global %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0), i64 4 }, align 8 @fasta.homosapiens = global %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0), i64 4 }, align 8
@.taddr.13 = private hidden global [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8 @.taddr.13 = private hidden global [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8
@fasta.homosapiens_p = global %"double[]" { double* getelementptr inbounds ([4 x double], [4 x double]* @.taddr.13, i32 0, i32 0), i64 4 }, align 8 @fasta.homosapiens_p = global %"double[]" { double* getelementptr inbounds ([4 x double], [4 x double]* @.taddr.13, i32 0, i32 0), i64 4 }, align 8
@fasta.LINELEN = constant i32 60, align 1 @fasta.LINELEN = constant i32 60, align 4
@.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", align 1 @.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", align 1
@.str.15 = private constant [26 x i8] c">TWO IUB ambiguity codes\0A\00", align 1 @.str.15 = private constant [26 x i8] c">TWO IUB ambiguity codes\0A\00", align 1
@.str.16 = private constant [31 x i8] c">THREE Homo sapiens frequency\0A\00", align 1 @.str.16 = private constant [31 x i8] c">THREE Homo sapiens frequency\0A\00", align 1
@@ -229,7 +230,7 @@ entry:
%symb = alloca %"char[]", align 8 %symb = alloca %"char[]", align 8
%probability = alloca %"double[]", align 8 %probability = alloca %"double[]", align 8
%n = alloca i32, align 4 %n = alloca i32, align 4
%len = alloca i32, align 4 %len5 = alloca i32, align 4
%i = alloca i32, align 4 %i = alloca i32, align 4
%v = alloca double, align 8 %v = alloca double, align 8
%j = alloca i32, align 4 %j = alloca i32, align 4
@@ -244,97 +245,103 @@ entry:
%hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1 %hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1
store i64 %3, i64* %hi3, align 8 store i64 %3, i64* %hi3, align 8
store i32 %4, i32* %n, align 4 store i32 %4, i32* %n, align 4
%len = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 1
%5 = load i64, i64* %len, align 8
%len4 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1 %len4 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1
%5 = load i64, i64* %len4, align 8 %6 = load i64, i64* %len4, align 8
%uisitrunc = trunc i64 %5 to i32 %eq = icmp eq i64 %5, %6
store i32 %uisitrunc, i32* %len, align 4 call void @llvm.assume(i1 %eq)
%len6 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1
%7 = load i64, i64* %len6, align 8
%uisitrunc = trunc i64 %7 to i32
store i32 %uisitrunc, i32* %len5, align 4
store i32 0, i32* %i, align 4 store i32 0, i32* %i, align 4
br label %for.cond br label %for.cond
for.cond: ; preds = %for.inc15, %entry for.cond: ; preds = %for.inc18, %entry
%6 = load i32, i32* %i, align 4 %8 = load i32, i32* %i, align 4
%7 = load i32, i32* %n, align 4 %9 = load i32, i32* %n, align 4
%lt = icmp slt i32 %6, %7 %lt = icmp slt i32 %8, %9
br i1 %lt, label %for.body, label %for.exit17 br i1 %lt, label %for.body, label %for.exit20
for.body: ; preds = %for.cond for.body: ; preds = %for.cond
%8 = call float @fasta.fasta_rand(float 1.000000e+00) %10 = call float @fasta.fasta_rand(float 1.000000e+00)
%fpfpext = fpext float %8 to double %fpfpext = fpext float %10 to double
store double %fpfpext, double* %v, align 8 store double %fpfpext, double* %v, align 8
store i32 0, i32* %j, align 4 store i32 0, i32* %j, align 4
br label %for.cond5 br label %for.cond7
for.cond5: ; preds = %for.inc, %for.body for.cond7: ; preds = %for.inc, %for.body
%9 = load i32, i32* %j, align 4 %11 = load i32, i32* %j, align 4
%10 = load i32, i32* %len, align 4 %12 = load i32, i32* %len5, align 4
%sub = sub i32 %10, 1 %sub = sub i32 %12, 1
%lt6 = icmp slt i32 %9, %sub %lt8 = icmp slt i32 %11, %sub
br i1 %lt6, label %for.body7, label %for.exit br i1 %lt8, label %for.body9, label %for.exit
for.body7: ; preds = %for.cond5 for.body9: ; preds = %for.cond7
%11 = load double, double* %v, align 8 %13 = load double, double* %v, align 8
%subarrayptr = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 0 %subarrayptr = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 0
%saptr = load double*, double** %subarrayptr, align 8 %saptr = load double*, double** %subarrayptr, align 8
%12 = load i32, i32* %j, align 4 %14 = load i32, i32* %j, align 4
%sisiext = sext i32 %12 to i64 %sisiext = sext i32 %14 to i64
%sarridx = getelementptr inbounds double, double* %saptr, i64 %sisiext %sarridx = getelementptr inbounds double, double* %saptr, i64 %sisiext
%13 = load double, double* %sarridx, align 8 %15 = load double, double* %sarridx, align 8
%fsub = fsub double %11, %13 %fsub = fsub double %13, %15
store double %fsub, double* %v, align 8 store double %fsub, double* %v, align 8
%14 = load double, double* %v, align 8 %16 = load double, double* %v, align 8
%lt8 = fcmp olt double %14, 0.000000e+00 %lt10 = fcmp olt double %16, 0.000000e+00
br i1 %lt8, label %if.then, label %if.exit br i1 %lt10, label %if.then, label %if.exit
if.then: ; preds = %for.body7 if.then: ; preds = %for.body9
br label %for.exit br label %for.exit
if.exit: ; preds = %for.body7 if.exit: ; preds = %for.body9
br label %for.inc br label %for.inc
for.inc: ; preds = %if.exit for.inc: ; preds = %if.exit
%15 = load i32, i32* %j, align 4 %17 = load i32, i32* %j, align 4
%add = add i32 %15, 1 %add = add i32 %17, 1
store i32 %add, i32* %j, align 4 store i32 %add, i32* %j, align 4
br label %for.cond5 br label %for.cond7
for.exit: ; preds = %if.then, %for.cond5 for.exit: ; preds = %if.then, %for.cond7
%subarrayptr9 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 0 %subarrayptr11 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 0
%saptr10 = load i8*, i8** %subarrayptr9, align 8 %saptr12 = load i8*, i8** %subarrayptr11, align 8
%16 = load i32, i32* %j, align 4 %18 = load i32, i32* %j, align 4
%sisiext11 = sext i32 %16 to i64 %sisiext13 = sext i32 %18 to i64
%sarridx12 = getelementptr inbounds i8, i8* %saptr10, i64 %sisiext11 %sarridx14 = getelementptr inbounds i8, i8* %saptr12, i64 %sisiext13
%17 = load i8, i8* %sarridx12, align 1 %19 = load i8, i8* %sarridx14, align 1
%uisiext = zext i8 %17 to i32 %uisiext = zext i8 %19 to i32
call void @putchar(i32 %uisiext) call void @putchar(i32 %uisiext)
%18 = load i32, i32* %i, align 4 %20 = load i32, i32* %i, align 4
%smod = srem i32 %18, 60 %smod = srem i32 %20, 60
%eq = icmp eq i32 %smod, 59 %eq15 = icmp eq i32 %smod, 59
br i1 %eq, label %if.then13, label %if.exit14 br i1 %eq15, label %if.then16, label %if.exit17
if.then13: ; preds = %for.exit if.then16: ; preds = %for.exit
call void @putchar(i32 10) call void @putchar(i32 10)
br label %if.exit14 br label %if.exit17
if.exit14: ; preds = %if.then13, %for.exit if.exit17: ; preds = %if.then16, %for.exit
br label %for.inc15 br label %for.inc18
for.inc15: ; preds = %if.exit14 for.inc18: ; preds = %if.exit17
%19 = load i32, i32* %i, align 4 %21 = load i32, i32* %i, align 4
%add16 = add i32 %19, 1 %add19 = add i32 %21, 1
store i32 %add16, i32* %i, align 4 store i32 %add19, i32* %i, align 4
br label %for.cond br label %for.cond
for.exit17: ; preds = %for.cond for.exit20: ; preds = %for.cond
%20 = load i32, i32* %i, align 4 %22 = load i32, i32* %i, align 4
%smod18 = srem i32 %20, 60 %smod21 = srem i32 %22, 60
%neq = icmp ne i32 %smod18, 0 %neq = icmp ne i32 %smod21, 0
br i1 %neq, label %if.then19, label %if.exit20 br i1 %neq, label %if.then22, label %if.exit23
if.then19: ; preds = %for.exit17 if.then22: ; preds = %for.exit20
call void @putchar(i32 10) call void @putchar(i32 10)
br label %if.exit20 br label %if.exit23
if.exit20: ; preds = %if.then19, %for.exit17 if.exit23: ; preds = %if.then22, %for.exit20
ret void ret void
} }
@@ -383,4 +390,4 @@ if.exit: ; preds = %if.then, %entry
%mul10 = mul i32 %11, 5 %mul10 = mul i32 %11, 5
call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10) call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10)
ret void ret void
} }

View File

@@ -31,7 +31,7 @@ func int test()
} }
// #expect: general_tests.ll /* #expect: general_tests.ll
%Baz = type { double } %Baz = type { double }
%Bar = type { i32, i32 } %Bar = type { i32, i32 }
@@ -52,15 +52,14 @@ entry:
%a = alloca [0 x i32], align 4 %a = alloca [0 x i32], align 4
%foo2 = alloca i32, align 4 %foo2 = alloca i32, align 4
%str = alloca i8*, align 8 %str = alloca i8*, align 8
%literal = alloca [1 x i8*], align 8
%x = alloca i8, align 1 %x = alloca i8, align 1
%literal1 = alloca [3 x i32], align 4 %literal = alloca [3 x i32], align 4
%b = alloca %Bar, align 4 %b = alloca %Bar, align 4
%z = alloca %Baz, align 8 %z = alloca %Baz, align 8
%sub = alloca %"int[]", align 8 %sub = alloca %"int[]", align 8
%literal2 = alloca [0 x i32], align 4 %literal1 = alloca [0 x i32], align 4
%foo = alloca %"Bar[]", align 8 %foo = alloca %"Bar[]", align 8
%literal3 = alloca [0 x %Bar], align 4 %literal2 = alloca [0 x %Bar], align 4
%baz = alloca [3 x %Baz], align 16 %baz = alloca [3 x %Baz], align 16
%0 = bitcast %Baz* %ffe to i8* %0 = bitcast %Baz* %ffe to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false) call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false)
@@ -69,40 +68,35 @@ entry:
%2 = bitcast [0 x i32]* %a to i8* %2 = bitcast [0 x i32]* %a to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 0, i1 false) call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 0, i1 false)
store i32 33, i32* %foo2, align 4 store i32 33, i32* %foo2, align 4
%3 = getelementptr inbounds i8*, [1 x i8*]* %literal, i32 0 store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8** %str, align 8
store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8** %3, align 8 %3 = getelementptr inbounds i32, [3 x i32]* %literal, i32 0
%arridx = getelementptr inbounds [1 x i8*], [1 x i8*]* %literal, i64 0, i64 0 store i32 1, i32* %3, align 4
%4 = load i8*, i8** %arridx, align 8 %4 = getelementptr inbounds i32, [3 x i32]* %literal, i32 1
store i8* %4, i8** %str, align 8 store i32 2, i32* %4, align 4
%5 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 0 %5 = getelementptr inbounds i32, [3 x i32]* %literal, i32 2
store i32 1, i32* %5, align 4 store i32 3, i32* %5, align 4
%6 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 1 %6 = bitcast [3 x i32]* %literal to i32*
store i32 2, i32* %6, align 4 %7 = insertvalue %"int[]" undef, i32* %6, 0
%7 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 2 %8 = insertvalue %"int[]" %7, i64 3, 1
store i32 3, i32* %7, align 4 %len = extractvalue %"int[]" %8, 1
%8 = bitcast [3 x i32]* %literal1 to i32* %not = icmp eq i64 %len, 0
%9 = insertvalue %"int[]" undef, i32* %8, 0 %9 = zext i1 %not to i8
%10 = insertvalue %"int[]" %9, i64 3, 1 store i8 %9, i8* %x, align 1
%11 = extractvalue %"int[]" %10, 1 %10 = bitcast %Bar* %b to i8*
%neq = icmp ne i64 %11, 0 call void @llvm.memset.p0i8.i64(i8* align 4 %10, i8 0, i64 8, i1 false)
%not = xor i1 %neq, true %11 = bitcast %Baz* %z to i8*
%12 = zext i1 %not to i8 call void @llvm.memset.p0i8.i64(i8* align 8 %11, i8 0, i64 8, i1 false)
store i8 %12, i8* %x, align 1 store [0 x i32] zeroinitializer, [0 x i32]* %literal1, align 4
%13 = bitcast %Bar* %b to i8* %12 = bitcast [0 x i32]* %literal1 to i32*
call void @llvm.memset.p0i8.i64(i8* align 4 %13, i8 0, i64 8, i1 false) %13 = insertvalue %"int[]" undef, i32* %12, 0
%14 = bitcast %Baz* %z to i8* %14 = insertvalue %"int[]" %13, i64 0, 1
call void @llvm.memset.p0i8.i64(i8* align 8 %14, i8 0, i64 8, i1 false) store %"int[]" %14, %"int[]"* %sub, align 8
store [0 x i32] zeroinitializer, [0 x i32]* %literal2, align 4 store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal2, align 4
%15 = bitcast [0 x i32]* %literal2 to i32* %15 = bitcast [0 x %Bar]* %literal2 to %Bar*
%16 = insertvalue %"int[]" undef, i32* %15, 0 %16 = insertvalue %"Bar[]" undef, %Bar* %15, 0
%17 = insertvalue %"int[]" %16, i64 0, 1 %17 = insertvalue %"Bar[]" %16, i64 0, 1
store %"int[]" %17, %"int[]"* %sub, align 8 store %"Bar[]" %17, %"Bar[]"* %foo, align 8
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal3, align 4 %18 = bitcast [3 x %Baz]* %baz to i8*
%18 = bitcast [0 x %Bar]* %literal3 to %Bar* call void @llvm.memset.p0i8.i64(i8* align 16 %18, i8 0, i64 24, i1 false)
%19 = insertvalue %"Bar[]" undef, %Bar* %18, 0
%20 = insertvalue %"Bar[]" %19, i64 0, 1
store %"Bar[]" %20, %"Bar[]"* %foo, align 8
%21 = bitcast [3 x %Baz]* %baz to i8*
call void @llvm.memset.p0i8.i64(i8* align 16 %21, i8 0, i64 24, i1 false)
ret i32 1 ret i32 1
} }

View File

@@ -0,0 +1,28 @@
func void test()
{
char* c = { 1, 3, "hello"}[2];
int x;
int z = { 1, 3 }[x]; // #error: To subscript a compile time list a compile time integer index is needed
}
func void test2()
{
int z = { 1, 3 }[-1]; // #error: The index may not be negative
}
func void test3()
{
int z = { 1, 3 }[0xFFFF_FFFF_FFFF_FFFFu64]; // #error: The index is out of range.
}
func void test4()
{
int z = { 1, 3 }[2]; // #error: An index of '2' is out of range, a value between 0 and 1 was expected.
int z2 = { 1 }[2]; // #error: An index of '2' is out of range, a value of 0 was expected.
}
func void test5()
{
int z = { 1, 3 }[^4]; // #error: An index of '4' from the end is out of range, a value between 1 and 2 was expected
int z2 = { 1 }[^4]; // #error: An index of '4' from the end is out of range, a value of 1 was expected.
}

View File

@@ -81,9 +81,9 @@ entry:
%b = alloca %Bar, align 4 %b = alloca %Bar, align 4
%z = alloca %Baz, align 8 %z = alloca %Baz, align 8
%sub = alloca %"int[]", align 8 %sub = alloca %"int[]", align 8
%literal9 = alloca [0 x i32], align 4 %literal10 = alloca [0 x i32], align 4
%foo = alloca %"Bar[]", align 8 %foo = alloca %"Bar[]", align 8
%literal10 = alloca [0 x %Bar], align 4 %literal11 = alloca [0 x %Bar], align 4
%baz = alloca [3 x %Baz], align 16 %baz = alloca [3 x %Baz], align 16
%saptr = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 %saptr = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8
%sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 1 %sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 1
@@ -145,36 +145,35 @@ entry:
%30 = bitcast [3 x i32]* %literal7 to i32* %30 = bitcast [3 x i32]* %literal7 to i32*
%31 = insertvalue %"int[]" undef, i32* %30, 0 %31 = insertvalue %"int[]" undef, i32* %30, 0
%32 = insertvalue %"int[]" %31, i64 3, 1 %32 = insertvalue %"int[]" %31, i64 3, 1
%33 = extractvalue %"int[]" %32, 1 %len8 = extractvalue %"int[]" %32, 1
%neq = icmp ne i64 %33, 0 %not = icmp eq i64 %len8, 0
%not = xor i1 %neq, true %33 = zext i1 %not to i8
%34 = zext i1 %not to i8 store i8 %33, i8* %xy, align 1
store i8 %34, i8* %xy, align 1 %34 = load i8, i8* %xy, align 1
%35 = load i8, i8* %xy, align 1 %35 = trunc i8 %34 to i1
%36 = trunc i8 %35 to i1 %not9 = xor i1 %35, true
%not8 = xor i1 %36, true br i1 %not9, label %if.then, label %if.exit
br i1 %not8, label %if.then, label %if.exit
if.then: ; preds = %entry if.then: ; preds = %entry
%37 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3 %36 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3
br label %if.exit br label %if.exit
if.exit: ; preds = %if.then, %entry if.exit: ; preds = %if.then, %entry
%38 = bitcast %Bar* %b to i8* %37 = bitcast %Bar* %b to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %38, i8 0, i64 8, i1 false) call void @llvm.memset.p0i8.i64(i8* align 4 %37, i8 0, i64 8, i1 false)
%39 = bitcast %Baz* %z to i8* %38 = bitcast %Baz* %z to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %39, i8 0, i64 8, i1 false) call void @llvm.memset.p0i8.i64(i8* align 8 %38, i8 0, i64 8, i1 false)
store [0 x i32] zeroinitializer, [0 x i32]* %literal9, align 4 store [0 x i32] zeroinitializer, [0 x i32]* %literal10, align 4
%40 = bitcast [0 x i32]* %literal9 to i32* %39 = bitcast [0 x i32]* %literal10 to i32*
%41 = insertvalue %"int[]" undef, i32* %40, 0 %40 = insertvalue %"int[]" undef, i32* %39, 0
%42 = insertvalue %"int[]" %41, i64 0, 1 %41 = insertvalue %"int[]" %40, i64 0, 1
store %"int[]" %42, %"int[]"* %sub, align 8 store %"int[]" %41, %"int[]"* %sub, align 8
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal10, align 4 store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal11, align 4
%43 = bitcast [0 x %Bar]* %literal10 to %Bar* %42 = bitcast [0 x %Bar]* %literal11 to %Bar*
%44 = insertvalue %"Bar[]" undef, %Bar* %43, 0 %43 = insertvalue %"Bar[]" undef, %Bar* %42, 0
%45 = insertvalue %"Bar[]" %44, i64 0, 1 %44 = insertvalue %"Bar[]" %43, i64 0, 1
store %"Bar[]" %45, %"Bar[]"* %foo, align 8 store %"Bar[]" %44, %"Bar[]"* %foo, align 8
%46 = bitcast [3 x %Baz]* %baz to i8* %45 = bitcast [3 x %Baz]* %baz to i8*
call void @llvm.memset.p0i8.i64(i8* align 16 %46, i8 0, i64 24, i1 false) call void @llvm.memset.p0i8.i64(i8* align 16 %45, i8 0, i64 24, i1 false)
ret i32 1 ret i32 1
} }

View File

@@ -43,7 +43,7 @@ func void main()
} }
// #expect: withbody.ll /* #expect: withbody.ll
define i32 @withbody.Foo__mutate(%Foo* %0) define i32 @withbody.Foo__mutate(%Foo* %0)
entry: entry:

View File

@@ -0,0 +1,66 @@
// #target: x64-darwin
macro foo($Foo)
{
$Foo a;
return a;
}
define Bar = short;
func void test()
{
int x = @foo(int);
var $Foo = double;
double d = @foo($Foo);
double d2 = @foo($typeof(d));
short z = @foo(Bar);
}
/* #expect: type_params.ll
%x = alloca i32, align 4
%blockret = alloca i32, align 4
%a = alloca i32, align 4
%d = alloca double, align 8
%blockret1 = alloca double, align 8
%a2 = alloca double, align 8
%d2 = alloca double, align 8
%blockret4 = alloca double, align 8
%a5 = alloca double, align 8
%z = alloca i16, align 2
%blockret7 = alloca i16, align 2
%a8 = alloca i16, align 2
store i32 0, i32* %a, align 4
%0 = load i32, i32* %a, align 4
store i32 %0, i32* %blockret, align 4
br label %expr_block.exit
expr_block.exit: ; preds = %entry
%1 = load i32, i32* %blockret, align 4
store i32 %1, i32* %x, align 4
store double 0.000000e+00, double* %a2, align 8
%2 = load double, double* %a2, align 8
store double %2, double* %blockret1, align 8
br label %expr_block.exit3
expr_block.exit3: ; preds = %expr_block.exit
%3 = load double, double* %blockret1, align 8
store double %3, double* %d, align 8
store double 0.000000e+00, double* %a5, align 8
%4 = load double, double* %a5, align 8
store double %4, double* %blockret4, align 8
br label %expr_block.exit6
expr_block.exit6: ; preds = %expr_block.exit3
%5 = load double, double* %blockret4, align 8
store double %5, double* %d2, align 8
store i16 0, i16* %a8, align 2
%6 = load i16, i16* %a8, align 2
store i16 %6, i16* %blockret7, align 2
br label %expr_block.exit9
expr_block.exit9: ; preds = %expr_block.exit6
%7 = load i16, i16* %blockret7, align 2
store i16 %7, i16* %z, align 2
ret void
}

View File

@@ -4,7 +4,7 @@ func void test1()
{ {
char a = 1; char a = 1;
int b = 2; int b = 2;
char c = b > a ? 1 : 0; char c = b > a ? 1u8 : 0u8;
} }
// #expect: comparison_widening.ll // #expect: comparison_widening.ll

View File

@@ -0,0 +1,12 @@
module test;
func void test()
{
int[3]! x;
int g;
foreach (z : x) // #error: It's not possible to enumerate an expression of type 'int[3]!'
{
g += z;
x[0] = 1;
}
}

View File

@@ -1,66 +0,0 @@
module test;
func void test()
{
int[3]! x;
int g;
foreach (z : x)
{
g += z;
x[0] = 1;
}
}
// #expect: test.ll
entry:
%x = alloca [3 x i32], align 4
%x.f = alloca i64, align 8
%g = alloca i32, align 4
%idx = alloca i64, align 8
%z = alloca i32, align 4
store i64 0, i64* %x.f, align 8
%0 = bitcast [3 x i32]* %x to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 12, i1 false)
store i32 0, i32* %g, align 4
%1 = load i64, i64* %x.f, align 8
%not_err = icmp eq i64 %1, 0
br i1 %not_err, label %after_check, label %foreach.exit
after_check:
store i64 0, i64* %idx, align 8
br label %foreach.cond
foreach.cond:
%2 = load i64, i64* %idx, align 8
%lt = icmp ult i64 %2, 3
br i1 %lt, label %foreach.body, label %foreach.exit
foreach.body:
%3 = getelementptr inbounds i32, [3 x i32]* %x, i64 %2
%4 = load i32, i32* %3, align 4
store i32 %4, i32* %z, align 4
%5 = load i32, i32* %g, align 4
%6 = load i32, i32* %z, align 4
%add = add i32 %5, %6
store i32 %add, i32* %g, align 4
%7 = load i64, i64* %x.f, align 8
%not_err1 = icmp eq i64 %7, 0
br i1 %not_err1, label %after_check2, label %voiderr
after_check2:
%arridx = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 0
store i32 1, i32* %arridx, align 4
br label %voiderr
voiderr:
br label %foreach.inc
foreach.inc:
%8 = load i64, i64* %idx, align 8
%9 = add i64 %8, 1
store i64 %9, i64* %idx, align 8
br label %foreach.cond
foreach.exit:
ret void

View File

@@ -3,7 +3,7 @@ module test;
func void test1() func void test1()
{ {
bool! x = 0; bool! x = 0;
if (x) // #error: 'bool!' cannot be converted into 'bool' if (x) // #error: 'bool!' cannot be converted to 'bool'
{ {
x = 100; x = 100;
} }
@@ -12,7 +12,7 @@ func void test1()
func void test2() func void test2()
{ {
bool! x = 0; bool! x = 0;
while (x) // #error: 'bool!' cannot be converted into 'bool' while (x) // #error: 'bool!' cannot be converted to 'bool'
{ {
x = false; x = false;
} }
@@ -30,5 +30,5 @@ func void test3()
{ {
x = !x; x = !x;
} }
while (x); // #error: 'bool!' cannot be converted into 'bool' while (x); // #error: 'bool!' cannot be converted to 'bool'
} }

View File

@@ -148,7 +148,7 @@ switch.case10: ; preds = %next_if8
br label %switch.case13 br label %switch.case13
next_if11: ; preds = %next_if8 next_if11: ; preds = %next_if8
%eq12 = icmp eq i64 16, %4 %eq12 = icmp eq i64 15, %4
br i1 %eq12, label %switch.case13, label %next_if14 br i1 %eq12, label %switch.case13, label %next_if14
switch.case13: ; preds = %next_if11, %switch.case10 switch.case13: ; preds = %next_if11, %switch.case10

View File

@@ -1,3 +1,4 @@
// #target: x64-darwin
char *message0 = """ char *message0 = """
hello hello

View File

@@ -2,6 +2,6 @@ func void test2()
{ {
int[2] a = { 1, 2 }; int[2] a = { 1, 2 };
int[2] b = 30; // #error: 'compint' into 'int[2]' int[2] b = 30; // #error: 'int' into 'int[2]'
int[2] c = a; int[2] c = a;
} }

View File

@@ -1,4 +1,4 @@
enum EnumTestOverflow enum EnumTestOverflow
{ {
VALUE = 0x80000000, // #error: The value '2147483648' is out of range for 'int' VALUE = 0x80000000i64, // #error: Cannot narrow 'long' to 'int'
} }

View File

@@ -24,7 +24,7 @@ func Xe foo(Xe a)
{ {
a.c = 123; a.c = 123;
a.a = 39249; a.a = 39249;
a.b = 12301230123123; a.b = 12301230123123i64;
a.z = 1; a.z = 1;
return a; return a;
} }

View File

@@ -106,4 +106,6 @@ bool llvm_link_mingw(const char **args, int arg_count, const char** error_string
return llvm_link(MINGW, args, arg_count, error_string); return llvm_link(MINGW, args, arg_count, error_string);
} }
} }