allow top level declarations to be lazy

this case now works:

```zig
const A = struct {
    b: B,
};
const B = fn (A) void;
```
This commit is contained in:
Andrew Kelley 2019-08-23 14:07:34 -04:00
parent 20049caaba
commit 1dd658d1d0
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
5 changed files with 47 additions and 38 deletions

View File

@ -423,6 +423,7 @@ enum TldResolution {
TldResolutionUnresolved,
TldResolutionResolving,
TldResolutionInvalid,
TldResolutionOkLazy,
TldResolutionOk,
};

View File

@ -3091,7 +3091,7 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source
void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name);
resolve_top_level_decl(g, tld, tld->source_node);
resolve_top_level_decl(g, tld, tld->source_node, false);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
tld_var->var->const_value = value;
@ -3333,7 +3333,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
return variable_entry;
}
static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
AstNode *source_node = tld_var->base.source_node;
AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration;
@ -3364,7 +3364,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
if (explicit_type && explicit_type->id == ZigTypeIdInvalid) {
implicit_type = explicit_type;
} else if (var_decl->expr) {
init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
init_value = analyze_const_value_allow_lazy(g, tld_var->base.parent_scope, var_decl->expr, explicit_type,
var_decl->symbol, allow_lazy);
assert(init_value);
implicit_type = init_value->type;
@ -3539,50 +3540,57 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco
}
}
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
if (tld->resolution != TldResolutionUnresolved)
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) {
bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy;
if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy)
return;
assert(tld->resolution != TldResolutionResolving);
tld->resolution = TldResolutionResolving;
switch (tld->id) {
case TldIdVar:
{
TldVar *tld_var = (TldVar *)tld;
resolve_decl_var(g, tld_var);
break;
}
case TldIdFn:
{
TldFn *tld_fn = (TldFn *)tld;
resolve_decl_fn(g, tld_fn);
break;
}
case TldIdContainer:
{
TldContainer *tld_container = (TldContainer *)tld;
resolve_decl_container(g, tld_container);
break;
}
case TldIdCompTime:
{
TldCompTime *tld_comptime = (TldCompTime *)tld;
resolve_decl_comptime(g, tld_comptime);
break;
case TldIdVar: {
TldVar *tld_var = (TldVar *)tld;
if (want_resolve_lazy) {
ir_resolve_lazy(g, source_node, tld_var->var->const_value);
} else {
resolve_decl_var(g, tld_var, allow_lazy);
}
tld->resolution = allow_lazy ? TldResolutionOkLazy : TldResolutionOk;
break;
}
case TldIdFn: {
TldFn *tld_fn = (TldFn *)tld;
resolve_decl_fn(g, tld_fn);
tld->resolution = TldResolutionOk;
break;
}
case TldIdContainer: {
TldContainer *tld_container = (TldContainer *)tld;
resolve_decl_container(g, tld_container);
tld->resolution = TldResolutionOk;
break;
}
case TldIdCompTime: {
TldCompTime *tld_comptime = (TldCompTime *)tld;
resolve_decl_comptime(g, tld_comptime);
tld->resolution = TldResolutionOk;
break;
}
case TldIdUsingNamespace: {
TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld;
assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls);
ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope;
preview_use_decl(g, tld_using_namespace, dest_decls_scope);
resolve_use_decl(g, tld_using_namespace, dest_decls_scope);
tld->resolution = TldResolutionOk;
break;
}
}
tld->resolution = TldResolutionOk;
if (g->trace_err != nullptr && source_node != nullptr) {
g->trace_err = add_error_note(g, g->trace_err, source_node, buf_create_from_str("referenced here"));
}
@ -4254,7 +4262,7 @@ void semantic_analyze(CodeGen *g) {
Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
g->trace_err = nullptr;
AstNode *source_node = nullptr;
resolve_top_level_decl(g, tld, source_node);
resolve_top_level_decl(g, tld, source_node, false);
}
for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
@ -6602,7 +6610,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) {
ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name));
resolve_top_level_decl(codegen, tld, nullptr);
resolve_top_level_decl(codegen, tld, nullptr, false);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
ConstExprValue *var_value = tld_var->var->const_value;

View File

@ -58,7 +58,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Bu
ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);
Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name);
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node);
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy);
ZigType *get_src_ptr_type(ZigType *type);
ZigType *get_codegen_ptr_type(ZigType *type);

View File

@ -8896,7 +8896,7 @@ static void gen_root_source(CodeGen *g) {
}
Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic"));
assert(panic_tld != nullptr);
resolve_top_level_decl(g, panic_tld, nullptr);
resolve_top_level_decl(g, panic_tld, nullptr, false);
}

View File

@ -17074,7 +17074,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
auto entry = container_scope->decl_table.maybe_get(field_name);
Tld *tld = entry ? entry->value : nullptr;
if (tld && tld->id == TldIdFn) {
resolve_top_level_decl(ira->codegen, tld, source_instr->source_node);
resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false);
if (tld->resolution == TldResolutionInvalid)
return ira->codegen->invalid_instruction;
TldFn *tld_fn = (TldFn *)tld;
@ -17317,7 +17317,7 @@ static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *so
}
static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node);
resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node, true);
if (tld->resolution == TldResolutionInvalid) {
return ira->codegen->invalid_instruction;
}
@ -19682,7 +19682,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
while ((curr_entry = decl_it.next()) != nullptr) {
// If the declaration is unresolved, force it to be resolved again.
if (curr_entry->value->resolution == TldResolutionUnresolved) {
resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node);
resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node, false);
if (curr_entry->value->resolution != TldResolutionOk) {
return ErrorSemanticAnalyzeFail;
}