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

Clean up Resolve.scala and related code to improve rigor and error reporting #2453

Merged
merged 60 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
3abfa6b
add module-init-error test
lihaoyi Apr 23, 2023
5cc0e35
flesh out ModuleInitErrorTests
lihaoyi Apr 23, 2023
9794eaf
fix
lihaoyi Apr 23, 2023
f06baed
wip try to collapse Resolve into one impl
lihaoyi Apr 23, 2023
00f0178
ResolveTasks compiles again with new implementation, incomplete
lihaoyi Apr 23, 2023
718be72
try to re-introduce resolve error reporting
lihaoyi Apr 24, 2023
092120d
wip
lihaoyi Apr 24, 2023
d5a1d2e
re-implement not-a-module error
lihaoyi Apr 24, 2023
dfc4328
wip
lihaoyi Apr 24, 2023
1d4b411
iwp
lihaoyi Apr 25, 2023
363e482
fixes
lihaoyi Apr 25, 2023
d35f58b
all MainTests pass
lihaoyi Apr 25, 2023
cd9c0ca
add doubleNestedModule tests, enable more tests
lihaoyi Apr 25, 2023
add13e1
try and re-enable other uses of resolve
lihaoyi Apr 25, 2023
4b95cc4
all main.test passes
lihaoyi Apr 25, 2023
184dfcb
break out ResolveNonEmpty
lihaoyi Apr 25, 2023
c07f8b0
fix-compile
lihaoyi Apr 25, 2023
fa085b8
scalafmt
lihaoyi Apr 25, 2023
9e7a40b
cleanup
lihaoyi Apr 25, 2023
35cfef0
cleanup
lihaoyi Apr 25, 2023
4862477
wip
lihaoyi Apr 25, 2023
b274839
split out ExpandBracesTests
lihaoyi Apr 25, 2023
3e186c8
cleanup
lihaoyi Apr 25, 2023
cea7c6c
Merge branch 'main' into module-init-error
lihaoyi Apr 25, 2023
424a1a9
fix
lihaoyi Apr 25, 2023
4669340
fixes
lihaoyi Apr 25, 2023
a229e4d
resolveTasks -> resolve
lihaoyi Apr 25, 2023
7b74968
things compile again after trying to make reflection return an Either
lihaoyi Apr 25, 2023
1655c51
first few module initialization error unit tests pass
lihaoyi Apr 25, 2023
9881f0d
comments
lihaoyi Apr 25, 2023
0de8d03
.
lihaoyi Apr 25, 2023
296f4ec
simple cross module partial initialization failure test
lihaoyi Apr 25, 2023
ca65172
simple cross module initialization failure
lihaoyi Apr 25, 2023
a430a0b
wip
lihaoyi Apr 25, 2023
2c57075
add ResolveMetadata testing to ResolversTests.scala
lihaoyi Apr 25, 2023
2ee6597
cleanup
lihaoyi Apr 25, 2023
e2bb92f
scalafmt
lihaoyi Apr 25, 2023
8f111a4
wip getting rid of rev List[Segment]
lihaoyi Apr 25, 2023
db51286
fix-tests
lihaoyi Apr 25, 2023
6c7bc42
fix-compile
lihaoyi Apr 25, 2023
a4dfa70
cleanup
lihaoyi Apr 25, 2023
096e6c4
cleanup
lihaoyi Apr 25, 2023
a1fdd47
add dependency test cases, assert stack traces are shortish
lihaoyi Apr 25, 2023
17fd69b
ensure output of resolution gets sorted
lihaoyi Apr 25, 2023
2e8bb12
.
lihaoyi Apr 25, 2023
c3b100d
fox
lihaoyi Apr 25, 2023
5071c2c
cleanup
lihaoyi Apr 25, 2023
540ddf7
.
lihaoyi Apr 25, 2023
12c844f
.
lihaoyi Apr 25, 2023
78f62b5
cleanup
lihaoyi Apr 25, 2023
53b1914
.
lihaoyi Apr 25, 2023
695280a
Merge branch 'main' into module-init-error
lihaoyi Apr 25, 2023
09e7484
try to fix getSimpleName on JDK8
lihaoyi Apr 25, 2023
d9ca2f8
.
lihaoyi Apr 25, 2023
18d7a6d
.
lihaoyi Apr 25, 2023
6079a36
.
lihaoyi Apr 25, 2023
5f174bf
.
lihaoyi Apr 25, 2023
fc6b17f
tweaks
lihaoyi Apr 26, 2023
4df0166
Merge branch 'main' into module-init-error
lihaoyi Apr 26, 2023
6b5f726
.
lihaoyi Apr 26, 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
4 changes: 2 additions & 2 deletions bsp/worker/src/mill/bsp/worker/MillBuildServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ class MillBuildServer(
val mainModule = new MainModule {
override implicit def millDiscover: Discover[_] = Discover[this.type]
}
val compileTargetName = (module.millModuleSegments ++ Segments(Label("compile"))).render
val compileTargetName = (module.millModuleSegments ++ Label("compile")).render
log.debug(s"about to clean: ${compileTargetName}")
val cleanTask = mainModule.clean(evaluator, Seq(compileTargetName): _*)
val cleanResult = evaluator.evaluate(
Expand All @@ -674,7 +674,7 @@ class MillBuildServer(
)
else {
val outPaths = evaluator.pathsResolver.resolveDest(
module.millModuleSegments ++ Seq(Label("compile"))
module.millModuleSegments ++ Label("compile")
)
val outPathSeq = Seq(outPaths.dest, outPaths.meta, outPaths.log)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package mill.contrib.scoverage
import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType
import mill.define.{Command, Module, Task}
import mill.eval.Evaluator
import mill.main.RunScript
import mill.main.{ResolveTasks, RunScript}
import mill.define.SelectMode
import mill.{PathRef, T}
import os.Path
Expand Down Expand Up @@ -81,17 +81,15 @@ trait ScoverageReport extends Module {
sources: String,
dataTargets: String
): Task[PathRef] = {
val sourcesTasks: Seq[Task[Seq[PathRef]]] = RunScript.resolveTasks(
mill.main.ResolveTasks,
val sourcesTasks: Seq[Task[Seq[PathRef]]] = ResolveTasks.resolve(
evaluator,
Seq(sources),
SelectMode.Single
) match {
case Left(err) => throw new Exception(err)
case Right(tasks) => tasks.asInstanceOf[Seq[Task[Seq[PathRef]]]]
}
val dataTasks: Seq[Task[PathRef]] = RunScript.resolveTasks(
mill.main.ResolveTasks,
val dataTasks: Seq[Task[PathRef]] = ResolveTasks.resolve(
evaluator,
Seq(dataTargets),
SelectMode.Single
Expand Down
21 changes: 21 additions & 0 deletions integration/failure/module-init-error/repo/build.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import mill._, scalalib._

def rootTarget = T{ println("Running rootTarget"); "rootTarget" }
def rootCommand(s: String) = T.command{ println(s"Running rootCommand $s") }

object foo extends Module{
def fooTarget = T{ println(s"Running fooTarget"); 123 }
def fooCommand(s: String) = T.command{ println(s"Running fooCommand $s") }
throw new Exception("Foo Boom")
}

object bar extends Module {
def barTarget = T { println(s"Running barTarget"); "abc" }
def barCommand(s: String) = T.command{ println(s"Running barCommand $s") }

object qux extends Module{
def quxTarget = T { println(s"Running quxTarget"); "xyz" }
def quxCommand(s: String) = T.command{ println(s"Running quxCommand $s") }
throw new Exception("Qux Boom")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package mill.integration

import mill.util.Util
import utest._

object ModuleInitErrorTests extends IntegrationTestSuite {
def captureOutErr = true
val tests = Tests {
initWorkspace()

test("rootTarget") {
// If we specify a target in the root module, we are not
// affected by the sub-modules failing to initialize
val res = evalStdout("rootTarget")
assert(res.isSuccess == true)
assert(res.out.contains("""Running rootTarget"""))
}
test("rootCommand") {
// If we specify a target in the root module, we are not
// affected by the sub-modules failing to initialize
val res = evalStdout("rootCommand", "hello")
assert(res.isSuccess == true)
assert(res.out.contains("""Running rootCommand hello"""))
}
test("fooTarget") {
val res = evalStdout("foo.fooTarget")
assert(res.isSuccess == false)
assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Foo Boom"""))
// Make sure the stack trace is "short" and does not contain all the stack
// frames from the Mill launcher
assert(fansi.Str(res.err).plainText.linesIterator.size < 20)
}
test("fooCommand") {
val res = evalStdout("foo.fooCommand", "hello")
assert(res.isSuccess == false)
assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Foo Boom"""))
assert(fansi.Str(res.err).plainText.linesIterator.size < 20)
}
test("barTarget") {
val res = evalStdout("bar.barTarget")
assert(res.isSuccess == true)
assert(res.out.contains("""Running barTarget"""))
}
test("barCommand") {
val res = evalStdout("bar.barCommand", "hello")
assert(res.isSuccess == true)
assert(res.out.contains("""Running barCommand hello"""))
}
test("quxTarget") {
val res = evalStdout("bar.qux.quxTarget")
assert(res.isSuccess == false)
assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Qux Boom"""))
assert(fansi.Str(res.err).plainText.linesIterator.size < 20)
}
test("quxCommand") {
val res = evalStdout("bar.qux.quxCommand", "hello")
assert(res.isSuccess == false)
assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Qux Boom"""))
assert(fansi.Str(res.err).plainText.linesIterator.size < 20)
}
}
}
2 changes: 1 addition & 1 deletion main/core/src/mill/define/BaseModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ abstract class ExternalModule(implicit
"External modules must be at a top-level static path, not " + millModuleEnclosing0.value
)
override implicit def millModuleSegments = {
Segments(millModuleEnclosing0.value.split('.').map(Segment.Label).toIndexedSeq: _*)
Segments(millModuleEnclosing0.value.split('.').map(Segment.Label).toIndexedSeq)
}
}
48 changes: 29 additions & 19 deletions main/core/src/mill/define/Cross.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mill.define

import language.experimental.macros
import scala.collection.SeqView
import scala.reflect.macros.blackbox

object Cross {
Expand Down Expand Up @@ -269,18 +270,27 @@ object Cross {
class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit ctx: mill.define.Ctx)
extends mill.define.Module()(ctx) {

private val items: List[(List[Any], List[String], M)] = for {
// We lazily initialize the instances of `Cross.Module` only when they are
// requested, to avoid unexpected failures in one module initialization
// causing problems using others.
private class Lazy[T](t: () => T) {
lazy val value = t()
}

private val items: List[(List[Any], List[String], Lazy[M])] = for {
factory <- factories.toList
(crossSegments, (crossValues, make)) <-
factory.crossSegmentsList.zip(factory.crossValuesListLists.zip(factory.makeList))
} yield {
val relPath = ctx.segment.pathSegments
val sub = make(
ctx
.withSegments(ctx.segments ++ Seq(ctx.segment))
.withMillSourcePath(ctx.millSourcePath / relPath)
.withSegment(Segment.Cross(crossSegments))
.withCrossValues(factories.flatMap(_.crossValuesRaw))
val sub = new Lazy(() =>
make(
ctx
.withSegments(ctx.segments ++ Seq(ctx.segment))
.withMillSourcePath(ctx.millSourcePath / relPath)
.withSegment(Segment.Cross(crossSegments))
.withCrossValues(factories.flatMap(_.crossValuesRaw))
)
)

(crossValues.toList, crossSegments.toList, sub)
Expand All @@ -293,25 +303,27 @@ class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit ctx: mi
* A list of the cross modules, in
* the order the original cross values were given in
*/
def crossModules: List[M] = items.collect { case (_, _, v) => v }
lazy val crossModules: Seq[M] = items.map { case (_, _, v) => v.value }

/**
* A mapping of the raw cross values to the cross modules, in
* the order the original cross values were given in
*/
val valuesToModules: collection.Map[List[Any], M] =
items.map { case (values, segments, subs) => (values, subs) }.to(
collection.mutable.LinkedHashMap
)
val valuesToModules: collection.MapView[List[Any], M] = items
.map { case (values, segments, subs) => (values, subs) }
.to(collection.mutable.LinkedHashMap)
.view
.mapValues(_.value)

/**
* A mapping of the string-ified string segments to the cross modules, in
* the order the original cross values were given in
*/
val segmentsToModules: collection.Map[List[String], M] =
items.map { case (values, segments, subs) => (segments, subs) }.to(
collection.mutable.LinkedHashMap
)
val segmentsToModules: collection.MapView[List[String], M] = items
.map { case (values, segments, subs) => (segments, subs) }
.to(collection.mutable.LinkedHashMap)
.view
.mapValues(_.value)

/**
* Fetch the cross module corresponding to the given cross values
Expand All @@ -321,9 +333,7 @@ class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit ctx: mi
/**
* Fetch the cross module corresponding to the given cross values
*/
def apply(arg0: Any, args: Any*): M = {
valuesToModules(arg0 :: args.toList)
}
def apply(arg0: Any, args: Any*): M = valuesToModules(arg0 :: args.toList)

/**
* Fetch the relevant cross module given the implicit resolver you have in
Expand Down
57 changes: 57 additions & 0 deletions main/core/src/mill/define/ExpandBraces.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package mill.define
import fastparse._
import fastparse.NoWhitespace.noWhitespaceImplicit

object ExpandBraces {
private sealed trait Fragment
private object Fragment {
case class Keep(value: String) extends Fragment
case class Expand(values: List[List[Fragment]]) extends Fragment
}

def expandBraces(selectorString: String): Either[String, Seq[String]] = {
parse(selectorString, parser(_)) match {
case f: Parsed.Failure => Left(s"Parsing exception ${f.msg}")
case Parsed.Success(fragmentLists, _) =>
def processFragmentSequence(remaining: List[Fragment]): List[List[String]] =
remaining match {
case Nil => List(List())
case head :: tail =>
val tailStrings = processFragmentSequence(tail)
head match {
case Fragment.Keep(s) => tailStrings.map(s :: _)
case Fragment.Expand(fragmentLists) =>
if (fragmentLists.length == 1) {
for {
lhs <- fragmentLists.flatMap(processFragmentSequence)
rhs <- tailStrings
} yield List("{") ::: lhs ::: List("}") ::: rhs
} else for {
lhs <- fragmentLists.flatMap(processFragmentSequence)
rhs <- tailStrings
} yield lhs ::: rhs
}
}

val res = processFragmentSequence(fragmentLists.toList).map(_.mkString)

Right(res)
}
}

private def plainChars[_p: P]: P[Fragment.Keep] =
P(CharsWhile(c => c != ',' && c != '{' && c != '}')).!.map(Fragment.Keep)

private def emptyExpansionBranch[_p: P] = P("").map(_ => List(Fragment.Keep("")))

private def toExpand[_p: P]: P[Fragment] =
P("{" ~ (braceParser.rep(1) | emptyExpansionBranch).rep(sep = ",") ~ "}").map(x =>
Fragment.Expand(x.toList.map(_.toList))
)

private def braceParser[_p: P]: P[Fragment] = P(toExpand | plainChars)

private def topLevelComma[_p: P] = P(",".!).map(Fragment.Keep(_))

private def parser[_p: P]: P[Seq[Fragment]] = P((braceParser | topLevelComma).rep(1) ~ End)
}
Loading