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

Integrate macro paradise under -Ymacro-annotations #6606

Merged
merged 1 commit into from
May 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

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