mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Fixup of enum types.
This commit is contained in:
@@ -130,6 +130,33 @@ error OtherError
|
||||
FOO_BAR
|
||||
}
|
||||
|
||||
enum Inf
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C = 10000
|
||||
}
|
||||
|
||||
enum Inf2 : byte
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C = 129,
|
||||
}
|
||||
|
||||
typedef Inf as BooInf;
|
||||
|
||||
func void enumInferenceTest()
|
||||
{
|
||||
Inf x = Inf.A;
|
||||
x = BooInf.B;
|
||||
x = A;
|
||||
int x1 = 0;
|
||||
bool y = x1 == x1;
|
||||
Inf2 z = C;
|
||||
if (z == Inf2.A) return;
|
||||
}
|
||||
|
||||
func int jumptest()
|
||||
{
|
||||
if (1) goto LABELX;
|
||||
|
||||
@@ -726,5 +726,6 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
||||
if (canonical->type_kind == TYPE_POINTER) return sapt(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
}
|
||||
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||
return sema_type_mismatch(expr, canonical, cast_type);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,11 @@ typedef struct
|
||||
char* chars;
|
||||
int len;
|
||||
} string;
|
||||
Decl *enum_constant;
|
||||
Decl *error_constant;
|
||||
};
|
||||
// Valid type kinds:
|
||||
// bool, ints, floats, enum, error, string
|
||||
TypeKind kind;
|
||||
} ExprConst;
|
||||
|
||||
@@ -1150,6 +1154,21 @@ static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE
|
||||
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
||||
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
|
||||
bool type_may_have_method_functions(Type *type);
|
||||
|
||||
static inline Type *type_reduced(Type *type)
|
||||
{
|
||||
Type *canonical = type->canonical;
|
||||
if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical;
|
||||
if (canonical->type_kind == TYPE_ERROR) TODO;
|
||||
return canonical;
|
||||
}
|
||||
|
||||
static inline Type *type_reduced_from_expr(Expr *expr)
|
||||
{
|
||||
return type_reduced(expr->type);
|
||||
}
|
||||
|
||||
|
||||
static inline bool type_is_integer(Type *type)
|
||||
{
|
||||
assert(type == type->canonical);
|
||||
|
||||
@@ -180,7 +180,7 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff)
|
||||
{
|
||||
Type *type = expr->type->canonical;
|
||||
Type *type = type_reduced_from_expr(expr);
|
||||
LLVMTypeRef llvm_type = llvm_type(type);
|
||||
|
||||
if (type->type_kind == TYPE_POINTER)
|
||||
@@ -221,6 +221,7 @@ static inline LLVMValueRef gencontext_emit_post_inc_dec(GenContext *context, Exp
|
||||
|
||||
LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
Type *type = type_reduced_from_expr(expr->unary_expr.expr);
|
||||
switch (expr->unary_expr.operator)
|
||||
{
|
||||
case UNARYOP_ERROR:
|
||||
@@ -233,11 +234,11 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
|
||||
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "negmod");
|
||||
case UNARYOP_NEG:
|
||||
// TODO improve how unsigned numbers are negated.
|
||||
if (type_is_float(expr->unary_expr.expr->type->canonical))
|
||||
if (type_is_float(type))
|
||||
{
|
||||
return LLVMBuildFNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "fneg");
|
||||
}
|
||||
if (type_is_unsigned(expr->unary_expr.expr->type->canonical))
|
||||
if (type_is_unsigned(type))
|
||||
{
|
||||
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg");
|
||||
}
|
||||
@@ -246,7 +247,7 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
|
||||
case UNARYOP_ADDR:
|
||||
return gencontext_emit_address(context, expr->unary_expr.expr);
|
||||
case UNARYOP_DEREF:
|
||||
return LLVMBuildLoad2(context->builder, llvm_type(expr->unary_expr.expr->type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
|
||||
return LLVMBuildLoad2(context->builder, llvm_type(type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
|
||||
case UNARYOP_INC:
|
||||
return gencontext_emit_pre_inc_dec(context, expr->unary_expr.expr, 1, false);
|
||||
case UNARYOP_DEC:
|
||||
@@ -440,7 +441,6 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
|
||||
{
|
||||
return gencontext_emit_logical_and_or(context, expr, binary_op);
|
||||
}
|
||||
Type *type = expr->type->canonical;
|
||||
Expr *lhs = expr->binary_expr.left;
|
||||
Expr *rhs = expr->binary_expr.right;
|
||||
|
||||
@@ -456,10 +456,10 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
|
||||
}
|
||||
|
||||
rhs_value = gencontext_emit_expr(context, rhs);
|
||||
Type *lhs_type = expr->binary_expr.left->type->canonical;
|
||||
Type *lhs_type = type_reduced_from_expr(lhs);
|
||||
if (type_is_integer(lhs_type) && binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ)
|
||||
{
|
||||
return gencontext_emit_int_comparison(context, lhs_type, rhs->type->canonical, lhs_value, rhs_value, binary_op);
|
||||
return gencontext_emit_int_comparison(context, lhs_type, type_reduced_from_expr(rhs), lhs_value, rhs_value, binary_op);
|
||||
}
|
||||
bool is_float = type_is_float(lhs_type);
|
||||
switch (binary_op)
|
||||
@@ -520,24 +520,24 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
|
||||
case BINARYOP_BIT_XOR:
|
||||
return LLVMBuildXor(context->builder, lhs_value, rhs_value, "xor");
|
||||
case BINARYOP_EQ:
|
||||
assert(!type_is_integer(lhs_type));
|
||||
// Unordered?
|
||||
assert(type_is_float(lhs_type));
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealUEQ, lhs_value, rhs_value, "eq");
|
||||
case BINARYOP_NE:
|
||||
assert(!type_is_integer(lhs_type));
|
||||
// Unordered?
|
||||
assert(type_is_float(lhs_type));
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealUNE, lhs_value, rhs_value, "neq");
|
||||
case BINARYOP_GE:
|
||||
assert(!type_is_integer(lhs_type));
|
||||
assert(type_is_float(lhs_type));
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealUGE, lhs_value, rhs_value, "ge");
|
||||
case BINARYOP_GT:
|
||||
assert(!type_is_integer(lhs_type));
|
||||
assert(type_is_float(lhs_type));
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealUGT, lhs_value, rhs_value, "gt");
|
||||
case BINARYOP_LE:
|
||||
assert(!type_is_integer(lhs_type));
|
||||
assert(type_is_float(lhs_type));
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "le");
|
||||
case BINARYOP_LT:
|
||||
assert(!type_is_integer(lhs_type));
|
||||
assert(type_is_float(lhs_type));
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "lt");
|
||||
case BINARYOP_AND:
|
||||
case BINARYOP_OR:
|
||||
@@ -666,7 +666,7 @@ static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *e
|
||||
|
||||
LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMTypeRef type = llvm_type(expr->type);
|
||||
LLVMTypeRef type = llvm_type(type_reduced_from_expr(expr));
|
||||
switch (expr->const_expr.kind)
|
||||
{
|
||||
case ALL_INTS:
|
||||
@@ -695,6 +695,11 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
|
||||
0));
|
||||
return global_name;
|
||||
}
|
||||
case TYPE_ERROR:
|
||||
// TODO emit as u128? u64?
|
||||
TODO
|
||||
case TYPE_ENUM:
|
||||
return gencontext_emit_expr(context, expr->const_expr.enum_constant->enum_constant.expr);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -160,10 +160,13 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
|
||||
return type->backend_type = llvm_get_type(context, type->canonical);
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERROR:
|
||||
case TYPE_ERROR_UNION:
|
||||
return type->backend_type = llvm_type_from_decl(context, type->decl);
|
||||
case TYPE_ENUM:
|
||||
return type->backend_type = llvm_get_type(context, type->decl->enums.type_info->type);
|
||||
case TYPE_ERROR:
|
||||
// TODO: u128? u64?
|
||||
TODO
|
||||
case TYPE_FUNC:
|
||||
return type->backend_type = llvm_func_type(context, type);
|
||||
case TYPE_VOID:
|
||||
|
||||
@@ -34,19 +34,6 @@ static int type_bits[TYPE_U64 + 1] = {
|
||||
[TYPE_I64] = 64,
|
||||
};
|
||||
|
||||
static int64_t int_type_max[TYPE_I64 + 1] = {
|
||||
[TYPE_I8] = 0x7F,
|
||||
[TYPE_I16] = 0x7FFF,
|
||||
[TYPE_I32] = 0x7FFFFFFFLL,
|
||||
[TYPE_I64] = 0x7FFFFFFFFFFFFFFFLL,
|
||||
};
|
||||
|
||||
static int64_t int_type_min[TYPE_I64 + 1] = {
|
||||
[TYPE_I8] = -0x80,
|
||||
[TYPE_I16] = -0x8000L,
|
||||
[TYPE_I32] = -0x80000000L,
|
||||
[TYPE_I64] = -0x8000000000000000LL,
|
||||
};
|
||||
|
||||
void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
|
||||
{
|
||||
@@ -74,6 +61,12 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
|
||||
case TYPE_FXX:
|
||||
fprintf(file, "%Lf", expr->f);
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
fprintf(file, "%s", expr->enum_constant->name);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
fprintf(file, "%s", expr->error_constant->name);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -172,6 +165,7 @@ static inline bool compare_fps(long double left, long double right, BinaryOp op)
|
||||
|
||||
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op)
|
||||
{
|
||||
bool is_eq;
|
||||
switch (left->kind)
|
||||
{
|
||||
case TYPE_BOOL:
|
||||
@@ -183,10 +177,30 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
|
||||
case TYPE_POINTER:
|
||||
return true;
|
||||
case TYPE_STRING:
|
||||
TODO
|
||||
if (left->string.len != right->string.len)
|
||||
{
|
||||
is_eq = false;
|
||||
break;
|
||||
}
|
||||
if (right->string.chars == left->string.chars)
|
||||
{
|
||||
is_eq = true;
|
||||
break;
|
||||
}
|
||||
is_eq = strncmp(left->string.chars, right->string.chars, left->string.len);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
assert(left->error_constant->type == right->error_constant->type);
|
||||
is_eq = left->error_constant == right->error_constant;
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
assert(left->enum_constant->type == right->enum_constant->type);
|
||||
return expr_const_compare(&left->enum_constant->enum_constant.expr->const_expr, &right->enum_constant->enum_constant.expr->const_expr, op);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
assert(op == BINARYOP_EQ || op == BINARYOP_NE);
|
||||
return op == BINARYOP_EQ == is_eq;
|
||||
}
|
||||
|
||||
bool expr_const_int_overflowed(const ExprConst *expr)
|
||||
@@ -239,6 +253,15 @@ const char *expr_const_to_error_string(const ExprConst *expr)
|
||||
case TYPE_FXX:
|
||||
asprintf(&buff, "%Lf", expr->f);
|
||||
return buff;
|
||||
case TYPE_ENUM:
|
||||
asprintf(&buff, "%s.%s", expr->enum_constant->type->name, expr->enum_constant->name);
|
||||
return buff;
|
||||
case TYPE_ERROR:
|
||||
asprintf(&buff, "%s.%s", expr->error_constant->type->name, expr->error_constant->name);
|
||||
return buff;
|
||||
case TYPE_STRING:
|
||||
asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars);
|
||||
return buff;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -114,15 +114,75 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, Decl *decl)
|
||||
{
|
||||
VECEACH(decl->enums.values, i)
|
||||
{
|
||||
Decl *enum_constant = decl->enums.values[i];
|
||||
if (enum_constant->name == name)
|
||||
{
|
||||
assert(enum_constant->resolve_status == RESOLVE_DONE);
|
||||
expr->type = enum_constant->type;
|
||||
expr->const_expr.kind = TYPE_ENUM;
|
||||
expr->const_expr.enum_constant = enum_constant;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_error_constant(Expr *expr, const char *name, Decl *decl)
|
||||
{
|
||||
VECEACH(decl->error.error_constants, i)
|
||||
{
|
||||
Decl *error_constant = decl->error.error_constants[i];
|
||||
if (error_constant->name == name)
|
||||
{
|
||||
assert(error_constant->resolve_status == RESOLVE_DONE);
|
||||
expr->type = decl->type;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
expr->const_expr.kind = TYPE_ERROR;
|
||||
expr->const_expr.error_constant = decl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool find_possible_inferred_identifier(Type *to, Expr *expr)
|
||||
{
|
||||
if (to->canonical->type_kind != TYPE_ENUM && to->canonical->type_kind != TYPE_ERROR) return false;
|
||||
Decl *parent_decl = to->canonical->decl;
|
||||
switch (parent_decl->decl_kind)
|
||||
{
|
||||
case DECL_ENUM:
|
||||
return sema_expr_analyse_enum_constant(expr, expr->identifier_expr.identifier, parent_decl);
|
||||
case DECL_ERROR:
|
||||
return sema_expr_analyse_error_constant(expr, expr->identifier_expr.identifier, parent_decl);
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
return false;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
}
|
||||
static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
// TODO what about struct functions
|
||||
Decl *ambiguous_decl;
|
||||
Decl *decl = sema_resolve_symbol(context, expr->identifier_expr.identifier, expr->identifier_expr.path, &ambiguous_decl);
|
||||
|
||||
|
||||
if (!decl && !expr->identifier_expr.path && to)
|
||||
{
|
||||
if (find_possible_inferred_identifier(to, expr)) return true;
|
||||
}
|
||||
|
||||
if (!decl)
|
||||
{
|
||||
SEMA_ERROR(expr, "Unknown symbol '%s'.", expr->identifier_expr.identifier);
|
||||
SEMA_ERROR(expr, "The symbol '%s' could not be found.", expr->identifier_expr.identifier);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -163,6 +223,7 @@ static inline bool sema_expr_analyse_binary_sub_expr(Context *context, Type *to,
|
||||
static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *expr) { TODO }
|
||||
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO };
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl)
|
||||
{
|
||||
Expr **args =expr->call_expr.arguments;
|
||||
@@ -284,41 +345,6 @@ static inline bool sema_expr_analyse_method_function(Context *context, Expr *exp
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_enum_constant(Context *context, Expr *expr, Decl *decl)
|
||||
{
|
||||
const char *name = expr->type_access.name.string;
|
||||
VECEACH(decl->enums.values, i)
|
||||
{
|
||||
Decl *enum_constant = decl->enums.values[i];
|
||||
if (enum_constant->name == name)
|
||||
{
|
||||
assert(enum_constant->resolve_status == RESOLVE_DONE);
|
||||
expr_replace(expr, enum_constant->enum_constant.expr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr, Decl *decl)
|
||||
{
|
||||
const char *name = expr->type_access.name.string;
|
||||
VECEACH(decl->error.error_constants, i)
|
||||
{
|
||||
Decl *error_constant = decl->error.error_constants[i];
|
||||
if (error_constant->name == name)
|
||||
{
|
||||
assert(error_constant->resolve_status == RESOLVE_DONE);
|
||||
expr->type = decl->type;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
expr_const_set_int(&expr->const_expr, decl->error_constant.value, TYPE_U32);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr, "'%s' has no error type '%s'.", decl->name, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int *index)
|
||||
{
|
||||
@@ -336,6 +362,7 @@ static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false;
|
||||
@@ -389,21 +416,38 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
|
||||
{
|
||||
TypeInfo *type_info = expr->type_access.type;
|
||||
if (!sema_resolve_type_info(context, type_info)) return false;
|
||||
if (!type_may_have_method_functions(type_info->type))
|
||||
Type *canonical = type_info->type->canonical;
|
||||
if (!type_may_have_method_functions(canonical))
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' does not have method functions.", type_to_error_string(type_info->type));
|
||||
return false;
|
||||
}
|
||||
Decl *decl = type_info->type->decl;
|
||||
Decl *decl = canonical->decl;
|
||||
// TODO add more constants that can be inspected?
|
||||
// e.g. SomeEnum.values, MyUnion.x.offset etc?
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_ENUM:
|
||||
if (expr->type_access.name.type == TOKEN_CONST_IDENT) return sema_expr_analyse_enum_constant(context, expr, decl);
|
||||
if (expr->type_access.name.type == TOKEN_CONST_IDENT)
|
||||
{
|
||||
if (!sema_expr_analyse_enum_constant(expr, expr->type_access.name.string, decl))
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, expr->type_access.name.string);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DECL_ERROR:
|
||||
if (expr->type_access.name.type == TOKEN_CONST_IDENT) return sema_expr_analyse_error_constant(context, expr, decl);
|
||||
if (expr->type_access.name.type == TOKEN_CONST_IDENT)
|
||||
{
|
||||
if (!sema_expr_analyse_error_constant(expr, expr->type_access.name.string, decl))
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' has no error type '%s'.", decl->name, expr->type_access.name.string);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
@@ -831,6 +875,8 @@ static bool binary_arithmetic_promotion(Expr *left, Expr *right, Type *left_type
|
||||
*/
|
||||
static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
|
||||
{
|
||||
// TODO enums
|
||||
|
||||
bool is_mod = expr->binary_expr.operator == BINARYOP_SUB_MOD;
|
||||
|
||||
// 1. Analyse a and b. Do not push down if this is a -%
|
||||
@@ -926,6 +972,8 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
|
||||
*/
|
||||
static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
|
||||
{
|
||||
// TODO enums
|
||||
|
||||
bool is_mod = expr->binary_expr.operator == BINARYOP_ADD_MOD;
|
||||
|
||||
// 1. Promote everything to the recipient type – if possible
|
||||
@@ -1446,11 +1494,15 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
|
||||
Type *max = type_find_max_type(left_type, right_type);
|
||||
|
||||
// 4. If no common type, then that's an error:
|
||||
if (!max) goto ERR;
|
||||
if (!max)
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' and '%s' are different types and cannot be compared.",
|
||||
type_to_error_string(left->type), type_to_error_string(right->type));
|
||||
};
|
||||
|
||||
// 5. Most types can do equality, but not all can do comparison,
|
||||
// so we need to check that as well.
|
||||
if (is_equality_type_op)
|
||||
if (!is_equality_type_op)
|
||||
{
|
||||
switch (max->type_kind)
|
||||
{
|
||||
@@ -1496,21 +1548,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
|
||||
// 7. Do constant folding.
|
||||
if (both_const(left, right))
|
||||
{
|
||||
switch (left->const_expr.kind)
|
||||
{
|
||||
case TYPE_BOOL:
|
||||
SEMA_ERROR(expr, "Cannot compare booleans, convert them into integers first.");
|
||||
return false;
|
||||
case ALL_FLOATS:
|
||||
case ALL_INTS:
|
||||
expr->const_expr.b = expr_const_compare(&left->const_expr, &right->const_expr, expr->binary_expr.operator);
|
||||
return true;
|
||||
case TYPE_STRING:
|
||||
SEMA_ERROR(expr, "Cannot compare strings.");
|
||||
return false;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
expr->const_expr.b = expr_const_compare(&left->const_expr, &right->const_expr, expr->binary_expr.operator);
|
||||
expr->const_expr.kind = TYPE_BOOL;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
}
|
||||
@@ -1678,6 +1716,9 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
|
||||
case TYPE_STRING:
|
||||
expr->const_expr.b = !inner->const_expr.string.len;
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
case TYPE_ENUM:
|
||||
TODO
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user