temp[1] = map_to_ascii(val & 15);
temp[2] = #char " ";
- runtime.__output_string(.{ ~~temp, 3 });
+ runtime.__output_string(~~temp);
if i % bytes_per_line == (bytes_per_line - 1) do runtime.__output_string("\n");
}
struct Entity* entity_type;
struct Entity* entity_defaults;
+
+ b32 stcache_is_valid : 1;
};
struct AstStructMember {
AstTyped_base;
EntityState state;
// TODO: Document this!
- u16 macro_attempts;
- u16 micro_attempts;
+ u32 macro_attempts;
+ u32 micro_attempts;
b32 entered_in_queue : 1;
if (unaryop->operation == Unary_Op_Cast) {
char* err;
+ if (unaryop->type == NULL) return Check_Yield_Macro;
+
if (!cast_is_legal(unaryop->expr->type, unaryop->type, &err)) {
onyx_report_error(unaryop->token->pos, "Cast Error: %s", err);
return Check_Error;
}
fill_in_type((AstTyped *) sl);
- if (sl->type == NULL) return Check_Error;
+ if (sl->type == NULL) return Check_Yield_Macro;
}
if (!type_is_structlike_strict(sl->type)) {
i32 mem_count = type_structlike_mem_count(sl->type);
arguments_ensure_length(&sl->args, mem_count);
- char* err_msg = NULL;
- if (!fill_in_arguments(&sl->args, (AstNode *) sl, &err_msg)) {
- onyx_report_error(sl->token->pos, err_msg);
-
- bh_arr_each(AstTyped *, value, sl->args.values) {
- if (*value == NULL) {
- i32 member_idx = value - sl->args.values; // Pointer subtraction hack
- StructMember smem;
- type_lookup_member_by_idx(sl->type, member_idx, &smem);
-
- onyx_report_error(sl->token->pos,
- "Value not given for %d%s member, '%s', for type '%s'.",
- member_idx + 1, bh_num_suffix(member_idx + 1),
- smem.name, type_get_name(sl->type));
+ // :Idempotency
+ if ((sl->flags & Ast_Flag_Has_Been_Checked) == 0) {
+ char* err_msg = NULL;
+ if (!fill_in_arguments(&sl->args, (AstNode *) sl, &err_msg)) {
+ onyx_report_error(sl->token->pos, err_msg);
+
+ bh_arr_each(AstTyped *, value, sl->args.values) {
+ if (*value == NULL) {
+ i32 member_idx = value - sl->args.values; // Pointer subtraction hack
+ StructMember smem;
+ type_lookup_member_by_idx(sl->type, member_idx, &smem);
+
+ onyx_report_error(sl->token->pos,
+ "Value not given for %d%s member, '%s', for type '%s'.",
+ member_idx + 1, bh_num_suffix(member_idx + 1),
+ smem.name, type_get_name(sl->type));
+ }
}
- }
- return Check_Error;
+ return Check_Error;
+ }
}
+ sl->flags |= Ast_Flag_Has_Been_Checked;
AstTyped** actual = sl->args.values;
StructMember smem;
}
CheckStatus check_array_literal(AstArrayLiteral* al) {
+ // :Idempotency
if ((al->flags & Ast_Flag_Array_Literal_Typed) == 0) {
if (al->atnode == NULL) return Check_Success;
}
fill_in_type((AstTyped *) al);
- if (al->type == NULL) return Check_Error;
+ if (al->type == NULL) return Check_Yield_Macro;
al->type = type_make_array(context.ast_alloc, al->type, bh_arr_length(al->values));
if (al->type == NULL || al->type->kind != Type_Kind_Array) {
bh_arr_each(AstTyped *, expr, al->values) {
CHECK(expression, expr);
+ // HACK HACK HACK
+ if ((*expr)->type == NULL &&
+ (*expr)->entity != NULL &&
+ (*expr)->entity->state <= Entity_State_Check_Types) {
+ return Check_Yield_Macro;
+ }
+
al->flags &= ((*expr)->flags & Ast_Flag_Comptime) | (al->flags &~ Ast_Flag_Comptime);
if (!type_check_or_auto_cast(expr, elem_type)) {
CHECK(expression, &(*mcall)->left);
AstTyped* implicit_argument = (*mcall)->left;
-
- // Implicitly take the address of the value if it is not already a pointer type.
- // This could be weird to think about semantically so some testing with real code
- // would be good. - brendanfh 2020/02/05
- if (implicit_argument->type->kind != Type_Kind_Pointer)
- implicit_argument = (AstTyped *) make_address_of(context.ast_alloc, implicit_argument);
-
- implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument);
// Symbol resolution should have ensured that this is call node.
AstCall* call_node = (AstCall *) (*mcall)->right;
assert(call_node->kind == Ast_Kind_Call);
- bh_arr_insertn(call_node->args.values, 0, 1);
- call_node->args.values[0] = implicit_argument;
+ // :Idempotency
+ if (((*mcall)->flags & Ast_Flag_Has_Been_Checked) == 0) {
+ // Implicitly take the address of the value if it is not already a pointer type.
+ // This could be weird to think about semantically so some testing with real code
+ // would be good. - brendanfh 2020/02/05
+ if (implicit_argument->type->kind != Type_Kind_Pointer)
+ implicit_argument = (AstTyped *) make_address_of(context.ast_alloc, implicit_argument);
+
+ implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument);
+
+ bh_arr_insertn(call_node->args.values, 0, 1);
+ call_node->args.values[0] = implicit_argument;
+ }
+ (*mcall)->flags |= Ast_Flag_Has_Been_Checked;
CHECK(call, call_node);
call_node->next = (*mcall)->next;
fill_in_array_count(so->so_ast_type);
so->so_type = type_build_from_ast(context.ast_alloc, so->so_ast_type);
- if (so->so_type == NULL) {
- onyx_report_error(so->token->pos, "Error with type used here.");
- return Check_Error;
- }
+ if (so->so_type == NULL) return Check_Yield_Macro;
+
so->size = type_size_of(so->so_type);
return Check_Success;
fill_in_array_count(ao->ao_ast_type);
ao->ao_type = type_build_from_ast(context.ast_alloc, ao->ao_ast_type);
- if (ao->ao_type == NULL) {
- onyx_report_error(ao->token->pos, "Error with type used here.");
- return Check_Error;
- }
+ if (ao->ao_type == NULL) return Check_Yield_Macro;
+
ao->alignment = type_alignment_of(ao->ao_type);
return Check_Success;
// in a block in order to efficiently allocate enough space and registers
// for them all. Now with LocalAllocator, this is no longer necessary.
// Therefore, locals stay in the tree and need to be passed along.
- case Ast_Kind_Local:
- fill_in_type((AstTyped *) stmt);
+ case Ast_Kind_Local: {
+ AstTyped* typed_stmt = (AstTyped *) stmt;
+ fill_in_type(typed_stmt);
+ if (typed_stmt->type_node != NULL && typed_stmt->type == NULL) return Check_Yield_Macro;
return Check_Success;
+ }
default:
CHECK(expression, (AstTyped **) pstmt);
expected_return_type = func->type->Function.return_type;
if (func->body) {
CheckStatus status = check_block(func->body);
- if (status != Check_Success && func->generated_from)
+ if (status == Check_Error && func->generated_from)
onyx_report_error(func->generated_from->pos, "Error in polymorphic procedure generated from this location.");
return status;
bh_arr_each(AstStructMember *, smem, s_node->members) {
if ((*smem)->type_node == NULL && (*smem)->initial_value != NULL) {
CHECK(expression, &(*smem)->initial_value);
+
fill_in_type((*smem)->initial_value);
+ if ((*smem)->initial_value->type == NULL) return Check_Yield_Macro;
+
(*smem)->type = resolve_expression_type((*smem)->initial_value);
if ((*smem)->type == NULL) {
if (local->type_node != NULL) CHECK(type, local->type_node);
fill_in_type((AstTyped *) local);
-
if (local->type == NULL) {
- onyx_report_error(param->local->token->pos,
- "Unable to resolve type for parameter, '%b'",
- local->token->text,
- local->token->length);
- return Check_Error;
+ // onyx_report_error(param->local->token->pos,
+ // "Unable to resolve type for parameter, '%b'",
+ // local->token->text,
+ // local->token->length);
+ return Check_Yield_Macro;
}
if (local->type->kind == Type_Kind_Compound) {
if (func->return_type != NULL) CHECK(type, func->return_type);
func->type = type_build_function_type(context.ast_alloc, func);
+ if (func->type == NULL) return Check_Yield_Macro;
return Check_Success;
}
CheckStatus check_memres_type(AstMemRes* memres) {
fill_in_type((AstTyped *) memres);
+ if (memres->type_node && !memres->type) return Check_Yield_Macro;
return Check_Success;
}
AstFunctionType* ftype_node = (AstFunctionType *) type_node;
u64 param_count = ftype_node->param_count;
+ Type* return_type = type_build_from_ast(alloc, ftype_node->return_type);
+ if (return_type == NULL) return NULL;
+
Type* func_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * param_count);
func_type->kind = Type_Kind_Function;
func_type->ast_type = type_node;
func_type->Function.param_count = param_count;
func_type->Function.needed_param_count = param_count;
- func_type->Function.return_type = type_build_from_ast(alloc, ftype_node->return_type);
+ func_type->Function.return_type = return_type;
if (param_count > 0)
fori (i, 0, (i64) param_count) {
func_type->Function.params[i] = type_build_from_ast(alloc, ftype_node->params[i]);
+
+ // LEAK LEAK LEAK
+ if (func_type->Function.params[i] == NULL) return NULL;
}
return func_type;
case Ast_Kind_Struct_Type: {
AstStructType* s_node = (AstStructType *) type_node;
- if (s_node->stcache != NULL) return s_node->stcache;
+ if (s_node->stcache != NULL && s_node->stcache_is_valid) return s_node->stcache;
+
+ Type* s_type;
+ if (s_node->stcache == NULL) {
+ s_type = bh_alloc(alloc, sizeof(Type));
+ s_node->stcache = s_type;
- Type* s_type = bh_alloc(alloc, sizeof(Type));
- s_node->stcache = s_type;
- s_type->kind = Type_Kind_Struct;
- s_type->ast_type = type_node;
+ s_type->kind = Type_Kind_Struct;
+ s_type->ast_type = type_node;
+ s_type->Struct.name = s_node->name;
+ s_type->Struct.unique_id = next_unique_id++;
+ s_type->Struct.mem_count = bh_arr_length(s_node->members);
+
+ } else {
+ s_type = s_node->stcache;
+ }
- s_type->Struct.unique_id = next_unique_id++;
- s_type->Struct.name = s_node->name;
- s_type->Struct.mem_count = bh_arr_length(s_node->members);
s_type->Struct.memarr = NULL;
s_type->Struct.poly_sln = NULL;
bh_table_init(global_heap_allocator, s_type->Struct.members, s_type->Struct.mem_count + 1);
bh_arr_new(global_heap_allocator, s_type->Struct.memarr, s_type->Struct.mem_count);
+ s_node->stcache_is_valid = 1;
+
b32 is_union = (s_node->flags & Ast_Flag_Struct_Is_Union) != 0;
u32 size = 0;
u32 offset = 0;
(*member)->type = type_build_from_ast(alloc, (*member)->type_node);
if ((*member)->type == NULL) {
- // :ExplicitTyping
- // onyx_report_error((*member)->token->pos, "Unable to resolve member type. Try adding it explicitly.");
- s_node->stcache = NULL;
+ // LEAK LEAK LEAK
+ s_node->stcache_is_valid = 0;
return NULL;
}
mem_alignment = type_alignment_of((*member)->type);
if (mem_alignment <= 0) {
onyx_report_error((*member)->token->pos, "Invalid member type: %s", type_get_name((*member)->type));
- return s_type;
+ return NULL;
}
if (mem_alignment > alignment) alignment = mem_alignment;
bh_arr_new(global_heap_allocator, slns, bh_arr_length(pc_type->params));
bh_arr_each(AstNode *, given, pc_type->params) {
if (node_is_type(*given)) {
+ Type* param_type = type_build_from_ast(alloc, (AstType *) *given);
+
+ // LEAK LEAK LEAK
+ if (param_type == NULL) return NULL;
+
bh_arr_push(slns, ((AstPolySolution) {
.kind = PSK_Type,
- .type = type_build_from_ast(alloc, (AstType *) *given),
+ .type = param_type,
}));
} else {
bh_arr_push(slns, ((AstPolySolution) {
fori (i, 0, type_count) {
assert(ctype->types[i] != NULL);
comp_type->Compound.types[i] = type_build_from_ast(alloc, ctype->types[i]);
+
+ // LEAK LEAK LEAK
+ if (comp_type->Compound.types[i] == NULL) return NULL;
+
comp_type->Compound.size += bh_max(type_size_of(comp_type->Compound.types[i]), 4);
}
return NULL;
}
+// CLEANUP: This needs to be merged with the very similar code from up above.
Type* type_build_function_type(bh_allocator alloc, AstFunction* func) {
u64 param_count = bh_arr_length(func->params);
+ Type* return_type = type_build_from_ast(alloc, func->return_type);
+ if (return_type == NULL) return NULL;
+
Type* func_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * param_count);
func_type->kind = Type_Kind_Function;
func_type->Function.param_count = param_count;
func_type->Function.needed_param_count = 0;
- func_type->Function.return_type = type_build_from_ast(alloc, func->return_type);
+ func_type->Function.return_type = return_type;
if (param_count > 0) {
i32 i = 0;
char* unique_key = build_poly_slns_unique_key(slns);
if (bh_table_has(AstStructType *, ps_type->concrete_structs, unique_key)) {
- return bh_table_get(AstStructType *, ps_type->concrete_structs, unique_key);
- }
+ AstStructType* concrete_struct = bh_table_get(AstStructType *, ps_type->concrete_structs, unique_key);
- scope_clear(ps_type->scope);
- insert_poly_slns_into_scope(ps_type->scope, slns);
+ if (concrete_struct->entity_type->state < Entity_State_Check_Types) {
+ return NULL;
+ }
- AstStructType* concrete_struct = (AstStructType *) ast_clone(context.ast_alloc, ps_type->base_struct);
- bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, concrete_struct);
+ Type* cs_type = type_build_from_ast(context.ast_alloc, (AstType *) concrete_struct);
+ if (!cs_type) return NULL;
- Entity struct_entity = {
- .state = Entity_State_Resolve_Symbols,
- .type = Entity_Type_Type_Alias,
- .type_alias = (AstType *) concrete_struct,
- .package = NULL,
- .scope = ps_type->scope,
- };
- Entity struct_default_entity = {
- .state = Entity_State_Resolve_Symbols,
- .type = Entity_Type_Struct_Member_Default,
- .type_alias = (AstType *) concrete_struct,
- .package = NULL,
- .scope = ps_type->scope,
- };
+ if (cs_type->Struct.poly_sln == NULL) cs_type->Struct.poly_sln = bh_arr_copy(global_heap_allocator, slns);
+ if (cs_type->Struct.name == NULL) cs_type->Struct.name = build_poly_struct_name(ps_type, cs_type);
- entity_bring_to_state(&struct_entity, Entity_State_Check_Types);
- entity_bring_to_state(&struct_default_entity, Entity_State_Check_Types);
- entity_bring_to_state(&struct_entity, Entity_State_Code_Gen);
- entity_bring_to_state(&struct_default_entity, Entity_State_Code_Gen);
-
- if (onyx_has_errors()) {
- onyx_report_error(pos, "Error in creating polymorphic struct instantiation here.");
- bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, NULL);
- return NULL;
+ return concrete_struct;
}
- Type* cs_type = type_build_from_ast(context.ast_alloc, (AstType *) concrete_struct);
+ Scope* sln_scope = scope_create(context.ast_alloc, ps_type->scope, ps_type->token->pos);
+ insert_poly_slns_into_scope(sln_scope, slns);
- // CLEANUP: This should not be necessary since the only place this function can be
- // called from is type_build_from_ast in the Ast_Kind_Poly_Call_Type case, which
- // allocates the 'slns' array on the heap. So, duplicating it should not be necessary.
- cs_type->Struct.poly_sln = bh_arr_copy(global_heap_allocator, slns);
+ AstStructType* concrete_struct = (AstStructType *) ast_clone(context.ast_alloc, ps_type->base_struct);
+ bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, concrete_struct);
- cs_type->Struct.name = build_poly_struct_name(ps_type, cs_type);
- return concrete_struct;
+ add_entities_for_node(NULL, (AstNode *) concrete_struct, sln_scope, NULL);
+ return NULL;
}
void entity_bring_to_state(Entity* ent, EntityState state) {