-
Notifications
You must be signed in to change notification settings - Fork 1.1k
tasty-reflect: Inspecting type tree fails when a macro is called inside a block or a non-type ascripted method #8764
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
Comments
Can you try to minimize this into a self contained example? We will treat these with priority. |
@odersky I'll try, but I probably wouldn't have enough time until next week. As it is, the macro codebase of that project is fairly small, but yes, it's not an isolated snippet and may be not ideal for debugging. |
@neko-kai what tree do you get in Inspector.scala#L118? I notice that you don't match |
@nicolasstucki
Note, if I add code to recurse on the
|
Also, in the macro expansion for
|
error: ``` [error] -- Error: PureModule.scala:77:86 [error] 77 | val static = ZIO.accessM[PureModule](_.get.static) [error] | ^ [error] |could not find implicit value for izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. Did you forget to put on a Tag, TagK or TagKK context bound on one of the parameters in zio.test.mock.module.PureModule.Service? e.g. def x[T: Tag, F[_]: TagK] = .... [error] |I found: [error] | [error] | { [error] | izumi.reflect.Tag.apply[zio.test.mock.module.PureModule.Service](classOf[Any] [error] | , [error] | { [error] | <empty> :izumi.reflect.macrortti.LightTypeTag [error] | } [error] | ):izumi.reflect.Tag[zio.test.mock.module.PureModule.Service] [error] | } [error] | [error] |But method tagFromTagMacro in object Tag does not match type izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. [error] | [error] |The following import might make progress towards fixing the problem: [error] | [error] | import izumi.reflect.Tag.tagFromTagMacro ```
error: ``` [error] -- Error: PureModule.scala:77:86 [error] 77 | val static = ZIO.accessM[PureModule](_.get.static) [error] | ^ [error] |could not find implicit value for izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. Did you forget to put on a Tag, TagK or TagKK context bound on one of the parameters in zio.test.mock.module.PureModule.Service? e.g. def x[T: Tag, F[_]: TagK] = .... [error] |I found: [error] | [error] | { [error] | izumi.reflect.Tag.apply[zio.test.mock.module.PureModule.Service](classOf[Any] [error] | , [error] | { [error] | <empty> :izumi.reflect.macrortti.LightTypeTag [error] | } [error] | ):izumi.reflect.Tag[zio.test.mock.module.PureModule.Service] [error] | } [error] | [error] |But method tagFromTagMacro in object Tag does not match type izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. [error] | [error] |The following import might make progress towards fixing the problem: [error] | [error] | import izumi.reflect.Tag.tagFromTagMacro ```
* Update to izumi-reflect-1.0.0-M1, depend on izumi-reflect in dotty * Use one VersionSpecific file for dotty & scala-2 * Adding type signatures to Mock modules to workaround scala/scala3#8764 error: ``` [error] -- Error: PureModule.scala:77:86 [error] 77 | val static = ZIO.accessM[PureModule](_.get.static) [error] | ^ [error] |could not find implicit value for izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. Did you forget to put on a Tag, TagK or TagKK context bound on one of the parameters in zio.test.mock.module.PureModule.Service? e.g. def x[T: Tag, F[_]: TagK] = .... [error] |I found: [error] | [error] | { [error] | izumi.reflect.Tag.apply[zio.test.mock.module.PureModule.Service](classOf[Any] [error] | , [error] | { [error] | <empty> :izumi.reflect.macrortti.LightTypeTag [error] | } [error] | ):izumi.reflect.Tag[zio.test.mock.module.PureModule.Service] [error] | } [error] | [error] |But method tagFromTagMacro in object Tag does not match type izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. [error] | [error] |The following import might make progress towards fixing the problem: [error] | [error] | import izumi.reflect.Tag.tagFromTagMacro ``` * add type signature to SpecSpec to workaround error: ``` [error] -- Error: SpecSpec.scala:17:51 [error] 17 | val layer = ZLayer.succeed(new Module.Service {}) [error] | ^ [error] |could not find implicit value for izumi.reflect.Tag[zio.test.SpecSpec.Module.Service]. Did you forget to put on a Tag, TagK or TagKK context bound on one of the parameters in zio.test.SpecSpec.Module.Service? e.g. def x[T: Tag, F[_]: TagK] = .... [error] |I found: [error] | [error] | { [error] | izumi.reflect.Tag.apply[zio.test.SpecSpec.Module.Service](classOf[Any], [error] | { [error] | <empty> :izumi.reflect.macrortti.LightTypeTag [error] | } [error] | ):izumi.reflect.Tag[zio.test.SpecSpec.Module.Service] [error] | } [error] | [error] |But method tagFromTagMacro in object Tag does not match type izumi.reflect.Tag[zio.test.SpecSpec.Module.Service]. [error] | [error] |The following import might make progress towards fixing the problem: [error] | [error] | import izumi.reflect.Tag.tagFromTagMacro ``` * Lift `exceptDotty` from HasSpec & ComposedMockSpec (TaggedSpec still won't pass because deriving is not implemented) * add type signatures to MockSpecUtils, update comments * Workaround type inference-caused test failures in PolyMockSpec - Any was inferred for `Tag` now, probably maybe because Tag parameter is AnyKind, add workaround * Fix `@mockable` macro, restrict valid `Tagged` definitions to just izumi.reflect.Tag * sbt fix
Add test for Schedule#onDecision and documentation for scheduling (zio#3346) * Add test for Schedule#onDecision and documentation for scheduling * Add documentation to datatypes, remove console functions from ScheduleSpec * fix mdoc compile issue specialize ChunkBuilder (zio#3400) Implement ZRefM (zio#3391) * implement ZRefM * fix Scala 2.13 compatibility issue * address review comments * implement SubscriptionRef * make constructor private * remove managed variant * remove unused import Implement ZIO#mapEffect (zio#3404) * implement mapEffect * implement mapPartial Improve TArray's performance (zio#3407) * Benchmark TArray * Implement fold and transform via unsafe * Improve readability * Implement find via unsafe * Implement findLast via unsafe * Implement foldM via unsafe * Benchmark indexWhere * Implement transformM via unsafe * Implement indexWhere via unsafe * Implement lastIndexOf via unsafe * Remove duplicated code * Implement foldM via ZIO.foldLeft * Remove 0-sized array from benchmark * Implement reduceOption via unsafe * Implement findM via foldM * Help inference via Option.empty * Implement findM via iterate * Implement findLastM via iterate * Remove useless val * Format the sources Update sbt-header to 5.6.0 (zio#3411) Add AssertionM for effectfull assertions (zio#3403) Add result field to AssertionValue to avoid test reevaluation. Protect AssertionValue.assertion to avoid test reevaluation. Use lazy val tryValue = Try(value) to avoid exception reevaluation: lazy val stores only successful case. implement launch (zio#3415) Add alternative combinator to ZSTM (zio#3414) * Drop duplicated test * Remove unnecessary .unit calls * Align the naming * Write failing tests * Keep semantically correct orElse tests * Fix test expectations * Fix orElse behavior on failures * Fix orElse behavior on retries * Reduce flakiness * Revert orElse changes * Introduce alternative combinator * Update docs * Reduce flakiness * Make right retry explicit * Race updater and transaction * Move left-right recovery test to JVM tests * Drop E from orElseSucceed Co-Authored-By: John A. De Goes <[email protected]> * Rename alternative to orTry Co-Authored-By: John A. De Goes <[email protected]> * Revert "Move left-right recovery test to JVM tests" This reverts commit 19f1162. * Tag retry test as JVM-only * Fix compilation issues * Fix docs * Improve scaladoc Co-Authored-By: John A. De Goes <[email protected]> * Fix doc mistake Co-authored-by: John A. De Goes <[email protected]> Update sbt-scalafix to 0.9.15 (zio#3423) Optimize TQueue (zio#3421) Update sbt-ci-release to 1.5.3 (zio#3425) ZIO Test: Support Laws for Capabilities Parameterized on Two Types (zio#3420) * implement ZLaws2 * use AnyF Back up Chunk[Boolean] by Chunk.BitChunks (zio#3419) fix publishing (zio#3433) WIP: Scala.js upgrade to v1.0.0 (zio#2392) (zio#2479) * Update to Scala.js 1.0.0-RC2 * fix for passing testJS * formatting fix * Merge remote-tracking branch 'upstream/master' into feature/scalajs-1.0.0-RC2 * Merge branch 'master' of https://github.com/zio/zio into feature/scalajs-1.0.0-RC2 * sonatype resolver added for izumi-reflect; magnolia updated to v0.12.8 Fix Scala.js build (post zio#2479) (zio#3436) * Fix Scala.js build (post zio#2479) * Move back to shared/Executor source and add jvm/js/native ExecutorPlatformSpecific trait * Fix imports causing build failure on 2.13/dotty Update Magnolia (zio#3432) * Update Magnolia There is a bug in Magnolia versions < 0.15 which causes derivation for case classes with default values to fail. The update should fix it. * Add scala-reflect % Provided dependency, now required for magnolia & exclude scala-compiler Co-authored-by: Kai <[email protected]> Co-authored-by: Kai <[email protected]> Update nyaya-gen to 0.9.1 (zio#3438) Remove sonatype public resolver (zio#3434) Add specialized accessor operations to Chunk (zio#3431) * Add specialized accessor operations to Chunk * Generate only non-empty chunks using chunkWithIndex generator Add ZIO STM blogpost (zio#3443) generalize (zio#3439) Update scala-java-time to 2.0.0 (zio#3446) suspend effects (zio#3444) Fix Publishing on Master (zio#3437) * fix publishing * fix bug add Scalac logo to the Sponsors section in Readme (zio#3379) Implement ZIO#service (zio#3422) * implement getService * add variants * rename Add Diagnostic Code to Has (zio#3377) * add diagnostic code * Fix environment composition * Fix 2.11/dotty Co-authored-by: ioleo <[email protected]> Use short forms where it makes sense (zio#3452) * Use short forms where it makes sense * One more `none` usage. Update to izumi-reflect 1.0.0-M1, use izumi-reflect on dotty (zio#3445) * Update to izumi-reflect-1.0.0-M1, depend on izumi-reflect in dotty * Use one VersionSpecific file for dotty & scala-2 * Adding type signatures to Mock modules to workaround scala/scala3#8764 error: ``` [error] -- Error: PureModule.scala:77:86 [error] 77 | val static = ZIO.accessM[PureModule](_.get.static) [error] | ^ [error] |could not find implicit value for izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. Did you forget to put on a Tag, TagK or TagKK context bound on one of the parameters in zio.test.mock.module.PureModule.Service? e.g. def x[T: Tag, F[_]: TagK] = .... [error] |I found: [error] | [error] | { [error] | izumi.reflect.Tag.apply[zio.test.mock.module.PureModule.Service](classOf[Any] [error] | , [error] | { [error] | <empty> :izumi.reflect.macrortti.LightTypeTag [error] | } [error] | ):izumi.reflect.Tag[zio.test.mock.module.PureModule.Service] [error] | } [error] | [error] |But method tagFromTagMacro in object Tag does not match type izumi.reflect.Tag[zio.test.mock.module.PureModule.Service]. [error] | [error] |The following import might make progress towards fixing the problem: [error] | [error] | import izumi.reflect.Tag.tagFromTagMacro ``` * add type signature to SpecSpec to workaround error: ``` [error] -- Error: SpecSpec.scala:17:51 [error] 17 | val layer = ZLayer.succeed(new Module.Service {}) [error] | ^ [error] |could not find implicit value for izumi.reflect.Tag[zio.test.SpecSpec.Module.Service]. Did you forget to put on a Tag, TagK or TagKK context bound on one of the parameters in zio.test.SpecSpec.Module.Service? e.g. def x[T: Tag, F[_]: TagK] = .... [error] |I found: [error] | [error] | { [error] | izumi.reflect.Tag.apply[zio.test.SpecSpec.Module.Service](classOf[Any], [error] | { [error] | <empty> :izumi.reflect.macrortti.LightTypeTag [error] | } [error] | ):izumi.reflect.Tag[zio.test.SpecSpec.Module.Service] [error] | } [error] | [error] |But method tagFromTagMacro in object Tag does not match type izumi.reflect.Tag[zio.test.SpecSpec.Module.Service]. [error] | [error] |The following import might make progress towards fixing the problem: [error] | [error] | import izumi.reflect.Tag.tagFromTagMacro ``` * Lift `exceptDotty` from HasSpec & ComposedMockSpec (TaggedSpec still won't pass because deriving is not implemented) * add type signatures to MockSpecUtils, update comments * Workaround type inference-caused test failures in PolyMockSpec - Any was inferred for `Tag` now, probably maybe because Tag parameter is AnyKind, add workaround * Fix `@mockable` macro, restrict valid `Tagged` definitions to just izumi.reflect.Tag * sbt fix fix type signature (zio#3455) Update util-core to 20.4.1 (zio#3457) generalize type signature (zio#3460) doc(test_effects) : add aspect ignore (zio#3462) upgrade monix version (zio#3467) Implement ZManaged#flattenM (zio#3464) * implement flattenM * format * fix Scaladoc reorder type parameters (zio#3463) Implement ZManaged#release (zio#3466) * implement ZManaged#release * rename Use ChunkBuilder more prominently in Chunk (zio#3453) * make Chunk use ChunkBuilder * fix lint failure * consistent parenthesis use * use parens for Chunkbuilder#make * followup * retrigger ci Update reactor-core to 3.3.5.RELEASE (zio#3472) Update magnolia to 0.16.0 (zio#3473) Update nyaya-gen to 0.9.2 (zio#3474) added blog to list (zio#3471) * updated blog for RC18 + http4s .21.x * added new blog to resource page Co-authored-by: Pierre Ricadat <[email protected]> Add zio-easymock to libraries with zio support list (zio#3481) Add ZIO#filterNot and ZSTM#filterNot (zio#3477) * Add ZIO#filterNot and ZSTM#filterNot * Fix typos implement assertElements and assertElements
Still need a self contained minimized example |
@nicolasstucki https://github.com/7mind/dottyreflection-repro You can test using that repo, It consists of just one file with minimized code and two files with test cases:
package test
import izumi.reflect.dottyreflection.Inspect.inspect
object Test1 extends App {
// ok in class body
class Foo
println(inspect[Foo])
// not ok in expression
def test() = {
locally {
inspect[Foo]
}
}
} Exception
package test
import izumi.reflect.dottyreflection.Inspect.inspect
object Test2 extends App {
// local class not ok
locally {
class Bar
inspect[Bar]
}
} Exception
3. Algorithmpackage izumi.reflect.dottyreflection
import scala.quoted.{Expr, QuoteContext}
object Inspect {
inline def inspect[T <: AnyKind]: String = ${ inspectAny[T] }
def inspectAny[T <: AnyKind : quoted.Type](using qctx0: QuoteContext): Expr[String] = {
val ref = new Inspector().buildTypeRef[T]
println(s"result: $ref")
Expr(ref.toString)
}
}
final case class NameReference(ref: String, prefix: Option[NameReference]) {
override def toString: String = prefix.fold("")(p => s"$p::") + ref
}
class Inspector(implicit qctx: QuoteContext) {
import qctx.tasty._
protected def log(s: String) = {
println(" -> " + s)
}
def buildTypeRef[T <: AnyKind](using tpe: quoted.Type[T]): NameReference = {
val uns = tpe.unseal
log(s" -------- about to inspect ${tpe} --------")
val v = inspectTree(uns)
log(s" -------- done inspecting ${tpe} --------")
v
}
private def inspectTree(tpeTree: TypeTree): NameReference = {
log(s"INSPECT: $tpeTree: ${tpeTree.getClass}")
if (tpeTree.symbol.isNoSymbol) {
inspectType(tpeTree.tpe)
} else {
inspectSymbol(tpeTree.symbol)
}
}
private def inspectType(tpe: Type): NameReference = {
log(s"INSPECT: type `$tpe`")
tpe match {
case r: TypeRef =>
inspectSymbol(r.typeSymbol)
case a: AnnotatedType =>
inspectType(a.underlying)
case lazyref if lazyref.getClass.getName.contains("LazyRef") => // upstream bug seems like
log(s"LazyRef occured $lazyref")
throw new RuntimeException(s"LazyRef occured $lazyref")
case o =>
log(s"Type, UNSUPPORTED: ${o.getClass} - $o")
throw new RuntimeException(s"Type, UNSUPPORTED: ${o.getClass} - $o")
}
}
private def inspectSymbol(symbol: Symbol): NameReference = {
log(s"INSPECT: symbol `$symbol`")
symbol.tree match {
case c: ClassDef =>
symbolToNameReference(symbol)
case t: TypeDef =>
inspectTree(t.rhs.asInstanceOf[TypeTree])
case v: ValDef =>
inspectTree(v.tpt)
case o =>
log(s"SYMBOL TREE, UNSUPPORTED: $o")
throw new RuntimeException(s"SYMBOL TREE, UNSUPPORTED: ${o.getClass} - $o")
}
}
private def symbolToNameReference(sym: Symbol): NameReference = {
val prefix = if (sym.maybeOwner.isNoSymbol) {
None
} else {
sym.owner.tree match {
case _: PackageDef => None
case _ => Some(inspectSymbol(sym.maybeOwner))
}
}
NameReference(sym.fullName, prefix)
}
}
|
@nicolasstucki : did you get a chance to look at this issue? |
Unfortunately, I did not |
This is still affecting users of ZIO on Scala 3 as of 0.27, there was a question on discord today from user |
|
Re (2): Seems like we need a " Previously we've been using prefixes, which may be logically incorrect but better than being unable to identify context at all. Could you suggest something? |
Could you please elaborate, what's wrong with prefixes? |
|
You cannot disambiguate these classes:
Current izumi-reflect implementation will consider their typetags equal. |
In this particular case, you should be able to distinguish them by their symbol. |
We need a serializable identifier though. Anyway, that's different from this issue and actually not that important. |
Maybe you can use their positions to serialize them when they are local. |
Yup, that's one of the options. |
Note that positions is unavailable for a symbols coming from another package. class T { class X }
val a = new T // a.X is accessible from other packages
val b = println({ class X; "hi" }) // b.X isn't accessible from the outside of this block So I'm not sure if it is possible to reliably serialize identifiers regardless of where they are inspected/come from. |
Usually, local definitions are represented with some special notation and a unique local id. This special notation tells us that it is local and hence not accessible from outside. If you want to serialize a symbol with a string name you may take inspiration from the semanticdb format https://scalameta.org/docs/semanticdb/specification.html#symbol. |
Current relevant PR: #9984 - this should fix the principal issue when merged (the interference between type inference and type info available in blackbox macros) |
To reproduce execute:
Output
Expectation
Compilation succeeds if the commented out wrappng method
def test(): Unit = { ... }
is uncommented.That is, the content of the
quoted.Type[_]
value depends directly on whether or not theLTT
inline method is called inside adef test
or inside the class body, even though the types referred to are defined inside the current block in both situations. Moreover if the inline calls are placed inside a method, but without a type ascription,def test() = { ... }
, the result is the same error./cc @nicolasstucki
The text was updated successfully, but these errors were encountered: