cast(Type)expr; Fix overloaded procedure determination on assignment

This commit is contained in:
Ginger Bill
2017-07-11 14:40:27 +01:00
parent 0be0fb2a57
commit c4c6975f1b
8 changed files with 184 additions and 28 deletions
+1 -3
View File
@@ -363,9 +363,7 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: boo
_arg_number :: proc(fi: ^FmtInfo, arg_index: int, format: string, offset, arg_count: int) -> (index, offset: int, ok: bool) { _arg_number :: proc(fi: ^FmtInfo, arg_index: int, format: string, offset, arg_count: int) -> (index, offset: int, ok: bool) {
parse_arg_number :: proc(format: string) -> (int, int, bool) { parse_arg_number :: proc(format: string) -> (int, int, bool) {
if len(format) < 3 { if len(format) < 3 do return 0, 1, false;
return 0, 1, false;
}
for i in 1...len(format) { for i in 1...len(format) {
if format[i] == ']' { if format[i] == ']' {
+14
View File
@@ -23,13 +23,27 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
} }
if (operand->mode == Addressing_Overload) {
if (e->type == nullptr) {
error(operand->expr, "Cannot determine type from overloaded procedure `%.*s`", LIT(operand->overload_entities[0]->token.string));
} else {
check_assignment(c, operand, e->type, str_lit("variable assignment"));
if (operand->mode != Addressing_Type) {
return operand->type;
}
}
}
if (e->type == nullptr) { if (e->type == nullptr) {
e->type = t_invalid; e->type = t_invalid;
} }
return nullptr; return nullptr;
} }
if (e->type == nullptr) { if (e->type == nullptr) {
// NOTE(bill): Use the type of the operand // NOTE(bill): Use the type of the operand
Type *t = operand->type; Type *t = operand->type;
if (is_type_untyped(t)) { if (is_type_untyped(t)) {
+128 -15
View File
@@ -192,7 +192,9 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
DeclInfo *old_decl = decl_info_of_entity(&c->info, base_entity); DeclInfo *old_decl = decl_info_of_entity(&c->info, base_entity);
GB_ASSERT(old_decl != nullptr); if (old_decl == nullptr) {
return false;
}
@@ -225,6 +227,9 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
scope->is_proc = true; scope->is_proc = true;
c->context.scope = scope; c->context.scope = scope;
c->context.allow_polymorphic_types = true; c->context.allow_polymorphic_types = true;
if (c->context.polymorphic_scope == nullptr) {
c->context.polymorphic_scope = scope;
}
if (param_operands == nullptr) { if (param_operands == nullptr) {
// c->context.no_polymorphic_errors = false; // c->context.no_polymorphic_errors = false;
} }
@@ -617,10 +622,61 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
return; return;
} }
if (operand->mode == Addressing_Overload) {
// GB_PANIC("HERE!\n");
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
defer (gb_temp_arena_memory_end(tmp));
Entity **procs = operand->overload_entities;
isize overload_count = operand->overload_count;
bool good = false;
// NOTE(bill): These should be done
for (isize i = 0; i < overload_count; i++) {
Type *t = base_type(procs[i]->type);
if (t == t_invalid) {
continue;
}
Operand x = {};
x.mode = Addressing_Value;
x.type = t;
if (check_is_assignable_to(c, &x, type)) {
Entity *e = procs[i];
add_entity_use(c, operand->expr, e);
good = true;
break;
}
}
if (!good) {
gbString expr_str = expr_to_string(operand->expr);
gbString op_type_str = type_to_string(operand->type);
gbString type_str = type_to_string(type);
defer (gb_string_free(type_str));
defer (gb_string_free(op_type_str));
defer (gb_string_free(expr_str));
// TODO(bill): is this a good enough error message?
error(operand->expr,
"Cannot assign overloaded procedure `%s` to `%s` in %.*s",
expr_str,
op_type_str,
LIT(context_name));
operand->mode = Addressing_Invalid;
}
return;
}
if (!check_is_assignable_to(c, operand, type)) { if (!check_is_assignable_to(c, operand, type)) {
gbString type_str = type_to_string(type);
gbString op_type_str = type_to_string(operand->type);
gbString expr_str = expr_to_string(operand->expr); gbString expr_str = expr_to_string(operand->expr);
gbString op_type_str = type_to_string(operand->type);
gbString type_str = type_to_string(type);
defer (gb_string_free(type_str));
defer (gb_string_free(op_type_str));
defer (gb_string_free(expr_str));
if (operand->mode == Addressing_Builtin) { if (operand->mode == Addressing_Builtin) {
// TODO(bill): is this a good enough error message? // TODO(bill): is this a good enough error message?
@@ -647,9 +703,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
} }
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
gb_string_free(expr_str);
gb_string_free(op_type_str);
gb_string_free(type_str);
return; return;
} }
} }
@@ -1040,13 +1093,21 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
Type *t = check_type(c, node); Type *t = check_type(c, node);
if (t != nullptr && t != t_invalid) { if (t != nullptr && t != t_invalid) {
bool ok = true; bool ok = true;
for_array(j, variants) { t = default_type(t);
if (are_types_identical(t, variants[j])) { if (is_type_untyped(t)) {
ok = false; ok = false;
gbString str = type_to_string(t); gbString str = type_to_string(t);
error(node, "Duplicate variant type `%s`", str); error(node, "Invalid type in union `%s`", str);
gb_string_free(str); gb_string_free(str);
break; } else {
for_array(j, variants) {
if (are_types_identical(t, variants[j])) {
ok = false;
gbString str = type_to_string(t);
error(node, "Duplicate variant type `%s`", str);
gb_string_free(str);
break;
}
} }
} }
if (ok) array_add(&variants, t); if (ok) array_add(&variants, t);
@@ -1380,6 +1441,26 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
} }
return false; return false;
case Type_Enum:
return false;
case Type_Union:
if (source->kind == Type_Union) {
TypeUnion *x = &poly->Union;
TypeUnion *y = &source->Union;
if (x->variant_count != y->variant_count) {
return false;
}
for (isize i = 1; i < x->variant_count; i++) {
Type *a = x->variants[i];
Type *b = y->variants[i];
bool ok = is_polymorphic_type_assignable(c, a, b, false, modify_type);
if (!ok) return false;
}
return true;
}
return false;
case Type_Record: case Type_Record:
if (source->kind == Type_Record) { if (source->kind == Type_Record) {
// TODO(bill): Polymorphic type assignment // TODO(bill): Polymorphic type assignment
@@ -2001,6 +2082,10 @@ bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *a
bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands) { bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands) {
ast_node(pt, ProcType, proc_type_node); ast_node(pt, ProcType, proc_type_node);
if (c->context.polymorphic_scope == nullptr && c->context.allow_polymorphic_types) {
c->context.polymorphic_scope = c->context.scope;
}
bool variadic = false; bool variadic = false;
bool success = true; bool success = true;
Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, operands); Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, operands);
@@ -2444,9 +2529,16 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
Token token = ident->Ident.token; Token token = ident->Ident.token;
Type *t = make_type_generic(c->allocator, 0, token.string); Type *t = make_type_generic(c->allocator, 0, token.string);
if (c->context.allow_polymorphic_types) { if (c->context.allow_polymorphic_types) {
Scope *ps = c->context.polymorphic_scope;
Scope *s = c->context.scope; Scope *s = c->context.scope;
Entity *e = make_entity_type_name(c->allocator, s, token, t); Scope *entity_scope = s;
if (ps != nullptr && ps != s) {
GB_ASSERT(is_scope_an_ancestor(ps, s) >= 0);
entity_scope = ps;
}
Entity *e = make_entity_type_name(c->allocator, entity_scope, token, t);
e->TypeName.is_type_alias = true; e->TypeName.is_type_alias = true;
add_entity(c, ps, ident, e);
add_entity(c, s, ident, e); add_entity(c, s, ident, e);
} }
*type = t; *type = t;
@@ -6057,6 +6149,8 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
if (operand->mode == Addressing_Type) { if (operand->mode == Addressing_Type) {
Type *t = operand->type; Type *t = operand->type;
gbString str = type_to_string(t); gbString str = type_to_string(t);
defer (gb_string_free(str));
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
isize arg_count = ce->args.count; isize arg_count = ce->args.count;
switch (arg_count) { switch (arg_count) {
@@ -6076,7 +6170,6 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
} break; } break;
} }
gb_string_free(str);
return Expr_Expr; return Expr_Expr;
} }
@@ -6892,6 +6985,26 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
} }
case_end; case_end;
case_ast_node(tc, TypeCast, node);
check_expr_or_type(c, o, tc->type);
if (o->mode != Addressing_Type) {
gbString str = expr_to_string(tc->type);
error(tc->type, "Expected a type, got %s", str);
gb_string_free(str);
o->mode = Addressing_Invalid;
}
if (o->mode == Addressing_Invalid) {
o->expr = node;
return kind;
}
Type *type = o->type;
check_expr_base(c, o, tc->expr, type);
if (o->mode != Addressing_Invalid) {
check_cast(c, o, type);
}
return Expr_Expr;
case_end;
case_ast_node(ue, UnaryExpr, node); case_ast_node(ue, UnaryExpr, node);
check_expr_base(c, o, ue->expr, type_hint); check_expr_base(c, o, ue->expr, type_hint);
if (o->mode == Addressing_Invalid) { if (o->mode == Addressing_Invalid) {
+16 -2
View File
@@ -250,6 +250,18 @@ void scope_reset(Scope *scope) {
array_clear(&scope->imported); array_clear(&scope->imported);
} }
i32 is_scope_an_ancestor(Scope *parent, Scope *child) {
isize i = 0;
while (child != nullptr) {
if (parent == child) {
return true;
}
child = child->parent;
i++;
}
return -1;
}
struct DelayedDecl { struct DelayedDecl {
Scope * parent; Scope * parent;
@@ -269,12 +281,14 @@ struct CheckerContext {
DeclInfo * decl; DeclInfo * decl;
u32 stmt_state_flags; u32 stmt_state_flags;
bool in_defer; // TODO(bill): Actually handle correctly bool in_defer; // TODO(bill): Actually handle correctly
bool allow_polymorphic_types;
bool no_polymorphic_errors;
String proc_name; String proc_name;
Type * type_hint; Type * type_hint;
DeclInfo * curr_proc_decl; DeclInfo * curr_proc_decl;
AstNode * curr_foreign_library; AstNode * curr_foreign_library;
bool allow_polymorphic_types;
bool no_polymorphic_errors;
Scope * polymorphic_scope;
}; };
+5
View File
@@ -4625,6 +4625,11 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
} }
case_end; case_end;
case_ast_node(tc, TypeCast, expr);
irValue *e = ir_build_expr(proc, tc->expr);
return ir_emit_conv(proc, e, tv.type);
case_end;
case_ast_node(ue, UnaryExpr, expr); case_ast_node(ue, UnaryExpr, expr);
switch (ue->op.kind) { switch (ue->op.kind) {
case Token_And: case Token_And:
+19 -6
View File
@@ -201,6 +201,7 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \ AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \ 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(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(_ExprEnd, "", i32) \ AST_NODE_KIND(_ExprEnd, "", i32) \
AST_NODE_KIND(_StmtBegin, "", i32) \ AST_NODE_KIND(_StmtBegin, "", i32) \
AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \ AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
@@ -542,6 +543,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_DerefExpr: return node->DerefExpr.op; case AstNode_DerefExpr: return node->DerefExpr.op;
case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond); case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond);
case AstNode_TypeAssertion: return ast_node_token(node->TypeAssertion.expr); case AstNode_TypeAssertion: return ast_node_token(node->TypeAssertion.expr);
case AstNode_TypeCast: return node->TypeCast.token;
case AstNode_BadStmt: return node->BadStmt.begin; case AstNode_BadStmt: return node->BadStmt.begin;
case AstNode_EmptyStmt: return node->EmptyStmt.token; case AstNode_EmptyStmt: return node->EmptyStmt.token;
@@ -1146,6 +1148,14 @@ AstNode *ast_type_assertion(AstFile *f, AstNode *expr, Token dot, AstNode *type)
result->TypeAssertion.type = type; result->TypeAssertion.type = type;
return result; return result;
} }
AstNode *ast_type_cast(AstFile *f, Token token, AstNode *type, AstNode *expr) {
AstNode *result = make_ast_node(f, AstNode_TypeCast);
result->TypeCast.token = token;
result->TypeCast.type = type;
result->TypeCast.expr = expr;
return result;
}
@@ -1875,12 +1885,8 @@ void expect_semicolon(AstFile *f, AstNode *s) {
if (is_semicolon_optional_for_node(f, s)) { if (is_semicolon_optional_for_node(f, s)) {
return; return;
} }
} else { } else if (f->curr_token.kind == Token_CloseBrace) {
if (s->kind == AstNode_ValueDecl) { return;
if (f->curr_token.kind == Token_CloseBrace) {
return;
}
}
} }
String node_string = ast_node_strings[s->kind]; String node_string = ast_node_strings[s->kind];
if (s->kind == AstNode_GenDecl) { if (s->kind == AstNode_GenDecl) {
@@ -2581,6 +2587,13 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
next_token(f); next_token(f);
return ast_unary_expr(f, op, parse_unary_expr(f, lhs)); return ast_unary_expr(f, op, parse_unary_expr(f, lhs));
} break; } break;
case Token_cast: {
Token token = expect_token(f, Token_cast);
Token open = expect_token_after(f, Token_OpenParen, "cast");
AstNode *type = parse_type(f);
Token close = expect_token(f, Token_CloseParen);
return ast_type_cast(f, token, type, parse_unary_expr(f, lhs));
} break;
} }
AstNode *operand = parse_operand(f, lhs); AstNode *operand = parse_operand(f, lhs);
+1
View File
@@ -114,6 +114,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_context, "context"), \ TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_push_context, "push_context"), \
-2
View File
@@ -73,8 +73,6 @@ enum TypeRecordKind {
TypeRecord_Struct, TypeRecord_Struct,
TypeRecord_RawUnion, TypeRecord_RawUnion,
// TypeRecord_Union, // Tagged
// TypeRecord_Enum,
TypeRecord_Count, TypeRecord_Count,
}; };