Open
Conversation
The subtype checker's arrow type reification had a bug: when comparing
two arrow types like `this->X!` and `this->X`, the function
`viewpoint_reifypair` used the left side's typeparamref to reify both
sides. Since the typeparamref carries the ephemeral marker (! or ^),
this meant both sides were reified with the same marker, making
`this->X!` and `this->X` appear identical during pairwise subtype
comparison.
This allowed code like:
```pony
class Foo
fun alias[X](x: X!) : X^ =>
let y : ref->X = consume x
consume y
```
to compile, which is unsound — it takes an aliased (tag) reference and
returns it as if it were the original capability (potentially iso),
enabling duplication of unique references.
Three fixes work together:
1. `viewpoint_reifypair` now walks both arrow types in parallel so each
side uses its own typeparamref with the correct ephemeral marker.
2. `viewpoint_reifytypeparam` now searches within the type being reified
for the matching typeparamref, preferring the local version's
ephemeral marker over one passed from the other side of a subtype
check. This covers call sites in subtype.c and compattype.c that
pass one side's typeparamref to reify the other.
3. `alias()` in alias.c now short-circuits for `val->A` arrow types.
A val viewpoint always produces val or tag, both of which alias to
themselves, so aliasing inside the arrow (`val->(A!)`) is
over-conservative when A=iso: `val->(iso!) = val->tag = tag`, but
`(val->iso)! = val! = val`. The stdlib's persistent list had four
signatures using `val->A!` that relied on the old behavior; these
are changed to `val->A`.
Closes #1798
947bc84 to
3902bc8
Compare
Member
Author
|
@jemc should this also get a "CHANGED" entry? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The subtype checker's arrow type reification had a bug: when comparing two arrow types like
this->X!andthis->X,viewpoint_reifypairused the left side's typeparamref to reify both sides. Since the typeparamref carries the ephemeral marker, both sides were reified identically, makingthis->X!andthis->Xappear equal during pairwise comparison.This allowed unsound code where an aliased (tag) reference could be returned as its original capability (potentially iso), enabling duplication of unique references.
Three fixes work together:
viewpoint_reifypairnow walks both arrow types in parallel so each side uses its own typeparamref with the correct ephemeral marker.viewpoint_reifytypeparamnow searches within the type being reified for the matching typeparamref, preferring the local version's ephemeral marker. This covers call sites insubtype.candcompattype.cthat pass one side's typeparamref to reify the other.alias()now short-circuits forval->Aarrow types. A val viewpoint always produces val or tag (both self-aliasing), so aliasing inside the arrow is over-conservative. The stdlib's persistent list had four signatures usingval->A!that relied on the old behavior; these are changed toval->A.This is a breaking change for code that relied on the bug. The most common affected pattern is reading a field into a local variable and returning it from a method with a
this->Areturn type — the local auto-aliases tothis->A!which is no longer accepted as a subtype ofthis->A. Returning the field directly avoids the aliasing.Closes #1798