Skip to content

Commit ed83899

Browse files
authored
[Custom Descriptors] Propagate subtyping to describees in Unsubtyping (#7927)
An upcoming change to the custom descriptor validation rules will require describees to be in a subtype relationship whenever their descriptors are. This is similar to the requirement we already have in the opposite direction. Update Unsubtyping to respect this upcoming rule.
1 parent cb75dcc commit ed83899

File tree

2 files changed

+80
-41
lines changed

2 files changed

+80
-41
lines changed

src/passes/Unsubtyping.cpp

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,6 @@ struct Unsubtyping : Pass {
525525
}
526526
if (HeapType::isSubType(*oldSuper, super)) {
527527
// sub <: oldSuper <: super
528-
processDescribed(sub, *oldSuper, super);
529528
noteSubtype(*oldSuper, super);
530529
// We already handled sub <: oldSuper, so we're done.
531530
return;
@@ -535,7 +534,6 @@ struct Unsubtyping : Pass {
535534
// super will already be in the same tree when we process them below, so
536535
// when we process casts we will know that we only need to process up to
537536
// oldSuper.
538-
processDescribed(sub, super, *oldSuper);
539537
process(super, *oldSuper);
540538
}
541539

@@ -547,42 +545,6 @@ struct Unsubtyping : Pass {
547545
processCasts(sub, super, oldSuper);
548546
}
549547

550-
void processDescribed(HeapType sub, HeapType mid, HeapType super) {
551-
// We are establishing sub <: mid <: super. If super describes the immediate
552-
// supertype of the type sub describes, then once we insert mid between them
553-
// we would have this:
554-
//
555-
// A -> super
556-
// ^ ^
557-
// | mid
558-
// | ^
559-
// C -> sub
560-
//
561-
// This violates the requirement that the descriptor of C's immediate
562-
// supertype must be the immediate supertype of C's descriptor. To fix it,
563-
// we have to find the type B that mid describes and insert it between A and
564-
// C:
565-
//
566-
// A -> super
567-
// ^ ^
568-
// B -> mid
569-
// ^ ^
570-
// C -> sub
571-
//
572-
// We do this eagerly before we establish sub <: mid <: super so that if
573-
// establishing that subtyping requires recursively establishing other
574-
// subtypings, we can depend on the invariant that the described types are
575-
// always set up correctly beforehand.
576-
auto subDescribed = sub.getDescribedType();
577-
auto superDescribed = super.getDescribedType();
578-
if (subDescribed && superDescribed &&
579-
types.getSupertype(*subDescribed) == superDescribed) {
580-
auto midDescribed = mid.getDescribedType();
581-
assert(midDescribed);
582-
process(*subDescribed, *midDescribed);
583-
}
584-
}
585-
586548
void processDefinitions(HeapType sub, HeapType super) {
587549
if (super.isBasic()) {
588550
return;
@@ -618,6 +580,11 @@ struct Unsubtyping : Pass {
618580
noteSubtype(*desc, *superDesc);
619581
}
620582
}
583+
if (auto desc = sub.getDescribedType()) {
584+
if (auto superDesc = super.getDescribedType()) {
585+
noteSubtype(*desc, *superDesc);
586+
}
587+
}
621588
}
622589

623590
void

test/lit/passes/unsubtyping-desc.wast

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,13 @@
4949
(type $A (sub (descriptor $A.desc (struct))))
5050
;; CHECK: (type $A.desc (sub (describes $A (struct))))
5151
(type $A.desc (sub (describes $A (struct))))
52-
;; CHECK: (type $B (sub (descriptor $B.desc (struct))))
52+
;; CHECK: (type $B (sub $A (descriptor $B.desc (struct))))
5353
(type $B (sub $A (descriptor $B.desc (struct))))
5454
;; CHECK: (type $B.desc (sub $A.desc (describes $B (struct))))
5555
(type $B.desc (sub $A.desc (describes $B (struct))))
5656
)
5757

58-
;; Now we directly require B.desc <: A.desc. This does *not* imply B <: A, so
59-
;; we can optimize $B (but not $B.desc).
58+
;; Now we require B.desc <: A.desc, which similarly implies B <: A.
6059
;; CHECK: (global $B.desc (ref null $B.desc) (ref.null none))
6160
(global $B.desc (ref null $B.desc) (ref.null none))
6261
;; CHECK: (global $A.desc (ref null $A.desc) (global.get $B.desc))
@@ -134,3 +133,76 @@
134133
;; CHECK: (global $bot-mid-desc (ref null $mid.desc) (struct.new_default $bot.desc))
135134
(global $bot-mid-desc (ref null $mid.desc) (struct.new $bot.desc))
136135
)
136+
137+
(module
138+
(rec
139+
;; CHECK: (rec
140+
;; CHECK-NEXT: (type $top (sub (descriptor $top.desc (struct))))
141+
(type $top (sub (descriptor $top.desc (struct))))
142+
;; CHECK: (type $mid (sub $top (descriptor $mid.desc (struct))))
143+
(type $mid (sub $top (descriptor $mid.desc (struct))))
144+
;; CHECK: (type $bot (sub $mid (descriptor $bot.desc (struct))))
145+
(type $bot (sub $mid (descriptor $bot.desc (struct))))
146+
;; CHECK: (type $top.desc (sub (describes $top (struct))))
147+
(type $top.desc (sub (describes $top (struct))))
148+
;; CHECK: (type $mid.desc (sub $top.desc (describes $mid (struct))))
149+
(type $mid.desc (sub $top.desc (describes $mid (struct))))
150+
;; CHECK: (type $bot.desc (sub $mid.desc (describes $bot (struct))))
151+
(type $bot.desc (sub $mid.desc (describes $bot (struct))))
152+
)
153+
154+
;; Now go the other direction:
155+
;;
156+
;; top ---> top.desc
157+
;; ^
158+
;; mid -> mid.desc |(2)
159+
;; ^ (1) |
160+
;; bot ---> bot.desc
161+
;;
162+
;; bot.desc <: top.desc implies bot <: top, but we already have bot <: mid, so
163+
;; that gives us bot <: mid <: top. This is only valid if we also have
164+
;; bot.desc <: mid.desc <: top.desc.
165+
166+
;; CHECK: (global $bot-mid (ref null $mid) (struct.new_default $bot
167+
;; CHECK-NEXT: (ref.null none)
168+
;; CHECK-NEXT: ))
169+
(global $bot-mid (ref null $mid) (struct.new $bot (ref.null none)))
170+
;; CHECK: (global $bot-top-desc (ref null $top.desc) (struct.new_default $bot.desc))
171+
(global $bot-top-desc (ref null $top.desc) (struct.new $bot.desc))
172+
)
173+
174+
(module
175+
(rec
176+
;; CHECK: (rec
177+
;; CHECK-NEXT: (type $top (sub (descriptor $top.desc (struct))))
178+
(type $top (sub (descriptor $top.desc (struct))))
179+
;; CHECK: (type $mid (sub $top (descriptor $mid.desc (struct))))
180+
(type $mid (sub $top (descriptor $mid.desc (struct))))
181+
;; CHECK: (type $bot (sub $mid (descriptor $bot.desc (struct))))
182+
(type $bot (sub $mid (descriptor $bot.desc (struct))))
183+
;; CHECK: (type $top.desc (sub (describes $top (struct))))
184+
(type $top.desc (sub (describes $top (struct))))
185+
;; CHECK: (type $mid.desc (sub $top.desc (describes $mid (struct))))
186+
(type $mid.desc (sub $top.desc (describes $mid (struct))))
187+
;; CHECK: (type $bot.desc (sub $mid.desc (describes $bot (struct))))
188+
(type $bot.desc (sub $mid.desc (describes $bot (struct))))
189+
)
190+
191+
;; Same as above, but the order of the initial subtypings is reversed.
192+
;;
193+
;; top ---> top.desc
194+
;; ^
195+
;; mid -> mid.desc |(1)
196+
;; ^ (2) |
197+
;; bot ---> bot.desc
198+
;;
199+
;; bot.desc <: top.desc implies bot <: top. When we add bot <: mid, that gives
200+
;; us bot <: mid <: top. This is only valid if we also have
201+
;; bot.desc <: mid.desc <: top.desc.
202+
;; CHECK: (global $bot-top-desc (ref null $top.desc) (struct.new_default $bot.desc))
203+
(global $bot-top-desc (ref null $top.desc) (struct.new $bot.desc))
204+
;; CHECK: (global $bot-mid (ref null $mid) (struct.new_default $bot
205+
;; CHECK-NEXT: (ref.null none)
206+
;; CHECK-NEXT: ))
207+
(global $bot-mid (ref null $mid) (struct.new $bot (ref.null none)))
208+
)

0 commit comments

Comments
 (0)