Skip to content

Commit 1e8c8a6

Browse files
authored
Merge pull request #3634 from dotty-staging/add-meta
A symmetric meta programming framework
2 parents 0cdc425 + 8f048a7 commit 1e8c8a6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1919
-245
lines changed

compiler/src/dotty/tools/dotc/CompilationUnit.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ class CompilationUnit(val source: SourceFile) {
2121

2222
/** Pickled TASTY binaries, indexed by class. */
2323
var pickled: Map[ClassSymbol, Array[Byte]] = Map()
24+
25+
/** Will be reset to `true` if `untpdTree` contains `Quote` trees. The information
26+
* is used in phase ReifyQuotes in order to avoid traversing a quote-less tree.
27+
*/
28+
var containsQuotesOrSplices: Boolean = false
2429
}
2530

2631
object CompilationUnit {

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ class Compiler {
4747
List(new sbt.ExtractAPI), // Sends a representation of the API of classes to sbt via callbacks
4848
List(new Pickler), // Generate TASTY info
4949
List(new LinkAll), // Reload compilation units from TASTY for library code (if needed)
50+
List(new ReifyQuotes), // Turn quoted trees into explicit run-time data structures
5051
List(new FirstTransform, // Some transformations to put trees into a canonical form
5152
new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars
52-
new ElimJavaPackages), // Eliminate syntactic references to Java packages
53+
new ElimPackagePrefixes), // Eliminate references to package prefixes in Select nodes
5354
List(new CheckStatic, // Check restrictions that apply to @static members
5455
new ElimRepeated, // Rewrite vararg parameters and arguments
5556
new NormalizeFlags, // Rewrite some definition flags
@@ -59,16 +60,16 @@ class Compiler {
5960
new ByNameClosures, // Expand arguments to by-name parameters to closures
6061
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
6162
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
62-
new ClassOf, // Expand `Predef.classOf` calls.
63-
new RefChecks), // Various checks mostly related to abstract members and overriding
63+
new ClassOf, // Expand `Predef.classOf` calls.
64+
new RefChecks), // Various checks mostly related to abstract members and overriding
6465
List(new TryCatchPatterns, // Compile cases in try/catch
6566
new PatternMatcher, // Compile pattern matches
6667
new ExplicitOuter, // Add accessors to outer classes from nested ones.
6768
new ExplicitSelf, // Make references to non-trivial self types explicit as casts
6869
new ShortcutImplicits, // Allow implicit functions without creating closures
6970
new CrossCastAnd, // Normalize selections involving intersection types.
7071
new Splitter), // Expand selections involving union types into conditionals
71-
List(new PhantomArgLift, // Extracts the evaluation of phantom arguments placing them before the call.
72+
List(new PhantomArgLift, // Extracts the evaluation of phantom arguments placing them before the call.
7273
new VCInlineMethods, // Inlines calls to value class methods
7374
new SeqLiterals, // Express vararg arguments as arrays
7475
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,8 @@ object desugar {
10691069
Select(t, op.name)
10701070
}
10711071
case PrefixOp(op, t) =>
1072-
Select(t, nme.UNARY_PREFIX ++ op.name)
1072+
val nspace = if (ctx.mode.is(Mode.Type)) tpnme else nme
1073+
Select(t, nspace.UNARY_PREFIX ++ op.name)
10731074
case Tuple(ts) =>
10741075
val arity = ts.length
10751076
def tupleTypeRef = defn.TupleType(arity)

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
264264
*/
265265
def lacksDefinition(mdef: MemberDef)(implicit ctx: Context) = mdef match {
266266
case mdef: ValOrDefDef =>
267-
mdef.unforcedRhs == EmptyTree && !mdef.name.isConstructorName && !mdef.mods.is(ParamAccessor)
267+
mdef.unforcedRhs == EmptyTree && !mdef.name.isConstructorName && !mdef.mods.is(TermParamOrAccessor)
268268
case mdef: TypeDef =>
269269
def isBounds(rhs: Tree): Boolean = rhs match {
270270
case _: TypeBoundsTree => true

compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import dotty.tools.dotc.transform.SymUtils._
3131
* gets two different denotations in the same period. Hence, if -Yno-double-bindings is
3232
* set, we would get a data race assertion error.
3333
*/
34-
final class TreeTypeMap(
34+
class TreeTypeMap(
3535
val typeMap: Type => Type = IdentityTypeMap,
3636
val treeMap: tpd.Tree => tpd.Tree = identity _,
3737
val oldOwners: List[Symbol] = Nil,
@@ -154,7 +154,7 @@ final class TreeTypeMap(
154154
assert(!to.exists(substFrom contains _))
155155
assert(!from.exists(newOwners contains _))
156156
assert(!to.exists(oldOwners contains _))
157-
new TreeTypeMap(
157+
newMap(
158158
typeMap,
159159
treeMap,
160160
from ++ oldOwners,
@@ -163,6 +163,16 @@ final class TreeTypeMap(
163163
to ++ substTo)
164164
}
165165

166+
/** A new map of the same class this one */
167+
protected def newMap(
168+
typeMap: Type => Type,
169+
treeMap: Tree => Tree,
170+
oldOwners: List[Symbol],
171+
newOwners: List[Symbol],
172+
substFrom: List[Symbol],
173+
substTo: List[Symbol])(implicit ctx: Context) =
174+
new TreeTypeMap(typeMap, treeMap, oldOwners, newOwners, substFrom, substTo)
175+
166176
/** Apply `typeMap` and `ownerMap` to given symbols `syms`
167177
* and return a treemap that contains the substitution
168178
* between original and mapped symbols.

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
104104
Closure(Nil, call, targetTpt))
105105
}
106106

107+
/** A closure whole anonymous function has the given method type */
108+
def Lambda(tpe: MethodType, rhsFn: List[Tree] => Tree)(implicit ctx: Context): Block = {
109+
val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic | Method, tpe)
110+
Closure(meth, tss => rhsFn(tss.head).changeOwner(ctx.owner, meth))
111+
}
112+
107113
def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef =
108114
ta.assignType(untpd.CaseDef(pat, guard, body), body)
109115

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
6969

7070
case class InfixOp(left: Tree, op: Ident, right: Tree) extends OpTree
7171
case class PostfixOp(od: Tree, op: Ident) extends OpTree
72-
case class PrefixOp(op: Ident, od: Tree) extends OpTree
72+
case class PrefixOp(op: Ident, od: Tree) extends OpTree {
73+
override def isType = op.isType
74+
override def isTerm = op.isTerm
75+
}
7376
case class Parens(t: Tree) extends ProxyTree {
7477
def forwardTo = t
7578
}
@@ -78,6 +81,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
7881
override def isType = !isTerm
7982
}
8083
case class Throw(expr: Tree) extends TermTree
84+
case class Quote(expr: Tree) extends TermTree
8185
case class WhileDo(cond: Tree, body: Tree) extends TermTree
8286
case class DoWhile(body: Tree, cond: Tree) extends TermTree
8387
case class ForYield(enums: List[Tree], expr: Tree) extends TermTree
@@ -449,6 +453,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
449453
case tree: Throw if expr eq tree.expr => tree
450454
case _ => finalize(tree, untpd.Throw(expr))
451455
}
456+
def Quote(tree: Tree)(expr: Tree) = tree match {
457+
case tree: Quote if expr eq tree.expr => tree
458+
case _ => finalize(tree, untpd.Quote(expr))
459+
}
452460
def WhileDo(tree: Tree)(cond: Tree, body: Tree) = tree match {
453461
case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree
454462
case _ => finalize(tree, untpd.WhileDo(cond, body))
@@ -507,6 +515,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
507515
cpy.Tuple(tree)(transform(trees))
508516
case Throw(expr) =>
509517
cpy.Throw(tree)(transform(expr))
518+
case Quote(expr) =>
519+
cpy.Quote(tree)(transform(expr))
510520
case WhileDo(cond, body) =>
511521
cpy.WhileDo(tree)(transform(cond), transform(body))
512522
case DoWhile(body, cond) =>
@@ -554,6 +564,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
554564
this(x, trees)
555565
case Throw(expr) =>
556566
this(x, expr)
567+
case Quote(expr) =>
568+
this(x, expr)
557569
case WhileDo(cond, body) =>
558570
this(this(x, cond), body)
559571
case DoWhile(body, cond) =>

compiler/src/dotty/tools/dotc/config/Printers.scala

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,27 @@ object Printers {
1111
}
1212

1313
val default: Printer = new Printer
14-
val dottydoc: Printer = noPrinter
15-
val core: Printer = noPrinter
16-
val typr: Printer = noPrinter
14+
1715
val constr: Printer = noPrinter
16+
val core: Printer = noPrinter
1817
val checks: Printer = noPrinter
19-
val overload: Printer = noPrinter
20-
val implicits: Printer = noPrinter
21-
val implicitsDetailed: Printer = noPrinter
22-
val subtyping: Printer = noPrinter
23-
val unapp: Printer = noPrinter
24-
val gadts: Printer = noPrinter
25-
val hk: Printer = noPrinter
26-
val variances: Printer = noPrinter
27-
val incremental: Printer = noPrinter
2818
val config: Printer = noPrinter
29-
val transforms: Printer = noPrinter
3019
val cyclicErrors: Printer = noPrinter
31-
val pickling: Printer = noPrinter
32-
val inlining: Printer = noPrinter
20+
val dottydoc: Printer = noPrinter
3321
val exhaustivity: Printer = noPrinter
22+
val incremental: Printer = noPrinter
23+
val gadts: Printer = noPrinter
24+
val hk: Printer = noPrinter
25+
val implicits: Printer = noPrinter
26+
val implicitsDetailed: Printer = noPrinter
27+
val inlining: Printer = noPrinter
28+
val overload: Printer = noPrinter
3429
val patmatch: Printer = noPrinter
30+
val pickling: Printer = noPrinter
3531
val simplify: Printer = noPrinter
32+
val subtyping: Printer = noPrinter
33+
val transforms: Printer = noPrinter
34+
val typr: Printer = noPrinter
35+
val unapp: Printer = noPrinter
36+
val variances: Printer = noPrinter
3637
}

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,15 @@ object Contexts {
359359
else if (untpd.isSuperConstrCall(stat) && this.owner.isClass) superCallContext
360360
else ctx.fresh.setOwner(exprOwner)
361361

362+
/** A new context that summarizes an import statement */
363+
def importContext(imp: Import[_], sym: Symbol) = {
364+
val impNameOpt = imp.expr match {
365+
case ref: RefTree[_] => Some(ref.name.asTermName)
366+
case _ => None
367+
}
368+
ctx.fresh.setImportInfo(new ImportInfo(implicit ctx => sym, imp.selectors, impNameOpt))
369+
}
370+
362371
/** The current source file; will be derived from current
363372
* compilation unit.
364373
*/

compiler/src/dotty/tools/dotc/core/Decorators.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ object Decorators {
175175
recur(enclosingInlineds, pos)
176176
}
177177

178+
implicit class reportingDeco[T](val x: T) extends AnyVal {
179+
def reporting(op: T => String): T = { println(op(x)); x }
180+
}
181+
178182
implicit class StringInterpolators(val sc: StringContext) extends AnyVal {
179183

180184
/** General purpose string formatting */

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package core
55
import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._
66
import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._, Periods._
77
import unpickleScala2.Scala2Unpickler.ensureConstructor
8-
import scala.annotation.{ switch, meta }
98
import scala.collection.{ mutable, immutable }
109
import PartialFunction._
1110
import collection.mutable
@@ -146,11 +145,20 @@ class Definitions {
146145
}
147146

148147
private def enterPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
149-
resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
148+
resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags,
149+
useCompleter: Boolean = false) = {
150150
val tparamNames = PolyType.syntheticParamNames(typeParamCount)
151151
val tparamInfos = tparamNames map (_ => TypeBounds.empty)
152-
val ptype = PolyType(tparamNames)(_ => tparamInfos, resultTypeFn)
153-
enterMethod(cls, name, ptype, flags)
152+
def ptype = PolyType(tparamNames)(_ => tparamInfos, resultTypeFn)
153+
val info =
154+
if (useCompleter)
155+
new LazyType {
156+
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
157+
denot.info = ptype
158+
}
159+
}
160+
else ptype
161+
enterMethod(cls, name, info, flags)
154162
}
155163

156164
private def enterT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
@@ -290,14 +298,23 @@ class Definitions {
290298
/** Marker method to indicate an argument to a call-by-name parameter.
291299
* Created by byNameClosures and elimByName, eliminated by Erasure,
292300
*/
293-
lazy val cbnArg = enterPolyMethod(
294-
OpsPackageClass, nme.cbnArg, 1,
301+
lazy val cbnArg = enterPolyMethod(OpsPackageClass, nme.cbnArg, 1,
295302
pt => MethodType(List(FunctionOf(Nil, pt.paramRefs(0))), pt.paramRefs(0)))
296303

297304
/** Method representing a throw */
298305
lazy val throwMethod = enterMethod(OpsPackageClass, nme.THROWkw,
299306
MethodType(List(ThrowableType), NothingType))
300307

308+
/** Method representing a term quote */
309+
lazy val quoteMethod = enterPolyMethod(OpsPackageClass, nme.QUOTE, 1,
310+
pt => MethodType(pt.paramRefs(0) :: Nil, QuotedExprType.appliedTo(pt.paramRefs(0) :: Nil)),
311+
useCompleter = true)
312+
313+
/** Method representing a type quote */
314+
lazy val typeQuoteMethod = enterPolyMethod(OpsPackageClass, nme.TYPE_QUOTE, 1,
315+
pt => QuotedTypeType.appliedTo(pt.paramRefs(0) :: Nil),
316+
useCompleter = true)
317+
301318
lazy val NothingClass: ClassSymbol = enterCompleteClassSymbol(
302319
ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyClass.typeRef))
303320
def NothingType = NothingClass.typeRef
@@ -585,6 +602,21 @@ class Definitions {
585602
def ClassTagClass(implicit ctx: Context) = ClassTagType.symbol.asClass
586603
def ClassTagModule(implicit ctx: Context) = ClassTagClass.companionModule
587604

605+
lazy val QuotedExprType = ctx.requiredClassRef("scala.quoted.Expr")
606+
def QuotedExprClass(implicit ctx: Context) = QuotedExprType.symbol.asClass
607+
608+
def QuotedExpr_~(implicit ctx: Context) = QuotedExprClass.requiredMethod(nme.UNARY_~)
609+
def QuotedExpr_run(implicit ctx: Context) = QuotedExprClass.requiredMethod(nme.run)
610+
611+
lazy val QuotedTypeType = ctx.requiredClassRef("scala.quoted.Type")
612+
def QuotedTypeClass(implicit ctx: Context) = QuotedTypeType.symbol.asClass
613+
614+
def QuotedType_~(implicit ctx: Context) =
615+
QuotedTypeClass.info.member(tpnme.UNARY_~).symbol.asType
616+
617+
def Unpickler_unpickleExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr")
618+
def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")
619+
588620
lazy val EqType = ctx.requiredClassRef("scala.Eq")
589621
def EqClass(implicit ctx: Context) = EqType.symbol.asClass
590622
def EqModule(implicit ctx: Context) = EqClass.companionModule
@@ -1071,7 +1103,8 @@ class Definitions {
10711103
OpsPackageClass)
10721104

10731105
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
1074-
lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)
1106+
lazy val syntheticCoreMethods =
1107+
AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod, quoteMethod, typeQuoteMethod)
10751108

10761109
lazy val reservedScalaClassNames: Set[Name] = syntheticScalaClasses.map(_.name).toSet
10771110

@@ -1081,13 +1114,13 @@ class Definitions {
10811114
def init()(implicit ctx: Context) = {
10821115
this.ctx = ctx
10831116
if (!_isInitialized) {
1084-
// force initialization of every symbol that is synthesized or hijacked by the compiler
1085-
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
1086-
10871117
// Enter all symbols from the scalaShadowing package in the scala package
10881118
for (m <- ScalaShadowingPackageClass.info.decls)
10891119
ScalaPackageClass.enter(m)
10901120

1121+
// force initialization of every symbol that is synthesized or hijacked by the compiler
1122+
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
1123+
10911124
_isInitialized = true
10921125
}
10931126
}

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ object Flags {
414414
/** A Scala 2.12 or higher trait */
415415
final val Scala_2_12_Trait = typeFlag(58, "<scala_2_12_trait>")
416416

417-
/** A macro (Scala 2.x only) */
417+
/** A macro */
418418
final val Macro = commonFlag(59, "<macro>")
419419

420420
/** A method that is known to have inherited default parameters */
@@ -575,7 +575,7 @@ object Flags {
575575
final val SyntheticOrPrivate = Synthetic | Private
576576

577577
/** A deferred member or a parameter accessor (these don't have right hand sides) */
578-
final val DeferredOrParamAccessor = Deferred | ParamAccessor
578+
final val DeferredOrParamOrAccessor = Deferred | Param | ParamAccessor
579579

580580
/** value that's final or inline */
581581
final val FinalOrInline = Final | Inline
@@ -598,6 +598,9 @@ object Flags {
598598
/** Is a default parameter in Scala 2*/
599599
final val DefaultParameter = allOf(Param, DefaultParameterized)
600600

601+
/** A Scala 2 Macro */
602+
final val Scala2Macro = allOf(Macro, Scala2x)
603+
601604
/** A trait that does not need to be initialized */
602605
final val NoInitsTrait = allOf(Trait, NoInits)
603606

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ object Phases {
276276
* and type applications.
277277
*/
278278
def relaxedTyping: Boolean = false
279+
280+
/** If set, implicit search is enabled */
281+
def allowsImplicitSearch: Boolean = false
282+
279283
/** List of names of phases that should precede this phase */
280284
def runsAfter: Set[Class[_ <: Phase]] = Set.empty
281285

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ object StdNames {
143143
val INITIALIZER_PREFIX: N = "initial$"
144144
val COMPANION_MODULE_METHOD: N = "companion$module"
145145
val COMPANION_CLASS_METHOD: N = "companion$class"
146+
val QUOTE: N = "'"
147+
val TYPE_QUOTE: N = "type_'"
146148
val TRAIT_SETTER_SEPARATOR: N = str.TRAIT_SETTER_SEPARATOR
147149

148150
// value types (and AnyRef) are all used as terms as well
@@ -484,6 +486,7 @@ object StdNames {
484486
val reflect : N = "reflect"
485487
val reify : N = "reify"
486488
val rootMirror : N = "rootMirror"
489+
val run: N = "run"
487490
val runOrElse: N = "runOrElse"
488491
val runtime: N = "runtime"
489492
val runtimeClass: N = "runtimeClass"

0 commit comments

Comments
 (0)