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

Bytecode reachability analysis for fine-grained target invalidation #2417

Merged
merged 176 commits into from
Jul 30, 2023
Merged
Show file tree
Hide file tree
Changes from 171 commits
Commits
Show all changes
176 commits
Select commit Hold shift + click to select a range
85a0bc9
wip
lihaoyi Apr 5, 2023
ba2b468
first sketch of CodeSig
lihaoyi Apr 5, 2023
9c502b1
first unit test passes
lihaoyi Apr 5, 2023
676f170
first unit test for analyser works
lihaoyi Apr 5, 2023
f54dd30
analyze tests now use ExpectedDepts annotation
lihaoyi Apr 5, 2023
b0b6023
add some test cases
lihaoyi Apr 5, 2023
6c3d16c
migrate to comment-based expectedTransitive
lihaoyi Apr 5, 2023
7e08330
more tests
lihaoyi Apr 6, 2023
8fa92af
add java invokedynamic test
lihaoyi Apr 6, 2023
2f71df0
break up transitive methods test
lihaoyi Apr 6, 2023
7912984
add handling for ignoring overriden virtual methods
lihaoyi Apr 6, 2023
3331c27
add unit test for overriden static method ignoring
lihaoyi Apr 6, 2023
42d6dc9
add some Scala test cases
lihaoyi Apr 6, 2023
b1e3e34
add failing external test case for 13-indirect-external-interface-method
lihaoyi Apr 6, 2023
0cf7ae4
merge
lihaoyi Apr 10, 2023
488fd9d
some basic external summarization now works
lihaoyi Apr 11, 2023
5d7ca57
14-indirect-delegation-external-interface-method passes
lihaoyi Apr 12, 2023
bfe397a
all tests pass
lihaoyi Apr 12, 2023
db63abb
make Analyzer logic all static
lihaoyi Apr 12, 2023
8dca8d0
add more bytecode analysis tests from metascala repo
lihaoyi Apr 12, 2023
f0545ba
break up CodeSigTests.scala
lihaoyi Apr 12, 2023
e37797b
comment
lihaoyi Apr 12, 2023
468d448
make sure we record call graph edges to <clinit> whenever we call met…
lihaoyi Apr 12, 2023
58ec5a4
most codesig tests pass again
lihaoyi Apr 12, 2023
61cfc37
rename MethodSig -> MethodDef
lihaoyi Apr 12, 2023
0101ccc
skip <init> method when considering possible external method calls
lihaoyi Apr 12, 2023
a6f625e
combine codesig.test modules into a single test module, since they ru…
lihaoyi Apr 12, 2023
1ef97e6
add codesig readme
lihaoyi Apr 12, 2023
6334a8f
Analyzer -> Resolver
lihaoyi Apr 12, 2023
9d05ffd
comma-separated arguments in codesig tests
lihaoyi Apr 12, 2023
27c121d
standardize on pretty method toString
lihaoyi Apr 12, 2023
691bc12
tidying
lihaoyi Apr 12, 2023
085a934
most tests pass after swapping MethodDef/LocalMethodDef to ResolvedMe…
lihaoyi Apr 12, 2023
3dc1463
tests pass again
lihaoyi Apr 12, 2023
0bc8a0d
.
lihaoyi Apr 12, 2023
3da62ee
.
lihaoyi Apr 12, 2023
68a540f
merge
lihaoyi Apr 12, 2023
6888c7f
.
lihaoyi Apr 12, 2023
12a97a6
Merge branch 'main' into codesig
lihaoyi Apr 12, 2023
8cfce07
add javagames.1-ribbon test
lihaoyi Apr 12, 2023
4ad5d97
add tetris unit test
lihaoyi Apr 12, 2023
624bf14
refinements around resolution of external method calls
lihaoyi Apr 12, 2023
a1d9b84
simplify codesig test case management
lihaoyi Apr 12, 2023
ec6c26a
cleanup
lihaoyi Apr 12, 2023
2389814
basic handsonscala examples, and failing 9-two-implementations tests
lihaoyi Apr 13, 2023
ec26120
replace directSubclasses bimap with directSuperclasses normal map
lihaoyi Apr 13, 2023
f58f041
try include externalDirectMethods in MethodCallResolver
lihaoyi Apr 13, 2023
a1f1f43
tighten up external call resolution logic, 9-two-implementations-inte…
lihaoyi Apr 13, 2023
7b5b0f3
rename external tests to label them as interface or abstract class tests
lihaoyi Apr 13, 2023
8d24572
import alias JType.Cls => JCls
lihaoyi Apr 13, 2023
1179e4d
most tests pass after simplifying resolveLocalReceivers to return Set…
lihaoyi Apr 13, 2023
fe9b0f0
tests pass again
lihaoyi Apr 13, 2023
00d1a86
add failing static method test
lihaoyi Apr 13, 2023
020fbc7
external/11-static-method test now passes
lihaoyi Apr 13, 2023
3321d40
basic json logging, fixes for external method call analysis. Still mi…
lihaoyi Apr 13, 2023
179fd73
add unit test for dispatch to inherited method in external class
lihaoyi Apr 13, 2023
14b702f
cleanup
lihaoyi Apr 13, 2023
c048501
treat private methods the same as InvokeSpecial, since even though th…
lihaoyi Apr 13, 2023
c1a140f
tweak-test
lihaoyi Apr 13, 2023
fc22de1
re-enable handsonscala tests
lihaoyi Apr 13, 2023
6181987
merge handsonscala/ and games/
lihaoyi Apr 13, 2023
2656db1
extract codesig graph operations
lihaoyi Apr 13, 2023
4f455fe
initial wiring of codesig into mill
lihaoyi Apr 13, 2023
1bd3777
wip trying to set up integration test for codesig in mill
lihaoyi Apr 13, 2023
88bf8ec
some basic caching on invariant code works, line numbers still bust c…
lihaoyi Apr 13, 2023
f6825a7
hackily disable sourcecode.line inference to avoid busting caches, al…
lihaoyi Apr 14, 2023
c53d0ca
avoid hashing opcode of discarded virtual instructions
lihaoyi Apr 14, 2023
9d56bca
simple integration tests for codesig pass
lihaoyi Apr 14, 2023
27ca2e2
swap over LocalSummarizer from tree API to visitor API
lihaoyi Apr 14, 2023
98b106b
swap ExternalSummarizer over from tree to visitor API
lihaoyi Apr 14, 2023
4d93623
tidy up ExternalSummarizer
lihaoyi Apr 14, 2023
554c764
simplify LocalSummarizer a bit, swap over to MurmurHash3
lihaoyi Apr 14, 2023
f2fa022
restructure LocalSummarizer.Result
lihaoyi Apr 14, 2023
534a558
re-organize tests
lihaoyi Apr 14, 2023
5506e2e
add scala module unit test
lihaoyi Apr 14, 2023
fe55e05
DRY up main.codesig.test.forkEnv
lihaoyi Apr 14, 2023
d1bf7bc
compiles after merging main
lihaoyi May 10, 2023
3de9aa0
manual tests pass
lihaoyi May 10, 2023
ebff1aa
first pass at codesig-scalamodule
lihaoyi May 10, 2023
cdb9ce1
codesig-scalamodule mostly passes
lihaoyi May 10, 2023
a37ae5d
Merge branch 'main' into codesig
lihaoyi May 14, 2023
b0bb71c
.
lihaoyi May 14, 2023
d6ea041
.
lihaoyi May 15, 2023
7973c7b
merge, compiles
lihaoyi Jun 17, 2023
13af93a
re-add codesig evaluator integration
lihaoyi Jun 17, 2023
8f8d8d7
codesig unit tests pass again
lihaoyi Jun 17, 2023
5a2bf7b
ensure Discover macro generates code in a deterministic manner
lihaoyi Jun 25, 2023
7c76e40
avoid O(n^2) list.contains loop in computeTransitive
lihaoyi Jun 26, 2023
017faf2
wip
lihaoyi Jun 28, 2023
0dc033e
preserve method calls as nodes in call graph to avoid exploding the s…
lihaoyi Jun 29, 2023
a938394
WIP reifying external class calls into the call graph to further redu…
lihaoyi Jun 29, 2023
40baec2
generalize def simplifiedCallGraph and fix indexGraphEdges, most unit…
lihaoyi Jun 29, 2023
23c875e
tidyup
lihaoyi Jun 29, 2023
86475fe
all unit tests pass again
lihaoyi Jun 29, 2023
6ed186e
all tests pass again
lihaoyi Jun 29, 2023
9ff3b7d
simplify transitiveExternalMethods
lihaoyi Jun 29, 2023
456c62d
tidy up externalClsToLocalClsMethodsDirect
lihaoyi Jun 29, 2023
b0e5c7d
cleanup
lihaoyi Jun 29, 2023
7d08506
chain together super-classes of external class calls rather than flat…
lihaoyi Jun 29, 2023
c55676d
more redundancy reduction in MethodCallResolver.Result
lihaoyi Jun 29, 2023
3aea908
add 16-scala-trait-constructor unit test
lihaoyi Jul 2, 2023
ecef91e
update codesig readme with conclusions from literation review
lihaoyi Jul 2, 2023
5a62d44
.
lihaoyi Jul 3, 2023
d2bac43
.
lihaoyi Jul 3, 2023
d72a6d7
.
lihaoyi Jul 3, 2023
0497aca
.
lihaoyi Jul 3, 2023
cfa3879
.
lihaoyi Jul 3, 2023
fcbe529
.
lihaoyi Jul 3, 2023
50b47af
.
lihaoyi Jul 3, 2023
1d47655
wip
lihaoyi Jul 4, 2023
d76a7d2
.
lihaoyi Jul 4, 2023
da069b4
cleanup MethodCallResolver
lihaoyi Jul 4, 2023
c6c600c
cache super/descendent queries in MethodCallResolvers
lihaoyi Jul 4, 2023
5f19c6e
improve methodExists
lihaoyi Jul 4, 2023
d3b443d
wip
lihaoyi Jul 4, 2023
8e8c354
add symboltable
lihaoyi Jul 4, 2023
b554f92
some speedups
lihaoyi Jul 4, 2023
9088dfa
more microoptimizations for Desc.read
lihaoyi Jul 4, 2023
861be75
add parsing flags to avoid unnecessary work in bytecode parsing
lihaoyi Jul 5, 2023
a197e37
break up CallGraphAnalysis into separate methods
lihaoyi Jul 5, 2023
bd92374
tidy up method hash management
lihaoyi Jul 5, 2023
c904a98
clean up CodeSig.compute
lihaoyi Jul 5, 2023
d221c47
more cleanup of ExternalSummarizer
lihaoyi Jul 5, 2023
95a8532
cleanup
lihaoyi Jul 5, 2023
91a9398
cleanup
lihaoyi Jul 5, 2023
dc4fd98
.
lihaoyi Jul 5, 2023
a636b5b
.
lihaoyi Jul 5, 2023
3d445e1
wip
lihaoyi Jul 12, 2023
09ad579
wip
lihaoyi Jul 12, 2023
c8e2687
.
lihaoyi Jul 12, 2023
e2b8d0f
.
lihaoyi Jul 12, 2023
bade8a1
.
lihaoyi Jul 12, 2023
77ef64a
Update runner/src/mill/runner/MillCliConfig.scala
lihaoyi Jul 12, 2023
adb3d2b
.
lihaoyi Jul 12, 2023
253634d
.
lihaoyi Jul 12, 2023
00f6057
.
lihaoyi Jul 12, 2023
cff4a1d
.
lihaoyi Jul 13, 2023
067107e
add some tests for transitive callgraph logic
lihaoyi Jul 14, 2023
c8e4bd1
.
lihaoyi Jul 14, 2023
6189da4
.
lihaoyi Jul 14, 2023
e855dbb
.
lihaoyi Jul 14, 2023
350e937
.
lihaoyi Jul 14, 2023
bbb5545
.
lihaoyi Jul 14, 2023
88719a1
.
lihaoyi Jul 14, 2023
0d9ed16
.
lihaoyi Jul 14, 2023
6a9db15
.
lihaoyi Jul 15, 2023
2081a24
.
lihaoyi Jul 15, 2023
16a980b
.
lihaoyi Jul 15, 2023
37cdc5d
avoid reporting cached key in profile for inputs that are never cached
lihaoyi Jul 15, 2023
59825b4
wip handling of constructor method hash signatures in GroupEvaluator.…
lihaoyi Jul 15, 2023
6e6995a
ignore Command methods during callgraph analysis
lihaoyi Jul 16, 2023
6456ec3
ensure JvmModel classes have a stable hashcode to ensuring orderings …
lihaoyi Jul 16, 2023
eb75eb0
.
lihaoyi Jul 16, 2023
c138c5a
Merge branch 'main' into codesig
lihaoyi Jul 16, 2023
bfb84d3
.
lihaoyi Jul 16, 2023
372ec12
.
lihaoyi Jul 16, 2023
a78eb46
.
lihaoyi Jul 16, 2023
9eba549
swap over to runtime module parent chain discovery
lihaoyi Jul 23, 2023
7844764
basic tests for module objects inside traits, still doesn't pass
lihaoyi Jul 23, 2023
5da6af8
add MinimalSpanningForest to help debug callgraph invalidation issues
lihaoyi Jul 23, 2023
2aaf8e7
cleanup to logging logic
lihaoyi Jul 24, 2023
3edfe88
tidying
lihaoyi Jul 24, 2023
b1bee5e
cleanup
lihaoyi Jul 24, 2023
b524191
failing test cases for special casing anonymous class SAM lambdas
lihaoyi Jul 24, 2023
0301005
special case SAM methods to work like indy lambdas
lihaoyi Jul 24, 2023
481c831
Merge branch 'main' into codesig
lihaoyi Jul 24, 2023
9eeb151
.
lihaoyi Jul 25, 2023
14c6bdc
Revert reflect comparison change
lihaoyi Jul 25, 2023
e96cb62
fix
lihaoyi Jul 25, 2023
47668f2
.
lihaoyi Jul 25, 2023
e73d815
.
lihaoyi Jul 29, 2023
fc705ea
merge
lihaoyi Jul 29, 2023
0237bd6
.
lihaoyi Jul 29, 2023
ea7c979
update readme
lihaoyi Jul 29, 2023
49a1373
update docs
lihaoyi Jul 29, 2023
6da9903
.
lihaoyi Jul 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion bsp/worker/src/mill/bsp/worker/MillBuildServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,14 @@ private class MillBuildServer(
if (statePromise.isCompleted) statePromise = Promise[State]() // replace the promise
evaluatorOpt = evaluator
evaluatorOpt.foreach(e =>
statePromise.success(new State(e.rootModule.millSourcePath, e.baseLogger, debug))
statePromise.success(
new State(
e.rootModule.millSourcePath,
e.baseLogger,
debug,
e.disableCallgraphInvalidation
)
)
)
}

Expand Down
10 changes: 8 additions & 2 deletions bsp/worker/src/mill/bsp/worker/State.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import mill.scalalib.internal.{JavaModuleUtils, ModuleUtils}
import mill.define.Module
import mill.util.ColorLogger

private class State(projectRoot: os.Path, baseLogger: ColorLogger, debug: String => Unit) {
private class State(
projectRoot: os.Path,
baseLogger: ColorLogger,
debug: String => Unit,
disableCallgraphInvalidation: Boolean
) {
lazy val bspModulesById: Map[BuildTargetIdentifier, BspModule] = {
val modules: Seq[(Module, Seq[Module])] = rootModules
.map(rootModule => (rootModule, JavaModuleUtils.transitiveModules(rootModule)))
Expand Down Expand Up @@ -39,7 +44,8 @@ private class State(projectRoot: os.Path, baseLogger: ColorLogger, debug: String
threadCount = None,
targetsAndParams = Seq("resolve", "_"),
prevRunnerState = mill.runner.RunnerState.empty,
logger = baseLogger
logger = baseLogger,
disableCallgraphInvalidation = disableCallgraphInvalidation
).evaluate()

val rootModules0 = evaluated.result.frames
Expand Down
66 changes: 65 additions & 1 deletion build.sc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// plugins and dependencies

import $file.ci.shared
import $file.ci.upload
import $ivy.`org.scalaj::scalaj-http:2.4.2`
Expand Down Expand Up @@ -356,6 +357,13 @@ trait MillPublishScalaModule extends MillScalaModule with MillPublishJavaModule

/** Publishable module which contains strictly handled API. */
trait MillStableScalaModule extends MillPublishScalaModule with Mima {
import com.github.lolgab.mill.mima._
override def mimaBinaryIssueFilters: T[Seq[ProblemFilter]] = Seq(
ProblemFilter.exclude[Problem]("mill.eval.ProfileLogger*"),
ProblemFilter.exclude[Problem]("mill.eval.GroupEvaluator*"),
ProblemFilter.exclude[Problem]("mill.eval.Tarjans*"),
ProblemFilter.exclude[Problem]("mill.define.Ctx#Impl*"),
lihaoyi marked this conversation as resolved.
Show resolved Hide resolved
)
def mimaPreviousVersions: T[Seq[String]] = Settings.mimaBaseVersions

def mimaPreviousArtifacts: T[Agg[Dep]] = T {
Expand Down Expand Up @@ -455,6 +463,7 @@ object main extends MillStableScalaModule with BuildInfo {
BuildInfo.Value("millVersion", millVersion(), "Mill version."),
BuildInfo.Value("millDocUrl", Settings.docUrl, "Mill documentation url.")
)

def ivyDeps = Agg(
Deps.osLib,
Deps.upickle,
Expand All @@ -463,10 +472,65 @@ object main extends MillStableScalaModule with BuildInfo {
Deps.sbtTestInterface
)
}

object util extends MillStableScalaModule {
def moduleDeps = Seq(api, client)
def ivyDeps = Agg(Deps.coursier, Deps.jline)
}

object codesig extends MillPublishScalaModule {
override def ivyDeps = Agg(ivy"org.ow2.asm:asm-tree:9.5", Deps.osLib, ivy"com.lihaoyi::pprint:0.8.1")
def moduleDeps = Seq(util)

override lazy val test: CodeSigTests = new CodeSigTests{}
trait CodeSigTests extends MillScalaTests{
val caseKeys = interp.watchValue(
os.walk(millSourcePath / "cases", maxDepth = 3)
.map(_.subRelativeTo(millSourcePath / "cases").segments)
.collect{case Seq(a, b, c) => s"$a-$b-$c"}
)

def testLogFolder = T{ T.dest }

def caseEnvs[V](f1: CaseModule => Task[V])(s: String, f2: V => String) = {
T.traverse(caseKeys) { i => f1(cases(i)).map(v => s"MILL_TEST_${s}_$i" -> f2(v)) }
}
def forkEnv = T{
Map("MILL_TEST_LOGS" -> testLogFolder().toString) ++
caseEnvs(_.compile)("CLASSES", _.classes.path.toString)() ++
caseEnvs(_.compileClasspath)("CLASSPATH", _.map(_.path).mkString(","))() ++
caseEnvs(_.sources)("SOURCES", _.head.path.toString)()
}

object cases extends Cross[CaseModule](caseKeys)
trait CaseModule extends ScalaModule with Cross.Module[String]{
def caseName = crossValue
object external extends ScalaModule{
def scalaVersion = "2.13.10"
}

def moduleDeps = Seq(external)

val Array(prefix, suffix, rest) = caseName.split("-", 3)
def millSourcePath = super.millSourcePath / prefix / suffix / rest
def scalaVersion = "2.13.10"
def ivyDeps = T{
if (!caseName.contains("realistic") && !caseName.contains("sourcecode")) super.ivyDeps()
else Agg(
ivy"com.lihaoyi::fastparse:3.0.1",
ivy"com.lihaoyi::scalatags:0.12.0",
ivy"com.lihaoyi::cask:0.9.1",
ivy"com.lihaoyi::castor:0.1.7",
Deps.mainargs,
Deps.requests,
Deps.osLib,
Deps.upickle,
)
}
}
}
}

object define extends MillStableScalaModule {
def moduleDeps = Seq(api, util)
def compileIvyDeps = Agg(Deps.scalaReflect(scalaVersion()))
Expand Down Expand Up @@ -1172,7 +1236,7 @@ def launcherScript(
}

object runner extends MillPublishScalaModule {
def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, bsp, linenumbers)
def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, bsp, linenumbers, main.codesig)
def skipPreviousVersions: T[Seq[String]] = Seq("0.11.0-M7")

object linenumbers extends MillPublishScalaModule {
Expand Down
6 changes: 6 additions & 0 deletions integration/feature/codesig-hello/repo/build.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import mill._

val valueFoo = 0
val valueFooUsedInBar = 0
def helperFoo = { println("running helperFoo"); 1 + valueFoo }
def foo = T{ println("running foo"); helperFoo }
55 changes: 55 additions & 0 deletions integration/feature/codesig-hello/test/src/CodeSigHelloTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package mill.integration

import utest._

object CodeSigHelloTests extends IntegrationTestSuite {
val tests = Tests {
val wsRoot = initWorkspace()
"simple" - {
// Make sure the simplest case where we have a single target calling a single helper
// method is properly invalidated when either the target body, or the helper method's body
// is changed, or something changed in the constructor
val initial = evalStdout("foo")

assert(initial.out.linesIterator.toSeq == Seq("running foo", "running helperFoo"))

val cached = evalStdout("foo")
assert(cached.out == "")

mangleFile(wsRoot / "build.sc", _.replace("running foo", "running foo2"))
val mangledFoo = evalStdout("foo")

assert(mangledFoo.out.linesIterator.toSeq == Seq("running foo2", "running helperFoo"))

val cached2 = evalStdout("foo")
assert(cached2.out == "")

mangleFile(wsRoot / "build.sc", _.replace("running helperFoo", "running helperFoo2"))
val mangledHelperFoo = evalStdout("foo")

assert(mangledHelperFoo.out.linesIterator.toSeq == Seq("running foo2", "running helperFoo2"))

// Make sure changing `val`s, which only affects the Module constructor and
// not the Target method itself, causes invalidation
mangleFile(wsRoot / "build.sc", _.replace("val valueFoo = 0", "val valueFoo = 10"))
val mangledValFoo = evalStdout("foo")
assert(mangledValFoo.out.linesIterator.toSeq == Seq("running foo2", "running helperFoo2"))

// Even modifying `val`s that do not affect the target invalidates it, because
// we only know that the constructor changed and don't do enough analysis to
// know that this particular val is not used
mangleFile(
wsRoot / "build.sc",
_.replace("val valueFooUsedInBar = 0", "val valueFooUsedInBar = 10")
)
val mangledValFooUsedInBar = evalStdout("foo")
assert(mangledValFooUsedInBar.out.linesIterator.toSeq == Seq(
"running foo2",
"running helperFoo2"
))

val cached3 = evalStdout("foo")
assert(cached3.out == "")
}
}
}
39 changes: 39 additions & 0 deletions integration/feature/codesig-nested/repo/build.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import mill._

val valueFoo = 0
val valueFooUsedInBar = 0
def helperFoo = { println("running helperFoo"); 1 + valueFoo }
def foo = T{ println("running foo"); helperFoo }

object outer extends Module{
val valueBar = 0
val valueBarUsedInQux = 0
def helperBar = { println("running helperBar"); 20 }
def bar = T{ println("running bar"); helperBar + valueBar + valueFooUsedInBar }

trait InnerModule extends Module{
val valueQux = 0
def helperQux = { println("running helperQux"); 300 + valueQux + valueBarUsedInQux }
def qux = T{ println("running qux"); foo() + bar() + helperQux }
}
object inner extends InnerModule
}

trait TraitOuter extends Module{
val valueTraitOuter = 0
def helperTraitOuter = { println("running helperTraitOuter"); 300 + valueTraitOuter }
def outer = T{ println("running outer"); foo() + helperTraitOuter }

object traitInner extends Module{
val valueTraitInner = 0
def helperTraitInner = { println("running helperTraitInner"); 300 + valueTraitOuter + valueTraitInner }
def inner = T{ println("running inner"); foo() + outer() + helperTraitInner }
}
}

object traitOuter extends TraitOuter

object crossOuter extends Cross[CrossOuter](1337, 31337, 31415926)
trait CrossOuter extends TraitOuter with Cross.Module[Int]{
override val valueTraitOuter = crossValue
}
Loading