fmonniot / scala3mock

Mocking framework for Scala 3
https://francois.monniot.eu/scala3mock
Other
19 stars 1 forks source link

Update to Scala 3.3.0 #2

Closed fmonniot closed 10 months ago

fmonniot commented 1 year ago

Given it's the first LTS, we should try to stay on it. Although given metaprogramming is one aspect that make progress relatively quickly, maybe we will jump on a feature release (for example if the implicit/using modified is made accessible when creating functions)

fmonniot commented 1 year ago

Ok, so it looks like the type inference is what causes the issue. When using methods that make use of the MethodType type, we now have to manually provide the type. If we do not, then the compiler throw a ClassCastException because it's expecting a MethodType type but a NoType is actually present. Not entirely sure yet if it's because of how the When macro is implemented, or if it's a compiler bug. Need a smaller reproducer first.

That being said, given it's a fix that can only be done by the user, I'm not sure we should upgrade to 3.3.0 yet.

Here is the stack trace of the compiler error:

``` [error] ## Exception when compiling 18 sources to /Users/francoismonniot/Projects/github.com/fmonniot/scala3mock/core/target/scala-3.3.0/test-classes [error] java.lang.ClassCastException: class dotty.tools.dotc.core.Types$NoType$ cannot be cast to class dotty.tools.dotc.core.Types$MethodType (dotty.tools.dotc.core.Types$NoType$ and dotty.tools.dotc.core.Types$MethodType are in unnamed module of loader sbt.internal.classpath.ClassLoaderCache$Key$CachedClassLoader @346cc773) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:297) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1409) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:49) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transformSelect(PostTyper.scala:199) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:295) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.app1$1(PostTyper.scala:318) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:331) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1228) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1228) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transformStats(PostTyper.scala:488) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock(tpd.scala:1233) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1429) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:49) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:479) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1481) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform$$anonfun$5(PostTyper.scala:381) [error] dotty.tools.dotc.transform.SuperAccessors.wrapDefDef(SuperAccessors.scala:223) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:381) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1228) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1228) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transformStats(PostTyper.scala:488) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock(tpd.scala:1233) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1429) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:49) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:479) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1510) [error] scala.collection.immutable.List.mapConserve(List.scala:472) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1510) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.app1$1(PostTyper.scala:317) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:331) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock$$anonfun$1$$anonfun$1(tpd.scala:1233) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1215) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1228) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transformStats(PostTyper.scala:488) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock(tpd.scala:1233) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1429) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:49) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:479) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1510) [error] scala.collection.immutable.List.mapConserve(List.scala:472) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1510) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.app1$1(PostTyper.scala:317) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:331) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.app1$1(PostTyper.scala:318) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:331) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1228) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1228) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transformStats(PostTyper.scala:488) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1230) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:47) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform$$anonfun$4$$anonfun$1(PostTyper.scala:366) [error] dotty.tools.dotc.transform.SuperAccessors.wrapTemplate(SuperAccessors.scala:208) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform$$anonfun$4(PostTyper.scala:366) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.withNoCheckNews(PostTyper.scala:105) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:368) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1483) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:418) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1228) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1228) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transformStats(PostTyper.scala:488) [error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1230) [error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1491) [error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40) [error] dotty.tools.dotc.transform.PostTyper$PostTyperTransformer.transform(PostTyper.scala:479) [error] dotty.tools.dotc.transform.MacroTransform.run(MacroTransform.scala:18) [error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:324) [error] scala.collection.immutable.List.map(List.scala:250) [error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:328) [error] dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:247) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) [error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) [error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1321) [error] dotty.tools.dotc.Run.runPhases$1(Run.scala:263) [error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:271) [error] dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:280) [error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67) [error] dotty.tools.dotc.Run.compileUnits(Run.scala:280) [error] dotty.tools.dotc.Run.compileSources(Run.scala:195) [error] dotty.tools.dotc.Run.compile(Run.scala:179) [error] dotty.tools.dotc.Driver.doCompile(Driver.scala:35) [error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:88) [error] dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22) [error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91) [error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:193) [error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23) [error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:248) [error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:183) [error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:163) [error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:239) [error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:163) [error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:211) [error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:534) [error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:534) [error] sbt.internal.inc.Incremental$.$anonfun$apply$5(Incremental.scala:179) [error] sbt.internal.inc.Incremental$.$anonfun$apply$5$adapted(Incremental.scala:177) [error] sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:463) [error] sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:116) [error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56) [error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52) [error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263) [error] sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:418) [error] sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:505) [error] sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:405) [error] sbt.internal.inc.Incremental$.apply(Incremental.scala:171) [error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:534) [error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:488) [error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332) [error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:425) [error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137) [error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:2366) [error] sbt.Defaults$.$anonfun$compileIncrementalTask$2(Defaults.scala:2316) [error] sbt.internal.server.BspCompileTask$.$anonfun$compute$1(BspCompileTask.scala:30) [error] sbt.internal.io.Retry$.apply(Retry.scala:46) [error] sbt.internal.io.Retry$.apply(Retry.scala:28) [error] sbt.internal.io.Retry$.apply(Retry.scala:23) [error] sbt.internal.server.BspCompileTask$.compute(BspCompileTask.scala:30) [error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:2314) [error] scala.Function1.$anonfun$compose$1(Function1.scala:49) [error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62) [error] sbt.std.Transform$$anon$4.work(Transform.scala:68) [error] sbt.Execute.$anonfun$submit$2(Execute.scala:282) [error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23) [error] sbt.Execute.work(Execute.scala:291) [error] sbt.Execute.$anonfun$submit$1(Execute.scala:282) [error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265) [error] sbt.CompletionService$$anon$2.call(CompletionService.scala:64) [error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) [error] java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577) [error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) [error] java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) [error] java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) [error] java.base/java.lang.Thread.run(Thread.java:1589) ```
fmonniot commented 1 year ago

I ran a code snippet on the compiler code base (snippet at the end) and found out that this bug was introduced in the commit https://github.com/lampepfl/dotty/commit/b429e6b8a76e57c1570ed93d874cf63b1f9e3a88. That being said, it is fairly possible that this commit only exhibit the issue (cause of the added cast) as opposed to be the root cause of it.

code snippet ```scala package mock import eu.monniot.scala3mock.main.withExpectations import eu.monniot.scala3mock.functions.MockFunctions import eu.monniot.scala3mock.main.* import eu.monniot.scala3mock.matchers.MatchAny import eu.monniot.scala3mock.macros.* import eu.monniot.scala3mock.handlers.CallHandler1 import eu.monniot.scala3mock.functions.MockFunction1 import eu.monniot.scala3mock.context.MockContext import eu.monniot.scala3mock.main.Default trait TestTrait { //def polymorphic[T](x: List[T]): String def polymorphic(x: (Int, Double)): String def oneParam(x: List[Int]): String } def main(using mc: MockContext) = val m = mock[TestTrait] when(m.oneParam).expects(List(2)) () ```
fmonniot commented 1 year ago

Confirmed that the commit only made the error apparent. When compiling the snippet under 3.2.2 with the -Ycheck:all parameter, then we have the same error even on 3.2.2. I'll try to minimize the when macro to reproduce this issue.

smarter commented 1 year ago

Thanks for the investigation! I've minimized this to:

class MockFunction1[T1]:
  def expects(v1: T1 | Foo): Any = ???
  def expects(matcher: String): Any = ???

def when[T1](f: T1 => Any): MockFunction1[T1] =
  ???

class Foo

def main =
    val f: Foo = new Foo
    when((x: Foo) => "").expects(f)

I'm working on a fix currently.

fmonniot commented 1 year ago

Oh nice! I didn't had time to work on side projects over the past two weeks, thanks for taking the time to write a minimizer!