| author | |
| committer | |
| log | 3cebaaad1ca16a9e0203ed8c1684d0ce72da9487 |
| tree | a153e50f75fad0a1b6c683ad5c06e28e102ff848 |
| parent | 08eedc962d8e2582db8fb5b4a50114f2913519fd |
GenZir struct now has rl_ty_inst field which tracks the result location
type (if any) a block expects all of its results to be coerced to.
Remove a redundant coercion on const local initialization with a
specified type.
Switch expressions, during elision of store_to_block_ptr instructions,
now re-purpose them to be type coercion when the block has a type in the
result location.4 files changed, 227 insertions(+), 105 deletions(-)
src/AstGen.zig+65-22| ... | @@ -1415,6 +1415,7 @@ fn varDecl( | ... | @@ -1415,6 +1415,7 @@ fn varDecl( |
| 1415 | const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); | 1415 | const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); |
| 1416 | opt_type_inst = type_inst; | 1416 | opt_type_inst = type_inst; |
| 1417 | init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); | 1417 | init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); |
| 1418 | init_scope.rl_ty_inst = type_inst; | ||
| 1418 | } else { | 1419 | } else { |
| 1419 | const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node); | 1420 | const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node); |
| 1420 | resolve_inferred_alloc = alloc; | 1421 | resolve_inferred_alloc = alloc; |
| ... | @@ -1441,20 +1442,13 @@ fn varDecl( | ... | @@ -1441,20 +1442,13 @@ fn varDecl( |
| 1441 | parent_zir.appendAssumeCapacity(src_inst); | 1442 | parent_zir.appendAssumeCapacity(src_inst); |
| 1442 | } | 1443 | } |
| 1443 | assert(parent_zir.items.len == expected_len); | 1444 | assert(parent_zir.items.len == expected_len); |
| 1444 | const casted_init = if (opt_type_inst != .none) | ||
| 1445 | try gz.addPlNode(.as_node, var_decl.ast.type_node, zir.Inst.As{ | ||
| 1446 | .dest_type = opt_type_inst, | ||
| 1447 | .operand = init_inst, | ||
| 1448 | }) | ||
| 1449 | else | ||
| 1450 | init_inst; | ||
| 1451 | 1445 | ||
| 1452 | const sub_scope = try block_arena.create(Scope.LocalVal); | 1446 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 1453 | sub_scope.* = .{ | 1447 | sub_scope.* = .{ |
| 1454 | .parent = scope, | 1448 | .parent = scope, |
| 1455 | .gen_zir = gz, | 1449 | .gen_zir = gz, |
| 1456 | .name = ident_name, | 1450 | .name = ident_name, |
| 1457 | .inst = casted_init, | 1451 | .inst = init_inst, |
| 1458 | .src = name_src, | 1452 | .src = name_src, |
| 1459 | }; | 1453 | }; |
| 1460 | return &sub_scope.base; | 1454 | return &sub_scope.base; |
| ... | @@ -3029,25 +3023,48 @@ fn switchExpr( | ... | @@ -3029,25 +3023,48 @@ fn switchExpr( |
| 3029 | // all prongs, except for prongs that ended with a noreturn instruction. | 3023 | // all prongs, except for prongs that ended with a noreturn instruction. |
| 3030 | // Elide all the `store_to_block_ptr` instructions. | 3024 | // Elide all the `store_to_block_ptr` instructions. |
| 3031 | 3025 | ||
| 3026 | // The break instructions need to have their operands coerced if the | ||
| 3027 | // switch's result location is a `ty`. In this case we overwrite the | ||
| 3028 | // `store_to_block_ptr` instruction with an `as` instruction and repurpose | ||
| 3029 | // it as the break operand. | ||
| 3030 | |||
| 3032 | var extra_index: usize = 0; | 3031 | var extra_index: usize = 0; |
| 3033 | extra_index += 2; | 3032 | extra_index += 2; |
| 3034 | extra_index += @boolToInt(multi_cases_len != 0); | 3033 | extra_index += @boolToInt(multi_cases_len != 0); |
| 3035 | if (special_prong != .none) { | 3034 | if (special_prong != .none) special_prong: { |
| 3036 | const body_len_index = extra_index; | 3035 | const body_len_index = extra_index; |
| 3037 | const body_len = scalar_cases_payload.items[extra_index]; | 3036 | const body_len = scalar_cases_payload.items[extra_index]; |
| 3038 | extra_index += 1; | 3037 | extra_index += 1; |
| 3038 | if (body_len < 2) { | ||
| 3039 | extra_index += body_len; | ||
| 3040 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3041 | break :special_prong; | ||
| 3042 | } | ||
| 3039 | extra_index += body_len - 2; | 3043 | extra_index += body_len - 2; |
| 3040 | const store_inst = scalar_cases_payload.items[extra_index]; | 3044 | const store_inst = scalar_cases_payload.items[extra_index]; |
| 3041 | if (zir_tags[store_inst] == .store_to_block_ptr) { | 3045 | if (zir_tags[store_inst] != .store_to_block_ptr) { |
| 3042 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | 3046 | extra_index += 2; |
| 3043 | scalar_cases_payload.items[body_len_index] -= 1; | ||
| 3044 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 3047 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| 3048 | break :special_prong; | ||
| 3049 | } | ||
| 3050 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | ||
| 3051 | if (block_scope.rl_ty_inst != .none) { | ||
| 3045 | extra_index += 1; | 3052 | extra_index += 1; |
| 3046 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | 3053 | const break_inst = scalar_cases_payload.items[extra_index]; |
| 3047 | extra_index += 1; | 3054 | extra_index += 1; |
| 3055 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3056 | zir_tags[store_inst] = .as; | ||
| 3057 | zir_datas[store_inst].bin = .{ | ||
| 3058 | .lhs = block_scope.rl_ty_inst, | ||
| 3059 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 3060 | }; | ||
| 3061 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | ||
| 3048 | } else { | 3062 | } else { |
| 3049 | extra_index += 2; | 3063 | scalar_cases_payload.items[body_len_index] -= 1; |
| 3050 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 3064 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| 3065 | extra_index += 1; | ||
| 3066 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | ||
| 3067 | extra_index += 1; | ||
| 3051 | } | 3068 | } |
| 3052 | } else { | 3069 | } else { |
| 3053 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 3070 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); |
| ... | @@ -3066,16 +3083,29 @@ fn switchExpr( | ... | @@ -3066,16 +3083,29 @@ fn switchExpr( |
| 3066 | } | 3083 | } |
| 3067 | extra_index += body_len - 2; | 3084 | extra_index += body_len - 2; |
| 3068 | const store_inst = scalar_cases_payload.items[extra_index]; | 3085 | const store_inst = scalar_cases_payload.items[extra_index]; |
| 3069 | if (zir_tags[store_inst] == .store_to_block_ptr) { | 3086 | if (zir_tags[store_inst] != .store_to_block_ptr) { |
| 3087 | extra_index += 2; | ||
| 3088 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3089 | continue; | ||
| 3090 | } | ||
| 3091 | if (block_scope.rl_ty_inst != .none) { | ||
| 3092 | extra_index += 1; | ||
| 3093 | const break_inst = scalar_cases_payload.items[extra_index]; | ||
| 3094 | extra_index += 1; | ||
| 3095 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3096 | zir_tags[store_inst] = .as; | ||
| 3097 | zir_datas[store_inst].bin = .{ | ||
| 3098 | .lhs = block_scope.rl_ty_inst, | ||
| 3099 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 3100 | }; | ||
| 3101 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | ||
| 3102 | } else { | ||
| 3070 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | 3103 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| 3071 | scalar_cases_payload.items[body_len_index] -= 1; | 3104 | scalar_cases_payload.items[body_len_index] -= 1; |
| 3072 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | 3105 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); |
| 3073 | extra_index += 1; | 3106 | extra_index += 1; |
| 3074 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | 3107 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); |
| 3075 | extra_index += 1; | 3108 | extra_index += 1; |
| 3076 | } else { | ||
| 3077 | extra_index += 2; | ||
| 3078 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3079 | } | 3109 | } |
| 3080 | } | 3110 | } |
| 3081 | extra_index = 0; | 3111 | extra_index = 0; |
| ... | @@ -3098,16 +3128,29 @@ fn switchExpr( | ... | @@ -3098,16 +3128,29 @@ fn switchExpr( |
| 3098 | } | 3128 | } |
| 3099 | extra_index += body_len - 2; | 3129 | extra_index += body_len - 2; |
| 3100 | const store_inst = multi_cases_payload.items[extra_index]; | 3130 | const store_inst = multi_cases_payload.items[extra_index]; |
| 3101 | if (zir_tags[store_inst] == .store_to_block_ptr) { | 3131 | if (zir_tags[store_inst] != .store_to_block_ptr) { |
| 3132 | extra_index += 2; | ||
| 3133 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3134 | continue; | ||
| 3135 | } | ||
| 3136 | if (block_scope.rl_ty_inst != .none) { | ||
| 3137 | extra_index += 1; | ||
| 3138 | const break_inst = multi_cases_payload.items[extra_index]; | ||
| 3139 | extra_index += 1; | ||
| 3140 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3141 | zir_tags[store_inst] = .as; | ||
| 3142 | zir_datas[store_inst].bin = .{ | ||
| 3143 | .lhs = block_scope.rl_ty_inst, | ||
| 3144 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 3145 | }; | ||
| 3146 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | ||
| 3147 | } else { | ||
| 3102 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | 3148 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| 3103 | multi_cases_payload.items[body_len_index] -= 1; | 3149 | multi_cases_payload.items[body_len_index] -= 1; |
| 3104 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | 3150 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); |
| 3105 | extra_index += 1; | 3151 | extra_index += 1; |
| 3106 | astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]); | 3152 | astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]); |
| 3107 | extra_index += 1; | 3153 | extra_index += 1; |
| 3108 | } else { | ||
| 3109 | extra_index += 2; | ||
| 3110 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3111 | } | 3154 | } |
| 3112 | } | 3155 | } |
| 3113 | 3156 |
src/Module.zig+8-1| ... | @@ -942,6 +942,8 @@ pub const Scope = struct { | ... | @@ -942,6 +942,8 @@ pub const Scope = struct { |
| 942 | break_result_loc: AstGen.ResultLoc = undefined, | 942 | break_result_loc: AstGen.ResultLoc = undefined, |
| 943 | /// When a block has a pointer result location, here it is. | 943 | /// When a block has a pointer result location, here it is. |
| 944 | rl_ptr: zir.Inst.Ref = .none, | 944 | rl_ptr: zir.Inst.Ref = .none, |
| 945 | /// When a block has a type result location, here it is. | ||
| 946 | rl_ty_inst: zir.Inst.Ref = .none, | ||
| 945 | /// Keeps track of how many branches of a block did not actually | 947 | /// Keeps track of how many branches of a block did not actually |
| 946 | /// consume the result location. astgen uses this to figure out | 948 | /// consume the result location. astgen uses this to figure out |
| 947 | /// whether to rely on break instructions or writing to the result | 949 | /// whether to rely on break instructions or writing to the result |
| ... | @@ -1001,7 +1003,11 @@ pub const Scope = struct { | ... | @@ -1001,7 +1003,11 @@ pub const Scope = struct { |
| 1001 | // we emit ZIR for the block break instructions to have the result values, | 1003 | // we emit ZIR for the block break instructions to have the result values, |
| 1002 | // and then rvalue() on that to pass the value to the result location. | 1004 | // and then rvalue() on that to pass the value to the result location. |
| 1003 | switch (parent_rl) { | 1005 | switch (parent_rl) { |
| 1004 | .discard, .none, .ty, .ptr, .ref => { | 1006 | .ty => |ty_inst| { |
| 1007 | gz.rl_ty_inst = ty_inst; | ||
| 1008 | gz.break_result_loc = parent_rl; | ||
| 1009 | }, | ||
| 1010 | .discard, .none, .ptr, .ref => { | ||
| 1005 | gz.break_result_loc = parent_rl; | 1011 | gz.break_result_loc = parent_rl; |
| 1006 | }, | 1012 | }, |
| 1007 | 1013 | ||
| ... | @@ -1016,6 +1022,7 @@ pub const Scope = struct { | ... | @@ -1016,6 +1022,7 @@ pub const Scope = struct { |
| 1016 | }, | 1022 | }, |
| 1017 | 1023 | ||
| 1018 | .block_ptr => |parent_block_scope| { | 1024 | .block_ptr => |parent_block_scope| { |
| 1025 | gz.rl_ty_inst = parent_block_scope.rl_ty_inst; | ||
| 1019 | gz.rl_ptr = parent_block_scope.rl_ptr; | 1026 | gz.rl_ptr = parent_block_scope.rl_ptr; |
| 1020 | gz.break_result_loc = .{ .block_ptr = gz }; | 1027 | gz.break_result_loc = .{ .block_ptr = gz }; |
| 1021 | }, | 1028 | }, |
src/Sema.zig+88-82| ... | @@ -4104,102 +4104,108 @@ fn coerce( | ... | @@ -4104,102 +4104,108 @@ fn coerce( |
| 4104 | } | 4104 | } |
| 4105 | assert(inst.ty.zigTypeTag() != .Undefined); | 4105 | assert(inst.ty.zigTypeTag() != .Undefined); |
| 4106 | 4106 | ||
| 4107 | // null to ?T | ||
| 4108 | if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) { | ||
| 4109 | return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); | ||
| 4110 | } | ||
| 4111 | |||
| 4112 | // T to ?T | ||
| 4113 | if (dest_type.zigTypeTag() == .Optional) { | ||
| 4114 | var buf: Type.Payload.ElemType = undefined; | ||
| 4115 | const child_type = dest_type.optionalChild(&buf); | ||
| 4116 | if (child_type.eql(inst.ty)) { | ||
| 4117 | return sema.wrapOptional(block, dest_type, inst); | ||
| 4118 | } else if (try sema.coerceNum(block, child_type, inst)) |some| { | ||
| 4119 | return sema.wrapOptional(block, dest_type, some); | ||
| 4120 | } | ||
| 4121 | } | ||
| 4122 | |||
| 4123 | // T to E!T or E to E!T | 4107 | // T to E!T or E to E!T |
| 4124 | if (dest_type.tag() == .error_union) { | 4108 | if (dest_type.tag() == .error_union) { |
| 4125 | return try sema.wrapErrorUnion(block, dest_type, inst); | 4109 | return try sema.wrapErrorUnion(block, dest_type, inst); |
| 4126 | } | 4110 | } |
| 4127 | 4111 | ||
| 4128 | // Coercions where the source is a single pointer to an array. | ||
| 4129 | src_array_ptr: { | ||
| 4130 | if (!inst.ty.isSinglePointer()) break :src_array_ptr; | ||
| 4131 | const array_type = inst.ty.elemType(); | ||
| 4132 | if (array_type.zigTypeTag() != .Array) break :src_array_ptr; | ||
| 4133 | const array_elem_type = array_type.elemType(); | ||
| 4134 | if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr; | ||
| 4135 | if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; | ||
| 4136 | |||
| 4137 | const dst_elem_type = dest_type.elemType(); | ||
| 4138 | switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) { | ||
| 4139 | .ok => {}, | ||
| 4140 | .no_match => break :src_array_ptr, | ||
| 4141 | } | ||
| 4142 | |||
| 4143 | switch (dest_type.ptrSize()) { | ||
| 4144 | .Slice => { | ||
| 4145 | // *[N]T to []T | ||
| 4146 | return sema.coerceArrayPtrToSlice(block, dest_type, inst); | ||
| 4147 | }, | ||
| 4148 | .C => { | ||
| 4149 | // *[N]T to [*c]T | ||
| 4150 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | ||
| 4151 | }, | ||
| 4152 | .Many => { | ||
| 4153 | // *[N]T to [*]T | ||
| 4154 | // *[N:s]T to [*:s]T | ||
| 4155 | const src_sentinel = array_type.sentinel(); | ||
| 4156 | const dst_sentinel = dest_type.sentinel(); | ||
| 4157 | if (src_sentinel == null and dst_sentinel == null) | ||
| 4158 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | ||
| 4159 | |||
| 4160 | if (src_sentinel) |src_s| { | ||
| 4161 | if (dst_sentinel) |dst_s| { | ||
| 4162 | if (src_s.eql(dst_s)) { | ||
| 4163 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | ||
| 4164 | } | ||
| 4165 | } | ||
| 4166 | } | ||
| 4167 | }, | ||
| 4168 | .One => {}, | ||
| 4169 | } | ||
| 4170 | } | ||
| 4171 | |||
| 4172 | // comptime known number to other number | 4112 | // comptime known number to other number |
| 4173 | if (try sema.coerceNum(block, dest_type, inst)) |some| | 4113 | if (try sema.coerceNum(block, dest_type, inst)) |some| |
| 4174 | return some; | 4114 | return some; |
| 4175 | 4115 | ||
| 4176 | const target = sema.mod.getTarget(); | 4116 | const target = sema.mod.getTarget(); |
| 4177 | 4117 | ||
| 4178 | // integer widening | 4118 | switch (dest_type.zigTypeTag()) { |
| 4179 | if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) { | 4119 | .Optional => { |
| 4180 | assert(inst.value() == null); // handled above | 4120 | // null to ?T |
| 4121 | if (inst.ty.zigTypeTag() == .Null) { | ||
| 4122 | return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); | ||
| 4123 | } | ||
| 4181 | 4124 | ||
| 4182 | const src_info = inst.ty.intInfo(target); | 4125 | // T to ?T |
| 4183 | const dst_info = dest_type.intInfo(target); | 4126 | var buf: Type.Payload.ElemType = undefined; |
| 4184 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or | 4127 | const child_type = dest_type.optionalChild(&buf); |
| 4185 | // small enough unsigned ints can get casted to large enough signed ints | 4128 | if (child_type.eql(inst.ty)) { |
| 4186 | (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits)) | 4129 | return sema.wrapOptional(block, dest_type, inst); |
| 4187 | { | 4130 | } else if (try sema.coerceNum(block, child_type, inst)) |some| { |
| 4188 | try sema.requireRuntimeBlock(block, inst_src); | 4131 | return sema.wrapOptional(block, dest_type, some); |
| 4189 | return block.addUnOp(inst_src, dest_type, .intcast, inst); | 4132 | } |
| 4190 | } | 4133 | }, |
| 4191 | } | 4134 | .Pointer => { |
| 4135 | // Coercions where the source is a single pointer to an array. | ||
| 4136 | src_array_ptr: { | ||
| 4137 | if (!inst.ty.isSinglePointer()) break :src_array_ptr; | ||
| 4138 | const array_type = inst.ty.elemType(); | ||
| 4139 | if (array_type.zigTypeTag() != .Array) break :src_array_ptr; | ||
| 4140 | const array_elem_type = array_type.elemType(); | ||
| 4141 | if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr; | ||
| 4142 | if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; | ||
| 4143 | |||
| 4144 | const dst_elem_type = dest_type.elemType(); | ||
| 4145 | switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) { | ||
| 4146 | .ok => {}, | ||
| 4147 | .no_match => break :src_array_ptr, | ||
| 4148 | } | ||
| 4192 | 4149 | ||
| 4193 | // float widening | 4150 | switch (dest_type.ptrSize()) { |
| 4194 | if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) { | 4151 | .Slice => { |
| 4195 | assert(inst.value() == null); // handled above | 4152 | // *[N]T to []T |
| 4153 | return sema.coerceArrayPtrToSlice(block, dest_type, inst); | ||
| 4154 | }, | ||
| 4155 | .C => { | ||
| 4156 | // *[N]T to [*c]T | ||
| 4157 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | ||
| 4158 | }, | ||
| 4159 | .Many => { | ||
| 4160 | // *[N]T to [*]T | ||
| 4161 | // *[N:s]T to [*:s]T | ||
| 4162 | const src_sentinel = array_type.sentinel(); | ||
| 4163 | const dst_sentinel = dest_type.sentinel(); | ||
| 4164 | if (src_sentinel == null and dst_sentinel == null) | ||
| 4165 | return sema.coerceArrayPtrToMany(block, dest_type, inst); | ||
| 4196 | 4166 | ||
| 4197 | const src_bits = inst.ty.floatBits(target); | 4167 | if (src_sentinel) |src_s| { |
| 4198 | const dst_bits = dest_type.floatBits(target); | 4168 | if (dst_sentinel) |dst_s| { |
| 4199 | if (dst_bits >= src_bits) { | 4169 | if (src_s.eql(dst_s)) { |
| 4200 | try sema.requireRuntimeBlock(block, inst_src); | 4170 | return sema.coerceArrayPtrToMany(block, dest_type, inst); |
| 4201 | return block.addUnOp(inst_src, dest_type, .floatcast, inst); | 4171 | } |
| 4202 | } | 4172 | } |
| 4173 | } | ||
| 4174 | }, | ||
| 4175 | .One => {}, | ||
| 4176 | } | ||
| 4177 | } | ||
| 4178 | }, | ||
| 4179 | .Int => { | ||
| 4180 | // integer widening | ||
| 4181 | if (inst.ty.zigTypeTag() == .Int) { | ||
| 4182 | assert(inst.value() == null); // handled above | ||
| 4183 | |||
| 4184 | const dst_info = dest_type.intInfo(target); | ||
| 4185 | const src_info = inst.ty.intInfo(target); | ||
| 4186 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or | ||
| 4187 | // small enough unsigned ints can get casted to large enough signed ints | ||
| 4188 | (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits)) | ||
| 4189 | { | ||
| 4190 | try sema.requireRuntimeBlock(block, inst_src); | ||
| 4191 | return block.addUnOp(inst_src, dest_type, .intcast, inst); | ||
| 4192 | } | ||
| 4193 | } | ||
| 4194 | }, | ||
| 4195 | .Float => { | ||
| 4196 | // float widening | ||
| 4197 | if (inst.ty.zigTypeTag() == .Float) { | ||
| 4198 | assert(inst.value() == null); // handled above | ||
| 4199 | |||
| 4200 | const src_bits = inst.ty.floatBits(target); | ||
| 4201 | const dst_bits = dest_type.floatBits(target); | ||
| 4202 | if (dst_bits >= src_bits) { | ||
| 4203 | try sema.requireRuntimeBlock(block, inst_src); | ||
| 4204 | return block.addUnOp(inst_src, dest_type, .floatcast, inst); | ||
| 4205 | } | ||
| 4206 | } | ||
| 4207 | }, | ||
| 4208 | else => {}, | ||
| 4203 | } | 4209 | } |
| 4204 | 4210 | ||
| 4205 | return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty }); | 4211 | return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty }); |
test/stage2/cbe.zig+66| ... | @@ -279,6 +279,72 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -279,6 +279,72 @@ pub fn addCases(ctx: *TestContext) !void { |
| 279 | \\ return a - 4; | 279 | \\ return a - 4; |
| 280 | \\} | 280 | \\} |
| 281 | , ""); | 281 | , ""); |
| 282 | |||
| 283 | // Switch expression missing else case. | ||
| 284 | case.addError( | ||
| 285 | \\export fn main() c_int { | ||
| 286 | \\ var cond: c_int = 0; | ||
| 287 | \\ const a: c_int = switch (cond) { | ||
| 288 | \\ 1 => 1, | ||
| 289 | \\ 2 => 2, | ||
| 290 | \\ 3 => 3, | ||
| 291 | \\ 4 => 4, | ||
| 292 | \\ }; | ||
| 293 | \\ return a - 4; | ||
| 294 | \\} | ||
| 295 | , &.{":3:22: error: switch must handle all possibilities"}); | ||
| 296 | |||
| 297 | // Switch expression, has an unreachable prong. | ||
| 298 | case.addCompareOutput( | ||
| 299 | \\export fn main() c_int { | ||
| 300 | \\ var cond: c_int = 0; | ||
| 301 | \\ const a: c_int = switch (cond) { | ||
| 302 | \\ 1 => 1, | ||
| 303 | \\ 2 => 2, | ||
| 304 | \\ 99...300, 12 => 3, | ||
| 305 | \\ 0 => 4, | ||
| 306 | \\ 13 => unreachable, | ||
| 307 | \\ else => 5, | ||
| 308 | \\ }; | ||
| 309 | \\ return a - 4; | ||
| 310 | \\} | ||
| 311 | , ""); | ||
| 312 | |||
| 313 | // Switch expression, has an unreachable prong and prongs write | ||
| 314 | // to result locations. | ||
| 315 | case.addCompareOutput( | ||
| 316 | \\export fn main() c_int { | ||
| 317 | \\ var cond: c_int = 0; | ||
| 318 | \\ var a: c_int = switch (cond) { | ||
| 319 | \\ 1 => 1, | ||
| 320 | \\ 2 => 2, | ||
| 321 | \\ 99...300, 12 => 3, | ||
| 322 | \\ 0 => 4, | ||
| 323 | \\ 13 => unreachable, | ||
| 324 | \\ else => 5, | ||
| 325 | \\ }; | ||
| 326 | \\ return a - 4; | ||
| 327 | \\} | ||
| 328 | , ""); | ||
| 329 | |||
| 330 | // Switch expression has duplicate case value. | ||
| 331 | case.addError( | ||
| 332 | \\export fn main() c_int { | ||
| 333 | \\ var cond: c_int = 0; | ||
| 334 | \\ const a: c_int = switch (cond) { | ||
| 335 | \\ 1 => 1, | ||
| 336 | \\ 2 => 2, | ||
| 337 | \\ 96, 11...13, 97 => 3, | ||
| 338 | \\ 0 => 4, | ||
| 339 | \\ 90, 12 => 100, | ||
| 340 | \\ else => 5, | ||
| 341 | \\ }; | ||
| 342 | \\ return a - 4; | ||
| 343 | \\} | ||
| 344 | , &.{ | ||
| 345 | ":8:13: error: duplicate switch value", | ||
| 346 | ":6:15: note: previous value here", | ||
| 347 | }); | ||
| 282 | } | 348 | } |
| 283 | //{ | 349 | //{ |
| 284 | // var case = ctx.exeFromCompiledC("optionals", .{}); | 350 | // var case = ctx.exeFromCompiledC("optionals", .{}); |