Skip to content

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

Closed
neko-kai opened this issue Apr 21, 2020 · 22 comments · Fixed by #9984
Milestone

Comments

@neko-kai
Copy link
Contributor

To reproduce execute:

git clone https://github.com/zio/izumi-reflect.git
cd izumi-reflect
git checkout feature/dotty-macro-expansion-fails-when-not-inside-type-ascripted-method
sbt '++0.24.0-bin-20200420-c560211-NIGHTLY test:compile'

Output

[error] 26 |      val bazTag = LTT[Baz]
[error]    |                   ^^^^^^^^
[error]    |Exception occurred while executing macro expansion.
[error]    |scala.NotImplementedError: an implementation is missing
[error]    |	at scala.Predef$.$qmark$qmark$qmark(Predef.scala:347)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:120)
[error]    |	at izumi.reflect.dottyreflection.Inspector.prefixOf(Inspector.scala:132)
[error]    |	at izumi.reflect.dottyreflection.Inspector.asNameRefSym(Inspector.scala:219)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:113)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:107)
[error]    |	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspector.scala:33)
[error]    |	at izumi.reflect.dottyreflection.TypeInspections$.apply(TypeInspections.scala:10)
[error]    |	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:21)
[error]    |
[error]    | This location contains code that was inlined from CurrentDottySupportExtentTest.scala:26
[error]    | This location contains code that was inlined from package.scala:73
[error] -- Error: /private/tmp/izumi-reflect/izumi-reflect/izumi-reflect/src/test/scala/izumi/reflect/test/CurrentDottySupportExtentTest.scala:27:23
[error] 27 |      val bazTag2 = LTT[Baz]
[error]    |                    ^^^^^^^^
[error]    |Exception occurred while executing macro expansion.
[error]    |scala.NotImplementedError: an implementation is missing
[error]    |	at scala.Predef$.$qmark$qmark$qmark(Predef.scala:347)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:120)
[error]    |	at izumi.reflect.dottyreflection.Inspector.prefixOf(Inspector.scala:132)
[error]    |	at izumi.reflect.dottyreflection.Inspector.asNameRefSym(Inspector.scala:219)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:113)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:107)
[error]    |	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspector.scala:33)
[error]    |	at izumi.reflect.dottyreflection.TypeInspections$.apply(TypeInspections.scala:10)
[error]    |	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:21)
[error]    |
[error]    | This location contains code that was inlined from CurrentDottySupportExtentTest.scala:27
[error]    | This location contains code that was inlined from package.scala:73
[error] -- Error: /private/tmp/izumi-reflect/izumi-reflect/izumi-reflect/src/test/scala/izumi/reflect/test/CurrentDottySupportExtentTest.scala:29:23
[error] 29 |      val barXTag = LTT[Bar[X]]
[error]    |                    ^^^^^^^^^^^
[error]    |Exception occurred while executing macro expansion.
[error]    |scala.NotImplementedError: an implementation is missing
[error]    |	at scala.Predef$.$qmark$qmark$qmark(Predef.scala:347)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:120)
[error]    |	at izumi.reflect.dottyreflection.Inspector.prefixOf(Inspector.scala:132)
[error]    |	at izumi.reflect.dottyreflection.Inspector.asNameRefSym(Inspector.scala:219)
[error]    |	at izumi.reflect.dottyreflection.Inspector.asNameRef(Inspector.scala:212)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:66)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:105)
[error]    |	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspector.scala:33)
[error]    |	at izumi.reflect.dottyreflection.TypeInspections$.apply(TypeInspections.scala:10)
[error]    |	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:21)
[error]    |
[error]    | This location contains code that was inlined from CurrentDottySupportExtentTest.scala:29
[error]    | This location contains code that was inlined from package.scala:73

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 the LTT inline method is called inside a def 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

@odersky
Copy link
Contributor

odersky commented Apr 21, 2020

Can you try to minimize this into a self contained example? We will treat these with priority.

@neko-kai
Copy link
Contributor Author

@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.

@nicolasstucki
Copy link
Contributor

@neko-kai what tree do you get in Inspector.scala#L118? I notice that you don't match ValDef.

@neko-kai
Copy link
Contributor Author

@nicolasstucki
I've pushed a commit adding debug messages to exceptions in that branch. The tree is a ValDef - but that's not supposed to be there, we're recursing over symbol.tree to collect information about the inheritance hierarchy, so we need the tree to always be the definition tree, unless there's some other way to traverse the type hierarchy.

Error:(26, 23) Exception occurred while executing macro expansion.
java.lang.RuntimeException: SYMBOL TREE, UNSUPPORTED: class dotty.tools.dotc.ast.Trees$ValDef - ValDef(<local CurrentDottySupportExtentTest>,TypeTree[NoType],EmptyTree)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:120)
	at izumi.reflect.dottyreflection.Inspector.prefixOf(Inspector.scala:132)
	at izumi.reflect.dottyreflection.Inspector.asNameRefSym(Inspector.scala:217)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:113)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:107)
	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspector.scala:33)
	at izumi.reflect.dottyreflection.TypeInspections$.apply(TypeInspections.scala:10)
	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:21)
      val bazTag = LTT[Baz]

Note, if I add code to recurse on the ValDef#tpt it arrives nowhere anyway:

Error:(26, 23) Exception occurred while executing macro expansion.
java.lang.RuntimeException: TTYPE, UNSUPPORTED: class dotty.tools.dotc.core.Types$NoType$ - NoType
	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:94)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:105)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:119)
	at izumi.reflect.dottyreflection.Inspector.prefixOf(Inspector.scala:134)
	at izumi.reflect.dottyreflection.Inspector.asNameRefSym(Inspector.scala:219)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:113)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:107)
	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspector.scala:33)
	at izumi.reflect.dottyreflection.TypeInspections$.apply(TypeInspections.scala:10)
	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:21)
      val bazTag = LTT[Baz]

@neko-kai
Copy link
Contributor Author

neko-kai commented Apr 22, 2020

Also, in the macro expansion for LTT[List[Int]], below LTT[Baz] aboe, a Types.LazyRef occurs, which seems like is a very low-level type that doesn't have any methods in tasty-reflect, specifically there's no way to call .underlying and dereference it:

[error] 52 |      val listIntTag0 = LTT[List[Int]]
[error]    |                        ^^^^^^^^^^^^^^
[error]    |Exception occurred while executing macro expansion.
[error]    |java.lang.RuntimeException: TTYPE, UNSUPPORTED: class dotty.tools.dotc.core.Types$LazyRef - LazyRef(...)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:94)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectToB(Inspector.scala:154)
[error]    |	at izumi.reflect.dottyreflection.Inspector.$anonfun$3(Inspector.scala:64)
[error]    |	at scala.collection.immutable.List.map(List.scala:223)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:64)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:71)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:90)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspector.scala:105)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspector.scala:115)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectTType(Inspector.scala:87)
[error]    |	at izumi.reflect.dottyreflection.Inspector.inspectToB(Inspector.scala:154)
[error]    |	at izumi.reflect.dottyreflection.Inspector.$anonfun$3(Inspector.scala:64)
[error]    |	at scala.collection.immutable.List.map(List.scala:223)

neko-kai added a commit to 7mind/zio that referenced this issue Apr 24, 2020
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
```
neko-kai added a commit to 7mind/zio that referenced this issue Apr 24, 2020
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
```
neko-kai added a commit to zio/zio that referenced this issue Apr 25, 2020
* 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
@nicolasstucki nicolasstucki added the stat:needs minimization Needs a self contained minimization label Apr 29, 2020
wi101 pushed a commit to wi101/scalaz-zio that referenced this issue Apr 29, 2020
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
@nicolasstucki nicolasstucki removed their assignment May 12, 2020
@nicolasstucki
Copy link
Contributor

Still need a self contained minimized example

@neko-kai
Copy link
Contributor Author

neko-kai commented Jun 2, 2020

@nicolasstucki
I've made a minimized example here:

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:

  1. inspecting the same class succeeds or fails with CyclicReferenceException depending on the point in code at which the inline was called:
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
Error:(14, 14) Exception occurred while executing macro expansion.
dotty.tools.dotc.core.CyclicReference: 
	at dotty.tools.dotc.core.CyclicReference$.apply(TypeErrors.scala:156)
	at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:257)
	at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:186)
	at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:188)
	at dotty.tools.dotc.ast.tpd$.polyDefDef(tpd.scala:235)
	at dotty.tools.dotc.ast.tpd$.DefDef(tpd.scala:225)
	at dotty.tools.dotc.ast.tpd$.DefDef(tpd.scala:222)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.defDefFromSym(FromSymbol.scala:46)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.definitionFromSym(FromSymbol.scala:19)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.$anonfun$5(FromSymbol.scala:35)
	at scala.collection.immutable.List.map(List.scala:250)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.classDef(FromSymbol.scala:35)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.definitionFromSym(FromSymbol.scala:16)
	at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.Symbol_tree(ReflectionCompilerInterface.scala:1672)
	at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.Symbol_tree(ReflectionCompilerInterface.scala:1671)
	at scala.tasty.Reflection$SymbolOps$.tree(Reflection.scala:2161)
	at izumi.reflect.dottyreflection.Inspector.symbolToNameReference(Inspect.scala:84)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspect.scala:66)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspect.scala:39)
	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspect.scala:29)
	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:9)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at dotty.tools.dotc.transform.Splicer$Interpreter.interpretedStaticMethodCall$$anonfun$2$$anonfun$1(Splicer.scala:320)
	at dotty.tools.dotc.transform.Splicer$Interpreter.stopIfRuntimeException(Splicer.scala:380)
	at dotty.tools.dotc.transform.Splicer$Interpreter.interpretedStaticMethodCall$$anonfun$1(Splicer.scala:320)
	at dotty.tools.dotc.transform.Splicer$Interpreter.interpretTree(Splicer.scala:245)
	at dotty.tools.dotc.transform.Splicer$Interpreter.interpretTree$$anonfun$4(Splicer.scala:265)
	at dotty.tools.dotc.transform.Splicer$.$anonfun$2(Splicer.scala:49)
	at scala.Option.fold(Option.scala:263)
	at dotty.tools.dotc.transform.Splicer$.splice(Splicer.scala:49)
	at dotty.tools.dotc.typer.Inliner.dotty$tools$dotc$typer$Inliner$$expandMacro(Inliner.scala:1430)
	at dotty.tools.dotc.typer.Inliner$InlineTyper.typedApply(Inliner.scala:1258)
	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2345)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2404)
	at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:124)
	at dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2443)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2452)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2455)
	at dotty.tools.dotc.typer.ReTyper.typedTyped(ReTyper.scala:60)
	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2350)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2404)
	at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:124)
	at dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2443)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2452)
	at dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2439)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2452)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2455)
	at dotty.tools.dotc.typer.Inliner.op$1(Inliner.scala:753)
	at dotty.tools.dotc.typer.Inliner.inlined(Inliner.scala:772)
	at dotty.tools.dotc.typer.Inliner$.inlineCall(Inliner.scala:115)
	at dotty.tools.dotc.typer.Typer.adaptNoArgsOther$4(Typer.scala:3084)
	at dotty.tools.dotc.typer.Typer.adaptNoArgs$1(Typer.scala:3181)
	at dotty.tools.dotc.typer.Typer.adapt1(Typer.scala:3389)
	at dotty.tools.dotc.typer.Typer.op$3(Typer.scala:2777)
	at dotty.tools.dotc.typer.Typer.adapt(Typer.scala:2778)
	at dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2443)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2452)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2455)
	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2566)
	at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:854)
	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2353)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2404)
	at dotty.tools.dotc.typer.ProtoTypes$FunProto.$anonfun$2(ProtoTypes.scala:337)
	at dotty.tools.dotc.typer.ProtoTypes$FunProto.cacheTypedArg(ProtoTypes.scala:293)
	at dotty.tools.dotc.typer.ProtoTypes$FunProto.typedArg(ProtoTypes.scala:338)
	at dotty.tools.dotc.typer.Applications$ApplyToUntyped.typedArg(Applications.scala:795)
	at dotty.tools.dotc.typer.Applications$ApplyToUntyped.typedArg(Applications.scala:795)
	at dotty.tools.dotc.typer.Applications$Application.addTyped$1(Applications.scala:530)
	at dotty.tools.dotc.typer.Applications$Application.matchArgs(Applications.scala:599)
	at dotty.tools.dotc.typer.Applications$Application.init(Applications.scala:355)
	at dotty.tools.dotc.typer.Applications$TypedApply.<init>(Applications.scala:692)
	at dotty.tools.dotc.typer.Applications$ApplyToUntyped.<init>(Applications.scala:794)
	at dotty.tools.dotc.typer.Applications.ApplyTo(Applications.scala:997)
	at dotty.tools.dotc.typer.Typer.ApplyTo(Typer.scala:85)
	at dotty.tools.dotc.typer.Applications.simpleApply$1(Applications.scala:864)
	at dotty.tools.dotc.typer.Applications.realApply$5$$anonfun$4(Applications.scala:925)
	at dotty.tools.dotc.typer.Typer.tryEither(Typer.scala:2574)
	at dotty.tools.dotc.typer.Applications.realApply$1(Applications.scala:936)
	at dotty.tools.dotc.typer.Applications.typedApply(Applications.scala:972)
	at dotty.tools.dotc.typer.Typer.typedApply(Typer.scala:85)
	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2345)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2404)
	at dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2443)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2452)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2455)
	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2566)
	at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:854)
	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2353)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2404)
	at dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2443)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2452)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2455)
	at dotty.tools.dotc.typer.Namer.typedAheadExpr$$anonfun$1(Namer.scala:1329)
	at dotty.tools.dotc.typer.Namer.typedAhead(Namer.scala:1319)
	at dotty.tools.dotc.typer.Namer.typedAheadExpr(Namer.scala:1329)
	at dotty.tools.dotc.typer.Namer.rhsType$2(Namer.scala:1463)
	at dotty.tools.dotc.typer.Namer.cookedRhsType$1(Namer.scala:1474)
	at dotty.tools.dotc.typer.Namer.lhsType$1(Namer.scala:1475)
	at dotty.tools.dotc.typer.Namer.inferredType$1(Namer.scala:1486)
	at dotty.tools.dotc.typer.Namer.valOrDefDefSig(Namer.scala:1494)
	at dotty.tools.dotc.typer.Namer.defDefSig(Namer.scala:1567)
	at dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:813)
	at dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:930)
	at dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:841)
	at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:259)
	at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:186)
	at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:188)
	at dotty.tools.dotc.ast.tpd$.polyDefDef(tpd.scala:235)
	at dotty.tools.dotc.ast.tpd$.DefDef(tpd.scala:225)
	at dotty.tools.dotc.ast.tpd$.DefDef(tpd.scala:222)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.defDefFromSym(FromSymbol.scala:46)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.definitionFromSym(FromSymbol.scala:19)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.$anonfun$5(FromSymbol.scala:35)
	at scala.collection.immutable.List.map(List.scala:250)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.classDef(FromSymbol.scala:35)
	at dotty.tools.dotc.tastyreflect.FromSymbol$.definitionFromSym(FromSymbol.scala:16)
	at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.Symbol_tree(ReflectionCompilerInterface.scala:1672)
	at dotty.tools.dotc.tastyreflect.ReflectionCompilerInterface.Symbol_tree(ReflectionCompilerInterface.scala:1671)
	at scala.tasty.Reflection$SymbolOps$.tree(Reflection.scala:2161)
	at izumi.reflect.dottyreflection.Inspector.symbolToNameReference(Inspect.scala:84)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspect.scala:66)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspect.scala:39)
	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspect.scala:29)
	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:9)
      inspect[Foo]
  1. A local class inside an expression has inaccessible prefix (ValDef with no type):
