Skip to content

Regression in scalamock/scalamock for accessing nested types #22424

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
WojciechMazur opened this issue Jan 21, 2025 · 4 comments · Fixed by #22448
Closed

Regression in scalamock/scalamock for accessing nested types #22424

WojciechMazur opened this issue Jan 21, 2025 · 4 comments · Fixed by #22448
Assignees
Labels
area:metaprogramming:reflection Issues related to the quotes reflection API itype:bug regression This worked in a previous version but doesn't anymore
Milestone

Comments

@WojciechMazur
Copy link
Contributor

Based on OpenCB failure scalamock/scalamock, version 7.1.0

Compiler version

Fails in 3.7.0-RC1-bin-20250120-db23c08-NIGHTL
Works in 3.6.3

Minimized code

Not minimized yet

Output

info] compiling 71 Scala sources and 7 Java sources to /Users/wmazur/projects/scala/community-build3/repo/core/jvm/target/scala-3.7.0-RC1-bin-20250120-db23c08-NIGHTLY/test-classes ...
[error] -- Error: /Users/wmazur/projects/scala/community-build3/repo/core/shared/src/test/scala/com/paulbutcher/test/mock/MockTest.scala:318:16 
[error] 318 |        val e = mock[m.Embedded[Double]]
[error]     |                ^^^^^^^^^^^^^^^^^^^^^^^^
[error]     |Exception occurred while executing macro expansion.
[error]     |java.lang.AssertionError: assertion failed: asTerm called on not-a-Term val <none>
[error]     |   at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error]     |   at dotty.tools.dotc.core.Symbols$Symbol.asTerm(Symbols.scala:186)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply$$anonfun$3(QuotesImpl.scala:306)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$.scala$quoted$runtime$impl$QuotesImpl$reflect$$$withDefaultPos(QuotesImpl.scala:3144)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply(QuotesImpl.scala:306)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply(QuotesImpl.scala:303)
[error]     |   at org.scalamock.clazz.MockMaker$.$anonfun$5(MockMaker.scala:141)
[error]     |   at scala.collection.immutable.List.flatMap(List.scala:294)
[error]     |   at org.scalamock.clazz.MockMaker$.instance(MockMaker.scala:98)
[error]     |   at org.scalamock.clazz.MockImpl$.mock(MockImpl.scala:34)
[error]     |
[error]     |---------------------------------------------------------------------------
[error]     |Inline stack trace
[error]     |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]     |This location contains code that was inlined from Mock.scala:30
[error]  30 |  inline def mock[T](implicit mockContext: MockContext): T = ${MockImpl.mock[T]('{mockContext})}
[error]     |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]      ---------------------------------------------------------------------------
[error] -- Error: /Users/wmazur/projects/scala/community-build3/repo/core/shared/src/test/scala/newapi/NewApiSpec.scala:274:16 
[error] 274 |    val e = stub[m.Embedded[Double]]
[error]     |            ^^^^^^^^^^^^^^^^^^^^^^^^
[error]     |Exception occurred while executing macro expansion.
[error]     |java.lang.AssertionError: assertion failed: asTerm called on not-a-Term val <none>
[error]     |   at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error]     |   at dotty.tools.dotc.core.Symbols$Symbol.asTerm(Symbols.scala:186)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply$$anonfun$3(QuotesImpl.scala:306)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$.scala$quoted$runtime$impl$QuotesImpl$reflect$$$withDefaultPos(QuotesImpl.scala:3144)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply(QuotesImpl.scala:306)
[error]     |   at scala.quoted.runtime.impl.QuotesImpl$reflect$DefDef$.apply(QuotesImpl.scala:303)
[error]     |   at org.scalamock.stubs.internal.StubMaker.$anonfun$4(StubMaker.scala:131)
[error]     |   at scala.collection.immutable.List.flatMap(List.scala:294)
[error]     |   at org.scalamock.stubs.internal.StubMaker.newInstance(StubMaker.scala:112)
[error]     |   at org.scalamock.stubs.Stubs$package$.stubMacro(Stubs.scala:210)
[error]     |   at org.scalamock.stubs.Stubs$package$.inline$stubMacro(Stubs.scala:209)
[error]     |
[error]     |---------------------------------------------------------------------------
[error]     |Inline stack trace
[error]     |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]     |This location contains code that was inlined from Stubs.scala:183
[error] 183 |  ${ stubMacro[T]('{ collector }) }
[error]     |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]     |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]     |This location contains code that was inlined from Stubs.scala:183
[error]  42 |  inline def stub[T]: Stub[T] = stubImpl[T]
[error]     |                                ^^^^^^^^^^^
[error]      ---------------------------------------------------------------------------
[error] two errors found
[error] (scalamockJVM / Test / compileIncremental) Compilation failed

