- 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.
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 MethodTypes 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 |
nicolasstucki left a comment
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
gwill match any expression that may contain references tof.