Skip to content

Add regression test #18300

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

Merged
merged 1 commit into from
Jul 28, 2023
Merged

Conversation

nicolasstucki
Copy link
Contributor

This add a prototype implementation for providing precise types without the overhead of quote pattern matching.

@nicolasstucki nicolasstucki requested a review from smarter July 27, 2023 09:08
@nicolasstucki
Copy link
Contributor Author

It seems that type parameter inference #18169 could help reduce some of the syntactic overhead in some of the examples.

This add a prototype implementation for providing precise types without
the overhead of quote pattern matching.
type X <: T
val exprX = expr.asInstanceOf[Expr[X]]
val tpeX = expr.asTerm.tpe.asType.asInstanceOf[Type[X]]
body[X](using tpeX)(exprX)
Copy link
Member

Choose a reason for hiding this comment

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

Why not pass T to body and avoid the casts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is to be able to refine the type of T to the precise type of the expression. For example if T is of type Any but the expression is of type Int, we can use that type in the generated code in a type safe way. Note that the cast would only be required in the stdlib method that provides this functionality.

Copy link
Member

Choose a reason for hiding this comment

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

but body is not inlined so I don't understand how this would change anything to the code we generate

Copy link
Contributor Author

@nicolasstucki nicolasstucki Jul 28, 2023

Choose a reason for hiding this comment

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

It is about the code generated inbody. For example

def foo[T: Type](expr: Expr[T])(using Quotes) =  '{ val y: T = $x }
def bar[T: Type](expr: Expr[T])(using Quotes) = 
  exprWithPreciseType(a) { [X] => _ ?=> x => 
    '{ val y: X = $x }
  }
val a: Expr[Int] = '{ 1 }
foo(a) // generates '{ val y: Int = 1 }
foo[Any](a) // generates '{ val y: Any = 1 } // boxing
foo(b) // generates '{ val y: Any = 1 } // boxing

val b: Expr[Any] = '{ 2 }
bar(a) // generates '{ val y: Int = 2 }
bar[Any](a) // generates '{ val y: Int = 2 }
bar(b) // generates '{ val y: Int = 2 }

Other uses involve getting the precise type to inspect it.

In general it is equivalent but will always be more efficient than

def baz[T: Type](expr: Expr[T])(using Quotes) = 
  expr match
    case '{ $x: t } =>  '{ val y: t = $x }

Though the main use case will probably be when we get a term or type from reflection and want to recover/name its precise type.

....
exprWithPreciseType(term.asExpr/*: Expr[Any]*/) { [T] => _ ?=> x =>
   '{ val y: T= $x; ... }
}

withType(tpe.asType/*: Type[? <: AnyKind]*/) { [T] => _ ?=> 
  someFunction[T]//(using Type.of[T])
}

Copy link
Member

@smarter smarter Aug 1, 2023

Choose a reason for hiding this comment

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

I'm still confused, if I make the following change:

diff --git tests/pos-macros/quoted-with-precise-types.scala tests/pos-macros/quoted-with-precise-types.scala
index e9620810377..ddfc5dfefa7 100644
--- tests/pos-macros/quoted-with-precise-types.scala
+++ tests/pos-macros/quoted-with-precise-types.scala
@@ -20,10 +20,8 @@ def test1(t1: Type[?], t2: Type[? <: Any])(using Quotes) =

 def exprWithPreciseType[T, U](expr: Expr[T])(body: [X <: T] => Type[X] ?=> Expr[X] => U)(using Quotes): U =
   import quotes.reflect.*
-  type X <: T
-  val exprX = expr.asInstanceOf[Expr[X]]
-  val tpeX = expr.asTerm.tpe.asType.asInstanceOf[Type[X]]
-  body[X](using tpeX)(exprX)
+  val tpe = expr.asTerm.tpe.asType.asInstanceOf[Type[T]]
+  body[T](using tpe)(expr)

 def test2(x: Expr[Any])(using Quotes) =
   // exprWithPreciseType(x) { [T] => x => // Inference limitation: x is assumed to be the Type[T] instead of the Expr[T]

Then the test still compiles, will it generate different code?

@smarter smarter assigned nicolasstucki and unassigned smarter Jul 27, 2023
@nicolasstucki nicolasstucki merged commit 675df77 into scala:main Jul 28, 2023
@nicolasstucki nicolasstucki deleted the add-regression-test branch July 28, 2023 08:46
@Kordyjan Kordyjan added this to the 3.4.0 milestone Dec 20, 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.

3 participants