package test

import izumi.reflect.dottyreflection.Inspect.inspect

object Test2 extends App {

  // local class not ok
  locally {
    class Bar
    inspect[Bar]
  }

}
Exception
Error:(10, 12) Exception occurred while executing macro expansion.
java.lang.RuntimeException: Type, UNSUPPORTED: class dotty.tools.dotc.core.Types$NoType$ - NoType
	at izumi.reflect.dottyreflection.Inspector.inspectType(Inspect.scala:58)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspect.scala:37)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspect.scala:72)
	at izumi.reflect.dottyreflection.Inspector.symbolToNameReference(Inspect.scala:86)
	at izumi.reflect.dottyreflection.Inspector.inspectSymbol(Inspect.scala:66)
	at izumi.reflect.dottyreflection.Inspector.inspectTree(Inspect.scala:39)
	at izumi.reflect.dottyreflection.Inspector.buildTypeRef(Inspect.scala:29)
	at izumi.reflect.dottyreflection.Inspect$.inspectAny(Inspect.scala:9)
    inspect[Bar]
3. Algorithm
package 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)
  }

}

@pshirshov
Copy link
Contributor

@nicolasstucki : did you get a chance to look at this issue?

@nicolasstucki
Copy link
Contributor

Unfortunately, I did not

@nicolasstucki nicolasstucki removed stat:needs info stat:needs minimization Needs a self contained minimization labels Aug 2, 2020
@neko-kai
Copy link
Contributor Author

