Commit cdf14baa45

Andrew Kelley <andrew@ziglang.org>
2019-06-13 03:46:04
fix double nested peer result locations
```zig export fn entry(x: bool) i32 { return if (x) if (x) a else b else if (x) c else d; } ```
1 parent 0d62c92
Changed files (2)
src/all_types.hpp
@@ -3649,10 +3649,16 @@ struct ResultLocReturn {
     ResultLoc base;
 };
 
+struct IrSuspendPosition {
+    size_t basic_block_index;
+    size_t instruction_index;
+};
+
 struct ResultLocPeerParent {
     ResultLoc base;
 
     bool skipped;
+    bool done_resuming;
     ResultLoc *parent;
     ResultLocPeer *peers;
     size_t peer_count;
@@ -3660,11 +3666,6 @@ struct ResultLocPeerParent {
     IrInstruction *is_comptime;
 };
 
-struct IrSuspendPosition {
-    size_t basic_block_index;
-    size_t instruction_index;
-};
-
 struct ResultLocPeer {
     ResultLoc base;
 
src/ir.cpp
@@ -16395,45 +16395,56 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
     }
 
     ResultLocPeerParent *peer_parent = phi_instruction->peer_parent;
-    if (peer_parent != nullptr && peer_parent->resolved_type == nullptr && !peer_parent->skipped) {
-        // Suspend the phi first so that it gets resumed last
-        ira->resume_stack.add_one();
-        for (size_t i = ira->resume_stack.length;;) {
-            if (i <= 1) break;
-            i -= 1;
-            ira->resume_stack.items[i] = ira->resume_stack.items[i-1];
+    if (peer_parent != nullptr && !peer_parent->skipped && !peer_parent->done_resuming) {
+        if (peer_parent->resolved_type == nullptr) {
+            IrInstruction **instructions = allocate<IrInstruction *>(peer_parent->peer_count);
+            for (size_t i = 0; i < peer_parent->peer_count; i += 1) {
+                ResultLocPeer *this_peer = &peer_parent->peers[i];
+
+                IrInstruction *gen_instruction = this_peer->base.gen_instruction;
+                if (gen_instruction == nullptr) {
+                    // unreachable instructions will cause implicit_elem_type to be null
+                    if (this_peer->base.implicit_elem_type == nullptr) {
+                        instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction);
+                    } else {
+                        instructions[i] = ir_const(ira, this_peer->base.source_instruction,
+                                this_peer->base.implicit_elem_type);
+                        instructions[i]->value.special = ConstValSpecialRuntime;
+                    }
+                } else {
+                    instructions[i] = gen_instruction;
+                }
+
+            }
+            ZigType *expected_type = ir_result_loc_expected_type(ira, &phi_instruction->base, peer_parent->parent);
+            peer_parent->resolved_type = ir_resolve_peer_types(ira,
+                    peer_parent->base.source_instruction->source_node, expected_type, instructions,
+                    peer_parent->peer_count);
+
+            // In case resolving the parent activates a suspend, do it now
+            IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent,
+                    peer_parent->resolved_type, nullptr);
+            if (parent_result_loc != nullptr &&
+                (type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc)))
+            {
+                return parent_result_loc;
+            }
         }
-        ira_suspend(ira, &phi_instruction->base, nullptr, &ira->resume_stack.items[0]);
 
-        IrInstruction **instructions = allocate<IrInstruction *>(peer_parent->peer_count);
+        IrSuspendPosition suspend_pos;
+        ira_suspend(ira, &phi_instruction->base, nullptr, &suspend_pos);
+        ira->resume_stack.append(suspend_pos);
+
         for (size_t i = 0; i < peer_parent->peer_count; i += 1) {
-            ResultLocPeer *this_peer = &peer_parent->peers[i];
             ResultLocPeer *opposite_peer = &peer_parent->peers[peer_parent->peer_count - i - 1];
-
-            IrInstruction *gen_instruction = this_peer->base.gen_instruction;
-            if (gen_instruction == nullptr) {
-                // unreachable instructions will cause implicit_elem_type to be null
-                if (this_peer->base.implicit_elem_type == nullptr) {
-                    instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction);
-                } else {
-                    instructions[i] = ir_const(ira, this_peer->base.source_instruction,
-                            this_peer->base.implicit_elem_type);
-                    instructions[i]->value.special = ConstValSpecialRuntime;
-                }
-            } else {
-                instructions[i] = gen_instruction;
-            }
             if (opposite_peer->base.implicit_elem_type != nullptr &&
                 opposite_peer->base.implicit_elem_type->id != ZigTypeIdUnreachable)
             {
                 ira->resume_stack.append(opposite_peer->suspend_pos);
             }
         }
-        ZigType *expected_type = ir_result_loc_expected_type(ira, &phi_instruction->base, peer_parent->parent);
-        peer_parent->resolved_type = ir_resolve_peer_types(ira,
-                peer_parent->base.source_instruction->source_node, expected_type, instructions,
-                peer_parent->peer_count);
 
+        peer_parent->done_resuming = true;
         return ira_resume(ira);
     }