Skip to content

Add Data Representation Flattening Pass - #555

Draft
NeilKleistGao wants to merge 12 commits into
hkust-taco:hkmc2from
NeilKleistGao:web🦚

Hidden character warning

The head ref may contain hidden characters: "web\ud83e\udd9a"
Draft

Add Data Representation Flattening Pass#555
NeilKleistGao wants to merge 12 commits into
hkust-taco:hkmc2from
NeilKleistGao:web🦚

Conversation

@NeilKleistGao

@NeilKleistGao NeilKleistGao commented Aug 28, 2026

Copy link
Copy Markdown
Member
  • Reuse web computation
  • Add annotations to Match nodes
  • Flatten data representation in a given web

Problems to be addressed:

  • How to track linearity (discussed in the meeting and decided to insert tags for class instances for pattern matching for now).

  • Block IR uses a flattened pattern matching, which makes tag checks difficult. e.g.,

if ls is
    Cons(1, Cons(2, Cons(3, Cons(x, Cons(y, Cons(z, Nil)))))) then x + y + z

It is flattened into:

if ls is
  Cons then
    let x = ls.x
    let xs = ls.xs
    if x == 1 and xs is Cons then ...

Assume that Cons(1, Cons(2, Cons(3, Cons(dyn, Cons(dyn, Cons(dyn, Nil))))))'s tag is 0, we need to check if we want to replace the whole huge matching with the tag checking. It is not clear when to set the boundary to say that the inner irrelevant matchings are untouched. e.g.,

let tmp1 = ...
let tmp2 = ...
let tmp3 = ...
if tmp1 is ....

how should we know whether we are now checking against a nested pattern (e.g., C(D(...), E(...), F(...))), or this is just a user code?

@NeilKleistGao

Copy link
Copy Markdown
Member Author

I think one possible way to address the second problem is:

  • We first compute all possible tags for a given scrutinee.
    e.g., for if x is ..., x's tag can range from 1 to 5, which means x can have 5 different shapes.
  • For a branch against a pattern, we filter out impossible tags. e.g., if tag 1 is for C(D(_)), and tag 2 is for C(E(1)), and other tags are not for C, then we transform if x is C into if x.__tag == 1 || x.__tag == 2
  • We track aliases for x's fields. e.g., let tmp = x.m, and when tmp becomes a nested matching's scrutinee, we check its shape tags against corresponding tags for x's fields. e.g., say D(_)'s shape tag is 10. If x.m's tag is 10, and tmp's tag is also 10, then we know that x.__tag == 1 implies tmp.__tag == 10. Then we split if x.__tag == 1 || x.__tag == 2 into if x.__tag == 1 and if x.__tag == 2, and omit check tmp.__tag == 10 in the first branch.

@LPTK

LPTK commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Hmm that does seem quite complicated. I don't think we actually need to transform the pattern matches in such a fine-grained way. We should be able to replace the entire deep pattern match by a single tag-check in one go. Indeed, the extracted ctor fields are only used for matching the shape itself, and not for something else; we should be able to not extract them at all. This might require a bit of a variable use analaysis, though. Or, better, we should simply find a way of annotating those "shape" pattern matches, which always discard the extracted fields, so the IR pass does not have to make a guess.

Actually, now that I think of it, why don't we just generate code that already includes all the necessary info (in the form of annotations) for easily compiling the shape match away? Eg, something like:

@matchShapes(C(D(_)), C(E(1)), F...) if x is // this is a top-level shape matching node
  C then
    @shapeMatchingOnly let y = x.f1
    if y is
      @shapeMatchingOnly D then ...
      @shapeMatchingOnly E then ...
  F then
    ...

@NeilKleistGao

Copy link
Copy Markdown
Member Author

Hmm that does seem quite complicated. I don't think we actually need to transform the pattern matches in such a fine-grained way. We should be able to replace the entire deep pattern match by a single tag-check in one go. Indeed, the extracted ctor fields are only used for matching the shape itself, and not for something else; we should be able to not extract them at all. This might require a bit of a variable use analaysis, though. Or, better, we should simply find a way of annotating those "shape" pattern matches, which always discard the extracted fields, so the IR pass does not have to make a guess.

Actually, now that I think of it, why don't we just generate code that already includes all the necessary info (in the form of annotations) for easily compiling the shape match away? Eg, something like:

@matchShapes(C(D(_)), C(E(1)), F...) if x is // this is a top-level shape matching node
  C then
    @shapeMatchingOnly let y = x.f1
    if y is
      @shapeMatchingOnly D then ...
      @shapeMatchingOnly E then ...
  F then
    ...

Actually, it seems that the @matchShapes annotation alone is enough. We do not flatten the UCS by ourselves, i.e., we only write (or generate)

@matchShapes(C(D(_)), C(E(1)), F(_))
if x is
  C(D(_)) then ...
  C(E(1)) then ...
  F(_) then ...

Those @shapeMatchingOnly annotations can be automatically done by checking sub matches.

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.

2 participants