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

Replace quoted type variables in signature of HOAS pattern result #16951

Merged
merged 2 commits into from
Mar 3, 2023

Conversation

nicolasstucki
Copy link
Contributor

@nicolasstucki nicolasstucki commented Feb 17, 2023

To be able to construct the lambda returned by the HOAS pattern we need:
first resolve the type variables and then use the result to construct the
signature of the lambdas.

To simplify this transformation, QuoteMatcher returns a Seq[MatchResult]
instead of an untyped Tuple containing Expr[?]. The tuple is created
once we have accumulated and processed all extracted values.

Fixes #15165

@nicolasstucki nicolasstucki marked this pull request as ready for review February 18, 2023 13:28
@nicolasstucki nicolasstucki marked this pull request as draft February 18, 2023 13:29
@nicolasstucki nicolasstucki marked this pull request as ready for review February 20, 2023 14:13
Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM.

}
Closure(meth, bodyFn)
}
val env = summon[Env]
Copy link
Member

Choose a reason for hiding this comment

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

Looks like the summon[Env] two lines below could become env with this addition.

/** Result of matching a part of an expression */
private type Matching = Option[Tuple]
Copy link
Member

Choose a reason for hiding this comment

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

The documentation comment for =?= still mention that we return a Some(tup: Tuple). That should be updated, but I also think that the meaning of None vs Some(Seq()) vs Some(...) should be explained in a documentation comment for type Matching itself.


QuoteMatcher.treeMatch(scrutinee, pat1)(using ctx1).map { matchings =>
import QuoteMatcher.MatchResult.*
lazy val spliceScope = SpliceScope.getCurrent
Copy link
Member

Choose a reason for hiding this comment

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

spliceScope appears to be unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I intended to use pass it to toExpr. I will change that.

val matchedExprs = matchings.map(_.toExpr(typeHoleMap))
val matchedTypes = typeHoleApproximations.map(reflect.TypeReprMethods.asType)
val results = matchedTypes ++ matchedExprs
Tuple.fromIArray(results.toArray.asInstanceOf[IArray[Object]])
Copy link
Member

Choose a reason for hiding this comment

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

Could this be:

Suggested change
Tuple.fromIArray(results.toArray.asInstanceOf[IArray[Object]])
Tuple.fromIArray(IArray.unsafeFromArray(results.toArray))

@@ -452,20 +433,52 @@ object QuoteMatcher {
accumulator.apply(Set.empty, term)
}

enum MatchResult:
case ClosedTree(tree: Tree)
case OpenTree(tree: Tree, patternTpe: Type, args: List[Tree], env: Env)
Copy link
Member

Choose a reason for hiding this comment

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

Woudl be nice to document the expectation on the valid values of the arguments here.

case MatchResult.ClosedTree(tree) =>
new ExprImpl(tree, SpliceScope.getCurrent)
case MatchResult.OpenTree(tree, patternTpe, args, env) =>
def hoasClosure = {
Copy link
Member

Choose a reason for hiding this comment

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

Why a def if we then immediately call it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Accident of refactoring.

case ClosedTree(tree: Tree)
case OpenTree(tree: Tree, patternTpe: Type, args: List[Tree], env: Env)

def toExpr(mapTypeHoles: TypeMap)(using Context): Expr[Any] = this match
Copy link
Member

Choose a reason for hiding this comment

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

Documenting what this method generates would also be nice.

val methTpe = MethodType(names)(_ => paramTypes, _ => mapTypeHoles(patternTpe))
val meth = newAnonFun(ctx.owner, methTpe)
def bodyFn(lambdaArgss: List[List[Tree]]): Tree = {
val argsMap = args.map(_.symbol).zip(lambdaArgss.head).toMap
Copy link
Member

Choose a reason for hiding this comment

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

Could use a view to avoid intermediate allocations:

Suggested change
val argsMap = args.map(_.symbol).zip(lambdaArgss.head).toMap
val argsMap = args.view.map(_.symbol).zip(lambdaArgss.head).toMap

Copy link
Contributor Author

@nicolasstucki nicolasstucki left a comment

Choose a reason for hiding this comment

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

I took care of the comments but also rebased on #16953 to take care of the conflicts before they happen.


QuoteMatcher.treeMatch(scrutinee, pat1)(using ctx1).map { matchings =>
import QuoteMatcher.MatchResult.*
lazy val spliceScope = SpliceScope.getCurrent
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I intended to use pass it to toExpr. I will change that.

case MatchResult.ClosedTree(tree) =>
new ExprImpl(tree, SpliceScope.getCurrent)
case MatchResult.OpenTree(tree, patternTpe, args, env) =>
def hoasClosure = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Accident of refactoring.

@nicolasstucki nicolasstucki requested a review from smarter March 2, 2023 19:09

/** Return the expression that was extracted from a hole.
*
* If the it was a closed expression it return that expression. Otherwise,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* If the it was a closed expression it return that expression. Otherwise,
* If it was a closed expression it returns that expression. Otherwise,

*/
def toExpr(mapTypeHoles: TypeMap, spliceScope: Scope)(using Context): Expr[Any] = this match
case MatchResult.ClosedTree(tree) =>
new ExprImpl(tree, SpliceScope.getCurrent)
Copy link
Member

Choose a reason for hiding this comment

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

Why isn't spliceScope used here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I missed it. Now it uses spliceScope.

@smarter smarter assigned nicolasstucki and unassigned smarter Mar 2, 2023
To be able to construct the lambda returned by the HOAS pattern we need:
first resolve the type variables and then use the result to construct the
signature of the lambdas.

To simplify this transformation, `QuoteMatcher` returns a `Seq[MatchResult]`
instead of an untyped `Tuple` containing `Expr[?]`. The tuple is created
once we have accumulated and processed all extracted values.

Fixes scala#15165
@nicolasstucki nicolasstucki enabled auto-merge March 3, 2023 06:59
@nicolasstucki nicolasstucki merged commit 6ea3ea6 into scala:main Mar 3, 2023
@nicolasstucki nicolasstucki deleted the fix-15165 branch March 3, 2023 08:12
@Kordyjan Kordyjan added this to the 3.3.1 milestone Aug 1, 2023
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.

Open code patterns have issues when substituting arguments with a generic/bound type.
3 participants