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" {
31633163 It must specify a tag type and cannot consume every enumeration value.
31643164 </p>
31653165 <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.
31673169 </p>
31683170 <p>
31693171 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" {
79727974 {#header_close#}
79737975
79747976 {#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>
79767978 <p>
79777979 Converts an integer into an {#link|enum#} value.
79787980 </p>
src/stage1/ir.cpp+25-14
......@@ -20007,29 +20007,24 @@ static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirI
2000720007 return ir_build_truncate_gen(ira, instruction->base.scope, instruction->base.source_node, dest_type, target);
2000820008}
2000920009
20010static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirInstIntCast *instruction) {
20011 ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
20012 if (type_is_invalid(dest_type))
20013 return ira->codegen->invalid_inst_gen;
20014
20010static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node,
20011 ZigType *dest_type, AstNode *dest_type_src_node,
20012 Stage1AirInst *target, AstNode *target_src_node)
20013{
2001520014 ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ?
2001620015 dest_type->data.vector.elem_type : dest_type;
2001720016
2001820017 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,
2002020019 buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name)));
2002120020 return ira->codegen->invalid_inst_gen;
2002220021 }
2002320022
20024 Stage1AirInst *target = instruction->target->child;
20025 if (type_is_invalid(target->value->type))
20026 return ira->codegen->invalid_inst_gen;
20027
2002820023 ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ?
2002920024 target->value->type->data.vector.elem_type : target->value->type;
2003020025
2003120026 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'",
2003320028 buf_ptr(&scalar_target_type->name)));
2003420029 return ira->codegen->invalid_inst_gen;
2003520030 }
......@@ -20039,10 +20034,24 @@ static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirI
2003920034 if (val == nullptr)
2004020035 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);
2004320038 }
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);
2004620055}
2004720056
2004820057static 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
2428224291 if (type_is_invalid(target->value->type))
2428324292 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);
2428624297 if (type_is_invalid(casted_target->value->type))
2428724298 return ira->codegen->invalid_inst_gen;
2428824299
test/behavior/enum.zig+1-1
......@@ -203,7 +203,7 @@ test "int to enum" {
203203 try testIntToEnumEval(3);
204204}
205205fn testIntToEnumEval(x: i32) !void {
206 try expect(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
206 try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
207207}
208208const IntToEnumNumber = enum {
209209 Zero,
test/compile_errors.zig+2-2
......@@ -7691,12 +7691,12 @@ pub fn addCases(ctx: *TestContext) !void {
76917691 \\};
76927692 \\
76937693 \\export fn entry() void {
7694 \\ var y = @as(u3, 3);
7694 \\ var y = @as(f32, 3);
76957695 \\ var x = @intToEnum(Small, y);
76967696 \\ _ = x;
76977697 \\}
76987698 , &[_][]const u8{
7699 "tmp.zig:10:31: error: expected type 'u2', found 'u3'",
7699 "tmp.zig:10:31: error: expected integer type, found 'f32'",
77007700 });
77017701
77027702 ctx.objErrStage1("union fields with value assignments",