authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-23 15:30:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-23 15:30:57-07:00
logbb38931c7146678548f63ae9ef71e534c7598fe3
tree3169ee6a69165cd9bebfc6676fb8f18d7684f390
parentd5ef5da5947d24792933847454c84daf1282b29e

stage1: `@intToEnum` implicitly does an `@intCast`

This is a backwards-compatible language change. Previously, `@intToEnum` coerced its integer operand to the integer tag type of the destination enum type, often requiring the callsite to additionally wrap the operand in an `@intCast`. Now, the `@intCast` is implicit, and any integer operand can be passed to `@intToEnum`. The same as before, it is illegal behavior to pass any integer which does not have a corresponding enum tag.

4 files changed, 32 insertions(+), 19 deletions(-)

doc/langref.html.in+4-2
...@@ -3163,7 +3163,9 @@ test "switch using enum literals" {...@@ -3163,7 +3163,9 @@ test "switch using enum literals" {
3163 It must specify a tag type and cannot consume every enumeration value.3163 It must specify a tag type and cannot consume every enumeration value.
3164 </p>3164 </p>
3165 <p>3165 <p>
3166 {#link|@intToEnum#} on a non-exhaustive enum cannot fail.3166 {#link|@intToEnum#} on a non-exhaustive enum involves the safety semantics
3167 of {#link|@intCast#} to the integer tag type, but beyond that always results in
3168 a well-defined enum value.
3167 </p>3169 </p>
3168 <p>3170 <p>
3169 A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong3171 A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
...@@ -7972,7 +7974,7 @@ test "@hasDecl" {...@@ -7972,7 +7974,7 @@ test "@hasDecl" {
7972 {#header_close#}7974 {#header_close#}
79737975
7974 {#header_open|@intToEnum#}7976 {#header_open|@intToEnum#}
7975 <pre>{#syntax#}@intToEnum(comptime DestType: type, int_value: std.meta.Tag(DestType)) DestType{#endsyntax#}</pre>7977 <pre>{#syntax#}@intToEnum(comptime DestType: type, integer: anytype) DestType{#endsyntax#}</pre>
7976 <p>7978 <p>
7977 Converts an integer into an {#link|enum#} value.7979 Converts an integer into an {#link|enum#} value.
7978 </p>7980 </p>
src/stage1/ir.cpp+25-14
...@@ -20007,29 +20007,24 @@ static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirI...@@ -20007,29 +20007,24 @@ static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirI
20007 return ir_build_truncate_gen(ira, instruction->base.scope, instruction->base.source_node, dest_type, target);20007 return ir_build_truncate_gen(ira, instruction->base.scope, instruction->base.source_node, dest_type, target);
20008}20008}
2000920009
20010static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirInstIntCast *instruction) {20010static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node,
20011 ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);20011 ZigType *dest_type, AstNode *dest_type_src_node,
20012 if (type_is_invalid(dest_type))20012 Stage1AirInst *target, AstNode *target_src_node)
20013 return ira->codegen->invalid_inst_gen;20013{
20014
20015 ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ?20014 ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ?
20016 dest_type->data.vector.elem_type : dest_type;20015 dest_type->data.vector.elem_type : dest_type;
2001720016
20018 if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) {20017 if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) {
20019 ir_add_error_node(ira, instruction->dest_type->source_node,20018 ir_add_error_node(ira, dest_type_src_node,
20020 buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name)));20019 buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name)));
20021 return ira->codegen->invalid_inst_gen;20020 return ira->codegen->invalid_inst_gen;
20022 }20021 }
2002320022
20024 Stage1AirInst *target = instruction->target->child;
20025 if (type_is_invalid(target->value->type))
20026 return ira->codegen->invalid_inst_gen;
20027
20028 ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ?20023 ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ?
20029 target->value->type->data.vector.elem_type : target->value->type;20024 target->value->type->data.vector.elem_type : target->value->type;
2003020025
20031 if (scalar_target_type->id != ZigTypeIdInt && scalar_target_type->id != ZigTypeIdComptimeInt) {20026 if (scalar_target_type->id != ZigTypeIdInt && scalar_target_type->id != ZigTypeIdComptimeInt) {
20032 ir_add_error_node(ira, instruction->target->source_node, buf_sprintf("expected integer type, found '%s'",20027 ir_add_error_node(ira, target_src_node, buf_sprintf("expected integer type, found '%s'",
20033 buf_ptr(&scalar_target_type->name)));20028 buf_ptr(&scalar_target_type->name)));
20034 return ira->codegen->invalid_inst_gen;20029 return ira->codegen->invalid_inst_gen;
20035 }20030 }
...@@ -20039,10 +20034,24 @@ static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirI...@@ -20039,10 +20034,24 @@ static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirI
20039 if (val == nullptr)20034 if (val == nullptr)
20040 return ira->codegen->invalid_inst_gen;20035 return ira->codegen->invalid_inst_gen;
2004120036
20042 return ir_implicit_cast2(ira, instruction->target->scope, instruction->target->source_node, target, dest_type);20037 return ir_implicit_cast2(ira, scope, target_src_node, target, dest_type);
20043 }20038 }
2004420039
20045 return ir_analyze_widen_or_shorten(ira, instruction->base.scope, instruction->base.source_node, target, dest_type);20040 return ir_analyze_widen_or_shorten(ira, scope, source_node, target, dest_type);
20041}
20042
20043static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirInstIntCast *instruction) {
20044 ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
20045 if (type_is_invalid(dest_type))
20046 return ira->codegen->invalid_inst_gen;
20047
20048 Stage1AirInst *target = instruction->target->child;
20049 if (type_is_invalid(target->value->type))
20050 return ira->codegen->invalid_inst_gen;
20051
20052 return ir_analyze_int_cast(ira, instruction->base.scope, instruction->base.source_node,
20053 dest_type, instruction->dest_type->source_node,
20054 target, instruction->target->source_node);
20046}20055}
2004720056
20048static Stage1AirInst *ir_analyze_instruction_float_cast(IrAnalyze *ira, Stage1ZirInstFloatCast *instruction) {20057static Stage1AirInst *ir_analyze_instruction_float_cast(IrAnalyze *ira, Stage1ZirInstFloatCast *instruction) {
...@@ -24282,7 +24291,9 @@ static Stage1AirInst *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, Stage1Z...@@ -24282,7 +24291,9 @@ static Stage1AirInst *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, Stage1Z
24282 if (type_is_invalid(target->value->type))24291 if (type_is_invalid(target->value->type))
24283 return ira->codegen->invalid_inst_gen;24292 return ira->codegen->invalid_inst_gen;
2428424293
24285 Stage1AirInst *casted_target = ir_implicit_cast(ira, target, tag_type);24294 Stage1AirInst *casted_target = ir_analyze_int_cast(ira, instruction->base.scope,
24295 instruction->base.source_node, tag_type, instruction->dest_type->source_node,
24296 target, instruction->target->source_node);
24286 if (type_is_invalid(casted_target->value->type))24297 if (type_is_invalid(casted_target->value->type))
24287 return ira->codegen->invalid_inst_gen;24298 return ira->codegen->invalid_inst_gen;
2428824299
test/behavior/enum.zig+1-1
...@@ -203,7 +203,7 @@ test "int to enum" {...@@ -203,7 +203,7 @@ test "int to enum" {
203 try testIntToEnumEval(3);203 try testIntToEnumEval(3);
204}204}
205fn testIntToEnumEval(x: i32) !void {205fn testIntToEnumEval(x: i32) !void {
206 try expect(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);206 try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
207}207}
208const IntToEnumNumber = enum {208const IntToEnumNumber = enum {
209 Zero,209 Zero,
test/compile_errors.zig+2-2
...@@ -7691,12 +7691,12 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -7691,12 +7691,12 @@ pub fn addCases(ctx: *TestContext) !void {
7691 \\};7691 \\};
7692 \\7692 \\
7693 \\export fn entry() void {7693 \\export fn entry() void {
7694 \\ var y = @as(u3, 3);7694 \\ var y = @as(f32, 3);
7695 \\ var x = @intToEnum(Small, y);7695 \\ var x = @intToEnum(Small, y);
7696 \\ _ = x;7696 \\ _ = x;
7697 \\}7697 \\}
7698 , &[_][]const u8{7698 , &[_][]const u8{
7699 "tmp.zig:10:31: error: expected type 'u2', found 'u3'",7699 "tmp.zig:10:31: error: expected integer type, found 'f32'",
7700 });7700 });
77017701
7702 ctx.objErrStage1("union fields with value assignments",7702 ctx.objErrStage1("union fields with value assignments",