Merge branch 'emekoi-fix-1711'

This commit is contained in:
Andrew Kelley 2019-02-18 13:12:03 -05:00
commit 74a335c4cc
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
5 changed files with 97 additions and 77 deletions

View File

@ -2221,8 +2221,9 @@ test "packed enum" {
{#header_close#}
{#header_open|union#}
{#code_begin|test|union#}
const assert = @import("std").debug.assert;
const mem = @import("std").mem;
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
// A union has only 1 active field at a time.
const Payload = union {
@ -2231,16 +2232,19 @@ const Payload = union {
Bool: bool,
};
test "simple union" {
var payload = Payload {.Int = 1234};
var payload = Payload{ .Int = 1234 };
// payload.Float = 12.34; // ERROR! field not active
assert(payload.Int == 1234);
// You can activate another field by assigning the entire union.
payload = Payload {.Float = 12.34};
payload = Payload{ .Float = 12.34 };
assert(payload.Float == 12.34);
}
// Unions can be given an enum tag type:
const ComplexTypeTag = enum { Ok, NotOk };
const ComplexTypeTag = enum {
Ok,
NotOk,
};
const ComplexType = union(ComplexTypeTag) {
Ok: u8,
NotOk: void,
@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {
// Declare a specific instance of the union variant.
test "declare union value" {
const c = ComplexType { .Ok = 0 };
const c = ComplexType{ .Ok = 0 };
assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
}
// @TagType can be used to access the enum tag type of a union.
// @TagType can be used to access the enum tag type of a tagged union.
test "@TagType" {
assert(@TagType(ComplexType) == ComplexTypeTag);
}
@ -2266,7 +2270,7 @@ const Foo = union(enum) {
None,
};
test "union variant switch" {
const p = Foo { .Number = 54 };
const p = Foo{ .Number = 54 };
const what_is_it = switch (p) {
// Capture by reference
Foo.String => |*x| blk: {
@ -2301,14 +2305,13 @@ const Variant = union(enum) {
};
test "union method" {
var v1 = Variant { .Int = 1 };
var v2 = Variant { .Bool = false };
var v1 = Variant{ .Int = 1 };
var v2 = Variant{ .Bool = false };
assert(v1.truthy());
assert(!v2.truthy());
}
const Small = union {
A: i32,
B: bool,
@ -5660,12 +5663,13 @@ test "main" {
{#header_close#}
{#header_open|@enumToInt#}
<pre>{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}</pre>
<pre>{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}</pre>
<p>
Converts an enumeration value into its integer tag type.
Converts an enumeration value into its integer tag type. When a tagged union is passed,
the tag value is used as the enumeration value.
</p>
<p>
If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#}
If there is only one possible enum value, the resut is a {#syntax#}comptime_int{#endsyntax#}
known at {#link|comptime#}.
</p>
{#see_also|@intToEnum#}

View File

@ -10305,49 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
return result;
}
static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, ZigType *wanted_type)
{
static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
assert(union_type->id == ZigTypeIdUnion);
Error err;
assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
return ira->codegen->builtin_types.entry_invalid;
ZigType *actual_type = target->value.type;
if ((err = ensure_complete_type(ira->codegen, actual_type)))
return ira->codegen->invalid_instruction;
AstNode *decl_node = union_type->data.unionation.decl_node;
if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
assert(union_type->data.unionation.tag_type != nullptr);
return union_type->data.unionation.tag_type;
} else {
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union '%s' has no tag",
buf_ptr(&union_type->name)));
add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
return ira->codegen->builtin_types.entry_invalid;
}
}
if (wanted_type != actual_type->data.enumeration.tag_int_type) {
ir_add_error(ira, source_instr,
buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
buf_ptr(&wanted_type->name),
buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
Error err;
IrInstruction *enum_target;
ZigType *enum_type;
if (target->value.type->id == ZigTypeIdUnion) {
enum_type = ir_resolve_union_tag_type(ira, target, target->value.type);
if (type_is_invalid(enum_type))
return ira->codegen->invalid_instruction;
enum_target = ir_implicit_cast(ira, target, enum_type);
if (type_is_invalid(enum_target->value.type))
return ira->codegen->invalid_instruction;
} else if (target->value.type->id == ZigTypeIdEnum) {
enum_target = target;
enum_type = target->value.type;
} else {
ir_add_error(ira, target,
buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
return ira->codegen->invalid_instruction;
}
assert(actual_type->id == ZigTypeIdEnum);
if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
if (instr_is_comptime(target)) {
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
ZigType *tag_type = enum_type->data.enumeration.tag_int_type;
assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt);
if (instr_is_comptime(enum_target)) {
ConstExprValue *val = ir_resolve_const(ira, enum_target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
IrInstruction *result = ir_const(ira, source_instr, tag_type);
init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
return result;
}
// If there is only one possible tag, then we know at comptime what it is.
if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
actual_type->data.enumeration.src_field_count == 1)
if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
enum_type->data.enumeration.src_field_count == 1)
{
assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type,
&actual_type->data.enumeration.fields[0].value);
assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
IrInstruction *result = ir_const(ira, source_instr, tag_type);
init_const_bigint(&result->value, tag_type,
&enum_type->data.enumeration.fields[0].value);
return result;
}
IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
source_instr->source_node, target);
result->value.type = wanted_type;
source_instr->source_node, enum_target);
result->value.type = tag_type;
return result;
}
@ -14358,12 +14384,12 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
if (dst_size == 0)
return ErrorNone;
opt_ir_add_error_node(ira, codegen, source_node,
buf_sprintf("attempt to read %zu bytes from null pointer",
buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from null pointer",
dst_size));
return ErrorSemanticAnalyzeFail;
case ConstPtrSpecialRef: {
opt_ir_add_error_node(ira, codegen, source_node,
buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from pointer to %s which is %" ZIG_PRI_usize " bytes",
dst_size, buf_ptr(&pointee->type->name), src_size));
return ErrorSemanticAnalyzeFail;
}
@ -14377,7 +14403,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
src_size = elem_size * (array_val->type->data.array.len - elem_index);
if (dst_size > src_size) {
opt_ir_add_error_node(ira, codegen, source_node,
buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes",
buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
return ErrorSemanticAnalyzeFail;
}
@ -21364,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
} else if (enum_type->id == ZigTypeIdUnion) {
if ((err = ensure_complete_type(ira->codegen, enum_type)))
ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
if (type_is_invalid(tag_type))
return ira->codegen->invalid_instruction;
AstNode *decl_node = enum_type->data.unionation.decl_node;
if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
assert(enum_type->data.unionation.tag_type != nullptr);
return ir_const_type(ira, &instruction->base, enum_type->data.unionation.tag_type);
} else {
ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
buf_ptr(&enum_type->name)));
add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
return ira->codegen->invalid_instruction;
}
return ir_const_type(ira, &instruction->base, tag_type);
} else {
ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
buf_ptr(&enum_type->name)));
@ -21958,23 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
Error err;
IrInstruction *target = instruction->target->child;
if (type_is_invalid(target->value.type))
return ira->codegen->invalid_instruction;
if (target->value.type->id != ZigTypeIdEnum) {
ir_add_error(ira, instruction->target,
buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
return ira->codegen->invalid_instruction;
}
if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
ZigType *tag_type = target->value.type->data.enumeration.tag_int_type;
return ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type);
return ir_analyze_enum_to_int(ira, &instruction->base, target);
}
static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {

View File

@ -9,6 +9,7 @@
#include "error.hpp"
#include "target.hpp"
#include "util.hpp"
#include "os.hpp"
#include <stdio.h>
@ -848,7 +849,7 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio
if (is_static) {
return ".a";
} else {
return buf_ptr(buf_sprintf(".so.%zu", version_major));
return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize, version_major));
}
}
}

View File

@ -350,3 +350,18 @@ test "union with only 1 field casted to its enum type which has enum value speci
expect(@enumToInt(t) == 33);
comptime expect(@enumToInt(t) == 33);
}
test "@enumToInt works on unions" {
const Bar = union(enum) {
A: bool,
B: u8,
C,
};
const a = Bar{ .A = true };
var b = Bar{ .B = undefined };
var c = Bar.C;
expect(@enumToInt(a) == 0);
expect(@enumToInt(b) == 1);
expect(@enumToInt(c) == 2);
}

View File

@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {
const source_file = ".tmp_source.zig";
fn init(input: []const u8) ErrLineIter {
return ErrLineIter {
.lines = mem.separate(input, "\n"),
};
return ErrLineIter{ .lines = mem.separate(input, "\n") };
}
fn next(self: *ErrLineIter) ?[]const u8 {
@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {
for (self.case.expected_errors.toSliceConst()) |expected| {
if (mem.indexOf(u8, stderr, expected) == null) {
warn(
\\=========== Expected compile error: ============
\\\n=========== Expected compile error: ============
\\{}
\\
, expected
);
, expected);
ok = false;
break;
}
@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {
\\================= Full output: =================
\\{}
\\
, stderr
);
, stderr);
return error.TestFailed;
}