mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-06 02:34:05 +00:00
Basic polymorphic named procedure parameters for procedures and records
This commit is contained in:
@@ -1193,7 +1193,6 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
|
||||
ProcUsingVar puv = {e, uvar};
|
||||
array_add(&using_entities, puv);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1221,7 +1220,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
check_open_scope(ctx, body);
|
||||
{
|
||||
for_array(i, using_entities) {
|
||||
|
||||
@@ -1117,6 +1117,9 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
||||
e->flags |= EntityFlag_Used;
|
||||
|
||||
Type *type = e->type;
|
||||
|
||||
o->type = type;
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Constant:
|
||||
if (type == t_invalid) {
|
||||
@@ -1127,6 +1130,14 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
||||
if (o->value.kind == ExactValue_Invalid) {
|
||||
return e;
|
||||
}
|
||||
if (o->value.kind == ExactValue_Procedure) {
|
||||
Entity *proc = strip_entity_wrapping(o->value.value_procedure);
|
||||
if (proc != nullptr) {
|
||||
o->mode = Addressing_Value;
|
||||
o->type = proc->type;
|
||||
return proc;
|
||||
}
|
||||
}
|
||||
o->mode = Addressing_Constant;
|
||||
break;
|
||||
|
||||
@@ -1144,6 +1155,7 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
||||
|
||||
case Entity_Procedure:
|
||||
o->mode = Addressing_Value;
|
||||
o->value = exact_value_procedure(n);
|
||||
break;
|
||||
|
||||
case Entity_Builtin:
|
||||
@@ -1180,7 +1192,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
||||
break;
|
||||
}
|
||||
|
||||
o->type = type;
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -3602,10 +3613,20 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
|
||||
add_entity_use(c, selector, entity);
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = entity->Constant.value;
|
||||
operand->mode = Addressing_Constant;
|
||||
if (operand->value.kind == ExactValue_Procedure) {
|
||||
Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
|
||||
if (proc != nullptr) {
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = proc->type;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Entity_Variable:
|
||||
// TODO(bill): Is this the rule I need?
|
||||
@@ -3628,6 +3649,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
break;
|
||||
case Entity_Procedure:
|
||||
operand->mode = Addressing_Value;
|
||||
operand->value = exact_value_procedure(node);
|
||||
break;
|
||||
case Entity_Builtin:
|
||||
operand->mode = Addressing_Builtin;
|
||||
@@ -3645,8 +3667,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
break;
|
||||
}
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value);
|
||||
|
||||
return entity;
|
||||
}
|
||||
@@ -7044,10 +7065,17 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
|
||||
}
|
||||
o->type = e->type;
|
||||
if (o->mode != Addressing_Constant) {
|
||||
if (show_error) {
|
||||
error(o->expr, "Expected a constant value for this polymorphic type argument");
|
||||
bool valid = false;
|
||||
if (is_type_proc(o->type)) {
|
||||
Entity *proc_entity = entity_from_expr(o->expr);
|
||||
valid = proc_entity != nullptr;
|
||||
}
|
||||
if (!valid) {
|
||||
if (show_error) {
|
||||
error(o->expr, "Expected a constant value for this polymorphic type argument");
|
||||
}
|
||||
err = CallArgumentError_NoneConstantParameter;
|
||||
}
|
||||
err = CallArgumentError_NoneConstantParameter;
|
||||
}
|
||||
score += s;
|
||||
}
|
||||
@@ -9257,29 +9285,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
|
||||
ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
||||
ExprKind kind = check_expr_base_internal(c, o, node, type_hint);
|
||||
Type *type = nullptr;
|
||||
ExactValue value = {ExactValue_Invalid};
|
||||
switch (o->mode) {
|
||||
case Addressing_Invalid:
|
||||
type = t_invalid;
|
||||
break;
|
||||
case Addressing_NoValue:
|
||||
type = nullptr;
|
||||
break;
|
||||
case Addressing_Constant:
|
||||
value = o->value;
|
||||
type = o->type;
|
||||
break;
|
||||
default:
|
||||
type = o->type;
|
||||
break;
|
||||
if (o->type != nullptr && is_type_untyped(o->type)) {
|
||||
add_untyped(&c->checker->info, node, false, o->mode, o->type, o->value);
|
||||
}
|
||||
|
||||
if (type != nullptr && is_type_untyped(type)) {
|
||||
add_untyped(&c->checker->info, node, false, o->mode, type, value);
|
||||
}
|
||||
add_type_and_value(&c->checker->info, node, o->mode, type, value);
|
||||
|
||||
add_type_and_value(&c->checker->info, node, o->mode, o->type, o->value);
|
||||
return kind;
|
||||
}
|
||||
|
||||
|
||||
@@ -469,7 +469,9 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
is_polymorphic = true;
|
||||
can_check_fields = false;
|
||||
}
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
if (e == nullptr) {
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_type_param) {
|
||||
@@ -1672,11 +1674,19 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
}
|
||||
}
|
||||
if (is_poly_name) {
|
||||
if (op.mode == Addressing_Constant) {
|
||||
poly_const = op.value;
|
||||
} else {
|
||||
error(op.expr, "Expected a constant value for this polymorphic name parameter");
|
||||
success = false;
|
||||
bool valid = false;
|
||||
if (is_type_proc(op.type)) {
|
||||
Entity *proc_entity = entity_from_expr(op.expr);
|
||||
valid = proc_entity != nullptr;
|
||||
poly_const = exact_value_procedure(proc_entity->identifier ? proc_entity->identifier : op.expr);
|
||||
}
|
||||
if (!valid) {
|
||||
if (op.mode == Addressing_Constant) {
|
||||
poly_const = op.value;
|
||||
} else {
|
||||
error(op.expr, "Expected a constant value for this polymorphic name parameter");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_type_untyped(default_type(type))) {
|
||||
|
||||
@@ -885,6 +885,7 @@ void destroy_checker(Checker *c) {
|
||||
|
||||
|
||||
Entity *entity_of_ident(Ast *identifier) {
|
||||
identifier = unparen_expr(identifier);
|
||||
if (identifier->kind == Ast_Ident) {
|
||||
return identifier->Ident.entity;
|
||||
}
|
||||
@@ -1042,6 +1043,8 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty
|
||||
expr->tav.value = value;
|
||||
} else if (mode == Addressing_Value && is_type_typeid(type)) {
|
||||
expr->tav.value = value;
|
||||
} else if (mode == Addressing_Value && is_type_proc(type)) {
|
||||
expr->tav.value = value;
|
||||
}
|
||||
|
||||
prev_expr = expr;
|
||||
|
||||
@@ -357,3 +357,23 @@ Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
|
||||
return alloc_entity_variable(scope, token, nullptr);
|
||||
}
|
||||
|
||||
|
||||
Entity *entity_from_expr(Ast *expr);
|
||||
|
||||
Entity *strip_entity_wrapping(Entity *e) {
|
||||
if (e == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (e->kind != Entity_Constant) {
|
||||
return e;
|
||||
}
|
||||
if (e->Constant.value.kind == ExactValue_Procedure) {
|
||||
return strip_entity_wrapping(e->Constant.value.value_procedure);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
Entity *strip_entity_wrapping(Ast *expr) {
|
||||
Entity *e = entity_from_expr(expr);
|
||||
return strip_entity_wrapping(e);
|
||||
}
|
||||
|
||||
@@ -592,6 +592,10 @@ i32 exact_value_order(ExactValue const &v) {
|
||||
return 5;
|
||||
case ExactValue_Pointer:
|
||||
return 6;
|
||||
case ExactValue_Procedure:
|
||||
return 7;
|
||||
// case ExactValue_Compound:
|
||||
// return 8;
|
||||
|
||||
default:
|
||||
GB_PANIC("How'd you get here? Invalid Value.kind");
|
||||
@@ -652,6 +656,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ExactValue_Procedure:
|
||||
return;
|
||||
}
|
||||
|
||||
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
|
||||
@@ -915,12 +922,23 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
|
||||
}
|
||||
break;
|
||||
|
||||
case ExactValue_Procedure:
|
||||
switch (op) {
|
||||
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
|
||||
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GB_PANIC("Invalid comparison");
|
||||
return false;
|
||||
}
|
||||
|
||||
Entity *strip_entity_wrapping(Ast *expr);
|
||||
Entity *strip_entity_wrapping(Entity *e);
|
||||
|
||||
gbString write_expr_to_string(gbString str, Ast *node);
|
||||
|
||||
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
|
||||
switch (v.kind) {
|
||||
@@ -956,9 +974,9 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
|
||||
case ExactValue_Pointer:
|
||||
return str;
|
||||
case ExactValue_Compound:
|
||||
return str;
|
||||
return write_expr_to_string(str, v.value_compound);
|
||||
case ExactValue_Procedure:
|
||||
return str;
|
||||
return write_expr_to_string(str, v.value_procedure);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
31
src/ir.cpp
31
src/ir.cpp
@@ -1984,7 +1984,11 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
|
||||
// case Basic_f16:
|
||||
case Basic_f32:
|
||||
case Basic_f64:
|
||||
return irDebugBasicEncoding_float;
|
||||
case Basic_f32le:
|
||||
case Basic_f64le:
|
||||
case Basic_f32be:
|
||||
case Basic_f64be:
|
||||
return irDebugBasicEncoding_float;
|
||||
|
||||
// case Basic_complex32:
|
||||
case Basic_complex64:
|
||||
@@ -7104,6 +7108,29 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
||||
return ir_emit_conv(proc, v, tv.type);
|
||||
}
|
||||
|
||||
if (tv.value.kind == ExactValue_Procedure) {
|
||||
Ast *expr = tv.value.value_procedure;
|
||||
if (expr->kind == Ast_ProcLit) {
|
||||
return ir_gen_anonymous_proc_lit(proc->module, str_lit("_proclit"), expr);
|
||||
}
|
||||
Entity *e = entity_from_expr(expr);
|
||||
e = strip_entity_wrapping(e);
|
||||
GB_ASSERT(e != nullptr);
|
||||
auto *found = map_get(&proc->module->values, hash_entity(e));
|
||||
if (found) {
|
||||
auto v = *found;
|
||||
// NOTE(bill): This is because pointers are already pointers in LLVM
|
||||
if (is_type_proc(ir_type(v))) {
|
||||
return v;
|
||||
}
|
||||
return ir_emit_load(proc, v);
|
||||
} else if (e != nullptr && e->kind == Entity_Variable) {
|
||||
return ir_addr_load(proc, ir_build_addr(proc, expr));
|
||||
}
|
||||
|
||||
GB_PANIC("Error in: %.*s(%td:%td) %s\n", LIT(proc->name), e->token.pos.line, e->token.pos.column);
|
||||
}
|
||||
|
||||
return ir_add_module_constant(proc->module, tv.type, tv.value);
|
||||
}
|
||||
|
||||
@@ -7139,6 +7166,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
||||
|
||||
case_ast_node(i, Ident, expr);
|
||||
Entity *e = entity_of_ident(expr);
|
||||
e = strip_entity_wrapping(e);
|
||||
|
||||
GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr));
|
||||
if (e->kind == Entity_Builtin) {
|
||||
Token token = ast_token(expr);
|
||||
|
||||
@@ -8565,6 +8565,30 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
GB_ASSERT(tv.mode != Addressing_Type);
|
||||
|
||||
if (tv.value.kind != ExactValue_Invalid) {
|
||||
if (tv.value.kind == ExactValue_Procedure) {
|
||||
Ast *expr = tv.value.value_procedure;
|
||||
if (expr->kind == Ast_ProcLit) {
|
||||
return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
|
||||
}
|
||||
Entity *e = entity_from_expr(expr);
|
||||
e = strip_entity_wrapping(e);
|
||||
GB_ASSERT(e != nullptr);
|
||||
auto *found = map_get(&p->module->values, hash_entity(e));
|
||||
if (found) {
|
||||
auto v = *found;
|
||||
// NOTE(bill): This is because pointers are already pointers in LLVM
|
||||
if (is_type_proc(v.type)) {
|
||||
return v;
|
||||
}
|
||||
return lb_emit_load(p, v);
|
||||
} else if (e != nullptr && e->kind == Entity_Variable) {
|
||||
return lb_addr_load(p, lb_build_addr(p, expr));
|
||||
}
|
||||
|
||||
GB_PANIC("Error in: %.*s(%td:%td) %s\n", LIT(p->name), e->token.pos.line, e->token.pos.column);
|
||||
// GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(e->pkg->name), LIT(e->token.string), e, type_to_string(e->type), expr);
|
||||
}
|
||||
|
||||
// NOTE(bill): Short on constant values
|
||||
return lb_const_value(p->module, tv.type, tv.value);
|
||||
}
|
||||
@@ -8599,7 +8623,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Ident, expr);
|
||||
Entity *e = entity_of_ident(expr);
|
||||
Entity *e = entity_from_expr(expr);
|
||||
e = strip_entity_wrapping(e);
|
||||
|
||||
GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr));
|
||||
if (e->kind == Entity_Builtin) {
|
||||
Token token = ast_token(expr);
|
||||
@@ -8626,8 +8652,12 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
} else if (e != nullptr && e->kind == Entity_Variable) {
|
||||
return lb_addr_load(p, lb_build_addr(p, expr));
|
||||
}
|
||||
gb_printf_err("Error in: %.*s(%td:%td)\n", LIT(p->name), i->token.pos.line, i->token.pos.column);
|
||||
GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(e->pkg->name), LIT(e->token.string), e, type_to_string(e->type), expr);
|
||||
gb_printf_err("Error in: %.*s(%td:%td) %s\n", LIT(p->name), i->token.pos.line, i->token.pos.column);
|
||||
String pkg = {};
|
||||
if (e->pkg) {
|
||||
pkg = e->pkg->name;
|
||||
}
|
||||
GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr);
|
||||
return {};
|
||||
case_end;
|
||||
|
||||
@@ -9085,7 +9115,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
if (tav.mode == Addressing_Type) { // Addressing_Type
|
||||
Selection sel = lookup_field(type, selector, true);
|
||||
Entity *e = sel.entity;
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
GB_ASSERT_MSG(e->kind == Entity_Variable, "Entity_%.*s", LIT(entity_strings[e->kind]));
|
||||
GB_ASSERT(e->flags & EntityFlag_TypeField);
|
||||
String name = e->token.string;
|
||||
/*if (name == "names") {
|
||||
|
||||
@@ -1039,6 +1039,9 @@ bool is_type_constant_type(Type *t) {
|
||||
if (t->kind == Type_BitSet) {
|
||||
return true;
|
||||
}
|
||||
if (t->kind == Type_Proc) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_float(Type *t) {
|
||||
|
||||
Reference in New Issue
Block a user