-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix bounds of encoded type variables in quote patterns #17956
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
Fix bounds of encoded type variables in quote patterns #17956
Conversation
var newBindingsRefs: List[Type] = mapping.values.toList.map(_.typeRef) | ||
for newBindings <- mapping.values do | ||
newBindings.info = newBindings.info.subst(oldBindings, newBindingsRefs) | ||
ctx.gadtState.addToConstraint(newBindings) // This must be preformed after the info has been updated |
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.
ctx.gadtState.addToConstraint(newBindings) // This must be preformed after the info has been updated | |
ctx.gadtState.addToConstraint(newBindings) // This must be performed after the info has been updated |
var oldBindings: List[Symbol] = mapping.keys.toList | ||
var newBindingsRefs: List[Type] = mapping.values.toList.map(_.typeRef) |
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.
Look like those don't need to be vars?
var oldBindings: List[Symbol] = mapping.keys.toList | |
var newBindingsRefs: List[Type] = mapping.values.toList.map(_.typeRef) | |
val oldBindings: List[Symbol] = mapping.keys.toList | |
val newBindingsRefs: List[Type] = mapping.values.toList.map(_.typeRef) |
* This mapping retains the original type variable definition order. | ||
*/ | ||
private def unapplyBindingsMapping(quoted: Tree)(using Context): collection.Map[Symbol, Bind] = { | ||
val mapping = mutable.LinkedHashMap.empty[Symbol, Symbol] |
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.
It looks like we never actually query this map, we only call mapping.keys and mapping.values, could we replace it by directly defining oldBindings and newBindingsRefs as ListBuffers?
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.
There is a mapping.contains(sym)
. I will simplify it to a LinkedHashSet
and a ListBuffer
.
@@ -288,7 +282,7 @@ trait QuotesAndSplices { | |||
report.error(IllegalVariableInPatternAlternative(tdef.symbol.name), tdef.srcPos) | |||
if variance == -1 then | |||
tdef.symbol.addAnnotation(Annotation(New(ref(defn.QuotedRuntimePatterns_fromAboveAnnot.typeRef)).withSpan(tdef.span))) | |||
val bindingType = getBinding(tdef.symbol).symbol.typeRef | |||
val bindingType = bindSymMapping(tdef.symbol).symbol.typeRef |
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.
If all we use bindSymMapping for is to get the symbol of the value, why do we need to have Bind nodes as values at all instead of symbols or typerefs?
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 function returns them. But I would create them later. I will refactor this to make it simpler.
e7d4857
to
a096e75
Compare
When we encode quote patterns into `unapply` methods, we need to create a copy of each type variable. One copy is kept within the quote(in the next stage) and the other is used in the `unapply` method to define the usual pattern type variables. When creating the latter we copied the symbols but did not update the infos. This implies that if type variables would be bounded by each other, the bounds of the copies would be the original types instead of the copies. We need to update those references. To update the info we now create all the symbols in one pass and the update all their infos in a second pass. This also implies that we cannot use the `newPatternBoundSymbol` to create the symbol as this constructor will register the info into GADT bounds. Instead we use the plain `newSymbol`. Then in the second pass, when we have updated the infos, we register the symbol into GADT bounds. Note that the code in the added test does compiles correctly, but it had the inconsistent bounds. This test is added in case we need to manually inspect the bounds latter. This test does fail to compile in scala#17935 if this fix is not applied.
Now, the mapping is a `SeqMap[Symbol, Symbol]` to convey its ordering and the `Bind` is created when we are creating the tree of the quote pattern.
a096e75
to
1f4d46c
Compare
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.
Otherwise LGTM.
val oldBindingsBuffer = mutable.LinkedHashSet.empty[Symbol] | ||
val newBindingsBuffer = mutable.ListBuffer.empty[Symbol] |
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.
Now that we're returning a map from old bindings to new bindings without creating Bind nodes, I think the original idea of directly having a LinkedHashMap here makes more sense, sorry for the back and forth!
We add the definition of the `QuotePattern` AST. In this first step, keep the typing of quote patterns untouched and decode the resulting `unapply` into a `QuotePattern`. This AST is used to perform all transformations until the `staging` phase, here it is encoded into an `unapply` and a `Quote` AST. We also encode the AST into an `unapply` when we pickle the tree to keep the same pickled representation as before. Based on #17956
Now, the mapping is a `SeqMap[Symbol, Symbol]` to convey its ordering and the `Bind` is created when we are creating the tree of the quote pattern. Follow up of the refactoring in #17956
When we encode quote patterns into
unapply
methods, we need to create a copy of each type variable. One copy is kept within the quote(in the next stage) and the other is used in theunapply
method to define the usual pattern type variables. When creating the latter we copied the symbols but did not update the infos. This implies that if type variables would be bounded by each other, the bounds of the copies would be the original types instead of the copies. We need to update those references.To update the info we now create all the symbols in one pass and the update all their infos in a second pass. This also implies that we cannot use the
newPatternBoundSymbol
to create the symbol as this constructor will register the info into GADT bounds. Instead we use the plainnewSymbol
. Then in the second pass, when we have updated the infos, we register the symbol into GADT bounds.Note that the code in the added test does compiles correctly, but it had the inconsistent bounds. This test is added in case we need to manually inspect the bounds latter. This test does fail to compile in #17935 if this fix is not applied.