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