@@ -14,30 +14,13 @@ import scala.collection.mutable
1414 * the `Task.Command` methods we find. This mapping from `Class[_]` to `MainData`
1515 * can then be used later to look up the `MainData` for any module.
1616 */
17- case class Discover private (
18- value : Map [
19- Class [_],
20- (Seq [String ], Seq [mainargs.MainData [_, _]], Seq [String ])
21- ],
22- dummy : Int = 0 /* avoid conflict with Discover.apply(value: Map) below*/
23- ) {
24- @ deprecated(" Binary compatibility shim" , " Mill 0.11.4" )
25- private [define] def this (value : Map [Class [_], Seq [mainargs.MainData [_, _]]]) =
26- this (value.view.mapValues((Nil , _, Nil )).toMap)
27- @ deprecated(" Binary compatibility shim" , " Mill 0.11.4" )
28- private [define] def copy (value : Map [Class [_], Seq [mainargs.MainData [_, _]]]): Discover = {
29- new Discover (value.view.mapValues((Nil , _, Nil )).toMap, dummy)
30- }
31- }
17+ class Discover (val classInfo : Map [Class [_], Discover .Node ], val allNames : Seq [String ])
3218
3319object Discover {
34- def apply2 [T ](value : Map [Class [_], (Seq [String ], Seq [mainargs.MainData [_, _]], Seq [String ])])
35- : Discover =
36- new Discover (value)
37-
38- @ deprecated(" Binary compatibility shim" , " Mill 0.11.4" )
39- def apply [T ](value : Map [Class [_], Seq [mainargs.MainData [_, _]]]): Discover =
40- new Discover (value.view.mapValues((Nil , _, Nil )).toMap)
20+ class Node (
21+ val entryPoints : Seq [mainargs.MainData [_, _]],
22+ val declaredNames : Seq [String ]
23+ )
4124
4225 inline def apply [T ]: Discover = $ { Router .applyImpl[T ] }
4326
@@ -46,7 +29,7 @@ object Discover {
4629 import mainargs .Macros .*
4730 import scala .util .control .NonFatal
4831
49- def applyImpl [T : Type ](using Quotes ): Expr [Discover ] = {
32+ def applyImpl [T : Type ](using quotes : Quotes ): Expr [Discover ] = {
5033 import quotes .reflect .*
5134 val seen = mutable.Set .empty[TypeRepr ]
5235 val moduleSym = Symbol .requiredClass(" mill.define.Module" )
@@ -62,10 +45,8 @@ object Discover {
6245 } {
6346 rec(memberTpe)
6447 memberTpe.asType match {
65- case ' [mill.define.Cross [m]] =>
66- rec(TypeRepr .of[m])
67- case _ =>
68- () // no cross argument to extract
48+ case ' [mill.define.Cross [m]] => rec(TypeRepr .of[m])
49+ case _ => () // no cross argument to extract
6950 }
7051 }
7152 }
@@ -107,89 +88,91 @@ object Discover {
10788 )
10889 )
10990
91+ def sortedMethods (curCls : TypeRepr , sub : TypeRepr , methods : Seq [Symbol ]): Seq [Symbol ] =
92+ for {
93+ m <- methods.toList.sortBy(_.fullName)
94+ mType = curCls.memberType(m)
95+ returnType = methodReturn(mType)
96+ if returnType <:< sub
97+ } yield m
98+
11099 // Make sure we sort the types and methods to keep the output deterministic;
111100 // otherwise the compiler likes to give us stuff in random orders, which
112101 // causes the code to be generated in random order resulting in code hashes
113102 // changing unnecessarily
114- val mapping = for {
103+ val mapping : Seq [( Expr [( Class [_], Node )], Seq [ String ])] = for {
115104 discoveredModuleType <- seen.toSeq.sortBy(_.typeSymbol.fullName)
116105 curCls = discoveredModuleType
117106 methods = filterDefs(curCls.typeSymbol.methodMembers)
118107 declMethods = filterDefs(curCls.typeSymbol.declaredMethods)
119- overridesRoutes = {
108+ _ = {
120109 assertParamListCounts(
121110 curCls,
122111 methods,
123112 (TypeRepr .of[mill.define.Command [? ]], 1 , " `Task.Command`" ),
124113 (TypeRepr .of[mill.define.Target [? ]], 0 , " Target" )
125114 )
115+ }
126116
127- def sortedMethods (sub : TypeRepr , methods : Seq [Symbol ] = methods): Seq [Symbol ] =
128- for {
129- m <- methods.toList.sortBy(_.fullName)
130- mType = curCls.memberType(m)
131- returnType = methodReturn(mType)
132- if returnType <:< sub
133- } yield m
134-
135- Tuple3 (
136- for {
137- m <- sortedMethods(sub = TypeRepr .of[mill.define.NamedTask [? ]])
138- } yield m.name, // .decoded // we don't need to decode the name in Scala 3
139- for {
140- m <- sortedMethods(sub = TypeRepr .of[mill.define.Command [? ]])
141- } yield curCls.asType match {
142- case ' [t] =>
143- val expr =
144- try
145- createMainData[Any , t](
146- m,
147- m.annotations.find(_.tpe =:= TypeRepr .of[mainargs.main]).getOrElse(' {
148- new mainargs.main()
149- }.asTerm),
150- m.paramSymss
151- ).asExprOf[mainargs.MainData [? , ? ]]
152- catch {
153- case NonFatal (e) =>
154- val (before, Array (after, _* )) = e.getStackTrace().span(e =>
155- ! (e.getClassName() == " mill.define.Discover$Router$" && e.getMethodName() == " applyImpl" )
156- ): @ unchecked
157- val trace =
158- (before :+ after).map(_.toString).mkString(" trace:\n " , " \n " , " \n ..." )
159- report.errorAndAbort(
160- s " Error generating maindata for ${m.fullName}: ${e}\n $trace" ,
161- m.pos.getOrElse(Position .ofMacroExpansion)
162- )
163- }
164- // report.warning(s"generated maindata for ${m.fullName}:\n${expr.asTerm.show}", m.pos.getOrElse(Position.ofMacroExpansion))
165- expr
166- },
167- for
168- m <- sortedMethods(sub = TypeRepr .of[mill.define.Task [? ]], methods = declMethods)
169- yield m.name.toString
170- )
117+ names =
118+ sortedMethods(curCls, sub = TypeRepr .of[mill.define.NamedTask [? ]], methods).map(_.name)
119+ entryPoints = for {
120+ m <- sortedMethods(curCls, sub = TypeRepr .of[mill.define.Command [? ]], methods)
121+ } yield curCls.asType match {
122+ case ' [t] =>
123+ val expr =
124+ try
125+ createMainData[Any , t](
126+ m,
127+ m.annotations.find(_.tpe =:= TypeRepr .of[mainargs.main]).getOrElse(' {
128+ new mainargs.main()
129+ }.asTerm),
130+ m.paramSymss
131+ ).asExprOf[mainargs.MainData [? , ? ]]
132+ catch {
133+ case NonFatal (e) =>
134+ val (before, Array (after, _* )) = e.getStackTrace().span(e =>
135+ ! (e.getClassName() == " mill.define.Discover$Router$" && e.getMethodName() == " applyImpl" )
136+ ): @ unchecked
137+ val trace =
138+ (before :+ after).map(_.toString).mkString(" trace:\n " , " \n " , " \n ..." )
139+ report.errorAndAbort(
140+ s " Error generating maindata for ${m.fullName}: ${e}\n $trace" ,
141+ m.pos.getOrElse(Position .ofMacroExpansion)
142+ )
143+ }
144+ expr
171145 }
172- if overridesRoutes._1.nonEmpty || overridesRoutes._2.nonEmpty || overridesRoutes._3.nonEmpty
146+ declaredNames =
147+ sortedMethods(
148+ curCls,
149+ sub = TypeRepr .of[mill.define.NamedTask [? ]],
150+ declMethods
151+ ).map(_.name)
152+ if names.nonEmpty || entryPoints.nonEmpty
173153 } yield {
174- val (names, mainDataExprs, taskNames) = overridesRoutes
175154 // by wrapping the `overridesRoutes` in a lambda function we kind of work around
176155 // the problem of generating a *huge* macro method body that finally exceeds the
177156 // JVM's maximum allowed method size
178157 val overridesLambda = ' {
179- def triple () = ($ { Expr (names) }, $ { Expr .ofList(mainDataExprs) }, $ { Expr (taskNames) })
158+ def triple () =
159+ new Node ($ { Expr .ofList(entryPoints) }, $ { Expr (declaredNames) })
180160 triple()
181161 }
182162 val lhs =
183163 Ref (defn.Predef_classOf ).appliedToType(discoveredModuleType.widen).asExprOf[Class [? ]]
184- ' { $lhs -> $overridesLambda }
164+ ( ' { $lhs -> $overridesLambda }, names)
185165 }
186166
187167 val expr : Expr [Discover ] =
188168 ' {
189169 // TODO: we can not import this here, so we have to import at the use site now, or redesign?
190170 // import mill.main.TokenReaders.*
191171 // import mill.api.JsonFormatters.*
192- Discover .apply2(Map ($ { Varargs (mapping) }* ))
172+ new Discover (
173+ Map [Class [_], Node ]($ { Varargs (mapping.map(_._1)) }* ),
174+ $ { Expr (mapping.iterator.flatMap(_._2).distinct.toList.sorted) }
175+ )
193176 }
194177 // TODO: if needed for debugging, we can re-enable this
195178 // report.warning(s"generated discovery for ${TypeRepr.of[T].show}:\n${expr.asTerm.show}", TypeRepr.of[T].typeSymbol.pos.getOrElse(Position.ofMacroExpansion))
0 commit comments