Skip to content

Num Rigid Vars #7805

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

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft

Num Rigid Vars #7805

wants to merge 2 commits into from

Conversation

jaredramirez
Copy link
Collaborator

@jaredramirez jaredramirez commented May 22, 2025

Overview

This PR originally implemented the "Unify by Ident.Idx" solution, but then I realized it was kinda a non-starter. Currently, this PR is WIP.

Background

In Elm's compiler, two rigid variables unify only if the Vars point to the exact same descriptor. This works because Elm creates and re-uses the same Var for the same rigid vars during instantiate. In Roc, this works fine for regular rigid vars, but this presents a problem in our specialized representation of Num.

pub const Num = union(enum) {
    flex_var: ?Ident.Idx,
    rigid_var: Ident.Idx,  // NEW
    int: Int,
    frac: Frac,
    ...
};

pub const Int = union(enum) {
    flex_var: ?Ident.Idx,
    rigid_var: Ident.Idx, // NEW
    exact: IntPrecision,
};

pub const IntPrecision = enum { u8, i8, u16, i16, u32, i32, u64, i64, u128, i128 };

Problem

Given this type:

add : Num(a), Num(a) -> Num(a)

We want a to refer to the same rigid var and unify with the other rigid vars in the signature. In our current system, this looks like:

const first_ident_idx = ident_store.insert("a", region);
const first = Content{ .num = Num{ .rigid_var = first_ident_idx } };

const second_ident_idx = ident_store.insert("a", region);
const second = Content{ .num = Num{ .rigid_var = second_ident_idx } };

const third_ident_idx = ident_store.insert("a", region);
const third = Content{ .num = Num{ .rigid_var = third_ident_idx } };

Since these rigid vars are not referencing other Vars, we can't unify by identical descriptor – so it's unclear how exactly these should unify.

Possible Solutions

Unify by Ident.Idx

We could update the variable instantiation to be:

const ident_idx = ident_store.insert("a", region);

const first = Content{ .num = Num{ .rigid_var = ident_idx } };
const second = Content{ .num = Num{ .rigid_var = ident_idx } };
const third = Content{ .num = Num{ .rigid_var = ident_idx } };

Then, update the unification logic to allow two rigid vars to unify if they point to the same Ident. This almost works, but for the fact that each Ident is intended to refer to exactly one thing (evidenced by the Region on each Ident), so reusing idents here seems like a non-starter.

Change how we represent Num

If we changed how we represented Num back to a type-apply-y approach, while still only supporting our explicit builtins, we could do something like:

pub const FlatType = union(enum) {
    ...,
    num: Var,
    int: Var,
    int_prec: IntPrecision,
};

pub const IntPrecision = enum { u8, i8, u16, i16, u32, i32, u64, i64, u128, i128 };

Then, we could unify sub variables normally and rely on regular rigid var semantics and every would Just Work.

However, this results in 3 type descriptors and vars needed to represent a single number, which is against the goal of more compact number representations. That said, this feels like the best option right now, imo.

Group equal rigid vars (not fleshed out)

In a function signature (and its def for scoped typed variables), we could somehow capture equal sets of rigid vars (ie all vars that are a). Then if this set-thing was passed to unify (maybe thru Scratch) we could allow rigid var idents to unify if they're equal. This might require an additional allocation tho, and adds extra work to how equal rigid vars are managed by Can/Solve. It's unclear to me how good/bad of an idea this is.

Something else

There are probably other solutions here to that I'm not thinking of!!

@jaredramirez jaredramirez self-assigned this May 22, 2025
Base automatically changed from push-vomrrrkqsmkz to main May 22, 2025 05:28
@jaredramirez jaredramirez changed the title Nominal Rigid Vars Num Rigid Vars May 22, 2025
@jaredramirez jaredramirez force-pushed the push-mtkummnwxvsr branch 2 times, most recently from 1a3e44d to 5c5b466 Compare May 29, 2025 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant