| ... | ... | @@ -14085,88 +14085,112 @@ fn beginComptimePtrMutation( |
| 14085 | 14085 | .elem_ptr => { |
| 14086 | 14086 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| 14087 | 14087 | var parent = try beginComptimePtrMutation(sema, block, src, elem_ptr.array_ptr); |
| 14088 | | const elem_ty = parent.ty.childType(); |
| 14089 | | switch (parent.val.tag()) { |
| 14090 | | .undef => { |
| 14091 | | // An array has been initialized to undefined at comptime and now we |
| 14092 | | // are for the first time setting an element. We must change the representation |
| 14093 | | // of the array from `undef` to `array`. |
| 14094 | | const arena = parent.beginArena(sema.gpa); |
| 14095 | | defer parent.finishArena(); |
| 14088 | switch (parent.ty.zigTypeTag()) { |
| 14089 | .Array, .Vector => { |
| 14090 | const check_len = parent.ty.arrayLenIncludingSentinel(); |
| 14091 | if (elem_ptr.index >= check_len) { |
| 14092 | // TODO have the parent include the decl so we can say "declared here" |
| 14093 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ |
| 14094 | elem_ptr.index, check_len, |
| 14095 | }); |
| 14096 | } |
| 14097 | const elem_ty = parent.ty.childType(); |
| 14098 | switch (parent.val.tag()) { |
| 14099 | .undef => { |
| 14100 | // An array has been initialized to undefined at comptime and now we |
| 14101 | // are for the first time setting an element. We must change the representation |
| 14102 | // of the array from `undef` to `array`. |
| 14103 | const arena = parent.beginArena(sema.gpa); |
| 14104 | defer parent.finishArena(); |
| 14105 | |
| 14106 | const array_len_including_sentinel = |
| 14107 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| 14108 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 14109 | mem.set(Value, elems, Value.undef); |
| 14110 | |
| 14111 | parent.val.* = try Value.Tag.array.create(arena, elems); |
| 14096 | 14112 | |
| 14097 | | const array_len_including_sentinel = |
| 14098 | | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| 14099 | | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 14100 | | mem.set(Value, elems, Value.undef); |
| 14113 | return ComptimePtrMutationKit{ |
| 14114 | .decl_ref_mut = parent.decl_ref_mut, |
| 14115 | .val = &elems[elem_ptr.index], |
| 14116 | .ty = elem_ty, |
| 14117 | }; |
| 14118 | }, |
| 14119 | .bytes => { |
| 14120 | // An array is memory-optimized to store a slice of bytes, but we are about |
| 14121 | // to modify an individual field and the representation has to change. |
| 14122 | // If we wanted to avoid this, there would need to be special detection |
| 14123 | // elsewhere to identify when writing a value to an array element that is stored |
| 14124 | // using the `bytes` tag, and handle it without making a call to this function. |
| 14125 | const arena = parent.beginArena(sema.gpa); |
| 14126 | defer parent.finishArena(); |
| 14127 | |
| 14128 | const bytes = parent.val.castTag(.bytes).?.data; |
| 14129 | const dest_len = parent.ty.arrayLenIncludingSentinel(); |
| 14130 | // bytes.len may be one greater than dest_len because of the case when |
| 14131 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. |
| 14132 | assert(bytes.len >= dest_len); |
| 14133 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| 14134 | for (elems) |*elem, i| { |
| 14135 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); |
| 14136 | } |
| 14101 | 14137 | |
| 14102 | | parent.val.* = try Value.Tag.array.create(arena, elems); |
| 14138 | parent.val.* = try Value.Tag.array.create(arena, elems); |
| 14103 | 14139 | |
| 14104 | | return ComptimePtrMutationKit{ |
| 14105 | | .decl_ref_mut = parent.decl_ref_mut, |
| 14106 | | .val = &elems[elem_ptr.index], |
| 14107 | | .ty = elem_ty, |
| 14108 | | }; |
| 14109 | | }, |
| 14110 | | .bytes => { |
| 14111 | | // An array is memory-optimized to store a slice of bytes, but we are about |
| 14112 | | // to modify an individual field and the representation has to change. |
| 14113 | | // If we wanted to avoid this, there would need to be special detection |
| 14114 | | // elsewhere to identify when writing a value to an array element that is stored |
| 14115 | | // using the `bytes` tag, and handle it without making a call to this function. |
| 14116 | | const arena = parent.beginArena(sema.gpa); |
| 14117 | | defer parent.finishArena(); |
| 14140 | return ComptimePtrMutationKit{ |
| 14141 | .decl_ref_mut = parent.decl_ref_mut, |
| 14142 | .val = &elems[elem_ptr.index], |
| 14143 | .ty = elem_ty, |
| 14144 | }; |
| 14145 | }, |
| 14146 | .repeated => { |
| 14147 | // An array is memory-optimized to store only a single element value, and |
| 14148 | // that value is understood to be the same for the entire length of the array. |
| 14149 | // However, now we want to modify an individual field and so the |
| 14150 | // representation has to change. If we wanted to avoid this, there would |
| 14151 | // need to be special detection elsewhere to identify when writing a value to an |
| 14152 | // array element that is stored using the `repeated` tag, and handle it |
| 14153 | // without making a call to this function. |
| 14154 | const arena = parent.beginArena(sema.gpa); |
| 14155 | defer parent.finishArena(); |
| 14156 | |
| 14157 | const repeated_val = try parent.val.castTag(.repeated).?.data.copy(arena); |
| 14158 | const array_len_including_sentinel = |
| 14159 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| 14160 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 14161 | mem.set(Value, elems, repeated_val); |
| 14162 | |
| 14163 | parent.val.* = try Value.Tag.array.create(arena, elems); |
| 14118 | 14164 | |
| 14119 | | const bytes = parent.val.castTag(.bytes).?.data; |
| 14120 | | const dest_len = parent.ty.arrayLenIncludingSentinel(); |
| 14121 | | // bytes.len may be one greater than dest_len because of the case when |
| 14122 | | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. |
| 14123 | | assert(bytes.len >= dest_len); |
| 14124 | | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| 14125 | | for (elems) |*elem, i| { |
| 14126 | | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); |
| 14127 | | } |
| 14165 | return ComptimePtrMutationKit{ |
| 14166 | .decl_ref_mut = parent.decl_ref_mut, |
| 14167 | .val = &elems[elem_ptr.index], |
| 14168 | .ty = elem_ty, |
| 14169 | }; |
| 14170 | }, |
| 14128 | 14171 | |
| 14129 | | parent.val.* = try Value.Tag.array.create(arena, elems); |
| 14172 | .array => return ComptimePtrMutationKit{ |
| 14173 | .decl_ref_mut = parent.decl_ref_mut, |
| 14174 | .val = &parent.val.castTag(.array).?.data[elem_ptr.index], |
| 14175 | .ty = elem_ty, |
| 14176 | }, |
| 14130 | 14177 | |
| 14131 | | return ComptimePtrMutationKit{ |
| 14132 | | .decl_ref_mut = parent.decl_ref_mut, |
| 14133 | | .val = &elems[elem_ptr.index], |
| 14134 | | .ty = elem_ty, |
| 14135 | | }; |
| 14178 | else => unreachable, |
| 14179 | } |
| 14136 | 14180 | }, |
| 14137 | | .repeated => { |
| 14138 | | // An array is memory-optimized to store only a single element value, and |
| 14139 | | // that value is understood to be the same for the entire length of the array. |
| 14140 | | // However, now we want to modify an individual field and so the |
| 14141 | | // representation has to change. If we wanted to avoid this, there would |
| 14142 | | // need to be special detection elsewhere to identify when writing a value to an |
| 14143 | | // array element that is stored using the `repeated` tag, and handle it |
| 14144 | | // without making a call to this function. |
| 14145 | | const arena = parent.beginArena(sema.gpa); |
| 14146 | | defer parent.finishArena(); |
| 14147 | | |
| 14148 | | const repeated_val = try parent.val.castTag(.repeated).?.data.copy(arena); |
| 14149 | | const array_len_including_sentinel = |
| 14150 | | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| 14151 | | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 14152 | | mem.set(Value, elems, repeated_val); |
| 14153 | | |
| 14154 | | parent.val.* = try Value.Tag.array.create(arena, elems); |
| 14155 | | |
| 14181 | else => { |
| 14182 | if (elem_ptr.index != 0) { |
| 14183 | // TODO include a "declared here" note for the decl |
| 14184 | return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ |
| 14185 | elem_ptr.index, |
| 14186 | }); |
| 14187 | } |
| 14156 | 14188 | return ComptimePtrMutationKit{ |
| 14157 | 14189 | .decl_ref_mut = parent.decl_ref_mut, |
| 14158 | | .val = &elems[elem_ptr.index], |
| 14159 | | .ty = elem_ty, |
| 14190 | .val = parent.val, |
| 14191 | .ty = parent.ty, |
| 14160 | 14192 | }; |
| 14161 | 14193 | }, |
| 14162 | | |
| 14163 | | .array => return ComptimePtrMutationKit{ |
| 14164 | | .decl_ref_mut = parent.decl_ref_mut, |
| 14165 | | .val = &parent.val.castTag(.array).?.data[elem_ptr.index], |
| 14166 | | .ty = elem_ty, |
| 14167 | | }, |
| 14168 | | |
| 14169 | | else => unreachable, |
| 14170 | 14194 | } |
| 14171 | 14195 | }, |
| 14172 | 14196 | .field_ptr => { |
| ... | ... | @@ -14296,15 +14320,41 @@ fn beginComptimePtrLoad( |
| 14296 | 14320 | .elem_ptr => { |
| 14297 | 14321 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| 14298 | 14322 | const parent = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr); |
| 14299 | | const elem_ty = parent.ty.childType(); |
| 14300 | | const elem_size = elem_ty.abiSize(target); |
| 14301 | | return ComptimePtrLoadKit{ |
| 14302 | | .root_val = parent.root_val, |
| 14303 | | .val = try parent.val.elemValue(sema.arena, elem_ptr.index), |
| 14304 | | .ty = elem_ty, |
| 14305 | | .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index), |
| 14306 | | .is_mutable = parent.is_mutable, |
| 14307 | | }; |
| 14323 | switch (parent.ty.zigTypeTag()) { |
| 14324 | .Array, .Vector => { |
| 14325 | const check_len = parent.ty.arrayLenIncludingSentinel(); |
| 14326 | if (elem_ptr.index >= check_len) { |
| 14327 | // TODO have the parent include the decl so we can say "declared here" |
| 14328 | return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{ |
| 14329 | elem_ptr.index, check_len, |
| 14330 | }); |
| 14331 | } |
| 14332 | const elem_ty = parent.ty.childType(); |
| 14333 | const elem_size = elem_ty.abiSize(target); |
| 14334 | return ComptimePtrLoadKit{ |
| 14335 | .root_val = parent.root_val, |
| 14336 | .val = try parent.val.elemValue(sema.arena, elem_ptr.index), |
| 14337 | .ty = elem_ty, |
| 14338 | .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index), |
| 14339 | .is_mutable = parent.is_mutable, |
| 14340 | }; |
| 14341 | }, |
| 14342 | else => { |
| 14343 | if (elem_ptr.index != 0) { |
| 14344 | // TODO have the parent include the decl so we can say "declared here" |
| 14345 | return sema.fail(block, src, "out of bounds comptime load of index {d}", .{ |
| 14346 | elem_ptr.index, |
| 14347 | }); |
| 14348 | } |
| 14349 | return ComptimePtrLoadKit{ |
| 14350 | .root_val = parent.root_val, |
| 14351 | .val = parent.val, |
| 14352 | .ty = parent.ty, |
| 14353 | .byte_offset = parent.byte_offset, |
| 14354 | .is_mutable = parent.is_mutable, |
| 14355 | }; |
| 14356 | }, |
| 14357 | } |
| 14308 | 14358 | }, |
| 14309 | 14359 | .field_ptr => { |
| 14310 | 14360 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |