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

Delayed Functional Invocation via Macro #8

Closed
darkfrog26 opened this issue May 15, 2018 · 10 comments
Closed

Delayed Functional Invocation via Macro #8

darkfrog26 opened this issue May 15, 2018 · 10 comments
Labels
bug Something isn't working

Comments

@darkfrog26
Copy link

Okay, this is a fairly corner-case scenario, but a big problem for me. I'm attempting to use this within my Scribe logging library. It takes in an anonymous function (message: => String) that gets passed into a Macro to set up lazy invocation when/if that message is actually logged (for performance). This works fine unless I try to use fs"" interpolation. In the following example:

val d = 12.3456
logger.info(fs"Value: $d"))

I get the following compile-time exception:

[error] /home/mhicks/projects/open/scribe/tests/shared/src/test/scala/specs/LoggingSpec.scala:71:19: exception during macro expansion: 
[error] scala.reflect.macros.TypecheckException: method stringBuilder in package fsi cannot be accessed in object com.sizmek.fsi.package
[error]         at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$3(Typers.scala:32)
[error]         at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$2(Typers.scala:26)
[error]         at scala.reflect.macros.contexts.Typers.doTypecheck$1(Typers.scala:25)
[error]         at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$7(Typers.scala:38)
[error]         at scala.reflect.internal.Trees.wrappingIntoTerm(Trees.scala:1731)
[error]         at scala.reflect.internal.Trees.wrappingIntoTerm$(Trees.scala:1728)
[error]         at scala.reflect.internal.SymbolTable.wrappingIntoTerm(SymbolTable.scala:18)
[error]         at scala.reflect.macros.contexts.Typers.typecheck(Typers.scala:38)
[error]         at scala.reflect.macros.contexts.Typers.typecheck$(Typers.scala:20)
[error]         at scala.reflect.macros.contexts.Context.typecheck(Context.scala:6)
[error]         at scala.reflect.macros.contexts.Context.typecheck(Context.scala:6)
[error]         at com.sizmek.fsi.package$Impl$.fx(package.scala:113)
[error]         at com.sizmek.fsi.package$Impl$.fs(package.scala:70)
[error]       logger.info(fs"It works! $d")

Any thoughts?

@plokhotnyuk plokhotnyuk added the bug Something isn't working label May 16, 2018
AnderEnder added a commit that referenced this issue May 16, 2018
Fix #8 by making of fsi.stringBuilder() call to be accessible from any package
@plokhotnyuk
Copy link
Owner

Hi Matt,

Thanks for reporting the bug!

Please try with latest release, it is promoted to jCenter already: https://github.com/Sizmek/fast-string-interpolator/releases/tag/v0.2.0

@darkfrog26
Copy link
Author

That did fix the TypecheckException, but now I'm experiencing the same problem I experience with f"" and s"" interpolation:

java.util.NoSuchElementException: value d
        at scala.collection.mutable.AnyRefMap$ExceptionDefault.apply(AnyRefMap.scala:425)
        at scala.collection.mutable.AnyRefMap$ExceptionDefault.apply(AnyRefMap.scala:424)
        at scala.collection.mutable.AnyRefMap.apply(AnyRefMap.scala:180)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder$locals$.load(BCodeSkelBuilder.scala:390)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:354)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.$anonfun$genLoadArguments$1(BCodeBodyBuilder.scala:935)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoadArguments(BCodeBodyBuilder.scala:935)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genApply(BCodeBodyBuilder.scala:665)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:296)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:270)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genStat(BCodeBodyBuilder.scala:80)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.$anonfun$genBlock$1(BCodeBodyBuilder.scala:812)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genBlock(BCodeBodyBuilder.scala:812)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:366)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:270)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genStat(BCodeBodyBuilder.scala:80)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.$anonfun$genBlock$1(BCodeBodyBuilder.scala:812)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genBlock(BCodeBodyBuilder.scala:812)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:366)
        at scala.tools.nsc.backend.jvm.BCodeBodyBuilder$PlainBodyBuilder.genLoad(BCodeBodyBuilder.scala:370)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.emitNormalMethodBody$1(BCodeSkelBuilder.scala:602)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.genDefDef(BCodeSkelBuilder.scala:634)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.gen(BCodeSkelBuilder.scala:508)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.$anonfun$gen$7(BCodeSkelBuilder.scala:510)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.gen(BCodeSkelBuilder.scala:510)
        at scala.tools.nsc.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.genPlainClass(BCodeSkelBuilder.scala:110)
        at scala.tools.nsc.backend.jvm.CodeGen.genClass(CodeGen.scala:69)
        at scala.tools.nsc.backend.jvm.CodeGen.genClassDef$1(CodeGen.scala:31)
        at scala.tools.nsc.backend.jvm.CodeGen.$anonfun$genUnit$3(CodeGen.scala:54)
        at scala.tools.nsc.backend.jvm.CodeGen.genClassDefs$1(CodeGen.scala:54)
        at scala.tools.nsc.backend.jvm.CodeGen.$anonfun$genUnit$2(CodeGen.scala:53)
        at scala.tools.nsc.backend.jvm.CodeGen.genClassDefs$1(CodeGen.scala:53)
        at scala.tools.nsc.backend.jvm.CodeGen.$anonfun$genUnit$4(CodeGen.scala:58)
        at scala.tools.nsc.backend.jvm.CodeGen.genUnit(CodeGen.scala:58)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase.apply(GenBCode.scala:67)
        at scala.tools.nsc.Global$GlobalPhase.$anonfun$applyPhase$1(Global.scala:426)
        at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:419)
        at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1(Global.scala:390)
        at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1$adapted(Global.scala:390)
        at scala.collection.Iterator.foreach(Iterator.scala:944)
        at scala.collection.Iterator.foreach$(Iterator.scala:944)
        at scala.collection.AbstractIterator.foreach(Iterator.scala:1432)
        at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:390)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase.super$run(GenBCode.scala:73)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase.$anonfun$run$1(GenBCode.scala:73)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase.run(GenBCode.scala:71)
        at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1446)
        at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1430)
        at scala.tools.nsc.Global$Run.compileSources(Global.scala:1423)
        at scala.tools.nsc.Global$Run.compile(Global.scala:1539)
        at xsbt.CachedCompiler0.run(CompilerInterface.scala:130)
        at xsbt.CachedCompiler0.run(CompilerInterface.scala:105)
        at xsbt.CompilerInterface.run(CompilerInterface.scala:31)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:237)
        at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:111)
        at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:90)
        at sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3(MixedAnalyzingCompiler.scala:83)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:134)
        at sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:74)
        at sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:117)
        at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:305)
        at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:305)
        at sbt.internal.inc.Incremental$.doCompile(Incremental.scala:101)
        at sbt.internal.inc.Incremental$.$anonfun$compile$4(Incremental.scala:82)
        at sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:110)
        at sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:57)
        at sbt.internal.inc.Incremental$.$anonfun$compile$3(Incremental.scala:84)
        at sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:129)
        at sbt.internal.inc.Incremental$.compile(Incremental.scala:75)
        at sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:61)
        at sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:309)
        at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:267)
        at sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:158)
        at sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:237)
        at sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:68)
        at sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:1429)
        at sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:1403)
        at scala.Function1.$anonfun$compose$1(Function1.scala:44)
        at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:39)
        at sbt.std.Transform$$anon$4.work(System.scala:66)
        at sbt.Execute.$anonfun$submit$2(Execute.scala:262)
        at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
        at sbt.Execute.work(Execute.scala:271)
        at sbt.Execute.$anonfun$submit$1(Execute.scala:262)
        at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:174)
        at sbt.CompletionService$$anon$2.call(CompletionService.scala:36)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

@plokhotnyuk
Copy link
Owner

plokhotnyuk commented May 16, 2018

@darkfrog26 I have tried to reproduce an error in the branch below but it works fine for me and prints log record like this:

 2018.05.16 15:55:00 [ScalaTest-run-running-Issue8Spec] INFO specs.Issue8Spec:11 - Value: 12.3456

Please check out and add missing to reproduce the error:
https://github.com/Sizmek/fast-string-interpolator/tree/issue-8-2

@darkfrog26
Copy link
Author

This is a quick hack, but here's a gist that will reproduce the problem: https://gist.github.com/darkfrog26/fb97f0bf329cdc6141e1599087e58854

Reminder: you need to have Test in a different project than BugTest (I just put it in test)

@darkfrog26
Copy link
Author

The reason you can't reproduce it on Scribe 2.3.4 is because the problem only exists on the functional branch. If I can resolve this issue, I'll be merging it into master and releasing 2.4.0.

@plokhotnyuk
Copy link
Owner

I reproduced it.

Will it be acceptable for you to a workaround through an additional sample method as in the following commit?

01a1502#diff-8729a78c7c14c74a798e2fb50861caf0R9

@darkfrog26
Copy link
Author

No, I considered that, but the whole reason it's directly hitting a Macro is to get compile-time access to the class, method, and line number that invoked it. If I go through an additional method that will be lost.

@plokhotnyuk
Copy link
Owner

It looks more like a bug in scalac... Here I reproduced it with the standard formatting interpolator: aa83fd5

@plokhotnyuk
Copy link
Owner

plokhotnyuk commented May 16, 2018

@darkfrog26 could you, please, create an issue in https://github.com/scala/bug ?

@darkfrog26
Copy link
Author

FINALLY FIGURED IT OUT!

This is not a bug in fast-string-interpolator, but technically one in Scribe:

  def example(c: blackbox.Context)(message: c.Tree): c.Tree = {
    import c.universe._

    val f = c.typecheck(q"() => $message")
    c.internal.changeOwner(message, c.internal.enclosingOwner, f.symbol)
    q"example.LogRecord($f)"
  }

That compiles and works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants