Commit e28a7a9
fix(emit): open-T nil compare / coalesce / unwrap emit verifiable IL (#839)
Issue #831. The emitter naively produced `ldarg.0; ldnull; ceq` for
`self == nil` when `self` had a binder-typed type parameter shape
(e.g. `T?` over `[T class]` or unconstrained T). The runtime JIT
tolerated it, but `ilverify` rejected the IL with
`[StackUnexpected]: found Nullobjref ... expected value 'T'` because
`ceq` cannot match an opaque `!!T` stack slot against a managed-null
reference at the verifier layer. The same gap existed for `?:`
(NullCoalesce) and `!!` (NullAssertion) over open-T operands, which
both used `dup; brtrue` patterns the verifier also rejects on opaque
type-parameter stack values. Eight `Gsharp.Extensions.Optional`
helpers (`Map`, `FlatMap`, `OrElse`, `OrCompute`, `OrThrow`,
`IfPresent`, `Filter`, plus a value-type `FlatMap` partner) tripped
the gate.
Root cause: the existing `liftedBinarySlots` /
`NullableValueTypeUnwrapCollector` /
`NullableValueTypeCoalesceCollector` paths gated on a static
`ClrType`, which open type parameters never have, so every shape over
an open T fell through to the bottom `ldnull; ceq` / `dup; brtrue`
opcodes.
Fix (emit-only — no new BoundNodeKind):
* `MethodBodyEmitter.Operators.cs`:
* For `T? == nil` / `T? != nil` over an open T (any constraint),
emit `box <T?>; ldnull; ceq` and append `ldc.i4.0; ceq` for the
`!=` lobe. ECMA-335 III.4.1 specifies that `box` of a
`Nullable<T>` yields a managed-null reference when HasValue is
false, so the same shape works uniformly for class-, struct-, and
unconstrained-T (the JIT elides the box when T resolves to a
reference type).
* For `T? ?: rhs` over a class/unconstrained-T LHS, spill the LHS
to a `T`-typed slot and probe via `box !!T; brfalse fallback`,
reloading the slot on the non-null path.
* For `!!` over a bare `T` or `T?` operand (class/unconstrained
T), spill to a `T`-typed slot and probe via `box !!T; brtrue
nonNull`, throwing NullReferenceException on null and reloading
the slot on non-null. Handles both the un-narrowed `self T?`
shape and the smart-cast narrowed bare-`T` shape produced after
an `if self == nil { return }` guard.
* `SlotPlanner.cs`:
* Extend `NullableValueTypeUnwrapCollector` and
`NullableValueTypeCoalesceCollector` to pre-allocate slots for
the new open-T paths (typed as `!!T`).
Tests (`Issue831OpenTNilCompareEmitTests`, 7 cases):
* `OpenTNilCompare_ClassConstrained_RoundTrip_Verifiable` — the
original Optional.Map repro.
* `OpenTNilCompare_ClassConstrained_NotEquals_Verifiable` — exercises
the `!= nil` negation lobe.
* `OpenTNullCoalesce_ClassConstrained_Verifiable` — Optional.OrElse
repro for `self ?: defaultValue`.
* `OpenTNullAssertion_ClassConstrained_NonNull_Verifiable` — smart-
cast unwrap after a nil-guard.
* `OpenTNullAssertion_ClassConstrained_NullThrows_Verifiable` —
confirms NRE still raised on null inputs.
* `OpenTNilCompare_StructConstrained_PassesIlverify` — verifies the
same box-and-compare guard handles struct-constrained T cleanly.
* `OpenTNilCompare_BothOverloads_DispatchedCorrectly` — dual-overload
dispatch end-to-end.
Each test compiles with gsc, gates the PE through
`IlVerifier.Verify`, then runs it via `dotnet exec` and asserts on
stdout. `Gsharp.Extensions.Optional` helpers now emit zero ilverify
errors (only the pre-existing unrelated `Sequences.Empty()` error
remains, tracked separately).
Closes #831
Related: #806, ADR-0084, parent #706
Co-authored-by: Copilot CLI <noreply@github.com>1 parent 02cab8c commit e28a7a9
3 files changed
Lines changed: 615 additions & 22 deletions
File tree
- src/Core/CodeAnalysis/Emit
- test/Compiler.Tests/Emit
Lines changed: 210 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
73 | 116 | | |
74 | 117 | | |
75 | 118 | | |
| |||
188 | 231 | | |
189 | 232 | | |
190 | 233 | | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
191 | 280 | | |
192 | 281 | | |
193 | 282 | | |
| |||
341 | 430 | | |
342 | 431 | | |
343 | 432 | | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
344 | 472 | | |
345 | 473 | | |
346 | 474 | | |
| |||
442 | 570 | | |
443 | 571 | | |
444 | 572 | | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
445 | 655 | | |
446 | 656 | | |
447 | 657 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
991 | 991 | | |
992 | 992 | | |
993 | 993 | | |
994 | | - | |
995 | | - | |
996 | | - | |
997 | | - | |
998 | | - | |
999 | | - | |
1000 | | - | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
1001 | 1015 | | |
1002 | 1016 | | |
1003 | 1017 | | |
| |||
1009 | 1023 | | |
1010 | 1024 | | |
1011 | 1025 | | |
1012 | | - | |
1013 | | - | |
1014 | | - | |
| 1026 | + | |
1015 | 1027 | | |
1016 | | - | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
1017 | 1049 | | |
1018 | 1050 | | |
1019 | 1051 | | |
1020 | 1052 | | |
1021 | 1053 | | |
1022 | 1054 | | |
1023 | 1055 | | |
1024 | | - | |
1025 | | - | |
1026 | | - | |
1027 | | - | |
1028 | | - | |
1029 | | - | |
1030 | | - | |
1031 | | - | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
1032 | 1075 | | |
1033 | 1076 | | |
1034 | 1077 | | |
| |||
1041 | 1084 | | |
1042 | 1085 | | |
1043 | 1086 | | |
1044 | | - | |
1045 | | - | |
| 1087 | + | |
1046 | 1088 | | |
1047 | | - | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
1048 | 1096 | | |
1049 | 1097 | | |
1050 | 1098 | | |
| |||
0 commit comments