diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 7ac2cd7ac..c37e97906 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -243,6 +243,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) { named->Named.base = base_type(bt); if (!is_distinct) { e->type = bt; + named->Named.base = bt; e->TypeName.is_type_alias = true; } // if (is_alias) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 47eb871f5..147c6c6a6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -394,7 +394,7 @@ bool find_or_generate_polymorphic_procedure_from_parameters(Checker *c, Entity * bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type); bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type); - +bool check_cast_internal(Checker *c, Operand *x, Type *type); i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { if (operand->mode == Addressing_Invalid || @@ -571,7 +571,15 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { } } - + AstNode *expr = unparen_expr(operand->expr); + if (expr != nullptr && expr->kind == AstNode_AutoCast) { + Operand x = *operand; + x.expr = expr->AutoCast.expr; + bool ok = check_cast_internal(c, &x, type); + if (ok) { + return 10; + } + } return -1; } @@ -1797,13 +1805,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { return false; } -void check_cast(Checker *c, Operand *x, Type *type) { - if (!is_operand_value(*x)) { - error(x->expr, "'cast' can only be applied to values"); - x->mode = Addressing_Invalid; - return; - } - +bool check_cast_internal(Checker *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; bool can_convert = false; @@ -1811,9 +1813,9 @@ void check_cast(Checker *c, Operand *x, Type *type) { if (is_const_expr && is_type_constant_type(bt)) { if (core_type(bt)->kind == Type_Basic) { if (check_representable_as_constant(c, x->value, bt, &x->value)) { - can_convert = true; + return true; } else if (is_type_pointer(type) && check_is_castable_to(c, x, type)) { - can_convert = true; + return true; } } } else if (check_is_castable_to(c, x, type)) { @@ -1822,8 +1824,21 @@ void check_cast(Checker *c, Operand *x, Type *type) { } else if (is_type_slice(type) && is_type_string(x->type)) { x->mode = Addressing_Value; } - can_convert = true; + return true; } + return false; + +} + +void check_cast(Checker *c, Operand *x, Type *type) { + if (!is_operand_value(*x)) { + error(x->expr, "Only values can be casted"); + x->mode = Addressing_Invalid; + return; + } + + bool is_const_expr = x->mode == Addressing_Constant; + bool can_convert = check_cast_internal(c, x, type); if (!can_convert) { gbString expr_str = expr_to_string(x->expr); @@ -5767,6 +5782,19 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return Expr_Expr; case_end; + case_ast_node(ac, AutoCast, node); + check_expr_base(c, o, ac->expr, type_hint); + if (o->mode == Addressing_Invalid) { + o->expr = node; + return kind; + } + if (type_hint) { + check_cast(c, o, type_hint); + } + o->expr = node; + return Expr_Expr; + case_end; + case_ast_node(ue, UnaryExpr, node); check_expr_base(c, o, ue->expr, type_hint); if (o->mode == Addressing_Invalid) { @@ -6215,7 +6243,8 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, ta->type); str = gb_string_append_rune(str, ')'); case_end; - case_ast_node(tc, TypeCast, node); + + case_ast_node(tc, TypeCast, node); str = string_append_token(str, tc->token); str = gb_string_append_rune(str, '('); str = write_expr_to_string(str, tc->type); @@ -6223,6 +6252,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, tc->expr); case_end; + case_ast_node(ac, AutoCast, node); + str = string_append_token(str, ac->token); + str = gb_string_append_rune(str, ' '); + str = write_expr_to_string(str, ac->expr); + case_end; + case_ast_node(ie, IndexExpr, node); str = write_expr_to_string(str, ie->expr); str = gb_string_append_rune(str, '['); diff --git a/src/ir.cpp b/src/ir.cpp index f0d0c4606..1a33f17e1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4979,6 +4979,10 @@ irValue *ir_build_expr_internal(irProcedure *proc, AstNode *expr) { GB_PANIC("Invalid AST TypeCast"); case_end; + case_ast_node(ac, AutoCast, expr); + return ir_build_expr(proc, ac->expr); + case_end; + case_ast_node(ue, UnaryExpr, expr); switch (ue->op.kind) { case Token_And: { @@ -6052,6 +6056,10 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ir_emit_store(proc, v, e); return ir_addr(v); case_end; + + case_ast_node(ac, AutoCast, expr); + return ir_build_addr(proc, ac->expr); + case_end; } TokenPos token_pos = ast_node_token(expr).pos; diff --git a/src/parser.cpp b/src/parser.cpp index 2643fb2b3..d54c63cd9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -25,35 +25,36 @@ Token ast_node_token(AstNode *node) { return ast_node_token(node->SelectorExpr.selector); } return node->SelectorExpr.token; - case AstNode_IndexExpr: return node->IndexExpr.open; - case AstNode_SliceExpr: return node->SliceExpr.open; - case AstNode_Ellipsis: return node->Ellipsis.token; - case AstNode_FieldValue: return node->FieldValue.eq; - case AstNode_DerefExpr: return node->DerefExpr.op; - case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond); - case AstNode_TypeAssertion: return ast_node_token(node->TypeAssertion.expr); - case AstNode_TypeCast: return node->TypeCast.token; + case AstNode_IndexExpr: return node->IndexExpr.open; + case AstNode_SliceExpr: return node->SliceExpr.open; + case AstNode_Ellipsis: return node->Ellipsis.token; + case AstNode_FieldValue: return node->FieldValue.eq; + case AstNode_DerefExpr: return node->DerefExpr.op; + case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond); + case AstNode_TypeAssertion: return ast_node_token(node->TypeAssertion.expr); + case AstNode_TypeCast: return node->TypeCast.token; + case AstNode_AutoCast: return node->AutoCast.token; - case AstNode_BadStmt: return node->BadStmt.begin; - case AstNode_EmptyStmt: return node->EmptyStmt.token; - case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr); - case AstNode_TagStmt: return node->TagStmt.token; - case AstNode_AssignStmt: return node->AssignStmt.op; - case AstNode_IncDecStmt: return ast_node_token(node->IncDecStmt.expr); - case AstNode_BlockStmt: return node->BlockStmt.open; - case AstNode_IfStmt: return node->IfStmt.token; - case AstNode_WhenStmt: return node->WhenStmt.token; - case AstNode_ReturnStmt: return node->ReturnStmt.token; - case AstNode_ForStmt: return node->ForStmt.token; - case AstNode_RangeStmt: return node->RangeStmt.token; - case AstNode_CaseClause: return node->CaseClause.token; - case AstNode_SwitchStmt: return node->SwitchStmt.token; - case AstNode_TypeSwitchStmt: return node->TypeSwitchStmt.token; - case AstNode_DeferStmt: return node->DeferStmt.token; - case AstNode_BranchStmt: return node->BranchStmt.token; - case AstNode_UsingStmt: return node->UsingStmt.token; - case AstNode_UsingInStmt: return node->UsingInStmt.using_token; - case AstNode_PushContext: return node->PushContext.token; + case AstNode_BadStmt: return node->BadStmt.begin; + case AstNode_EmptyStmt: return node->EmptyStmt.token; + case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr); + case AstNode_TagStmt: return node->TagStmt.token; + case AstNode_AssignStmt: return node->AssignStmt.op; + case AstNode_IncDecStmt: return ast_node_token(node->IncDecStmt.expr); + case AstNode_BlockStmt: return node->BlockStmt.open; + case AstNode_IfStmt: return node->IfStmt.token; + case AstNode_WhenStmt: return node->WhenStmt.token; + case AstNode_ReturnStmt: return node->ReturnStmt.token; + case AstNode_ForStmt: return node->ForStmt.token; + case AstNode_RangeStmt: return node->RangeStmt.token; + case AstNode_CaseClause: return node->CaseClause.token; + case AstNode_SwitchStmt: return node->SwitchStmt.token; + case AstNode_TypeSwitchStmt: return node->TypeSwitchStmt.token; + case AstNode_DeferStmt: return node->DeferStmt.token; + case AstNode_BranchStmt: return node->BranchStmt.token; + case AstNode_UsingStmt: return node->UsingStmt.token; + case AstNode_UsingInStmt: return node->UsingInStmt.using_token; + case AstNode_PushContext: return node->PushContext.token; case AstNode_BadDecl: return node->BadDecl.begin; case AstNode_Label: return node->Label.token; @@ -633,6 +634,12 @@ AstNode *ast_type_cast(AstFile *f, Token token, AstNode *type, AstNode *expr) { result->TypeCast.expr = expr; return result; } +AstNode *ast_auto_cast(AstFile *f, Token token, AstNode *expr) { + AstNode *result = make_ast_node(f, AstNode_AutoCast); + result->AutoCast.token = token; + result->AutoCast.expr = expr; + return result; +} @@ -2195,6 +2202,13 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) { AstNode *expr = parse_unary_expr(f, lhs); return ast_type_cast(f, token, type, expr); } + + case Token_auto_cast: { + Token token = advance_token(f); + AstNode *expr = parse_unary_expr(f, lhs); + return ast_auto_cast(f, token, expr); + } + case Token_Add: case Token_Sub: case Token_Not: diff --git a/src/parser.hpp b/src/parser.hpp index d641e8a97..5f8bf8a19 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -220,6 +220,7 @@ AST_NODE_KIND(_ExprBegin, "", struct {}) \ AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \ AST_NODE_KIND(TypeAssertion, "type assertion", struct { AstNode *expr; Token dot; AstNode *type; }) \ AST_NODE_KIND(TypeCast, "type cast", struct { Token token; AstNode *type, *expr; }) \ + AST_NODE_KIND(AutoCast, "auto_cast", struct { Token token; AstNode *expr; }) \ AST_NODE_KIND(_ExprEnd, "", struct {}) \ AST_NODE_KIND(_StmtBegin, "", struct {}) \ AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \ diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 6b7a50638..b10bfb132 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -108,6 +108,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \ + TOKEN_KIND(Token_auto_cast, "auto_cast"), \ TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_distinct, "distinct"), \