-
Notifications
You must be signed in to change notification settings - Fork 238
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
[compiler] add newtype for bound names in IR #14547
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. Join @patrick-schultz and the rest of your teammates on |
38496f3
to
e682651
Compare
e682651
to
8a784ec
Compare
cc @ehigham |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is heroic.
case class Name(str: String) extends AnyVal { | ||
override def toString: String = str | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think you can do this in one line :)
case class Name(str: String) extends AnyVal { | |
override def toString: String = str | |
} | |
case class Name(override val toString: String) extends AnyVal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like your idea of using object equality rather than string equality.
Keeping the string, however, might allow us to better keep track of where a name came from through lowering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely! From the description:
keep a string in the Name, but no longer require it to be unique. Instead it's just a suggestion for how to show the name in printouts, adding a uniqueifying suffix as needed. With NormalizeNames gone, this would let us preserve meaningful variable names further in the lowering pipeline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think you can do this in one line :)
I could... but I'd rather not commit to this choice of toString
permanently.
…4579) I believe #14547 introduced a bug that broke IR function deserialization in QoB by changing `value_parameter_names` from `Array[String]` to `Array[Name]`. This fixes the issue by pushing the introduction of the `Name` wrapper object to after deserialization. Another option is to incorporate the `{ str: String }` structure of `Name` into the python -> scala payload, but I'm not sure I see a use case for that and we can always do that later (there is no issue of backwards compatibility with this communication between python and scala). My main concern here is that clearly this isn't tested. I'd appreciate guidance on the current advised practice for testing this behavior.
This PR introduces a new type
Name
for representing bound variables in the IR, replacingString
. For now, it is just anAnyVal
wrapper aroundString
, but in the future I would like to take advantage of the new type. For example, I'd like to:Name
from string comparison to comparing object identity witheq
. That wayfreshName
becomes justnew Name()
, with stronger guarantees that the new name doesn't occur anywhere in the current IR, without needing to maintain global state as we do now.NormalizeNames
, instead enforcing the global uniqueness of names as a basic invariant of the IR (typecheck could also check this invariant)Name
, but no longer require it to be unique. Instead it's just a suggestion for how to show the name in printouts, adding a uniqueifying suffix as needed. WithNormalizeNames
gone, this would let us preserve meaningful variable names further in the lowering pipeline.Name
, for example to allow a more efficient implementation of environments, similar to themark
state onBaseIR
This is obviously a large change, but there are only a few conceptual pieces (appologies for not managing to separate these out):
Name
constructor is called, to make future refactorings easierfreshName()
, which just wrapsgenUID()
, returning aName
ir.package
, which take scala lambdas to represent blocks with bound variables, instead of manually creating new variable namesrow
,va
,sa
,g
,global
) with constants (TableIR.{rowName, globalName}
,MatrixIR.{rowName, colName, entryName, globalName}
)NormalizeNames
optionally allows the IR to contain free variables. But it didn't do anything to ensure the newly generated variable names are distinct from any contained free variables. Thus it was possible to rename a bound variable to mistakenly capture a contained free variable. I've fixed that.SimplifySuite
compared simplified IR with the pre-constructed expected IR, carefully controlling thegenUID
global state to make simplify generate exactly the names expected. I've replaced that by just comparing with the expected IR using a alpha-equivalence comparison.