-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Make HOAS Quote pattern match with def method capture #17567
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
Conversation
val capturedArgs = args.map(_.symbol) | ||
val captureEnv = env.filter((k, v) => !capturedArgs.contains(v)) | ||
val capturedIds = args.map(getCapturedIdent) | ||
val capturedSymbols = capturedIds.map(_.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.
getCapturedIdent
could return the Symbol
directly. This way, we can avoid this extra map
.
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.
Here I intended to use capturedIds
as a parameter to matchedOpen
and we cannot omit it (we get compiler errors if we use args
for matchedOpen
instead).
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.
According to your other comment on i17105.check, it's likely I need to change this part anyway.
tests/run-macros/i17105.check
Outdated
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.
These outputs show that we need to adapt the type of g
in the lambdas. For example g: (y: scala.Int)scala.Int
should be g: scala.Int => scala.Int
. We probably need to addapt the type here
https://github.com/lampepfl/dotty/blob/main/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala#LL468C13-L468C13. We need to convert MethodType
s into funtion types. The defn.FunctionOf
method might be useful here (defined in Definitions.scala
).
I would expect this output to look like
((g: scala.Int => scala.Int, n: scala.Int) => g(n))
((g: (scala.Int, scala.Int) => scala.Int) => g(1, 2))
((g2: (scala.math.Ordered[scala.Int]) => scala.Boolean, ord: scala.math.Ordered[scala.Int]) => (g2(ord).||(2.<(3)): scala.Boolean))
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.
Thank you, I'll try to fix this issue (and add appropriate test cases)
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.
Int => Int
could also be scala.Function1[scala.Int, scala.Int]
. From Function0
up to Function22
we have concrete FnunctionN
classes that implement the lambda type. T => R
is equivalent to Function1[T, R]
in the Scala type system. This only applies to normal function parameters, not if the argument is implicit as in def f(using T): R = ...
or T ?=> R
(similar for functions that contain erased parameters).
Hi @nicolasstucki, I'm trying to fix the issue that types of parameters in higher-order term holes being method types with the commit 209d763. However, the current hotfix fails even with the simplest test case (I used this test case). I got the following error
I found this message is caused at a method in QuoteMatcher.scala:l524, which generates a method body from a quote that matched against higher-order term pattern. def bodyFn(lambdaArgss: List[List[Tree]]): Tree = {
val argsMap = args.view.map(_.symbol).zip(lambdaArgss.head).toMap
val body = new TreeMap {
override def transform(tree: Tree)(using Context): Tree =
tree match
case tree: Ident => env.get(tree.symbol).flatMap(argsMap.get).getOrElse(tree)
case tree => super.transform(tree)
}.transform(tree)
TreeOps(body).changeNonLocalOwners(meth)
} In the test case, the matched body is To avoid this issue, we want to refine tree match
case Apply(fnId: Ident, args) => {
val fnId2 = env.get(tree.symbol).flatMap(argsMap.get).getOrElse(tree)
??? // want to return '{$fnId2.apply($args)} Not sure what is desirable way to construct Tree here...
}
case tree => super.transform(tree) That's something I'd like your feedback. Does it sound valid to you? If so, what can I fill for ??? part? |
// TODO issue-17105: Is this pattern appropriate for methods? | ||
case tp: MethodOrPoly => cpy.Apply(tree)(tfun, targs) | ||
// TODO issue-17105: Appropriate pattern for function (appliable?) types? | ||
case _ => ctx.typer.typed( |
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.
Is this the right way to construct a typed tree?
val targs = transform(args) | ||
tfun.tpe match | ||
// TODO issue-17105: Is this pattern appropriate for methods? | ||
case tp: MethodOrPoly => cpy.Apply(tree)(tfun, targs) |
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.
Is this the right pattern to match against methods?
case Apply(methId: Ident, args) => | ||
env.get(tree.symbol).flatMap(argsMap.get) | ||
.map(fnId => ctx.typer.typed( | ||
untpd.Apply( |
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.
Is this the right pattern to construct typed tree?
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.
Typing an untyped tree is dangerous. Depending on the context where this is typed, we could end up with different result. It is also a bit inefficient.
The correct way to do this is to create the typed tree directly. In this case you can use the select
and appliedToArgs
helper methods to construct this tree. The code should be fnId.select(nme.apply).appliedToArgs(args))
.
case Apply(methId: Ident, args) => | ||
env.get(tree.symbol).flatMap(argsMap.get) | ||
.map(fnId => ctx.typer.typed( | ||
untpd.Apply( |
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.
Typing an untyped tree is dangerous. Depending on the context where this is typed, we could end up with different result. It is also a bit inefficient.
The correct way to do this is to create the typed tree directly. In this case you can use the select
and appliedToArgs
helper methods to construct this tree. The code should be fnId.select(nme.apply).appliedToArgs(args))
.
case Apply(fun, args) => | ||
val tfun = transform(fun) | ||
val targs = transform(args) | ||
(fun.tpe, tfun.tpe) match |
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.
Do we want to use fun.tpe.widenTermRefExpr
in this case?
val (pEnv, pmatch) = matchParamss(paramss1, paramss2) | ||
val defEnv = pEnv + (scrutinee.symbol -> pattern.symbol) | ||
|
||
ematch |
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.
ematch
is always Seq.empty
and pmatch
should also return Seq.empty
on match.
Should I remove the part ematch &&& pmatch &&&
to simplify logic?
The latest test report says that the test case quote-nested-6.scala fails, but it passes in my environment https://github.com/lampepfl/dotty/actions/runs/5298658706/jobs/9591140406?pr=17567
The issue is that I cannot reproduce this failure in my environment. It might be due to different JDK (I'm using OpenJDK 11). I'll try switching OpenJDK 16. [update] Hmm, tests keep passing with OpenJDK 16. |
The failure of |
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
case OpenTree(tree: Tree, patternTpe: Type, argIds: List[Tree], argTypes: List[Type], env: Env) | ||
|
||
/** The Definitions object */ | ||
def defn(using Context): Definitions = ctx.definitions |
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.
defn
should have been imported by import dotty.tools.dotc.core.Symbols.*
. This definition should be removed.
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.
Thank you, I've followed your advice.
This PR will fix #17105 by extracting symbols from eta-expanded identifiers.
This fix enables the use of patterns such as
where
g
will match any expression that may contain references tof
.