Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Existing overloading implementation doesn't scale with tagged-unions #832

Open
emil14 opened this issue Jan 11, 2025 · 0 comments
Open

Existing overloading implementation doesn't scale with tagged-unions #832

emil14 opened this issue Jan 11, 2025 · 0 comments
Assignees
Labels

Comments

@emil14
Copy link
Collaborator

emil14 commented Jan 11, 2025

The way overloading is implemented was reflecting untagged unions and doesn't scale with new design with tagged unions. For example:

type AddInput union {
    Int int
    Float float
    String string
}

#extern(int int_add, float float_add, string string_add)
pub def Add<T AddInput>(left T, right T) (res T)

2 things here made overloading work in the past:

  1. #extern compiler-directive with types and their implementations
  2. exactly one type-parameter (T in this case) with constraint of type (that resolves to) union

How it was working - compiler should match type-argument (e.g. Add<int>) with int int_add from #extern and select int_add runtime-function. But here's the problem:

With untagged unions

def Add<T int | string | float>(left T, right T) (res T)

For Add<int> return (send) type is int because int <: int | string, but tagged unions doesn't work like that - because statement int <: union { Int int, String string } is FALSE! In other words we need to pass union type-argument to satisfy union constraint, because for tagged unions only union is a sub-type of super-type union, unlike untagged-union where for union super-type both union and NOT union might be valid sub-types (depending on the definition).

This means that return type of components like Add and other overloaded operators are unions, even though we would like to have the underlaying type. This complecates implementation of operators as syntax sugar

Solution

We need to implement real overloading where you actually have several signatures and not just multiple runtime implementations and a union.

#extern(int_add)
pub def Add(left int, right int) (res int)

#extern(float_add)
pub def Add(float int, float int) (float int)

#extern(string_add)
pub def Add(left string, right string) (res string)

This way when you do Add<int> compiler knows that it needs to select Add(left int, right int) (res int) signature and that input/output types are int, no need to mess with unions!

Challanges

Program structure doesn't support multiple entities with the same name as well as entity reference resolution algorithm, so first thing that we need to do is to figure out how to extend those APIs in the way, that makes it possible to add overloading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: In Progress
Development

No branches or pull requests

1 participant