mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Enum fixes
This commit is contained in:
@@ -302,13 +302,24 @@ bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from compile time int to any signed or unsigned int
|
||||
* @return true unless the conversion was lossy.
|
||||
*/
|
||||
bool ixxen(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
assert(canonical->type_kind == TYPE_ENUM);
|
||||
canonical = canonical->decl->enums.type_info->type->canonical;
|
||||
return ixxxi(left, canonical, type, cast_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast signed int -> signed int
|
||||
* @return true if this is a widening, an explicit cast or if it is an implicit assign add
|
||||
*/
|
||||
bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
|
||||
bool sisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
|
||||
bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize;
|
||||
|
||||
if (is_narrowing && cast_type != CAST_TYPE_EXPLICIT)
|
||||
{
|
||||
@@ -330,9 +341,9 @@ bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
||||
* Cast unsigned int -> unsigned int
|
||||
* @return true if this was not a narrowing implicit assign or narrowing implicit assign add
|
||||
*/
|
||||
bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
|
||||
bool uiui(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
|
||||
bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize;
|
||||
|
||||
if (is_narrowing && cast_type != CAST_TYPE_EXPLICIT)
|
||||
{
|
||||
@@ -355,9 +366,9 @@ bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
||||
* Cast unsigned int -> signed int
|
||||
* @return true if this is an explicit cast or if it is an implicit assign add or if it is a widening cast.
|
||||
*/
|
||||
bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
|
||||
bool uisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
bool is_widening = from->builtin.bytesize < canonical->builtin.bytesize;
|
||||
bool is_widening = from_canonical->builtin.bytesize < canonical->builtin.bytesize;
|
||||
|
||||
if (!is_widening && cast_type != CAST_TYPE_EXPLICIT)
|
||||
{
|
||||
@@ -505,9 +516,45 @@ bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xixi(Expr *left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
assert(from_canonical->canonical == from_canonical);
|
||||
switch (from_canonical->type_kind)
|
||||
{
|
||||
case TYPE_IXX:
|
||||
return ixxxi(left, canonical, type, cast_type);
|
||||
case ALL_SIGNED_INTS:
|
||||
if (type_is_unsigned(canonical)) return siui(left, canonical, type, cast_type);
|
||||
return sisi(left, from_canonical, canonical, type, cast_type);
|
||||
case ALL_UNSIGNED_INTS:
|
||||
if (type_is_unsigned(canonical)) return uiui(left, from_canonical, canonical, type, cast_type);
|
||||
return uisi(left, from_canonical, canonical, type, cast_type);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
bool enxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
Type *enum_type = from->decl->enums.type_info->type;
|
||||
Type *enum_type_canonical = enum_type->canonical;
|
||||
// 1. If the underlying type is the same, this is just setting the type.
|
||||
if (canonical == enum_type_canonical)
|
||||
{
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
// 2. See if we can convert to the target type.
|
||||
if (cast_type != CAST_TYPE_EXPLICIT && type_find_max_type(enum_type_canonical, canonical) != canonical)
|
||||
{
|
||||
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||
SEMA_ERROR(left, "Cannot implictly convert '%s' with underlying type of '%s' to '%s',"
|
||||
" use an explicit cast if this is what you want.", type_to_error_string(from),
|
||||
type_to_error_string(enum_type_canonical), type_to_error_string(canonical));
|
||||
return false;
|
||||
}
|
||||
// 3. Dispatch to the right cast:
|
||||
return xixi(left, enum_type_canonical, canonical, type, cast_type);
|
||||
}
|
||||
bool erxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
@@ -632,6 +679,7 @@ CastKind cast_to_bool_kind(Type *type)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
||||
{
|
||||
Type *from_type = expr->type->canonical;
|
||||
@@ -656,6 +704,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
||||
if (type_is_float(canonical)) return ixxfp(expr, canonical, to_type, cast_type);
|
||||
if (canonical == type_bool) return ixxbo(expr, to_type);
|
||||
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_ENUM) return ixxen(expr, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
|
||||
@@ -57,7 +57,7 @@ typedef struct
|
||||
Decl *error_constant;
|
||||
};
|
||||
// Valid type kinds:
|
||||
// bool, ints, floats, enum, error, string
|
||||
// bool, ints, floats, string
|
||||
TypeKind kind;
|
||||
} ExprConst;
|
||||
|
||||
@@ -317,7 +317,6 @@ typedef struct
|
||||
{
|
||||
FunctionSignature function_signature;
|
||||
TypeInfo *type_info;
|
||||
Type *type;
|
||||
};
|
||||
} TypedefDecl;
|
||||
|
||||
@@ -1140,6 +1139,7 @@ Type *type_find_max_type(Type *type, Type *other);
|
||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; }
|
||||
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; }
|
||||
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; }
|
||||
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; }
|
||||
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I64; }
|
||||
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64; }
|
||||
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
||||
|
||||
@@ -690,10 +690,6 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
|
||||
0));
|
||||
return global_name;
|
||||
}
|
||||
case TYPE_ERROR:
|
||||
return LLVMConstInt(llvm_type(type_error), expr->const_expr.error_constant->error_constant.value, false);
|
||||
case TYPE_ENUM:
|
||||
return gencontext_emit_expr(context, expr->const_expr.enum_constant->enum_constant.expr);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
|
||||
|
||||
}
|
||||
case DECL_TYPEDEF:
|
||||
return llvm_get_type(context, decl->typedef_decl.type);
|
||||
return llvm_get_type(context, decl->typedef_decl.type_info->type);
|
||||
case DECL_STRUCT:
|
||||
{
|
||||
LLVMTypeRef *types = NULL;
|
||||
|
||||
@@ -189,13 +189,6 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -324,6 +324,8 @@ static Expr *parse_access_expr(Context *context, Expr *left)
|
||||
access_expr->access_expr.parent = left;
|
||||
access_expr->access_expr.sub_element = context->tok;
|
||||
TRY_CONSUME_OR(TOKEN_IDENT, "Expected identifier", &poisoned_expr);
|
||||
access_expr->span = left->span;
|
||||
access_expr->span.end_loc = access_expr->access_expr.sub_element.span.end_loc;
|
||||
return access_expr;
|
||||
}
|
||||
|
||||
|
||||
@@ -891,7 +891,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
|
||||
{
|
||||
if (context->tok.type != TOKEN_COMMA && context->tok.type != TOKEN_RPAREN)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Unexpected end of the parameter list, did you forget an ')'?");
|
||||
sema_error_at(context->prev_tok_end, "Unexpected end of the parameter list, did you forget an ')'?");
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(type, "The function parameter must be named.");
|
||||
@@ -1955,6 +1955,7 @@ void parse_file(Context *context)
|
||||
static Expr *parse_type_access(Context *context, TypeInfo *type)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE_ACCESS, context->tok);
|
||||
expr->span = type->span;
|
||||
expr->type_access.type = type;
|
||||
|
||||
advance_and_verify(context, TOKEN_DOT);
|
||||
@@ -1966,6 +1967,7 @@ static Expr *parse_type_access(Context *context, TypeInfo *type)
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
advance(context);
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
return expr;
|
||||
default:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a function name, macro, or constant.");
|
||||
|
||||
@@ -235,7 +235,7 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl)
|
||||
return true;
|
||||
}
|
||||
if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false;
|
||||
decl->type->canonical = decl->typedef_decl.type_info->type;
|
||||
decl->type->canonical = decl->typedef_decl.type_info->type->canonical;
|
||||
// Do we need anything else?
|
||||
return true;
|
||||
}
|
||||
@@ -246,7 +246,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
||||
if (!sema_resolve_type_info(context, decl->enums.type_info)) return false;
|
||||
|
||||
Type *type = decl->enums.type_info->type;
|
||||
Type *canonical = decl->enums.type_info->type;
|
||||
Type *canonical = type->canonical;
|
||||
|
||||
// Require an integer type
|
||||
if (!type_is_integer(canonical))
|
||||
|
||||
@@ -124,8 +124,7 @@ static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *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->const_expr = enum_constant->enum_constant.expr->const_expr;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
return true;
|
||||
}
|
||||
@@ -143,8 +142,7 @@ static inline bool sema_expr_analyse_error_constant(Expr *expr, const char *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 = error_constant;
|
||||
expr_const_set_int(&expr->const_expr, error_constant->error_constant.value, type_error->canonical->type_kind);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,29 +550,40 @@ static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cast the case expression to the switch type and ensure it is constant.
|
||||
*
|
||||
* @return true if the analysis succeeds.
|
||||
*/
|
||||
static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_stmt)
|
||||
{
|
||||
assert(to_type);
|
||||
Expr *case_expr = case_stmt->case_stmt.expr;
|
||||
// TODO handle enums
|
||||
// TODO string expr
|
||||
if (!sema_analyse_expr_of_required_type(context, to_type, case_expr)) return false;
|
||||
|
||||
// 1. Try to do implicit conversion to the correct type.
|
||||
if (!sema_analyse_expr(context, to_type, case_expr)) return false;
|
||||
|
||||
// 2. Skip continued analysis if it's not constant.
|
||||
if (case_expr->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(case_expr, "This must be a constant expression.");
|
||||
SEMA_ERROR(case_expr, "A case value must always be constant at compile time.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cast_to_runtime(case_expr)) return false;
|
||||
Type *case_type = case_expr->type->canonical;
|
||||
Type *to_type_canonical = to_type->canonical;
|
||||
|
||||
if (case_expr->const_expr.kind == TYPE_BOOL) return true;
|
||||
// 3. If we already have the same type we're done.
|
||||
if (to_type_canonical == case_type) return true;
|
||||
|
||||
if (!type_is_integer(case_expr->type))
|
||||
// 4. Otherwise check if we have an enum receiving type and a number on
|
||||
// in the case. In that case we do an implicit conversion.
|
||||
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_expr->type))
|
||||
{
|
||||
SEMA_ERROR(case_expr, "The 'case' value must be a boolean or integer constant.");
|
||||
return false;
|
||||
return cast(case_expr, to_type, CAST_TYPE_EXPLICIT);
|
||||
}
|
||||
return true;
|
||||
|
||||
return cast_implicit(case_expr, to_type);
|
||||
}
|
||||
|
||||
|
||||
@@ -614,15 +625,23 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
|
||||
bool success = sema_analyse_cond(context, cond, false);
|
||||
|
||||
Type *switch_type = ast_cond_type(cond)->canonical;
|
||||
if (switch_type == type_bool || !type_is_integer(switch_type))
|
||||
switch (switch_type->type_kind)
|
||||
{
|
||||
SEMA_ERROR(cond, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type));
|
||||
return false;
|
||||
case ALL_INTS:
|
||||
assert(switch_type->type_kind != TYPE_IXX);
|
||||
case TYPE_BOOL:
|
||||
case TYPE_ERROR:
|
||||
case TYPE_META_TYPE:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_STRING:
|
||||
break;
|
||||
default:
|
||||
SEMA_ERROR(cond, "It is not possible to switch over '%s'.", type_to_error_string(switch_type));
|
||||
return false;
|
||||
}
|
||||
Ast *default_case = NULL;
|
||||
assert(context->current_scope->defers.start == context->current_scope->defers.end);
|
||||
|
||||
// TODO enum, exhaustive cases.
|
||||
ExitType prev_exit = context->current_scope->exit;
|
||||
bool exhaustive = false;
|
||||
ExitType lowest_exit = EXIT_NONE;
|
||||
@@ -693,15 +712,10 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
|
||||
}
|
||||
context_pop_defers_and_replace_ast(context, statement);
|
||||
if (lowest_exit <= EXIT_BREAK) lowest_exit = prev_exit;
|
||||
// Check exhaustive use.
|
||||
context->current_scope->exit = exhaustive ? lowest_exit : EXIT_NONE;
|
||||
context_pop_scope(context);
|
||||
if (!success) return false;
|
||||
// Is this a typeless switch value?
|
||||
if (switch_type->type_kind == TYPE_IXX)
|
||||
{
|
||||
|
||||
TODO
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
|
||||
return type_info_poison(type_info);
|
||||
}
|
||||
DEBUG_LOG("Resolved %s.", type_info->unresolved.name_loc.string);
|
||||
type_info->type = decl->type;
|
||||
type_info->type = decl->typedef_decl.type_info->type;
|
||||
type_info->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
case DECL_POISONED:
|
||||
|
||||
@@ -643,6 +643,7 @@ Type *type_find_max_type(Type *type, Type *other)
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
case TYPE_FXX:
|
||||
|
||||
Reference in New Issue
Block a user