Make array types (quasi-)lazy

Fixes #3843
master
LemonBoy 2019-12-08 17:38:03 +01:00 committed by Andrew Kelley
parent 1cb19d1a46
commit d5e788072d
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
4 changed files with 131 additions and 58 deletions

View File

@ -322,6 +322,7 @@ enum LazyValueId {
LazyValueIdSliceType,
LazyValueIdFnType,
LazyValueIdErrUnionType,
LazyValueIdArrayType,
};
struct LazyValue {
@ -355,6 +356,15 @@ struct LazyValueSliceType {
bool is_allowzero;
};
struct LazyValueArrayType {
LazyValue base;
IrAnalyze *ira;
IrInstruction *sentinel; // can be null
IrInstruction *elem_type;
uint64_t length;
};
struct LazyValuePtrType {
LazyValue base;

View File

@ -1147,6 +1147,21 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent
parent_type_val, is_zero_bits);
}
}
case LazyValueIdArrayType: {
LazyValueArrayType *lazy_array_type =
reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
if (lazy_array_type->length < 1) {
*is_zero_bits = true;
return ErrorNone;
}
if ((err = type_val_resolve_zero_bits(g, lazy_array_type->elem_type->value,
parent_type, nullptr, is_zero_bits)))
return err;
return ErrorNone;
}
case LazyValueIdOptType:
case LazyValueIdSliceType:
case LazyValueIdErrUnionType:
@ -1181,6 +1196,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ZigValue *type_val, bool *is_o
case LazyValueIdFnType:
case LazyValueIdOptType:
case LazyValueIdErrUnionType:
case LazyValueIdArrayType:
*is_opaque_type = false;
return ErrorNone;
}
@ -1208,6 +1224,10 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ZigValue *type
LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(type_val->data.x_lazy);
return type_val_resolve_requires_comptime(g, lazy_opt_type->payload_type->value);
}
case LazyValueIdArrayType: {
LazyValueArrayType *lazy_array_type = reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
return type_val_resolve_requires_comptime(g, lazy_array_type->elem_type->value);
}
case LazyValueIdFnType: {
LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy);
if (lazy_fn_type->is_generic)
@ -1305,6 +1325,7 @@ start_over:
return ErrorNone;
case LazyValueIdOptType:
case LazyValueIdErrUnionType:
case LazyValueIdArrayType:
if ((err = ir_resolve_lazy(g, source_node, type_val)))
return err;
goto start_over;
@ -1340,6 +1361,11 @@ Error type_val_resolve_abi_align(CodeGen *g, ZigValue *type_val, uint32_t *abi_a
LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(type_val->data.x_lazy);
return type_val_resolve_abi_align(g, lazy_opt_type->payload_type->value, abi_align);
}
case LazyValueIdArrayType: {
LazyValueArrayType *lazy_array_type =
reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
return type_val_resolve_abi_align(g, lazy_array_type->elem_type->value, abi_align);
}
case LazyValueIdErrUnionType: {
LazyValueErrUnionType *lazy_err_union_type =
reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy);
@ -1370,6 +1396,13 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV
case LazyValueIdOptType: // it has the optional bit
case LazyValueIdFnType:
return OnePossibleValueNo;
case LazyValueIdArrayType: {
LazyValueArrayType *lazy_array_type =
reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
if (lazy_array_type->length < 1)
return OnePossibleValueYes;
return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value);
}
case LazyValueIdPtrType: {
Error err;
bool zero_bits;

View File

@ -20551,73 +20551,28 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs
static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
IrInstructionArrayType *array_type_instruction)
{
Error err;
IrInstruction *result = ir_const(ira, &array_type_instruction->base, ira->codegen->builtin_types.entry_type);
result->value->special = ConstValSpecialLazy;
IrInstruction *size_value = array_type_instruction->size->child;
uint64_t size;
if (!ir_resolve_usize(ira, size_value, &size))
LazyValueArrayType *lazy_array_type = allocate<LazyValueArrayType>(1, "LazyValueArrayType");
lazy_array_type->ira = ira; ira_ref(ira);
result->value->data.x_lazy = &lazy_array_type->base;
lazy_array_type->base.id = LazyValueIdArrayType;
lazy_array_type->elem_type = array_type_instruction->child_type->child;
if (ir_resolve_type_lazy(ira, lazy_array_type->elem_type) == nullptr)
return ira->codegen->invalid_instruction;
IrInstruction *child_type_value = array_type_instruction->child_type->child;
ZigType *child_type = ir_resolve_type(ira, child_type_value);
if (type_is_invalid(child_type))
if (!ir_resolve_usize(ira, array_type_instruction->size->child, &lazy_array_type->length))
return ira->codegen->invalid_instruction;
ZigValue *sentinel_val;
if (array_type_instruction->sentinel != nullptr) {
IrInstruction *uncasted_sentinel = array_type_instruction->sentinel->child;
if (type_is_invalid(uncasted_sentinel->value->type))
lazy_array_type->sentinel = array_type_instruction->sentinel->child;
if (ir_resolve_const(ira, lazy_array_type->sentinel, LazyOk) == nullptr)
return ira->codegen->invalid_instruction;
IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, child_type);
if (type_is_invalid(sentinel->value->type))
return ira->codegen->invalid_instruction;
sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
if (sentinel_val == nullptr)
return ira->codegen->invalid_instruction;
} else {
sentinel_val = nullptr;
}
switch (child_type->id) {
case ZigTypeIdInvalid: // handled above
zig_unreachable();
case ZigTypeIdUnreachable:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
ir_add_error_node(ira, array_type_instruction->base.source_node,
buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));
return ira->codegen->invalid_instruction;
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
case ZigTypeIdBool:
case ZigTypeIdInt:
case ZigTypeIdFloat:
case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdStruct:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdEnumLiteral:
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
{
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
ZigType *result_type = get_array_type(ira->codegen, child_type, size, sentinel_val);
return ir_const_type(ira, &array_type_instruction->base, result_type);
}
}
zig_unreachable();
return result;
}
static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructionSizeOf *instruction) {
@ -29016,6 +28971,72 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
// We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
return ErrorNone;
}
case LazyValueIdArrayType: {
LazyValueArrayType *lazy_array_type = reinterpret_cast<LazyValueArrayType *>(val->data.x_lazy);
IrAnalyze *ira = lazy_array_type->ira;
ZigType *elem_type = ir_resolve_type(ira, lazy_array_type->elem_type);
if (type_is_invalid(elem_type))
return ErrorSemanticAnalyzeFail;
switch (elem_type->id) {
case ZigTypeIdInvalid: // handled above
zig_unreachable();
case ZigTypeIdUnreachable:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
ir_add_error(ira, lazy_array_type->elem_type,
buf_sprintf("array of type '%s' not allowed",
buf_ptr(&elem_type->name)));
return ErrorSemanticAnalyzeFail;
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
case ZigTypeIdBool:
case ZigTypeIdInt:
case ZigTypeIdFloat:
case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdStruct:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdEnumLiteral:
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
break;
}
if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
return err;
ZigValue *sentinel_val = nullptr;
if (lazy_array_type->sentinel != nullptr) {
if (type_is_invalid(lazy_array_type->sentinel->value->type))
return ErrorSemanticAnalyzeFail;
IrInstruction *sentinel = ir_implicit_cast(ira, lazy_array_type->sentinel, elem_type);
if (type_is_invalid(sentinel->value->type))
return ErrorSemanticAnalyzeFail;
sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
if (sentinel_val == nullptr)
return ErrorSemanticAnalyzeFail;
}
assert(val->type->id == ZigTypeIdMetaType);
val->data.x_type = get_array_type(ira->codegen, elem_type, lazy_array_type->length, sentinel_val);
val->special = ConstValSpecialStatic;
// We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
return ErrorNone;
}
case LazyValueIdOptType: {
LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(val->data.x_lazy);
IrAnalyze *ira = lazy_opt_type->ira;

View File

@ -813,3 +813,12 @@ test "anon struct literal field value initialized with fn call" {
S.doTheTest();
comptime S.doTheTest();
}
test "self-referencing struct via array member" {
const T = struct {
children: [1]*@This(),
};
var x: T = undefined;
x = T{ .children = .{&x} };
expect(x.children[0] == &x);
}