Skip to content

Commit fa502b7

Browse files
committed
WIP 41 - polish all Task macros
1 parent edfd308 commit fa502b7

File tree

6 files changed

+138
-124
lines changed

6 files changed

+138
-124
lines changed

main/api/src/mill/api/Ctx.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import scala.language.implicitConversions
77
* Provides access to various resources in the context of a currently execution Target.
88
*/
99
object Ctx {
10-
// @compileTimeOnly("Target.ctx() / T.ctx() / T.* APIs can only be used with a T{...} block")
10+
@compileTimeOnly("Target.ctx() / T.ctx() / T.* APIs can only be used with a T{...} block")
1111
@ImplicitStub
1212
implicit def taskCtx: Ctx = ???
1313

main/define/src/mill/define/Applicative.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object Applicative {
2626
def apply[T](t: M[T]): T
2727
}
2828
object ApplyHandler {
29-
// @compileTimeOnly("Target#apply() can only be used with a T{...} block")
29+
@compileTimeOnly("Target#apply() can only be used with a T{...} block")
3030
implicit def defaultApplyHandler[M[+_]]: ApplyHandler[M] = ???
3131
}
3232
trait Applyable[M[+_], +T] {

main/define/src/mill/define/Task.scala

Lines changed: 107 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -200,16 +200,22 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
200200
* return type is JSON serializable. In return they automatically caches their
201201
* return value to disk, only re-computing if upstream [[Task]]s change
202202
*/
203-
implicit inline def apply[T](inline t: T)(implicit rw: RW[T], ctx: mill.define.Ctx): Target[T] =
203+
implicit inline def apply[T](inline t: T)(implicit
204+
inline rw: RW[T],
205+
inline ctx: mill.define.Ctx
206+
): Target[T] =
204207
${ Internal.targetImpl[T]('t)('rw, 'ctx, 'this) }
205208

206209
implicit inline def apply[T](inline t: Result[T])(implicit
207-
rw: RW[T],
208-
ctx: mill.define.Ctx
210+
inline rw: RW[T],
211+
inline ctx: mill.define.Ctx
209212
): Target[T] =
210213
${ Internal.targetResultImpl[T]('t)('rw, 'ctx, 'this) }
211214

212-
inline def apply[T](inline t: Task[T])(implicit rw: RW[T], ctx: mill.define.Ctx): Target[T] =
215+
inline def apply[T](inline t: Task[T])(implicit
216+
inline rw: RW[T],
217+
inline ctx: mill.define.Ctx
218+
): Target[T] =
213219
${ Internal.targetTaskImpl[T]('t)('rw, 'ctx) }
214220

215221
/**
@@ -226,8 +232,8 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
226232
* Violating that invariant can result in confusing mis-behaviors
227233
*/
228234
inline def persistent[T](inline t: Result[T])(implicit
229-
rw: RW[T],
230-
ctx: mill.define.Ctx
235+
inline rw: RW[T],
236+
inline ctx: mill.define.Ctx
231237
): Target[T] =
232238
${ Internal.persistentImpl[T]('t)('rw, 'ctx, 'this) }
233239

@@ -242,24 +248,28 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
242248
* [[TargetImpl]]s need to be invalidated and re-computed.
243249
*/
244250
inline def sources(inline values: Result[os.Path]*)(implicit
245-
ctx: mill.define.Ctx
251+
inline ctx: mill.define.Ctx
246252
): Target[Seq[PathRef]] = ${ Internal.sourcesImpl1('values)('ctx, 'this) }
247253

248254
inline def sources(inline values: Result[Seq[PathRef]])(implicit
249-
ctx: mill.define.Ctx
255+
inline ctx: mill.define.Ctx
250256
): Target[Seq[PathRef]] =
251257
${ Internal.sourcesImpl2('values)('ctx, 'this) }
252258

253259
/**
254260
* Similar to [[Source]], but only for a single source file or folder. Defined
255261
* using `T.source`.
256262
*/
257-
def source(value: Result[os.Path])(implicit ctx: mill.define.Ctx): Target[PathRef] =
258-
??? // macro Internal.sourceImpl1
263+
inline def source(inline value: Result[os.Path])(implicit
264+
inline ctx: mill.define.Ctx
265+
): Target[PathRef] =
266+
${ Internal.sourceImpl1('value)('ctx, 'this) }
259267

260268
@annotation.targetName("source2")
261-
def source(value: Result[PathRef])(implicit ctx: mill.define.Ctx): Target[PathRef] =
262-
??? // macro Internal.sourceImpl2
269+
inline def source(inline value: Result[PathRef])(implicit
270+
inline ctx: mill.define.Ctx
271+
): Target[PathRef] =
272+
${ Internal.sourceImpl2('value)('ctx, 'this) }
263273

264274
/**
265275
* [[InputImpl]]s, normally defined using `T.input`, are [[NamedTask]]s that
@@ -278,8 +288,8 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
278288
* used for detecting changes to source files.
279289
*/
280290
inline def input[T](inline value: Result[T])(implicit
281-
w: upickle.default.Writer[T],
282-
ctx: mill.define.Ctx
291+
inline w: upickle.default.Writer[T],
292+
inline ctx: mill.define.Ctx
283293
): Target[T] =
284294
${ Internal.inputImpl[T]('value)('w, 'ctx, 'this) }
285295

@@ -290,17 +300,17 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
290300
* take arguments that are automatically converted to command-line
291301
* arguments, as long as an implicit [[mainargs.TokensReader]] is available.
292302
*/
293-
def command[T](t: Task[T])(implicit
294-
ctx: mill.define.Ctx,
295-
w: W[T],
296-
cls: EnclosingClass
297-
): Command[T] = ??? // macro Internal.commandFromTask[T]
298-
299-
def command[T](t: Result[T])(implicit
300-
w: W[T],
301-
ctx: mill.define.Ctx,
302-
cls: EnclosingClass
303-
): Command[T] = ??? // macro Internal.commandImpl[T]
303+
inline def command[T](inline t: Task[T])(implicit
304+
inline ctx: mill.define.Ctx,
305+
inline w: W[T],
306+
inline cls: EnclosingClass
307+
): Command[T] = ${ Internal.commandFromTask[T]('t)('ctx, 'w, 'cls) }
308+
309+
inline def command[T](inline t: Result[T])(implicit
310+
inline w: W[T],
311+
inline ctx: mill.define.Ctx,
312+
inline cls: EnclosingClass
313+
): Command[T] = ${ Internal.commandImpl[T]('t)('w, 'ctx, 'cls, 'this) }
304314

305315
/**
306316
* [[Worker]] is a [[NamedTask]] that lives entirely in-memory, defined using
@@ -316,10 +326,10 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
316326
* responsibility of ensuring the implementation is idempotent regardless of
317327
* what in-memory state the worker may have.
318328
*/
319-
def worker[T](t: Task[T])(implicit ctx: mill.define.Ctx): Worker[T] =
320-
??? // macro Internal.workerImpl1[T]
329+
inline def worker[T](inline t: Task[T])(implicit inline ctx: mill.define.Ctx): Worker[T] =
330+
${ Internal.workerImpl1[T]('t)('ctx) }
321331

322-
inline def worker[T](inline t: Result[T])(implicit ctx: mill.define.Ctx): Worker[T] =
332+
inline def worker[T](inline t: Result[T])(implicit inline ctx: mill.define.Ctx): Worker[T] =
323333
${ Internal.workerImpl2[T]('t)('ctx, 'this) }
324334

325335
/**
@@ -493,45 +503,47 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
493503

494504
def sourceImpl1(using
495505
Quotes
496-
)(value: Expr[Result[os.Path]])(ctx: Expr[mill.define.Ctx]): Expr[Target[PathRef]] = {
497-
// import c.universe._
498-
499-
// val wrapped =
500-
// Applicative.impl0[Task, PathRef, mill.api.Ctx](c)(
501-
// '{value.splice.map(PathRef(_))).tree
502-
// )
503-
504-
// val taskIsPrivate = isPrivateTargetOption(c)
505-
506-
// mill.moduledefs.Cacher.impl0[Target[PathRef]](c)(
507-
// '{
508-
// new SourceImpl(
509-
// wrapped.splice,
510-
// ctx.splice,
511-
// taskIsPrivate.splice
512-
// )
513-
// }
514-
// )
515-
???
506+
)(value: Expr[Result[os.Path]])(
507+
ctx: Expr[mill.define.Ctx],
508+
caller: Expr[Applicative.Applyer[Task, Task, Result, mill.api.Ctx]]
509+
): Expr[Target[PathRef]] = {
510+
val wrapped =
511+
Applicative.impl[Task, Task, Result, PathRef, mill.api.Ctx](
512+
caller,
513+
'{ $value.map(PathRef(_)) }
514+
)
515+
516+
val taskIsPrivate = isPrivateTargetOption()
517+
518+
mill.moduledefs.Cacher.impl0[Target[PathRef]](
519+
'{
520+
new SourceImpl(
521+
$wrapped,
522+
$ctx,
523+
$taskIsPrivate
524+
)
525+
}
526+
)
516527
}
517528

518529
def sourceImpl2(using
519530
Quotes
520-
)(value: Expr[Result[PathRef]])(ctx: Expr[mill.define.Ctx]): Expr[Target[PathRef]] = {
521-
// import c.universe._
522-
523-
// val taskIsPrivate = isPrivateTargetOption(c)
524-
525-
// mill.moduledefs.Cacher.impl0[Target[PathRef]](c)(
526-
// '{
527-
// new SourceImpl(
528-
// Applicative.impl0[Task, PathRef, mill.api.Ctx](c)(value.tree).splice,
529-
// ctx.splice,
530-
// taskIsPrivate.splice
531-
// )
532-
// }
533-
// )
534-
???
531+
)(value: Expr[Result[PathRef]])(
532+
ctx: Expr[mill.define.Ctx],
533+
caller: Expr[Applicative.Applyer[Task, Task, Result, mill.api.Ctx]]
534+
): Expr[Target[PathRef]] = {
535+
val taskIsPrivate = isPrivateTargetOption()
536+
537+
val lhs = Applicative.impl[Task, Task, Result, PathRef, mill.api.Ctx](caller, value)
538+
mill.moduledefs.Cacher.impl0[Target[PathRef]](
539+
'{
540+
new SourceImpl(
541+
$lhs,
542+
$ctx,
543+
$taskIsPrivate
544+
)
545+
}
546+
)
535547
}
536548

537549
def inputImpl[T: Type](using Quotes)(value: Expr[Result[T]])(
@@ -560,56 +572,49 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] {
560572
w: Expr[W[T]],
561573
cls: Expr[EnclosingClass]
562574
): Expr[Command[T]] = {
563-
// import c.universe._
564-
565-
// val taskIsPrivate = isPrivateTargetOption(c)
566-
567-
// '{
568-
// new Command[T](
569-
// t.splice,
570-
// ctx.splice,
571-
// w.splice,
572-
// cls.splice.value,
573-
// taskIsPrivate.splice
574-
// }
575-
// )
576-
???
575+
val taskIsPrivate = isPrivateTargetOption()
576+
577+
'{
578+
new Command[T](
579+
$t,
580+
$ctx,
581+
$w,
582+
$cls.value,
583+
$taskIsPrivate
584+
)
585+
}
577586
}
578587

579-
def commandImpl[T: Type](using Quotes)(t: Expr[T])(
588+
def commandImpl[T: Type](using Quotes)(t: Expr[Result[T]])(
580589
w: Expr[W[T]],
581590
ctx: Expr[mill.define.Ctx],
582-
cls: Expr[EnclosingClass]
591+
cls: Expr[EnclosingClass],
592+
caller: Expr[Applicative.Applyer[Task, Task, Result, mill.api.Ctx]]
583593
): Expr[Command[T]] = {
584-
// import c.universe._
585-
586-
// val taskIsPrivate = isPrivateTargetOption(c)
587-
588-
// '{
589-
// new Command[T](
590-
// Applicative.impl[Task, Task, Result, T, mill.api.Ctx](c)(t).splice,
591-
// ctx.splice,
592-
// w.splice,
593-
// cls.splice.value,
594-
// taskIsPrivate.splice
595-
// }
596-
// )
597-
???
594+
val taskIsPrivate = isPrivateTargetOption()
595+
596+
val lhs = Applicative.impl[Task, Task, Result, T, mill.api.Ctx](caller, t)
597+
'{
598+
new Command[T](
599+
$lhs,
600+
$ctx,
601+
$w,
602+
$cls.value,
603+
$taskIsPrivate
604+
)
605+
}
598606
}
599607

600608
def workerImpl1[T: Type](using
601609
Quotes
602610
)(t: Expr[Task[T]])(ctx: Expr[mill.define.Ctx]): Expr[Worker[T]] = {
603-
// import c.universe._
604-
605-
// val taskIsPrivate = isPrivateTargetOption(c)
611+
val taskIsPrivate = isPrivateTargetOption()
606612

607-
// mill.moduledefs.Cacher.impl0[Worker[T]](
608-
// '{
609-
// new Worker[T](t.splice, ctx.splice, taskIsPrivate.splice)
610-
// }
611-
// )
612-
???
613+
mill.moduledefs.Cacher.impl0[Worker[T]](
614+
'{
615+
new Worker[T]($t, $ctx, $taskIsPrivate)
616+
}
617+
)
613618
}
614619

615620
def workerImpl2[T: Type](using

main/define/src/mill/moduledefs/Cacher.scala

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,39 +20,49 @@ object Cacher {
2020
// In Scala 3, the top level splice of a macro is owned by a symbol called "macro" with the macro flag set,
2121
// but not the method flag.
2222
def isMacroOwner(sym: Symbol)(using Quotes): Boolean =
23-
sym.name == "macro" && sym.flags.is(Flags.Macro | Flags.Synthetic) && !sym.flags.is(Flags.Method)
23+
sym.name == "macro" && sym.flags.is(Flags.Macro | Flags.Synthetic) && !sym.flags.is(
24+
Flags.Method
25+
)
2426

2527
def loop(owner: Symbol): T =
2628
if owner.isPackageDef || owner == Symbol.noSymbol then
27-
report.errorAndAbort("Cannot find the owner of the macro expansion", Position.ofMacroExpansion)
29+
report.errorAndAbort(
30+
"Cannot find the owner of the macro expansion",
31+
Position.ofMacroExpansion
32+
)
2833
else if isMacroOwner(owner) then op(owner.owner) // Skip the "macro" owner
2934
else loop(owner.owner)
3035

3136
loop(Symbol.spliceOwner)
3237
}
3338

34-
3539
def impl0[T: Type](using Quotes)(t: Expr[T]): Expr[T] = {
3640
import quotes.reflect.*
3741
wrapCached[T](t.asTerm).asExprOf[T]
3842
}
39-
def wrapCached[R: Type](using Quotes)(t: quotes.reflect.Tree): quotes.reflect.Tree = withMacroOwner { owner =>
40-
import quotes.reflect.*
43+
def wrapCached[R: Type](using Quotes)(t: quotes.reflect.Tree): quotes.reflect.Tree =
44+
withMacroOwner { owner =>
45+
import quotes.reflect.*
4146

42-
val CacherSym = TypeRepr.of[Cacher].typeSymbol
47+
val CacherSym = TypeRepr.of[Cacher].typeSymbol
4348

44-
val ownerIsCacherClass =
45-
owner.owner.isClassDef &&
46-
owner.owner.typeRef.baseClasses.contains(CacherSym)
49+
val ownerIsCacherClass =
50+
owner.owner.isClassDef &&
51+
owner.owner.typeRef.baseClasses.contains(CacherSym)
4752

48-
if (ownerIsCacherClass && owner.flags.is(Flags.Method)) {
49-
// q"this.cachedTarget[${weakTypeTag[R]}]($t)"
50-
val thisSel = This(owner.owner).asExprOf[Cacher]
51-
'{ $thisSel.cachedTarget[R](${t.asExprOf[R]}) }.asTerm
53+
if (ownerIsCacherClass && owner.flags.is(Flags.Method)) {
54+
// q"this.cachedTarget[${weakTypeTag[R]}]($t)"
55+
val enclosingCtx = Expr.summon[sourcecode.Enclosing].getOrElse(
56+
report.errorAndAbort("Cannot find enclosing context", Position.ofMacroExpansion)
57+
)
58+
59+
val thisSel = This(owner.owner).asExprOf[Cacher]
60+
val res = '{ $thisSel.cachedTarget[R](${ t.asExprOf[R] })(using $enclosingCtx) }.asTerm
61+
// report.errorAndAbort(s"cached ${res.show}", Position.ofMacroExpansion)
62+
res
63+
} else report.errorAndAbort(
64+
"T{} members must be defs defined in a Cacher class/trait/object body",
65+
Position.ofMacroExpansion
66+
)
5267
}
53-
else report.errorAndAbort(
54-
"T{} members must be defs defined in a Cacher class/trait/object body",
55-
Position.ofMacroExpansion
56-
)
57-
}
5868
}

main/define/test/src/mill/define/ApplicativeTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ object ApplicativeTests extends TestSuite {
2828
value
2929
}
3030
}
31-
// @compileTimeOnly("Target.ctx() can only be used with a T{...} block")
31+
@compileTimeOnly("Target.ctx() can only be used with a T{...} block")
3232
@ImplicitStub
3333
implicit def taskCtx: String = ???
3434

0 commit comments

Comments
 (0)