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

allow partially const tuples #206

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

cmlsharp
Copy link
Contributor

@cmlsharp cmlsharp commented Aug 4, 2024

Currently, the following program fails to compile:

struct X {
    u32 a
    u32 b
}

def foo<A>() -> u32:
    return A

def main(u32 a) -> u32:
    X x = X {a: a, b: 12}
    u32 xb = x.b
    return foo::<xb>()

Even though x.b is conceptually a const value, the way constant folding works at present makes it so the entire tuple is const or it isn't and since x.a is not const, x is not const. This makes a very useful paradigm of creating values that are "tagged" with e.g. their bit width for the purpose of range checking infeasible. This PR aims to change that.

I do want to flag that the fundamental difficulty here (and why it wasn't implemented this way in the first place) is that the constant folding optimization relies on turning a Term into a Value and then calling eval_op to do the evaluation. For "partially-const" tuples, there is no such corresponding Value, so the constant folding code ends up duplicating some logic that is in eval_op (adapting it to work on Terms instead). For tuples this logic is pretty minimal, but for arrays it was less so which is why I did not implement an analogous fix for arrays, even though it would be nice to have that as well.

I'm not sure what the "cleanest" way to unify these are (maybe one could introduce a temporary Value::Phantom used only in the constant folding optimization to represent the non-const children of a Value::Tuple? or maybe this is overengineering and I should just duplicate the array evaluation code on Terms).

@alex-ozdemir
Copy link
Contributor

Great PR. Strengthening the constant-folder for tuples is a strict win.
IMO, duplicating some logic between the folder and the evaluator is totally fine. They have slightly different goals, and having just two "copies" of the logic is worth it to make sure they each perform their task well.

Once the stronger constant-folder has a test to prevent regressions, this PR is good to go.

@cmlsharp
Copy link
Contributor Author

I actually found a small edge case that this change doesn't cover. Specifically, the following:

struct Foo {
    u32 a
    u32 b
}

def foo<N>() -> bool:
    return true

def main(u32 b) -> bool:
    Foo f = Foo { a: 10, b: b }
    f.b = 5
    f.b = b
    u32 fa = f.a
    assert(foo::<fa>())
    return true

The above causes an error because fa is not seen as const.

The culprit is that f.b = 5 causes f to become totally const, and the Term is replaced by a Value, but then the f.b = b line just doesn't get resolved because the operand of Op::Update is Op::Const rather than Op::Tuple. So either I need to add code that can convert Values back into Terms or I should do the Term->Value conversions on a second pass.

Copy link
Contributor

@alex-ozdemir alex-ozdemir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!
I left a suggestion inline.

let term = get(0).cs()[*n].clone();
Some(term.as_value_opt().cloned().map(const_).unwrap_or(term))
}
_ => None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another simple solution: just match on Op::Const(Value::Tuple(..)) too.

Some(new_tuple(children))

}
_ => None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

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