Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
argss.foldLeft(self: Term)(Apply(_, _))
def appliedToNone: Apply =
self.appliedToArgs(Nil)
def ensureApplied: Term =
def isParameterless(tpe: TypeRepr): Boolean = !tpe.isInstanceOf[MethodType]
if (isParameterless(self.tpe.widen)) self else self.appliedToNone
def appliedToType(targ: TypeRepr): Term =
self.appliedToTypes(targ :: Nil)
def appliedToTypes(targs: List[TypeRepr]): Term =
Expand Down
3 changes: 3 additions & 0 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** The current tree applied to (): `tree()` */
def appliedToNone: Apply

/** The current tree applied to `()` unless the tree's widened type is parameterless or expects type parameters */
def ensureApplied: Term

/** The current tree applied to given type argument: `tree[targ]` */
def appliedToType(targ: TypeRepr): Term

Expand Down
1 change: 1 addition & 0 deletions project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ object MiMaFilters {
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ValDefModule.let"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SymbolModule.newClass"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SymbolModule.newModule"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TermMethods.ensureApplied"),

// Changes to lazy vals (added static constructors)
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.Tuple.<clinit>"),
Expand Down
7 changes: 0 additions & 7 deletions tests/neg-macros/i23008.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
| ^^^^^^^^^^^^^^^^^^
| Exception occurred while executing macro expansion.
| java.lang.IllegalArgumentException: requirement failed: value of StringConstant cannot be `null`
| at scala.Predef$.require(Predef.scala:394)
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2542)
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2541)
| at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:82)
| at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:80)
| at scala.quoted.Expr$.apply(Expr.scala:72)
| at Macros$.buildStringCode(Macro_1.scala:9)
|
|---------------------------------------------------------------------------------------------------------------------
|Inline stack trace
Expand Down
7 changes: 6 additions & 1 deletion tests/neg-macros/i23008/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ object Macros {
def buildStringCode(using Quotes): Expr[String] = {
import quotes.reflect.*
val str: String = null
Expr(str)
try
Expr(str)
catch
case error: java.lang.IllegalArgumentException =>
error.setStackTrace(Array[StackTraceElement]())
throw error
}
}
41 changes: 41 additions & 0 deletions tests/pos-macros/i23969/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import scala.quoted._

object TestMethods:
def a1 = ()
def a2() = ()
Comment on lines +5 to +6
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious about what will happen if we do this?

Suggested change
def a1 = ()
def a2() = ()
def a1[T] = ()
def a2[T]() = ()

At least, we should include them in the test.

def a3[T] = ()
def a4[T]() = ()

transparent inline def runMacro() = ${runMacroImpl}
def runMacroImpl(using Quotes): Expr[Any] =
import quotes.reflect._

// ensureApplied test
Select.unique('{TestMethods}.asTerm, "a1").ensureApplied match
case Select(_, _) =>
case _ => assert(false)
Select.unique('{TestMethods}.asTerm, "a2").ensureApplied match
case Apply(_, _) =>
case _ => assert(false)
Select.unique('{TestMethods}.asTerm, "a3").ensureApplied match
case Select(_, _) =>
case other => assert(false)
Select.unique('{TestMethods}.asTerm, "a4").ensureApplied match
Copy link
Member

Choose a reason for hiding this comment

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

Mmmh, this is a legitimate question, but if we have a transparent inline method, it is subject to type inference, why shouldn't we wrap then in an Apply and let type inference do it's thing?

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 will result in:

-- Error: tests/pos-macros/i23969/Main.scala:1:19 ------------------------------
1 |@main def Test() = runMacro()
  |                   ^^^^^^^^^^
  |                  method a4 in object TestMethods does not take parameters

error, thrown from tpd.Apply. Even if we were to change that, we would have to deal with the TreeChecker run right after the macro expansion. In general, I believe we have to return fully typed trees and I am not aware of any additional type inference done to inlined code after inlining it (so it will be done for quoted code before the macro is expanded, or for non-macro inline method contents, but not changed after inlining, even for non-macro transparent inline methods, more info here: #8739).

Also apologies for weird response times! And thank you for looking at this @hamzaremmal

case Select(_, _) =>
case other => assert(false)

TypeApply(Select.unique('{TestMethods}.asTerm, "a3"), List(TypeTree.of[Nothing])).ensureApplied match
case TypeApply(_, _) =>
case other => assert(false)
TypeApply(Select.unique('{TestMethods}.asTerm, "a4"), List(TypeTree.of[Nothing])).ensureApplied match
case Apply(_, _) =>
case other => assert(false)

// regression test
val Inlined(_, _, generated) = '{BigDecimal(0).toString()}.asTerm : @unchecked
val Inlined(_, _, bigDecimal) = '{BigDecimal(0)}.asTerm : @unchecked
val custom = Select.unique(bigDecimal, "toString").ensureApplied
// ensure both have the same shape
assert(custom.toString == generated.toString)
custom.asExpr
1 change: 1 addition & 0 deletions tests/pos-macros/i23969/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@main def Test() = runMacro()