Expectation

@WojciechMazur WojciechMazur added area:metaprogramming:reflection Issues related to the quotes reflection API itype:bug regression This worked in a previous version but doesn't anymore stat:needs minimization Needs a self contained minimization labels Jan 21, 2025
@WojciechMazur
Copy link
Contributor Author

@jchyb Can you take a look at it? You're having the most expertise with both scalamock codebase and quotes-reflection

@jchyb jchyb self-assigned this Jan 21, 2025
@jchyb
Copy link
Contributor

jchyb commented Jan 22, 2025

Minimised:
Macro.scala

import scala.quoted.*

object MockMaker:
  inline def mock[T]: T = ${instance[T]}

  def instance[T: Type](using quotes: Quotes): Expr[T] =
    import quotes.reflect._
    val tpe = TypeRepr.of[T]
    val symbol = tpe.typeSymbol.methodMember("innerTraitInOptions").head
    val a = tpe.memberType(symbol)
    println(a.show)

    '{???}


trait PolymorphicTrait {
  
  trait Embedded {
    trait ATrait[A, B]
    def innerTraitInOptions(x: ATrait[String, Int]): ATrait[String, Int]
  }
}

Test.scala

@main def Test = 
  val m = new PolymorphicTrait {}
  val e = MockMaker.mock[m.Embedded]

In 3.6.3 the shown method type is:

(x: m.Embedded#ATrait[scala.Predef.String, scala.Int])m.Embedded#ATrait[scala.Predef.String, scala.Int]

In 3.7.0-RC1-bin-20250120-db23c08-NIGHTLY:

(x: scala.Nothing)m.Embedded#ATrait[scala.Predef.String, scala.Int]

For some reason we lose the information about the method argument, which later causes issues in ScalaMock.

@jchyb
Copy link
Contributor

jchyb commented Jan 22, 2025

Bisect script points to 26ecda5 (I adjusted the minimisation slightly to error on arguments of type Nothing)

@Gedochao Gedochao removed the stat:needs minimization Needs a self contained minimization label Jan 23, 2025
@jchyb
Copy link
Contributor

jchyb commented Jan 24, 2025

The issue lies with asSeenFrom used by the typeMember method. Since it is usually used for type checker purposes, it tends to approximate the types if the prefixing type is unstable (like in the m.Embedded here) - in the commit introducing the regression the rule for isLegalPrefix was changed to not require being in the Typer phase, which means that indeed, now the m.Embedded#ATrait[scala.Predef.String, scala.Int] is approximated to Nothing if non-transparent macro is used. It also means that the issue shown here was also a problem if the macro was transparent, even before 26ecda5 introduced the changes. I imagine that ideally, we should have an asSeenFrom-like method that does not approximate the types, for use in macros.

@jchyb jchyb closed this as completed in 2685750 Mar 4, 2025
@WojciechMazur WojciechMazur added this to the 3.7.0 milestone Mar 11, 2025
tgodzik pushed a commit to scala/scala3-lts that referenced this issue Apr 23, 2025
…cala#22448)

To achieve this, we substitute This types in `member.info` referencing classSymbol with TypeReprs actual self (which may or may not be a This type)
Fixes scala#22424
tgodzik added a commit to scala/scala3-lts that referenced this issue Apr 23, 2025
…cala#22448)

To achieve this, we substitute This types in `member.info` referencing classSymbol with TypeReprs actual self (which may or may not be a This type)
Fixes scala#22424
[Cherry-picked 2685750][modified]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:metaprogramming:reflection Issues related to the quotes reflection API itype:bug regression This worked in a previous version but doesn't anymore
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants