Enum fixes

This commit is contained in:
Christoffer Lerno
2020-04-05 11:31:05 +02:00
parent 336e6cf47d
commit 60c60a3205
15 changed files with 160 additions and 78 deletions

View File

@@ -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:

View File

@@ -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; }

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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.");

View File

@@ -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))

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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: