Compile time type assignment (eg $Foo = int) is no longer an expression.

This commit is contained in:
Christoffer Lerno
2025-06-20 23:31:22 +02:00
parent 5efc721b0c
commit dd80e8b799
9 changed files with 52 additions and 36 deletions

View File

@@ -24,6 +24,7 @@
- Allow generics over distinct types #2216.
- Support distrinct types as the base type of bitstructs. #2218
- Add hash::sha512 module to stdlib. #2227
- Compile time type assignment (eg `$Foo = int`) is no longer an expression.
### Fixes
- `-2147483648`, MIN literals work correctly.

View File

@@ -772,6 +772,7 @@ static void c_emit_stmt(GenContext *c, Ast *stmt)
case AST_CT_FOR_STMT:
case AST_CT_IF_STMT:
case AST_CT_SWITCH_STMT:
case AST_CT_TYPE_ASSIGN_STMT:
UNREACHABLE
case AST_DECLARE_STMT:
{

View File

@@ -1359,6 +1359,12 @@ typedef struct
} AstCtSwitchStmt;
typedef struct
{
const char *var_name;
Expr *type_expr;
} AstCtTypeAssignStmt;
typedef struct
{
DeclId index;
@@ -1500,6 +1506,7 @@ typedef struct Ast_
AstContractStmt contract_stmt; // 32
AstDocFault contract_fault; // 24
AstId ct_else_stmt; // 4
AstCtTypeAssignStmt ct_type_assign_stmt;
AstCtForeachStmt ct_foreach_stmt; // 40
AstCtIfStmt ct_if_stmt; // 24
AstCtSwitchStmt ct_switch_stmt; // 16

View File

@@ -643,6 +643,9 @@ RETRY:
{
case AST_POISONED:
break;
case AST_CT_TYPE_ASSIGN_STMT:
MACRO_COPY_EXPR(ast->ct_type_assign_stmt.type_expr);
break;
case AST_DECLS_STMT:
MACRO_COPY_DECL_LIST(ast->decls_stmt);
break;

View File

@@ -208,6 +208,7 @@ typedef enum
AST_CT_FOR_STMT,
AST_CT_IF_STMT,
AST_CT_SWITCH_STMT,
AST_CT_TYPE_ASSIGN_STMT,
AST_DECLARE_STMT,
AST_DECLS_STMT,
AST_DEFAULT_STMT,
@@ -1629,7 +1630,7 @@ typedef enum
#define CT_AST \
AST_CT_ASSERT: case AST_CT_ECHO_STMT: case AST_CT_ELSE_STMT: \
case AST_CT_FOREACH_STMT: case AST_CT_FOR_STMT: \
case AST_CT_IF_STMT: case AST_CT_SWITCH_STMT
case AST_CT_IF_STMT: case AST_CT_SWITCH_STMT: case AST_CT_TYPE_ASSIGN_STMT
// -- Decl helper macros
#define NON_TYPE_DECLS DECL_IMPORT: case DECL_MACRO: \

View File

@@ -965,9 +965,23 @@ static inline Ast *parse_expr_stmt(ParseContext *c)
}
static inline Ast *parse_ct_type_assign_stmt(ParseContext *c)
{
Ast *stmt = new_ast(AST_CT_TYPE_ASSIGN_STMT, c->span);
stmt->ct_type_assign_stmt.var_name = symstr(c);
advance_and_verify(c, TOKEN_CT_TYPE_IDENT);
advance_and_verify(c, TOKEN_EQ);
ASSIGN_EXPR_OR_RET(stmt->ct_type_assign_stmt.type_expr, parse_expr(c), poisoned_ast);
CONSUME_EOS_OR_RET(poisoned_ast);
return stmt;
}
static inline Ast *parse_decl_or_expr_stmt(ParseContext *c)
{
if (tok_is(c, TOKEN_CT_TYPE_IDENT) && peek(c) == TOKEN_EQ)
{
return parse_ct_type_assign_stmt(c);
}
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_ast);
// We might be parsing "int!"
// If so we need to unwrap this.
@@ -1275,9 +1289,9 @@ Ast *parse_stmt(ParseContext *c)
return parse_decl_or_expr_stmt(c);
case TOKEN_VAR:
return parse_var_stmt(c);
case TOKEN_TLOCAL: // Global means declaration!
case TOKEN_TLOCAL: // Global means declaration!
case TOKEN_STATIC: // Static means declaration!
case TOKEN_CONST: // Const means declaration!
case TOKEN_CONST: // Const means declaration!
return parse_declaration_stmt(c);
case TOKEN_RETURN:
return parse_return_stmt(c);

View File

@@ -4172,8 +4172,9 @@ static inline bool sema_check_body_const(SemaContext *context, Ast *body)
case AST_CT_FOREACH_STMT:
case AST_CT_FOR_STMT:
case AST_CT_IF_STMT:
case AST_CT_SWITCH_STMT:
case AST_CT_ELSE_STMT:
case AST_CT_SWITCH_STMT:
case AST_CT_TYPE_ASSIGN_STMT:
case AST_DECLARE_STMT:
case AST_DECLS_STMT:
case AST_NOP_STMT:

View File

@@ -93,7 +93,6 @@ static bool sema_expr_check_shift_rhs(SemaContext *context, Expr *expr, Type *le
static bool sema_expr_analyse_and_or(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool *failed_ref);
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, BinaryOp operator);
@@ -6364,30 +6363,6 @@ static bool sema_expr_analyse_ct_subscript_assign(SemaContext *context, Expr *ex
return true;
}
static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{
TypeInfo *info = left->type_expr;
if (info->kind != TYPE_INFO_CT_IDENTIFIER)
{
RETURN_SEMA_ERROR(left, "A type cannot be assigned to.");
}
if (!sema_analyse_expr_value(context, right)) return false;
if (right->expr_kind == EXPR_TYPEINFO)
{
expr_rewrite_const_typeid(right, right->type_expr->type);
}
if (!expr_is_const_typeid(right)) RETURN_SEMA_ERROR(right, "Expected a type or constant typeid here.");
Decl *decl = sema_find_symbol(context, info->unresolved.name);
if (!decl) RETURN_SEMA_ERROR(info, "'%s' is not defined in this scope yet.", info->unresolved.name);
decl->var.init_expr = right;
expr->expr_kind = EXPR_NOP;
expr->type = type_void;
return true;
}
static bool sema_expr_fold_hash(SemaContext *context, Expr *expr)
{
@@ -6414,13 +6389,6 @@ static bool sema_expr_fold_hash(SemaContext *context, Expr *expr)
*/
static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref)
{
// 1. Evaluate left side
if (left->expr_kind == EXPR_TYPEINFO)
{
// Later make sure this can be handled in lvalue
// $Foo = ...
return sema_expr_analyse_ct_type_identifier_assign(context, expr, left, right);
}
if (!sema_analyse_expr_lvalue(context, left, failed_ref)) return false;
switch (left->expr_kind)
{

View File

@@ -1187,6 +1187,24 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType
return true;
}
static inline bool sema_analyse_ct_type_assign_stmt(SemaContext *context, Ast *statement)
{
Expr *right = statement->ct_type_assign_stmt.type_expr;
if (!sema_analyse_expr_value(context, right)) return false;
if (right->expr_kind == EXPR_TYPEINFO)
{
expr_rewrite_const_typeid(right, right->type_expr->type);
}
if (!expr_is_const_typeid(right)) RETURN_SEMA_ERROR(right, "Expected a type or constant typeid here.");
Decl *decl = sema_find_symbol(context, statement->ct_type_assign_stmt.var_name);
if (!decl) RETURN_SEMA_ERROR(statement, "'%s' is not defined in this scope yet.", statement->ct_type_assign_stmt.var_name);
decl->var.init_expr = right;
statement->ast_kind = AST_NOP_STMT;
return true;
}
static inline bool sema_analyse_decls_stmt(SemaContext *context, Ast *statement)
{
@@ -3044,6 +3062,8 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
case AST_ASM_LABEL:
case AST_CONTRACT_FAULT:
UNREACHABLE
case AST_CT_TYPE_ASSIGN_STMT:
return sema_analyse_ct_type_assign_stmt(context, statement);
case AST_DECLS_STMT:
return sema_analyse_decls_stmt(context, statement);
case AST_ASM_BLOCK_STMT: