Skip to content

Commit

Permalink
Merge pull request #6606 from adriaanm/macro-annot
Browse files Browse the repository at this point in the history
Integrate macro paradise under `-Ymacro-annotations`
  • Loading branch information
adriaanm authored May 10, 2018
2 parents d0b1722 + 50077e9 commit c4adc81
Show file tree
Hide file tree
Showing 82 changed files with 3,602 additions and 13 deletions.
55 changes: 52 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@
* - to modularize the Scala compiler or library further
*/

import java.io.{PrintWriter, StringWriter}

import sbt.TestResult
import sbt.testing.TestSelector

import scala.build._
import VersionUtil._
import scala.tools.nsc.util.ScalaClassLoader.URLClassLoader

// Scala dependencies:
val partestDep = scalaDep("org.scala-lang.modules", "scala-partest", versionProp = "partest")
Expand Down Expand Up @@ -118,6 +117,34 @@ lazy val instanceSettings = Seq[Setting[_]](
Quiet.silenceScalaBinaryVersionWarning
)

// be careful with using this instance, as it may cause performance problems (e.g., MetaSpace exhaustion)r
lazy val quickInstanceSettings = Seq[Setting[_]](
organization := "org.scala-lang",
// we don't cross build Scala itself
crossPaths := false,
// do not add Scala library jar as a dependency automatically
autoScalaLibrary := false,
// Avoid circular dependencies for scalaInstance (see https://github.com/sbt/sbt/issues/1872)
managedScalaInstance := false,
scalaInstance := {
// TODO: express in terms of distDependencies?
val cpElems: Seq[java.io.File] = (fullClasspath in Compile in replFrontend).value.map(_.data) ++ (fullClasspath in Compile in scaladoc).value.map(_.data)
val libraryJar = cpElems.find(_.getPath.endsWith("classes/library")).get
val compilerJar = cpElems.find(_.getPath.endsWith("classes/compiler")).get
val extraJars = cpElems.filter(f => (f ne libraryJar) && (f ne compilerJar))
val v = (version in Global).value
new ScalaInstance(v, new URLClassLoader(cpElems.map(_.toURI.toURL).toArray[URL], null), libraryJar, compilerJar, extraJars, Some(v))
},
// As of sbt 0.13.12 (sbt/sbt#2634) sbt endeavours to align both scalaOrganization and scalaVersion
// in the Scala artefacts, for example scala-library and scala-compiler.
// This doesn't work in the scala/scala build because the version of scala-library and the scalaVersion of
// scala-library are correct to be different. So disable overriding.
ivyScala ~= (_ map (_ copy (overrideScalaVersion = false))),
Quiet.silenceScalaBinaryVersionWarning
)



lazy val commonSettings = instanceSettings ++ clearSourceAndResourceDirectories ++ publishSettings ++ Seq[Setting[_]](
// we always assume that Java classes are standalone and do not have any dependency
// on Scala classes
Expand Down Expand Up @@ -560,6 +587,27 @@ lazy val junit = project.in(file("test") / "junit")
unmanagedSourceDirectories in Test := List(baseDirectory.value)
)

// imported from scalamacros/paradise for the test suite -- TODO: integrate into build structure, get rid of quickInstanceSettings?
lazy val macroAnnot = project.in(file("test") / "macro-annot")
.dependsOn(library, reflect, compiler, repl, replFrontend, scaladoc)
.settings(disableDocs)
.settings(disablePublishing)
.settings(quickInstanceSettings) // use quick compiler as Scala Instance
.settings(
fork in Test := true,
javaOptions in Test += "-Xss1M",
libraryDependencies ++= Seq(junitDep, junitInterfaceDep),
testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-v",
s"-Dsbt.paths.tests.classpath=${(fullClasspath in Test).value.files.map(_.getAbsolutePath).mkString(java.io.File.pathSeparatorChar.toString)}"),

baseDirectory in Compile := (baseDirectory in ThisBuild).value,
baseDirectory in Test := (baseDirectory in ThisBuild).value,

scalacOptions += "-Ymacro-annotations",
scalacOptions += "-Ywarn-unused-import",
scalacOptions += "-Xfatal-warnings"
)

lazy val scalacheck = project.in(file("test") / "scalacheck")
.dependsOn(library, reflect, compiler, scaladoc)
.settings(clearSourceAndResourceDirectories)
Expand Down Expand Up @@ -804,6 +852,7 @@ lazy val root: Project = (project in file("."))
val results = ScriptCommands.sequence[(Result[Unit], String)](List(
(Keys.test in Test in junit).result map (_ -> "junit/test"),
(Keys.test in Test in scalacheck).result map (_ -> "scalacheck/test"),
(Keys.test in Test in macroAnnot).result map (_ -> "macroAnnot/test"),
(testOnly in IntegrationTest in testP).toTask(" -- run").result map (_ -> "partest run"),
(testOnly in IntegrationTest in testP).toTask(" -- pos neg jvm").result map (_ -> "partest pos neg jvm"),
(testOnly in IntegrationTest in testP).toTask(" -- res scalap specialized").result map (_ -> "partest res scalap specialized"),
Expand Down Expand Up @@ -871,7 +920,7 @@ lazy val root: Project = (project in file("."))
}
)
.aggregate(library, reflect, compiler, interactive, repl, replFrontend,
scaladoc, scalap, partestExtras, junit, scalaDist).settings(
scaladoc, scalap, partestExtras, junit, scalaDist, macroAnnot).settings(
sources in Compile := Seq.empty,
onLoadMessage := """|*** Welcome to the sbt build definition for Scala! ***
|Check README.md for more information.""".stripMargin
Expand Down
2 changes: 1 addition & 1 deletion project/ScalaOptionParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ object ScalaOptionParser {
"-Ybreak-cycles", "-Ydebug", "-Ycompact-trees", "-YdisableFlatCpCaching", "-Ydoc-debug",
"-Yide-debug", "-Yinfer-argument-types",
"-Yissue-debug", "-Ylog-classpath", "-Ymacro-debug-lite", "-Ymacro-debug-verbose", "-Ymacro-no-expand",
"-Yno-completion", "-Yno-generic-signatures", "-Yno-imports", "-Yno-predef",
"-Yno-completion", "-Yno-generic-signatures", "-Yno-imports", "-Yno-predef", "-Ymacro-annotations",
"-Yoverride-objects", "-Yoverride-vars", "-Ypatmat-debug", "-Yno-adapted-args", "-Ypos-debug", "-Ypresentation-debug",
"-Ypresentation-strict", "-Ypresentation-verbose", "-Yquasiquote-debug", "-Yrangepos", "-Yreify-copypaste", "-Yreify-debug", "-Yrepl-class-based",
"-Yrepl-sync", "-Yshow-member-pos", "-Yshow-symkinds", "-Yshow-symowners", "-Yshow-syms", "-Yshow-trees", "-Yshow-trees-compact", "-Yshow-trees-stringified", "-Ytyper-debug",
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/scala/tools/nsc/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
// I only changed analyzer.
//
// factory for phases: namer, packageobjects, typer
lazy val analyzer = new {
val global: Global.this.type = Global.this
} with Analyzer
lazy val analyzer =
if (settings.YmacroAnnotations) new { val global: Global.this.type = Global.this } with Analyzer with MacroAnnotationNamers
else new { val global: Global.this.type = Global.this } with Analyzer

// phaseName = "patmat"
object patmat extends {
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/scala/tools/nsc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
package scala.tools.nsc
package ast

import scala.reflect.internal.MacroAnnotionTreeInfo

/** This class ...
*
* @author Martin Odersky
* @version 1.0
*/
abstract class TreeInfo extends scala.reflect.internal.TreeInfo {
abstract class TreeInfo extends scala.reflect.internal.TreeInfo with MacroAnnotionTreeInfo {
val global: Global
import global._
import definitions._
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ trait ScalaSettings extends AbsScalaSettings
val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
val Ymacroexpand = ChoiceSetting ("-Ymacro-expand", "policy", "Control expansion of macros, useful for scaladoc and presentation compiler.", List(MacroExpand.Normal, MacroExpand.None, MacroExpand.Discard), MacroExpand.Normal)
val Ymacronoexpand = BooleanSetting ("-Ymacro-no-expand", "Don't expand macros. Might be useful for scaladoc and presentation compiler, but will crash anything which uses macros and gets past typer.") withDeprecationMessage(s"Use ${Ymacroexpand.name}:${MacroExpand.None}") withPostSetHook(_ => Ymacroexpand.value = MacroExpand.None)
val YmacroAnnotations = BooleanSetting ("-Ymacro-annotations", "Enable support for macro annotations, formerly in macro paradise.")
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
val Yreplclassbased = BooleanSetting ("-Yrepl-class-based", "Use classes to wrap REPL snippets instead of objects")
val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "")
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ trait Analyzer extends AnyRef
with TypeDiagnostics
with ContextErrors
with StdAttachments
with MacroAnnotationAttachments
with AnalyzerPlugins
{
val global : Global
Expand Down
62 changes: 62 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,68 @@ trait ContextErrors {

def MacroImplementationNotFoundError(expandee: Tree) =
macroExpansionError(expandee, macroImplementationNotFoundMessage(expandee.symbol.name))

def MacroAnnotationShapeError(clazz: Symbol) = {
val sym = clazz.info.member(nme.macroTransform)
var actualSignature = sym.toString
if (sym.isOverloaded) actualSignature += "(...) = ..."
else if (sym.isMethod) {
if (sym.typeParams.nonEmpty) {
def showTparam(tparam: Symbol) =
tparam.typeSignature match {
case tpe @ TypeBounds(_, _) => s"${tparam.name}$tpe"
case _ => tparam.name
}
def showTparams(tparams: List[Symbol]) = "[" + (tparams map showTparam mkString ", ") + "]"
actualSignature += showTparams(sym.typeParams)
}
if (sym.paramss.nonEmpty) {
def showParam(param: Symbol) = s"${param.name}: ${param.typeSignature}"
def showParams(params: List[Symbol]) = {
val s_mods = if (params.nonEmpty && params(0).hasFlag(scala.reflect.internal.Flags.IMPLICIT)) "implicit " else ""
val s_params = params map showParam mkString ", "
"(" + s_mods + s_params + ")"
}
def showParamss(paramss: List[List[Symbol]]) = paramss map showParams mkString ""
actualSignature += showParamss(sym.paramss)
}
if (sym.isTermMacro) actualSignature = actualSignature.replace("macro method", "def") + " = macro ..."
else actualSignature = actualSignature.replace("method", "def") + " = ..."
}
issueSymbolTypeError(clazz, s"""
|macro annotation has wrong shape:
| required: def macroTransform(annottees: Any*) = macro ...
| found : $actualSignature
""".trim.stripMargin)
}

def MacroAnnotationMustBeStaticError(clazz: Symbol) =
issueSymbolTypeError(clazz, s"macro annotation must extend scala.annotation.StaticAnnotation")

def MacroAnnotationCannotBeInheritedError(clazz: Symbol) =
issueSymbolTypeError(clazz, s"macro annotation cannot be @Inherited")

def MacroAnnotationCannotBeMemberError(clazz: Symbol) =
issueSymbolTypeError(clazz, s"macro annotation cannot be a member of another class")

def MacroAnnotationNotExpandedMessage: String = {
"macro annotation could not be expanded " + (
if (!settings.YmacroAnnotations) "(since these are experimental, you must enable them with -Ymacro-annotations)"
else "(you cannot use a macro annotation in the same compilation run that defines it)")
}

def MacroAnnotationOnlyDefinitionError(ann: Tree) =
issueNormalTypeError(ann, "macro annotations can only be put on definitions")

def MacroAnnotationTopLevelClassWithCompanionBadExpansion(ann: Tree) =
issueNormalTypeError(ann, "top-level class with companion can only expand into a block consisting in eponymous companions")

def MacroAnnotationTopLevelClassWithoutCompanionBadExpansion(ann: Tree) =
issueNormalTypeError(ann, "top-level class without companion can only expand either into an eponymous class or into a block consisting in eponymous companions")

def MacroAnnotationTopLevelModuleBadExpansion(ann: Tree) =
issueNormalTypeError(ann, "top-level object can only expand into an eponymous object")

}

/** This file will be the death of me. */
Expand Down
Loading

0 comments on commit c4adc81

Please sign in to comment.