diff --git a/src/passes/AbstractTypeRefining.cpp b/src/passes/AbstractTypeRefining.cpp index a29dfe9a8d8..30f3a98641d 100644 --- a/src/passes/AbstractTypeRefining.cpp +++ b/src/passes/AbstractTypeRefining.cpp @@ -394,6 +394,22 @@ struct AbstractTypeRefining : public Pass { } } + // If we optimize away a descriptor type, then we must fix up any + // ref.get_desc of it, as ReFinalize would fix us up to return it. This + // can only happen when no such descriptor is created, which means the + // instruction will never be reached (no struct with such a descriptor was + // created). + void visitRefGetDesc(RefGetDesc* curr) { + auto optimized = getOptimized(curr->type); + if (!optimized) { + return; + } + + Builder builder(*getModule()); + replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref), + builder.makeUnreachable())); + } + void visitBrOn(BrOn* curr) { if (curr->op == BrOnNull || curr->op == BrOnNonNull) { return; diff --git a/test/lit/passes/abstract-type-refining-desc.wast b/test/lit/passes/abstract-type-refining-desc.wast index 6f590ff8d27..8b3f1e64932 100644 --- a/test/lit/passes/abstract-type-refining-desc.wast +++ b/test/lit/passes/abstract-type-refining-desc.wast @@ -1020,3 +1020,48 @@ ) ) ) + +(module + ;; $B is never created. When removing it from the result of the function, we + ;; must remove the ref.get_desc too (otherwise it would return a non- + ;; validating type for the new result; and it traps anyhow). + (rec + ;; YESTNH: (rec + ;; YESTNH-NEXT: (type $A (sub (descriptor $B (struct)))) + ;; NO_TNH: (rec + ;; NO_TNH-NEXT: (type $A (sub (descriptor $B (struct)))) + (type $A (sub (descriptor $B (struct)))) + ;; YESTNH: (type $B (describes $A (struct))) + ;; NO_TNH: (type $B (describes $A (struct))) + (type $B (describes $A (struct))) + ) + + ;; YESTNH: (type $2 (func (result (ref none)))) + + ;; YESTNH: (func $test (type $2) (result (ref none)) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (struct.new_default $A + ;; YESTNH-NEXT: (ref.null none) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (type $2 (func (result (ref none)))) + + ;; NO_TNH: (func $test (type $2) (result (ref none)) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (struct.new_default $A + ;; NO_TNH-NEXT: (ref.null none) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + (func $test (result (ref (exact $B))) + (ref.get_desc $A + (struct.new_default $A + (ref.null none) + ) + ) + ) +) +