This is still affecting users of ZIO on Scala 3 as of 0.27, there was a question on discord today from user aappddeevv bumping into this issue: https://discordapp.com/channels/629491597070827530/630498701860929559/763866388367671347

@nicolasstucki
Copy link
Contributor

  1. Seems to have the correct behavior. Here the owner of Bar is the local dummy, a marker val that lets us know that this is locally defined in the constructor of Test2. This dummy can be identified with isLocalDummy.

@pshirshov
Copy link
Contributor

pshirshov commented Oct 12, 2020

Re (2): Seems like we need a "localDummyIdentifier" thingy, something similar to FQN but considering scoping. So we may distinguish different Bars in local contexts.

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?

@IndiscriminateCoding
Copy link

@pshirshov

Previously we've been using prefixes, which may be logically incorrect

Could you please elaborate, what's wrong with prefixes?

@nicolasstucki
Copy link
Contributor

  1. The issue here is that we are trying to type the signature of the members at the same time we are expanding the macro. For non-transparent macros this could be fixed by expanding macros after Typer (see Move blackbox macro expansion to ReifyQuotes #7825). Not sure how to avoid it for transparent inline yet (seems to be the same issue as in Can't use Symbol.tree to access DefDef body with blackbox macro using Tasty reflect #7592).

@pshirshov
Copy link
Contributor

Could you please elaborate, what's wrong with prefixes?

You cannot disambiguate these classes:

locally {
class Bar
}

locally {
class Bar
}

Current izumi-reflect implementation will consider their typetags equal.

@nicolasstucki
Copy link
Contributor

In this particular case, you should be able to distinguish them by their symbol.

@pshirshov
Copy link
Contributor

We need a serializable identifier though. Anyway, that's different from this issue and actually not that important.

@nicolasstucki
Copy link
Contributor

Maybe you can use their positions to serialize them when they are local.

@pshirshov
Copy link
Contributor

Yup, that's one of the options.

@IndiscriminateCoding
Copy link

Note that positions is unavailable for a symbols coming from another package.
And it is not that simple to distinguish between this two cases:

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.

@nicolasstucki
Copy link
Contributor

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.

@neko-kai
Copy link
Contributor Author

Current relevant PR: #9984 - this should fix the principal issue when merged (the interference between type inference and type info available in blackbox macros)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants