Commit 03b8206f27

Veikka Tuominen <git@vexu.eu>
2022-03-11 15:48:44
Sema: make check for whether call should be memoized more thorough
1 parent 01cd411
Changed files (2)
src/Sema.zig
@@ -4618,7 +4618,7 @@ fn analyzeCall(
                         },
                         else => {},
                     }
-                    should_memoize = should_memoize and !arg_val.isComptimeMutablePtr();
+                    should_memoize = should_memoize and !arg_val.canMutateComptimeVarState();
                     memoized_call_key.args[arg_i] = .{
                         .ty = param_ty,
                         .val = arg_val,
@@ -4644,7 +4644,7 @@ fn analyzeCall(
                         },
                         else => {},
                     }
-                    should_memoize = should_memoize and !arg_val.isComptimeMutablePtr();
+                    should_memoize = should_memoize and !arg_val.canMutateComptimeVarState();
                     memoized_call_key.args[arg_i] = .{
                         .ty = sema.typeOf(uncasted_arg),
                         .val = arg_val,
@@ -13603,7 +13603,8 @@ fn analyzeShuffle(
     // in 1 call because these calls to analyzeShuffle guarantee a_len == b_len.
     if (a_len != b_len) {
         const min_len = std.math.min(a_len, b_len);
-        const max_len = std.math.max(a_len, b_len);
+        const max_src = if (a_len > b_len) a_src else b_src;
+        const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len));
 
         const expand_mask_values = try sema.arena.alloc(Value, max_len);
         i = 0;
src/value.zig
@@ -1157,6 +1157,7 @@ pub const Value = extern union {
     ) Allocator.Error!Value {
         switch (ty.zigTypeTag()) {
             .Int => {
+                if (buffer.len == 0) return Value.zero;
                 const int_info = ty.intInfo(target);
                 const endian = target.cpu.arch.endian();
                 const Limb = std.math.big.Limb;
@@ -2185,6 +2186,33 @@ pub const Value = extern union {
         };
     }
 
+    pub fn canMutateComptimeVarState(val: Value) bool {
+        if (val.isComptimeMutablePtr()) return true;
+        switch (val.tag()) {
+            .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(),
+            .array => {
+                const elems = val.cast(Payload.Array).?.data;
+                for (elems) |elem| {
+                    if (elem.canMutateComptimeVarState()) return true;
+                }
+                return false;
+            },
+            .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(),
+            .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.canMutateComptimeVarState(),
+            .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(),
+            .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.canMutateComptimeVarState(),
+            .@"struct" => {
+                const fields = val.cast(Payload.Struct).?.data;
+                for (fields) |field| {
+                    if (field.canMutateComptimeVarState()) return true;
+                }
+                return false;
+            },
+            .@"union" => return val.cast(Payload.Union).?.data.val.canMutateComptimeVarState(),
+            else => return false,
+        }
+    }
+
     /// Gets the decl referenced by this pointer.  If the pointer does not point
     /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),
     /// this function returns null.