Calling by method name on a union of distinct types with distinct capabilities.
- Dominant language
- Pony
- Stars
- 6.2k
- Forks
- 437
- Avg merge
- 7h 14m
- Merged PRs (30d)
- 161
Description
I was doing some brainstorming about a common interface for "byte writers" that would cover both `class ref` and `actor tag` implementations of methods for writing out bytes. I quickly figured out that I couldn't have the same interface cover both cases, but I thought a type union of two interfaces could work well, so I created `OutClass` and `OutActor` interfaces, and called the union of them `Out`:
```pony
type Out is (OutActor tag | OutClass ref)
interface tag OutActor
be print(string : String)
interface ref OutClass
fun ref print(string : String)
class StringWriter is OutClass
var _string: String iso = recover String end
fun ref finish(): String iso^ => _string = recover String end
fun ref print(string : String) =>
_string.append(string)
actor Main
new create(env: Env) =>
let out_1: Out = env.out
out_1.print("Hello, world!")
let out_2: Out = StringWriter
out_2.print("Hello, world!")
try env.out.print((out_2 as StringWriter).finish()) end
```
Doing so gives this error output:
```
Error:
main.pony:19:16: receiver type is not a subtype of target type
out_1.print("Hello, world!")
^
Info:
main.pony:19:5: receiver type: (OutActor tag | OutClass ref)
out_1.print("Hello, world!")
^
main.pony:7:3: target type: (OutActor ref | OutClass ref)
fun ref print(string : String)
^
main.pony:1:14: OutActor tag is not a subtype of OutActor ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of OutClass ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of any element of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: not every element of (OutActor tag | OutClass ref) is a subtype of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
Error:
main.pony:22:16: receiver type is not a subtype of target type
out_2.print("Hello, world!")
^
Info:
main.pony:22:5: receiver type: (OutActor tag | OutClass ref)
out_2.print("Hello, world!")
^
main.pony:7:3: target type: (OutActor ref | OutClass ref)
fun ref print(string : String)
^
main.pony:1:14: OutActor tag is not a subtype of OutActor ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of OutClass ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of any element of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: not every element of (OutActor tag | OutClass ref) is a subtype of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
```
Note that if I change the code to use the specific interface rather than the type union, everything works okay:
```pony
actor Main
new create(env: Env) =>
let out_1: OutActor = env.out
out_1.print("Hello, world!")
let out_2: OutClass = StringWriter
out_2.print("Hello, world!")
try env.out.print((out_2 as StringWriter).finish()) end
```
```
Hello, world!
Hello, world!
```
Contributor guide
Research direction
Start with the minimal Pony example in the issue and inspect how the compiler resolves method calls on unions with differing capabilities. Define the expected behavior for OutActor tag | OutClass ref and capture it in a regression test; the issue does not name source files or existing tests.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100