diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-03-31 18:05:37 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-03-31 18:05:37 -0700 |
| commit | 3cebaaad1ca16a9e0203ed8c1684d0ce72da9487 (patch) | |
| tree | a153e50f75fad0a1b6c683ad5c06e28e102ff848 /src/Sema.zig | |
| parent | 08eedc962d8e2582db8fb5b4a50114f2913519fd (diff) | |
| download | zig-3cebaaad1ca16a9e0203ed8c1684d0ce72da9487.tar.gz zig-3cebaaad1ca16a9e0203ed8c1684d0ce72da9487.zip | |
astgen: improved handling of coercion
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.
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 170 |
1 files changed, 88 insertions, 82 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 5ea1836fbe..504edfe97b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4104,102 +4104,108 @@ fn coerce( } assert(inst.ty.zigTypeTag() != .Undefined); - // null to ?T - if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) { - return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); - } - - // T to ?T - if (dest_type.zigTypeTag() == .Optional) { - var buf: Type.Payload.ElemType = undefined; - const child_type = dest_type.optionalChild(&buf); - if (child_type.eql(inst.ty)) { - return sema.wrapOptional(block, dest_type, inst); - } else if (try sema.coerceNum(block, child_type, inst)) |some| { - return sema.wrapOptional(block, dest_type, some); - } - } - // T to E!T or E to E!T if (dest_type.tag() == .error_union) { return try sema.wrapErrorUnion(block, dest_type, inst); } - // Coercions where the source is a single pointer to an array. - src_array_ptr: { - if (!inst.ty.isSinglePointer()) break :src_array_ptr; - const array_type = inst.ty.elemType(); - if (array_type.zigTypeTag() != .Array) break :src_array_ptr; - const array_elem_type = array_type.elemType(); - if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr; - if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; - - const dst_elem_type = dest_type.elemType(); - switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) { - .ok => {}, - .no_match => break :src_array_ptr, - } - - switch (dest_type.ptrSize()) { - .Slice => { - // *[N]T to []T - return sema.coerceArrayPtrToSlice(block, dest_type, inst); - }, - .C => { - // *[N]T to [*c]T - return sema.coerceArrayPtrToMany(block, dest_type, inst); - }, - .Many => { - // *[N]T to [*]T - // *[N:s]T to [*:s]T - const src_sentinel = array_type.sentinel(); - const dst_sentinel = dest_type.sentinel(); - if (src_sentinel == null and dst_sentinel == null) - return sema.coerceArrayPtrToMany(block, dest_type, inst); - - if (src_sentinel) |src_s| { - if (dst_sentinel) |dst_s| { - if (src_s.eql(dst_s)) { - return sema.coerceArrayPtrToMany(block, dest_type, inst); - } - } - } - }, - .One => {}, - } - } - // comptime known number to other number if (try sema.coerceNum(block, dest_type, inst)) |some| return some; const target = sema.mod.getTarget(); - // integer widening - if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) { - assert(inst.value() == null); // handled above + switch (dest_type.zigTypeTag()) { + .Optional => { + // null to ?T + if (inst.ty.zigTypeTag() == .Null) { + return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); + } - const src_info = inst.ty.intInfo(target); - const dst_info = dest_type.intInfo(target); - if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or - // small enough unsigned ints can get casted to large enough signed ints - (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits)) - { - try sema.requireRuntimeBlock(block, inst_src); - return block.addUnOp(inst_src, dest_type, .intcast, inst); - } - } + // T to ?T + var buf: Type.Payload.ElemType = undefined; + const child_type = dest_type.optionalChild(&buf); + if (child_type.eql(inst.ty)) { + return sema.wrapOptional(block, dest_type, inst); + } else if (try sema.coerceNum(block, child_type, inst)) |some| { + return sema.wrapOptional(block, dest_type, some); + } + }, + .Pointer => { + // Coercions where the source is a single pointer to an array. + src_array_ptr: { + if (!inst.ty.isSinglePointer()) break :src_array_ptr; + const array_type = inst.ty.elemType(); + if (array_type.zigTypeTag() != .Array) break :src_array_ptr; + const array_elem_type = array_type.elemType(); + if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr; + if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; + + const dst_elem_type = dest_type.elemType(); + switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) { + .ok => {}, + .no_match => break :src_array_ptr, + } - // float widening - if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) { - assert(inst.value() == null); // handled above + switch (dest_type.ptrSize()) { + .Slice => { + // *[N]T to []T + return sema.coerceArrayPtrToSlice(block, dest_type, inst); + }, + .C => { + // *[N]T to [*c]T + return sema.coerceArrayPtrToMany(block, dest_type, inst); + }, + .Many => { + // *[N]T to [*]T + // *[N:s]T to [*:s]T + const src_sentinel = array_type.sentinel(); + const dst_sentinel = dest_type.sentinel(); + if (src_sentinel == null and dst_sentinel == null) + return sema.coerceArrayPtrToMany(block, dest_type, inst); - const src_bits = inst.ty.floatBits(target); - const dst_bits = dest_type.floatBits(target); - if (dst_bits >= src_bits) { - try sema.requireRuntimeBlock(block, inst_src); - return block.addUnOp(inst_src, dest_type, .floatcast, inst); - } + if (src_sentinel) |src_s| { + if (dst_sentinel) |dst_s| { + if (src_s.eql(dst_s)) { + return sema.coerceArrayPtrToMany(block, dest_type, inst); + } + } + } + }, + .One => {}, + } + } + }, + .Int => { + // integer widening + if (inst.ty.zigTypeTag() == .Int) { + assert(inst.value() == null); // handled above + + const dst_info = dest_type.intInfo(target); + const src_info = inst.ty.intInfo(target); + if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or + // small enough unsigned ints can get casted to large enough signed ints + (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits)) + { + try sema.requireRuntimeBlock(block, inst_src); + return block.addUnOp(inst_src, dest_type, .intcast, inst); + } + } + }, + .Float => { + // float widening + if (inst.ty.zigTypeTag() == .Float) { + assert(inst.value() == null); // handled above + + const src_bits = inst.ty.floatBits(target); + const dst_bits = dest_type.floatBits(target); + if (dst_bits >= src_bits) { + try sema.requireRuntimeBlock(block, inst_src); + return block.addUnOp(inst_src, dest_type, .floatcast, inst); + } + } + }, + else => {}, } return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty }); |
