diff options
Diffstat (limited to 'src')
112 files changed, 1335 insertions, 804 deletions
diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml deleted file mode 100644 index a2c3eefbca..0000000000 --- a/src/build/maven/maven-deploy.xml +++ /dev/null @@ -1,281 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- -THIS FILE WILL SOON SELF DESTRUCT; DO NOT USE -see publish.* targets in /build.xml ---> -<project name="sabbus-maven-deploy" xmlns:artifact="urn:maven-artifact-ant"> - - <description> - SuperSabbus extension for deploying a distribution to Maven. THIS FILE IS MEANT TO BE RUN STANDALONE IN THE MAVEN "distpack" DIRECTORY - </description> - - - <macrodef name="deploy-remote"> - <attribute name="jar" default=""/> - <attribute name="pom"/> - <element name="artifacts" implicit="true" optional="true"/> - <sequential> - <if><equals arg1="@{jar}" arg2="true"/><then> - <artifact:deploy settingsFile="${settings.file}"> - <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" /> - <artifact:pom refid="@{pom}" /> - <artifacts/> - </artifact:deploy> - </then><else> - <artifact:deploy file="@{jar}" settingsFile="${settings.file}"> - <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" /> - <artifact:pom refid="@{pom}" /> - <artifacts/> - </artifact:deploy> - </else></if> - </sequential> - </macrodef> - - <macrodef name="deploy-local"> - <attribute name="jar" default=""/> - <attribute name="pom"/> - <element name="artifacts" implicit="true" optional="true"/> - <sequential> - <if><equals arg1="@{jar}" arg2="true"/><then> - <artifact:install> - <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" /> - <artifact:pom refid="@{pom}" /> - <artifacts/> - </artifact:install> - </then><else> - <artifact:install file="@{jar}"> - <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" /> - <artifact:pom refid="@{pom}" /> - <artifacts/> - </artifact:install> - </else></if> - </sequential> - </macrodef> - - <macrodef name="deploy-to"> - <attribute name="jar" default=""/> - <attribute name="pom"/> - <attribute name="local"/> - <element name="artifacts" implicit="true" optional="true"/> - <sequential> - <if><equals arg1="@{local}" arg2="true"/><then> - <deploy-local jar="@{jar}" pom="@{pom}"> <artifacts/> </deploy-local> - </then><else> - <deploy-remote jar="@{jar}" pom="@{pom}"> <artifacts/> </deploy-remote> - </else></if> - </sequential> - </macrodef> - - <macrodef name="filter-pom"> - <attribute name="path" /> - <attribute name="name" /> - - <sequential> - <copy file="${path}-pom.xml" tofile="${path}-pom-filtered.xml" overwrite="true"> - <filterset> - <filter token="VERSION" value="${maven.version.number}" /> - <filter token="SCALA_BINARY_VERSION" value="${scala.binary.version}" /> - <filter token="XML_VERSION" value="${scala-xml.version.number}" /> - <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" /> - <filter token="CONTINUATIONS_PLUGIN_VERSION" value="${scala-continuations-plugin.version.number}" /> - <filter token="CONTINUATIONS_LIBRARY_VERSION" value="${scala-continuations-library.version.number}" /> - <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" /> - <filter token="RELEASE_REPOSITORY" value="${remote.release.repository}" /> - <filter token="SNAPSHOT_REPOSITORY" value="${remote.snapshot.repository}" /> - <filter token="JLINE_VERSION" value="${jline.version}" /> - <filter token="AKKA_ACTOR_VERSION" value="${akka-actor.version.number}" /> - <filter token="ACTORS_MIGRATION_VERSION" value="${actors-migration.version.number}" /> - - <!-- TODO modularize compiler. - <filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}" /> - <filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}" /> - --> - </filterset> - </copy> - <artifact:pom id="@{name}.pom" file="${path}-pom-filtered.xml" /> - </sequential> - </macrodef> - - <macrodef name="deploy-one"> - <attribute name="name" /> - <attribute name="local" default="false"/> - <attribute name="signed" default="false"/> - - <sequential> - <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/> - - <echo>Deploying ${path}-[pom.xml|src.jar|docs.jar].</echo> - - <filter-pom name="@{name}" path="@{path}"/> - - <if><equals arg1="@{signed}" arg2="false"/><then> - <if><isset property="docs.skip"/><then> - <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom"> - <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" /> - </deploy-to> - </then><else> - <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom"> - <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" /> - <artifact:attach type="jar" file="${path}-docs.jar" classifier="javadoc" /> - </deploy-to> - </else></if> - </then><else> - <local name="repo"/> - <if><equals arg1="@{local}" arg2="false"/><then> - <property name="repo" value="${remote.repository}"/> - </then><else> - <property name="repo" value="${local.repository}"/> - </else></if> - <artifact:mvn failonerror="true"> - <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" /> - <arg value="-Durl=${repo}" /> - <arg value="-DrepositoryId=${repository.credentials.id}" /> - <arg value="-DpomFile=${path}-pom-filtered.xml" /> - <arg value= "-Dfile=${path}.jar" /> - <arg value="-Dsources=${path}-src.jar" /> - <arg value="-Djavadoc=${path}-docs.jar" /> - <arg value="-Pgpg" /> - <arg value="-Dgpg.useagent=true" /> - </artifact:mvn> - </else></if> - </sequential> - </macrodef> - - <macrodef name="deploy-jar"> - <attribute name="name" /> - <attribute name="local" default="false"/> - <attribute name="signed" default="false"/> - - <sequential> - <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/> - - <echo>Deploying ${path}.jar with ${path}-pom.xml.</echo> - - <filter-pom name="@{name}" path="@{path}"/> - - <if><equals arg1="@{signed}" arg2="false"/><then> - <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom"/> - </then><else> - <local name="repo"/> - <if><equals arg1="@{local}" arg2="false"/><then> - <property name="repo" value="${remote.repository}"/> - </then><else> - <property name="repo" value="${local.repository}"/> - </else></if> - <artifact:mvn failonerror="true"> - <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" /> - <arg value="-Durl=${repo}" /> - <arg value="-DrepositoryId=${repository.credentials.id}" /> - <arg value="-DpomFile=${path}-pom-filtered.xml" /> - <arg value= "-Dfile=${path}.jar" /> - <arg value="-Pgpg" /> - <arg value="-Dgpg.useagent=true" /> - </artifact:mvn> - </else></if> - </sequential> - </macrodef> - - <macrodef name="deploy-pom"> - <attribute name="name" /> - <attribute name="local" default="false"/> - <attribute name="signed" default="false"/> - - <sequential> - <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/> - - <echo>Deploying ${path}-pom.xml.</echo> - - <filter-pom name="@{name}" path="@{path}"/> - - <if><equals arg1="@{signed}" arg2="false"/><then> - <deploy-to local="@{local}" pom="@{name}.pom"/> - </then><else> - <local name="repo"/> - <if><equals arg1="@{local}" arg2="false"/><then> - <property name="repo" value="${remote.repository}"/> - </then><else> - <property name="repo" value="${local.repository}"/> - </else></if> - <artifact:mvn failonerror="true"> - <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" /> - <arg value="-Durl=${repo}" /> - <arg value="-DrepositoryId=${repository.credentials.id}" /> - <arg value="-DpomFile=${path}-pom-filtered.xml" /> - <arg value= "-Dfile=${path}-pom-filtered.xml" /> - <arg value="-Pgpg" /> - <arg value="-Dgpg.useagent=true" /> - </artifact:mvn> - </else></if> - </sequential> - </macrodef> - - <macrodef name="deploy"> - <attribute name="local" default="false"/> - <attribute name="signed" default="false"/> - - <sequential> - <deploy-one name="scala-library" local="@{local}" signed="@{signed}"/> - <deploy-one name="scala-reflect" local="@{local}" signed="@{signed}"/> - <deploy-one name="scala-compiler" local="@{local}" signed="@{signed}"/> - - <!-- TODO modularize compiler. - <deploy-one name="scala-compiler-doc" local="@{local}" signed="@{signed}"/> - <deploy-one name="scala-compiler-interactive" local="@{local}" signed="@{signed}"/> - --> - - <deploy-one name="scala-actors" local="@{local}" signed="@{signed}"/> - <deploy-one name="scalap" local="@{local}" signed="@{signed}"/> - </sequential> - </macrodef> - - - <target name="boot.maven"> - <!-- Pull in properties from build --> - <property file="build.properties" /> - <!-- Set up Ant contrib tasks so we can use <if><then><else> instead of the clunky `unless` attribute --> - <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="ant-contrib.jar"/> - - <!-- Add our maven ant tasks --> - <path id="maven-ant-tasks.classpath" path="maven-ant-tasks-2.1.1.jar" /> - <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" /> - </target> - - <target name="init.maven" depends="boot.maven"> - <property name="remote.snapshot.repository" value="https://oss.sonatype.org/content/repositories/snapshots" /> - <property name="remote.release.repository" value="https://oss.sonatype.org/service/local/staging/deploy/maven2" /> - - <property name="local.snapshot.repository" value="${user.home}/.m2/repository" /> - <property name="local.release.repository" value="${user.home}/.m2/repository" /> - - <property name="repository.credentials.id" value="sonatype-nexus" /> - <property name="settings.file" value="${user.home}/.m2/settings.xml" /> - - <if><contains string="${maven.version.number}" substring="-SNAPSHOT"/><then> - <property name="remote.repository" value="${remote.snapshot.repository}"/> - <property name="local.repository" value="${local.snapshot.repository}"/> - </then><else> - <property name="remote.repository" value="${remote.release.repository}"/> - <property name="local.repository" value="${local.release.repository}"/> - </else></if> - - <echo>Using server[${repository.credentials.id}] for maven repository credentials. - Please make sure that your ~/.m2/settings.xml has the needed username/password for this server id - </echo> - </target> - - <target name="deploy" depends="init.maven" description="Deploys unsigned artifacts to the maven repo."> - <echo message="WARNING!1! THIS TARGET HAS BEEN DEPRECATED -- CALL `ant publish` FROM /build.xml"/> - <deploy/> - </target> - - <target name="deploy.local" depends="init.maven" description="Deploys unsigned artifacts to the local maven repo."> - <echo message="WARNING!1! THIS TARGET HAS BEEN DEPRECATED -- CALL `ant publish.local` FROM /build.xml"/> - <deploy local="true"/> - </target> - - <target name="deploy.signed" depends="init.maven" description="Deploys signed artifacts to the remote maven repo."> - <echo message="WARNING!1! THIS TARGET HAS BEEN DEPRECATED -- CALL `ant publish.signed` FROM /build.xml"/> - <deploy signed="true"/> - </target> -</project> diff --git a/src/build/maven/scala-dist-pom.xml b/src/build/maven/scala-dist-pom.xml index 9a566d231b..22a24dea21 100644 --- a/src/build/maven/scala-dist-pom.xml +++ b/src/build/maven/scala-dist-pom.xml @@ -39,6 +39,12 @@ <artifactId>scala-compiler</artifactId> <version>@VERSION@</version> </dependency> + <dependency> + <groupId>org.scala-lang.plugins</groupId> + <!-- plugins are fully cross-versioned. But, we don't publish with 2.11.0-SNAPSHOT, instead use full version of the last non-snapshot version --> + <artifactId>scala-continuations-plugin_@SCALA_FULL_VERSION@</artifactId> + <version>@CONTINUATIONS_PLUGIN_VERSION@</version> + </dependency> <!-- duplicated from scala-compiler, where it's optional, so that resolving scala-dist's transitive dependencies does not include jline, even though we need to include it in the dist, but macros depending on the compiler diff --git a/src/build/maven/scala-library-all-pom.xml b/src/build/maven/scala-library-all-pom.xml index b649c8c525..3fcf207559 100644 --- a/src/build/maven/scala-library-all-pom.xml +++ b/src/build/maven/scala-library-all-pom.xml @@ -49,11 +49,11 @@ <artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId> <version>@PARSER_COMBINATORS_VERSION@</version> </dependency> - <dependency> - <groupId>org.scala-lang.plugins</groupId> - <artifactId>scala-continuations-plugin_@SCALA_BINARY_VERSION@</artifactId> - <version>@CONTINUATIONS_PLUGIN_VERSION@</version> - </dependency> + <!-- + the continuations plugin is a dependency of scala-dist, as scala-library-all should be + a drop-in replacement for scala-library, and as such should not (indirectly) + depend on plugins/the compiler. + --> <dependency> <groupId>org.scala-lang.plugins</groupId> <artifactId>scala-continuations-library_@SCALA_BINARY_VERSION@</artifactId> diff --git a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala index 1413065a27..a13a778b2f 100644 --- a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala +++ b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala @@ -53,7 +53,7 @@ abstract class DefaultMacroCompiler extends Resolvers (EmptyTree, TermName(""), Nil) } val bundleImplRef = MacroImplRefCompiler( - atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Ident(Predef_???)))), methName), targs)), + atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Literal(Constant(null))))), methName), targs)), isImplBundle = true ) val vanillaResult = tryCompile(vanillaImplRef) diff --git a/src/compiler/scala/reflect/macros/contexts/Names.scala b/src/compiler/scala/reflect/macros/contexts/Names.scala index 299af40b94..5a5bb428b5 100644 --- a/src/compiler/scala/reflect/macros/contexts/Names.scala +++ b/src/compiler/scala/reflect/macros/contexts/Names.scala @@ -33,8 +33,9 @@ trait Names { // // TODO: hopefully SI-7823 will provide an ultimate answer to this problem. // In the meanwhile I will also keep open the original issue: SI-6879 "c.freshName is broken". + val prefix = if (name.endsWith("$")) name else name + "$" // SI-8425 val sortOfUniqueSuffix = freshNameCreator.newName(nme.FRESH_SUFFIX) - name + "$" + sortOfUniqueSuffix + prefix + sortOfUniqueSuffix } def freshName[NameType <: Name](name: NameType): NameType = diff --git a/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala index ecdd48db22..be114efbc0 100644 --- a/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala +++ b/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala @@ -14,7 +14,7 @@ trait JavaReflectionRuntimes { def resolveJavaReflectionRuntime(classLoader: ClassLoader): MacroRuntime = { val implClass = Class.forName(className, true, classLoader) - val implMeths = implClass.getDeclaredMethods.find(_.getName == methName) + val implMeths = implClass.getMethods.find(_.getName == methName) // relies on the fact that macro impls cannot be overloaded // so every methName can resolve to at maximum one method val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") } diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl index 88fee71843..f58223a39e 100644..100755 --- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl @@ -144,6 +144,10 @@ classpathArgs () { fi } +# SI-8358, SI-8368 -- the default should really be false, +# but I don't want to flip the default during 2.11's RC cycle +OVERRIDE_USEJAVACP="-Dscala.usejavacp=true" + while [[ $# -gt 0 ]]; do case "$1" in -D*) @@ -151,6 +155,8 @@ while [[ $# -gt 0 ]]; do # need it, e.g. communicating with a server compiler. java_args=("${java_args[@@]}" "$1") scala_args=("${scala_args[@@]}" "$1") + # respect user-supplied -Dscala.usejavacp + case "$1" in -Dscala.usejavacp*) OVERRIDE_USEJAVACP="";; esac shift ;; -J*) @@ -199,7 +205,7 @@ execCommand \ "${java_args[@@]}" \ $(classpathArgs) \ -Dscala.home="$SCALA_HOME" \ - -Dscala.usejavacp=true \ + $OVERRIDE_USEJAVACP \ "$EMACS_OPT" \ $WINDOWS_OPT \ @properties@ @class@ @toolflags@ "$@@" diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index 8441f3af23..cf0e003f10 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -25,6 +25,10 @@ shift :notoolcp +rem SI-8358, SI-8368 -- the default should really be false, +rem but I don't want to flip the default during 2.11's RC cycle +set _OVERRIDE_USEJAVACP="-Dscala.usejavacp=true" + rem We keep in _JAVA_PARAMS all -J-prefixed and -D-prefixed arguments set _JAVA_PARAMS= @@ -45,6 +49,10 @@ if "%_TEST_PARAM:~0,2%"=="-J" ( ) if "%_TEST_PARAM:~0,2%"=="-D" ( + rem Only match beginning of the -D option. The relevant bit is 17 chars long. + if "%_TEST_PARAM:~0,17%"=="-Dscala.usejavacp" ( + set _OVERRIDE_USEJAVACP= + ) rem test if this was double-quoted property "-Dprop=42" for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO ( if not "%%G" == "%_TEST_PARAM%" ( @@ -126,7 +134,7 @@ if "%_TOOL_CLASSPATH%"=="" ( if not "%_LINE_TOOLCP%"=="" call :add_cpath "%_LINE_TOOLCP%" -set _PROPS=-Dscala.home="!_SCALA_HOME!" -Denv.emacs="%EMACS%" -Dscala.usejavacp=true @properties@ +set _PROPS=-Dscala.home="!_SCALA_HOME!" -Denv.emacs="%EMACS%" %_OVERRIDE_USEJAVACP% @properties@ rem echo "%_JAVACMD%" %_JAVA_OPTS% %_PROPS% -cp "%_TOOL_CLASSPATH%" @class@ @toolflags@ %* "%_JAVACMD%" %_JAVA_OPTS% %_PROPS% -cp "%_TOOL_CLASSPATH%" @class@ @toolflags@ %* diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 6b14461cac..35eab94333 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -236,6 +236,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) override def inform(msg: String) = inform(NoPosition, msg) override def globalError(msg: String) = globalError(NoPosition, msg) override def warning(msg: String) = warning(NoPosition, msg) + override def deprecationWarning(pos: Position, msg: String) = currentUnit.deprecationWarning(pos, msg) def globalError(pos: Position, msg: String) = reporter.error(pos, msg) def warning(pos: Position, msg: String) = if (settings.fatalWarnings) globalError(pos, msg) else reporter.warning(pos, msg) @@ -1236,7 +1237,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } private val unitbuf = new SyncedCompilationBuffer - + val compiledFiles = new mutable.HashSet[String] /** A map from compiled top-level symbols to their source files */ @@ -1491,7 +1492,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) made to the underlying structure. */ def units: Iterator[CompilationUnit] = unitbuf.iterator - + def registerPickle(sym: Symbol): Unit = () /** does this run compile given class, module, or case factory? */ @@ -1798,8 +1799,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) private def writeICode() { val printer = new icodes.TextPrinter(null, icodes.linearizer) icodes.classes.values.foreach((cls) => { - val suffix = s"${if (cls.symbol.hasModuleFlag) "$" else ""}_${phase}.icode" - val file = getFile(cls.symbol, suffix) + val moduleSfx = if (cls.symbol.hasModuleFlag) "$" else "" + val phaseSfx = if (settings.debug) phase else "" // only for debugging, appending the full phasename breaks windows build + val file = getFile(cls.symbol, s"$moduleSfx$phaseSfx.icode") + try { val stream = new FileOutputStream(file) printer.setWriter(new PrintWriter(stream, true)) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 9ca06427e8..3652f51153 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -240,6 +240,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => registerLocal(sym.moduleClass) registerLocal(sym.companionClass) registerLocal(sym.companionModule) + registerLocal(sym.deSkolemize) sym match { case sym: TermSymbol => registerLocal(sym.referenced) case _ => ; @@ -309,7 +310,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // if we move these trees into lexical contexts different from their original locations. if (dupl.hasSymbol) { val sym = dupl.symbol - val vetoScope = !brutally && !(locals contains sym) + val vetoScope = !brutally && !(locals contains sym) && !(locals contains sym.deSkolemize) val vetoThis = dupl.isInstanceOf[This] && sym.isPackageClass if (!(vetoScope || vetoThis)) dupl.symbol = NoSymbol } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 3542fe5945..ffc45b21ea 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -654,9 +654,10 @@ self => def isIdentExcept(except: Name) = isIdent && in.name != except def isIdentOf(name: Name) = isIdent && in.name == name - def isUnaryOp = isIdent && raw.isUnary(in.name) - def isRawStar = isIdent && in.name == raw.STAR - def isRawBar = isIdent && in.name == raw.BAR + def isUnaryOp = isIdent && raw.isUnary(in.name) + def isRawStar = isRawIdent && in.name == raw.STAR + def isRawBar = isRawIdent && in.name == raw.BAR + def isRawIdent = in.token == IDENTIFIER def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw @@ -1001,19 +1002,30 @@ self => } def infixTypeRest(t: Tree, mode: InfixMode.Value): Tree = { - if (isIdent && in.name != nme.STAR) { - val opOffset = in.offset + // Detect postfix star for repeated args. + // Only RPAREN can follow, but accept COMMA and EQUALS for error's sake. + // Take RBRACE as a paren typo. + def checkRepeatedParam = if (isRawStar) { + lookingAhead (in.token match { + case RPAREN | COMMA | EQUALS | RBRACE => t + case _ => EmptyTree + }) + } else EmptyTree + def asInfix = { + val opOffset = in.offset val leftAssoc = treeInfo.isLeftAssoc(in.name) - if (mode != InfixMode.FirstOp) checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp) - val op = identForType() - val tycon = atPos(opOffset) { Ident(op) } + if (mode != InfixMode.FirstOp) + checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp) + val tycon = atPos(opOffset) { Ident(identForType()) } newLineOptWhenFollowing(isTypeIntroToken) def mkOp(t1: Tree) = atPos(t.pos.start, opOffset) { AppliedTypeTree(tycon, List(t, t1)) } if (leftAssoc) infixTypeRest(mkOp(compoundType()), InfixMode.LeftOp) else mkOp(infixType(InfixMode.RightOp)) - } else t + } + if (isIdent) checkRepeatedParam orElse asInfix + else t } /** {{{ @@ -3096,10 +3108,6 @@ self => stats ++= importClause() acceptStatSepOpt() } - else if (isExprIntro) { - stats += statement(InBlock) - if (!isCaseDefEnd) acceptStatSep() - } else if (isDefIntro || isLocalModifier || isAnnotation) { if (in.token == IMPLICIT) { val start = in.skipToken() @@ -3110,6 +3118,10 @@ self => } acceptStatSepOpt() } + else if (isExprIntro) { + stats += statement(InBlock) + if (!isCaseDefEnd) acceptStatSep() + } else if (isStatSep) { in.nextToken() } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 359e5d6c29..f800dbf9cd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -239,6 +239,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { } /* + * must-single-thread + */ + def serialVUID(csym: Symbol): Option[Long] = csym getAnnotation definitions.SerialVersionUIDAttr collect { + case AnnotationInfo(_, _, (_, LiteralAnnotArg(const)) :: Nil) => const.longValue + } + + /* * Populates the InnerClasses JVM attribute with `refedInnerClasses`. * In addition to inner classes mentioned somewhere in `jclass` (where `jclass` is a class file being emitted) * `refedInnerClasses` should contain those inner classes defined as direct member classes of `jclass` @@ -881,13 +888,6 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { val MIN_SWITCH_DENSITY = 0.7 /* - * must-single-thread - */ - def serialVUID(csym: Symbol): Option[Long] = csym getAnnotation definitions.SerialVersionUIDAttr collect { - case AnnotationInfo(_, Literal(const) :: _, _) => const.longValue - } - - /* * Add public static final field serialVersionUID with value `id` * * can-multi-thread diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index a389816caf..b7f9b30e19 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -1142,9 +1142,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { def isParcelableClass = isAndroidParcelableClass(clasz.symbol) - def serialVUID: Option[Long] = clasz.symbol getAnnotation SerialVersionUIDAttr collect { - case AnnotationInfo(_, Literal(const) :: _, _) => const.longValue - } + def serialVUID: Option[Long] = genBCode.serialVUID(clasz.symbol) private def getSuperInterfaces(c: IClass): Array[String] = { diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index bd2f6f0018..e036035397 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -600,7 +600,7 @@ abstract class Erasure extends AddInterfaces if (tree.symbol == NoSymbol) { tree } else if (name == nme.CONSTRUCTOR) { - if (tree.symbol.owner == AnyValClass) tree.symbol = ObjectClass.info.decl(nme.CONSTRUCTOR) + if (tree.symbol.owner == AnyValClass) tree.symbol = ObjectClass.primaryConstructor tree } else if (tree.symbol == Any_asInstanceOf) adaptMember(atPos(tree.pos)(Select(qual, Object_asInstanceOf))) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 8a7d30235f..d77c6b54a9 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -221,7 +221,9 @@ abstract class UnCurry extends InfoTransform def mkMethod(owner: Symbol, name: TermName, additionalFlags: FlagSet = NoFlags): DefDef = gen.mkMethodFromFunction(localTyper)(fun, owner, name, additionalFlags) - if (inlineFunctionExpansion) { + val canUseDelamdafyMethod = (inConstructorFlag == 0) // Avoiding synthesizing code prone to SI-6666, SI-8363 by using old-style lambda translation + + if (inlineFunctionExpansion || !canUseDelamdafyMethod) { val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe)) val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation anonClass setInfo ClassInfoType(parents, newScope, anonClass) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index e0bc478fad..fde0aca584 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -86,7 +86,7 @@ trait Logic extends Debugging { def mayBeNull: Boolean // compute the domain and return it (call registerNull first!) - def domainSyms: Option[Set[Sym]] + def domainSyms: Option[mutable.LinkedHashSet[Sym]] // the symbol for this variable being equal to its statically known type // (only available if registerEquality has been called for that type before) @@ -162,11 +162,18 @@ trait Logic extends Debugging { // to govern how much time we spend analyzing matches for unreachability/exhaustivity object AnalysisBudget { - private val budgetProp = scala.sys.Prop[Int]("scalac.patmat.analysisBudget") + private val budgetProp = scala.sys.Prop[String]("scalac.patmat.analysisBudget") private val budgetOff = "off" val max: Int = { val DefaultBudget = 256 - budgetProp.option.getOrElse(if (budgetProp.get.equalsIgnoreCase("off")) Integer.MAX_VALUE else DefaultBudget) + budgetProp.option match { + case Some(`budgetOff`) => + Integer.MAX_VALUE + case Some(x) => + x.toInt + case None => + DefaultBudget + } } abstract class Exception(val advice: String) extends RuntimeException("CNF budget exceeded") @@ -197,7 +204,7 @@ trait Logic extends Debugging { def removeVarEq(props: List[Prop], modelNull: Boolean = false): (Formula, List[Formula]) = { val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaVarEq) else null - val vars = new scala.collection.mutable.HashSet[Var] + val vars = mutable.LinkedHashSet[Var]() object gatherEqualities extends PropTraverser { override def apply(p: Prop) = p match { @@ -334,9 +341,9 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { // we enumerate the subtypes of the full type, as that allows us to filter out more types statically, // once we go to run-time checks (on Const's), convert them to checkable types // TODO: there seems to be bug for singleton domains (variable does not show up in model) - lazy val domain: Option[Set[Const]] = { - val subConsts = enumerateSubtypes(staticTp).map{ tps => - tps.toSet[Type].map{ tp => + lazy val domain: Option[mutable.LinkedHashSet[Const]] = { + val subConsts: Option[mutable.LinkedHashSet[Const]] = enumerateSubtypes(staticTp).map { tps => + mutable.LinkedHashSet(tps: _*).map{ tp => val domainC = TypeConst(tp) registerEquality(domainC) domainC @@ -479,7 +486,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { } // accessing after calling registerNull will result in inconsistencies - lazy val domainSyms: Option[Set[Sym]] = domain map { _ map symForEqualsTo } + lazy val domainSyms: Option[collection.mutable.LinkedHashSet[Sym]] = domain map { _ map symForEqualsTo } lazy val symForStaticTp: Option[Sym] = symForEqualsTo.get(TypeConst(staticTpCheckable)) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 699e98f963..4cf8980689 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -81,14 +81,14 @@ trait MatchTranslation { object SymbolAndTypeBound { def unapply(tree: Tree): Option[(Symbol, Type)] = tree match { - case SymbolBound(sym, SymbolAndTypeBound(_, tpe)) => Some(sym -> tpe) - case TypeBound(tpe) => Some(binder -> tpe) - case _ => None + case SymbolBound(sym, TypeBound(tpe)) => Some(sym -> tpe) + case TypeBound(tpe) => Some(binder -> tpe) + case _ => None } } object TypeBound { - def unapply(tree: Tree): Option[Type] = unbind(tree) match { + def unapply(tree: Tree): Option[Type] = tree match { case Typed(Ident(_), _) if tree.tpe != null => Some(tree.tpe) case _ => None } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 2043eb5d5d..9715fdaf00 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -359,6 +359,14 @@ trait ContextErrors { //setError(sel) } + def SelectWithUnderlyingError(sel: Tree, err: AbsTypeError) = { + // if there's no position, this is likely the result of a MissingRequirementError + // use the position of the selection we failed to type check to report the original message + if (err.errPos == NoPosition) issueNormalTypeError(sel, err.errMsg) + else issueTypeError(err) + setError(sel) + } + //typedNew def IsAbstractError(tree: Tree, sym: Symbol) = { issueNormalTypeError(tree, sym + " is abstract; cannot be instantiated") @@ -725,11 +733,18 @@ trait ContextErrors { NormalTypeError(expandee, "too many argument lists for " + fun) } - def MacroIncompatibleEngineError(macroEngine: String) = { - val message = s"macro cannot be expanded, because it was compiled by an incompatible macro engine $macroEngine" + private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = { + def debugDiagnostic = s"(internal diagnostic: $internalMessage)" + val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage issueNormalTypeError(lastTreeToTyper, message) } + def MacroCantExpand210xMacrosError(internalMessage: String) = + MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage) + + def MacroCantExpandIncompatibleMacrosError(internalMessage: String) = + MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage) + case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable protected def macroExpansionError(expandee: Tree, msg: String, pos: Position = NoPosition) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 98ee4ad94d..8e1ceffecd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -103,7 +103,7 @@ trait Contexts { self: Analyzer => // there must be a scala.xml package when xml literals were parsed in this unit if (unit.hasXml && ScalaXmlPackage == NoSymbol) - unit.error(unit.firstXmlPos, "To compile XML syntax, the scala.xml package must be on the classpath.\nPlease see https://github.com/scala/scala/wiki/Scala-2.11#xml.") + unit.error(unit.firstXmlPos, "To compile XML syntax, the scala.xml package must be on the classpath.\nPlease see http://docs.scala-lang.org/overviews/core/scala-2.11.html#scala-xml.") // scala-xml needs `scala.xml.TopScope` to be in scope globally as `$scope` // We detect `scala-xml` by looking for `scala.xml.TopScope` and @@ -433,8 +433,10 @@ trait Contexts { self: Analyzer => case _ => false } val isImport = tree match { - case _: Import => true - case _ => false + // The guard is for SI-8403. It prevents adding imports again in the context created by + // `Namer#createInnerNamer` + case _: Import if tree != this.tree => true + case _ => false } val sameOwner = owner == this.owner val prefixInChild = @@ -542,6 +544,8 @@ trait Contexts { self: Analyzer => if (checking) onTreeCheckerError(pos, msg) else unit.error(pos, msg) @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) { + // TODO: are errors allowed to have pos == NoPosition?? + // if not, Jason suggests doing: val pos = err.errPos.orElse( { devWarning("Que?"); context.tree.pos }) if (settings.Yissuedebug) { log("issue error: " + err.errMsg) (new Exception).printStackTrace() @@ -652,6 +656,13 @@ trait Contexts { self: Analyzer => c } + def enclosingNonImportContext: Context = { + var c = this + while (c != NoContext && c.tree.isInstanceOf[Import]) + c = c.outer + c + } + /** Is `sym` accessible as a member of `pre` in current context? */ def isAccessible(sym: Symbol, pre: Type, superAccess: Boolean = false): Boolean = { lastAccessCheckDetails = "" diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index c8ac3622e2..d87090fa46 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -82,7 +82,7 @@ trait Implicits { // `implicitSearchContext.undetparams`, *not* in `context.undetparams` // Here, we copy them up to parent context (analogously to the way the errors are copied above), // and then filter out any which *were* inferred and are part of the substitutor in the implicit search result. - context.undetparams = ((context.undetparams ++ implicitSearchContext.undetparams) filterNot result.subst.from.contains).distinct + context.undetparams = ((context.undetparams ++ result.undetparams) filterNot result.subst.from.contains).distinct if (Statistics.canEnable) Statistics.stopTimer(implicitNanos, start) if (Statistics.canEnable) Statistics.stopCounter(rawTypeImpl, rawTypeStart) @@ -162,8 +162,9 @@ trait Implicits { * @param tree The tree representing the implicit * @param subst A substituter that represents the undetermined type parameters * that were instantiated by the winning implicit. + * @param undetparams undeterminted type parameters */ - class SearchResult(val tree: Tree, val subst: TreeTypeSubstituter) { + class SearchResult(val tree: Tree, val subst: TreeTypeSubstituter, val undetparams: List[Symbol]) { override def toString = "SearchResult(%s, %s)".format(tree, if (subst.isEmpty) "" else subst) @@ -173,16 +174,16 @@ trait Implicits { final def isSuccess = !isFailure } - lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter, Nil) { override def isFailure = true } - lazy val DivergentSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + lazy val DivergentSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter, Nil) { override def isFailure = true override def isDivergent = true } - lazy val AmbiguousSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + lazy val AmbiguousSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter, Nil) { override def isFailure = true override def isAmbiguousFailure = true } @@ -719,7 +720,7 @@ trait Implicits { case Some(err) => fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg) case None => - val result = new SearchResult(unsuppressMacroExpansion(itree3), subst) + val result = new SearchResult(unsuppressMacroExpansion(itree3), subst, context.undetparams) if (Statistics.canEnable) Statistics.incCounter(foundImplicits) typingLog("success", s"inferred value of type $ptInstantiated is $result") result @@ -832,19 +833,41 @@ trait Implicits { * so that if there is a best candidate it can still be selected. */ object DivergentImplicitRecovery { - // symbol of the implicit that caused the divergence. - // Initially null, will be saved on first diverging expansion. - private var implicitSym: Symbol = _ - private var countdown: Int = 1 - - def sym: Symbol = implicitSym - def apply(search: SearchResult, i: ImplicitInfo): SearchResult = - if (search.isDivergent && countdown > 0) { - countdown -= 1 - implicitSym = i.sym - log(s"discarding divergent implicit $implicitSym during implicit search") + private var divergentError: Option[DivergentImplicitTypeError] = None + + private def saveDivergent(err: DivergentImplicitTypeError) { + if (divergentError.isEmpty) divergentError = Some(err) + } + + def issueSavedDivergentError() { + divergentError foreach (err => context.issue(err)) + } + + def apply(search: SearchResult, i: ImplicitInfo, errors: Seq[AbsTypeError]): SearchResult = { + // A divergent error from a nested implicit search will be found in `errors`. Stash that + // aside to be re-issued if this implicit search fails. + errors.collectFirst { case err: DivergentImplicitTypeError => err } foreach saveDivergent + + if (search.isDivergent && divergentError.isEmpty) { + // Divergence triggered by `i` at this level of the implicit serach. We haven't + // seen divergence so far, we won't issue this error just yet, and instead temporarily + // treat `i` as a failed candidate. + saveDivergent(DivergentImplicitTypeError(tree, pt, i.sym)) + log(s"discarding divergent implicit ${i.sym} during implicit search") SearchFailure - } else search + } else { + if (search.isFailure) { + // We don't want errors that occur during checking implicit info + // to influence the check of further infos, but we should retain divergent implicit errors + // (except for the one we already squirreled away) + val saved = divergentError.getOrElse(null) + context.reportBuffer.retainErrors { + case err: DivergentImplicitTypeError => err ne saved + } + } + search + } + } } /** Sorted list of eligible implicits. @@ -868,31 +891,33 @@ trait Implicits { * - if it matches, forget about all others it improves upon */ @tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match { - case Nil => acc - case i :: is => - DivergentImplicitRecovery(typedImplicit(i, ptChecked = true, isLocalToCallsite), i) match { - case sr if sr.isDivergent => - Nil - case sr if sr.isFailure => - // We don't want errors that occur during checking implicit info - // to influence the check of further infos. - context.reportBuffer.retainErrors { - case err: DivergentImplicitTypeError => true + case Nil => acc + case firstPending :: otherPending => + def firstPendingImproves(alt: ImplicitInfo) = + firstPending == alt || ( + try improves(firstPending, alt) + catch { + case e: CyclicReference => + debugwarn(s"Discarding $firstPending during implicit search due to cyclic reference.") + true } - rankImplicits(is, acc) - case newBest => - best = newBest - val newPending = undoLog undo { - is filterNot (alt => alt == i || { - try improves(i, alt) - catch { - case e: CyclicReference => - debugwarn(s"Discarding $i during implicit search due to cyclic reference") - true - } - }) + ) + + val typedFirstPending = typedImplicit(firstPending, ptChecked = true, isLocalToCallsite) + + // Pass the errors to `DivergentImplicitRecovery` so that it can note + // the first `DivergentImplicitTypeError` that is being propagated + // from a nested implicit search; this one will be + // re-issued if this level of the search fails. + DivergentImplicitRecovery(typedFirstPending, firstPending, context.errors) match { + case sr if sr.isDivergent => Nil + case sr if sr.isFailure => rankImplicits(otherPending, acc) + case newBest => + best = newBest // firstPending is our new best, since we already pruned last time around: + val pendingImprovingBest = undoLog undo { + otherPending filterNot firstPendingImproves } - rankImplicits(newPending, i :: acc) + rankImplicits(pendingImprovingBest, firstPending :: acc) } } @@ -920,12 +945,9 @@ trait Implicits { } if (best.isFailure) { - /* If there is no winner, and we witnessed and caught divergence, - * now we can throw it for the error message. - */ - if (DivergentImplicitRecovery.sym != null) { - DivergingImplicitExpansionError(tree, pt, DivergentImplicitRecovery.sym)(context) - } + // If there is no winner, and we witnessed and recorded a divergence error, + // our recovery attempt has failed, so we must now issue it. + DivergentImplicitRecovery.issueSavedDivergentError() if (invalidImplicits.nonEmpty) setAddendum(pos, () => @@ -1126,7 +1148,7 @@ trait Implicits { val tree1 = typedPos(pos.focus)(arg) context.firstError match { case Some(err) => processMacroExpansionError(err.errPos, err.errMsg) - case None => new SearchResult(tree1, EmptyTreeTypeSubstituter) + case None => new SearchResult(tree1, EmptyTreeTypeSubstituter, Nil) } } catch { case ex: TypeError => @@ -1196,7 +1218,7 @@ trait Implicits { def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass) def mot(tp0: Type, from: List[Symbol], to: List[Type]): SearchResult = { implicit def wrapResult(tree: Tree): SearchResult = - if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to)) + if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to), Nil) val tp1 = tp0.dealias tp1 match { @@ -1284,7 +1306,7 @@ trait Implicits { } def wrapResult(tree: Tree): SearchResult = - if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter) + if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter, Nil) /** Materializes implicits of predefined types (currently, manifests and tags). * Will be replaced by implicit macros once we fix them. diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index b42113c84f..fc0e2c7c80 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -578,13 +578,21 @@ trait Infer extends Checkable { */ private[typechecker] def isApplicableBasedOnArity(tpe: Type, argsCount: Int, varargsStar: Boolean, tuplingAllowed: Boolean): Boolean = followApply(tpe) match { case OverloadedType(pre, alts) => + // followApply may return an OverloadedType (tpe is a value type with multiple `apply` methods) alts exists (alt => isApplicableBasedOnArity(pre memberType alt, argsCount, varargsStar, tuplingAllowed)) case _ => val paramsCount = tpe.params.length + // simpleMatch implies we're not using defaults val simpleMatch = paramsCount == argsCount val varargsTarget = isVarArgsList(tpe.params) + + // varargsMatch implies we're not using defaults, as varargs and defaults are mutually exclusive def varargsMatch = varargsTarget && (paramsCount - 1) <= argsCount + // another reason why auto-tupling is a bad idea: it can hide the use of defaults, so must rule those out explicitly def tuplingMatch = tuplingAllowed && eligibleForTupleConversion(paramsCount, argsCount, varargsTarget) + // varargs and defaults are mutually exclusive, so not using defaults if `varargsTarget` + // we're not using defaults if there are (at least as many) arguments as parameters (not using exact match to allow for tupling) + def notUsingDefaults = varargsTarget || paramsCount <= argsCount // A varargs star call, e.g. (x, y:_*) can only match a varargs method // with the same number of parameters. See SI-5859 for an example of what @@ -592,7 +600,7 @@ trait Infer extends Checkable { if (varargsStar) varargsTarget && simpleMatch else - simpleMatch || varargsMatch || tuplingMatch + simpleMatch || varargsMatch || (tuplingMatch && notUsingDefaults) } private[typechecker] def followApply(tp: Type): Type = tp match { @@ -633,7 +641,7 @@ trait Infer extends Checkable { if (pos == -1) { if (positionalAllowed) { // treat assignment as positional argument argPos(index) = index - res = UnitTpe + res = UnitTpe // TODO: this is a bit optimistic, the name may not refer to a mutable variable... } else // unknown parameter name namesOK = false } else if (argPos.contains(pos)) { // parameter specified twice @@ -1316,21 +1324,33 @@ trait Infer extends Checkable { * @param varargsStar true if the call site has a `: _*` attached to the last argument */ private def overloadsToConsiderBySpecificity(eligible: List[Symbol], argtpes: List[Type], varargsStar: Boolean): List[Symbol] = { + // TODO spec: this namesMatch business is not spec'ed, and is the wrong fix for SI-4592 + // we should instead clarify what the spec means by "typing each argument with an undefined expected type". + // What does typing a named argument entail when we don't know what the valid parameter names are? + // (Since we're doing overload resolution, there are multiple alternatives that can define different names.) + // Luckily, the next step checks applicability to the individual alternatives, so it knows whether an assignment is: + // 1) a valid named argument + // 2) a well-typed assignment + // 3) an error (e.g., rhs does not refer to a variable) + // + // For now, the logic is: // If there are any foo=bar style arguments, and any of the overloaded - // methods has a parameter named `foo`, then only those methods are considered. - val namesMatch = namesOfNamedArguments(argtpes) match { + // methods has a parameter named `foo`, then only those methods are considered when we must disambiguate. + def namesMatch = namesOfNamedArguments(argtpes) match { case Nil => Nil case names => eligible filter (m => names forall (name => m.info.params exists (p => paramMatchesName(p, name)))) } - if (namesMatch.nonEmpty) - namesMatch - else if (eligible.isEmpty || eligible.tail.isEmpty) - eligible + if (eligible.isEmpty || eligible.tail.isEmpty) eligible else - eligible filter (alt => - !alt.info.params.exists(_.hasDefault) // run/t8197b first parameter list only! - && isApplicableBasedOnArity(alt.tpe, argtpes.length, varargsStar, tuplingAllowed = true) - ) + namesMatch match { + case namesMatch if namesMatch.nonEmpty => namesMatch // TODO: this has no basis in the spec, remove! + case _ => + // If there are multiple applicable alternatives, drop those using default arguments. + // This is done indirectly by checking applicability based on arity in `isApplicableBasedOnArity`. + // If defaults are required in the application, the arities won't match up exactly. + // TODO: should we really allow tupling here?? (If we don't, this is the only call-site with `tuplingAllowed = true`) + eligible filter (alt => isApplicableBasedOnArity(alt.tpe, argtpes.length, varargsStar, tuplingAllowed = true)) + } } /** Assign `tree` the type of an alternative which is applicable diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 677c94e063..9cf92ca5b9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -224,7 +224,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { val Apply(_, pickledPayload) = wrapped val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap - def fail(msg: String) = abort(s"bad macro impl binding: $msg") + import typer.TyperErrorGen._ + def fail(msg: String) = MacroCantExpandIncompatibleMacrosError(msg) def unpickle[T](field: String, clazz: Class[T]): T = { def failField(msg: String) = fail(s"$field $msg") if (!payload.contains(field)) failField("is supposed to be there") @@ -236,8 +237,9 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { raw.asInstanceOf[T] } + if (!payload.contains("macroEngine")) MacroCantExpand210xMacrosError("macroEngine field not found") val macroEngine = unpickle("macroEngine", classOf[String]) - if (self.macroEngine != macroEngine) typer.TyperErrorGen.MacroIncompatibleEngineError(macroEngine) + if (self.macroEngine != macroEngine) MacroCantExpandIncompatibleMacrosError(s"expected = ${self.macroEngine}, actual = $macroEngine") val isBundle = unpickle("isBundle", classOf[Boolean]) val isBlackbox = unpickle("isBlackbox", classOf[Boolean]) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index b166bf988d..4540017b62 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -132,7 +132,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans defaultMethodNames.toList.distinct foreach { name => val methods = clazz.info.findMember(name, 0L, requiredFlags = METHOD, stableOnly = false).alternatives - val haveDefaults = methods filter (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name)) + def hasDefaultParam(tpe: Type): Boolean = tpe match { + case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe) + case _ => false + } + val haveDefaults = methods filter ( + if (settings.isScala211) + (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name)) + else + (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name)) + ) if (haveDefaults.lengthCompare(1) > 0) { val owners = haveDefaults map (_.owner) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 87da565142..9b9e641cad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -346,12 +346,14 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT * performance hit for the compiler as a whole. */ override def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = { + val savedValid = validCurrentOwner if (owner.isClass) validCurrentOwner = true val savedLocalTyper = localTyper localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner) typers = typers updated (owner, localTyper) val result = super.atOwner(tree, owner)(trans) localTyper = savedLocalTyper + validCurrentOwner = savedValid typers -= owner result } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 14aa25eeb8..bf98c0e3dc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -197,7 +197,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper !from.isError && !to.isError && context.implicitsEnabled - && (inferView(EmptyTree, from, to, reportAmbiguous = false) != EmptyTree) + && (inferView(context.tree, from, to, reportAmbiguous = false, saveErrors = true) != EmptyTree) + // SI-8230 / SI-8463 We'd like to change this to `saveErrors = false`, but can't. + // For now, we can at least pass in `context.tree` rather then `EmptyTree` so as + // to avoid unpositioned type errors. ) def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = @@ -1041,11 +1044,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (tree.tpe <:< AnyTpe) pt.dealias match { case TypeRef(_, UnitClass, _) => // (12) if (settings.warnValueDiscard) - context.unit.warning(tree.pos, "discarded non-Unit value") + context.warning(tree.pos, "discarded non-Unit value") return typedPos(tree.pos, mode, pt)(Block(List(tree), Literal(Constant(())))) case TypeRef(_, sym, _) if isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt) => if (settings.warnNumericWiden) - context.unit.warning(tree.pos, "implicit numeric widening") + context.warning(tree.pos, "implicit numeric widening") return typedPos(tree.pos, mode, pt)(Select(tree, "to" + sym.name)) case _ => } @@ -2479,7 +2482,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * an alternative TODO: add partial function AST node or equivalent and get rid of this synthesis --> do everything in uncurry (or later) * however, note that pattern matching codegen is designed to run *before* uncurry */ - def synthesizePartialFunction(paramName: TermName, paramPos: Position, tree: Tree, mode: Mode, pt: Type): Tree = { + def synthesizePartialFunction(paramName: TermName, paramPos: Position, paramSynthetic: Boolean, + tree: Tree, mode: Mode, pt: Type): Tree = { assert(pt.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt.") val targs = pt.dealiasWiden.typeArgs @@ -2507,7 +2511,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val casesTrue = cases map (c => deriveCaseDef(c)(x => atPos(x.pos.focus)(TRUE)).duplicate.asInstanceOf[CaseDef]) // must generate a new tree every time - def selector: Tree = gen.mkUnchecked( + def selector(paramSym: Symbol): Tree = gen.mkUnchecked( if (sel != EmptyTree) sel.duplicate else atPos(tree.pos.focusStart)( // SI-6925: subsume type of the selector to `argTp` @@ -2518,7 +2522,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // hence the cast, which will be erased in posterasure // (the cast originally caused extremely weird types to show up // in test/scaladoc/run/SI-5933.scala because `variantToSkolem` was missing `tpSym.initialize`) - gen.mkCastPreservingAnnotations(Ident(paramName), argTp) + gen.mkCastPreservingAnnotations(Ident(paramSym), argTp) )) def mkParam(methodSym: Symbol, tp: Type = argTp) = @@ -2546,14 +2550,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper methodSym setInfo polyType(List(A1, B1), MethodType(paramSyms, B1.tpe)) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) - // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) + if (!paramSynthetic) methodBodyTyper.context.scope enter x // First, type without the default case; only the cases provided // by the user are typed. The LUB of these becomes `B`, the lower // bound of `B1`, which in turn is the result type of the default // case - val match0 = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val match0 = methodBodyTyper.typedMatch(selector(x), cases, mode, resTp) val matchResTp = match0.tpe B1 setInfo TypeBounds.lower(matchResTp) // patch info @@ -2627,11 +2630,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val paramSym = mkParam(methodSym) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - methodBodyTyper.context.scope enter paramSym + if (!paramSynthetic) methodBodyTyper.context.scope enter paramSym methodSym setInfo MethodType(List(paramSym), BooleanTpe) val defaultCase = mkDefaultCase(FALSE) - val match_ = methodBodyTyper.typedMatch(selector, casesTrue :+ defaultCase, mode, BooleanTpe) + val match_ = methodBodyTyper.typedMatch(selector(paramSym), casesTrue :+ defaultCase, mode, BooleanTpe) DefDef(methodSym, methodBodyTyper.virtualizedMatch(match_, mode, BooleanTpe)) } @@ -2645,10 +2648,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper methodSym setInfo MethodType(List(paramSym), AnyTpe) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) - // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - methodBodyTyper.context.scope enter paramSym + if (!paramSynthetic) methodBodyTyper.context.scope enter paramSym - val match_ = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val match_ = methodBodyTyper.typedMatch(selector(paramSym), cases, mode, resTp) val matchResTp = match_.tpe methodSym setInfo MethodType(List(paramSym), matchResTp) // patch info @@ -2920,7 +2922,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val p = fun.vparams.head if (p.tpt.tpe == null) p.tpt setType outerTyper.typedType(p.tpt).tpe - outerTyper.synthesizePartialFunction(p.name, p.pos, fun.body, mode, pt) + outerTyper.synthesizePartialFunction(p.name, p.pos, paramSynthetic = false, fun.body, mode, pt) // Use synthesizeSAMFunction to expand `(p1: T1, ..., pN: TN) => body` // to an instance of the corresponding anonymous subclass of `pt`. @@ -3214,10 +3216,23 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper args.map { case arg @ AssignOrNamedArg(Ident(name), rhs) => // named args: only type the righthand sides ("unknown identifier" errors otherwise) - val rhs1 = typedArg0(rhs) // the assign is untyped; that's ok because we call doTypedApply - val arg1 = treeCopy.AssignOrNamedArg(arg, arg.lhs, rhs1) - (arg1, NamedType(name, rhs1.tpe.deconst)) + val typedRhs = typedArg0(rhs) + val argWithTypedRhs = treeCopy.AssignOrNamedArg(arg, arg.lhs, typedRhs) + + // TODO: SI-8197/SI-4592: check whether this named argument could be interpreted as an assign + // infer.checkNames must not use UnitType: it may not be a valid assignment, or the setter may return another type from Unit + // + // var typedAsAssign = true + // val argTyped = silent(_.typedArg(argWithTypedRhs, amode, BYVALmode, WildcardType)) orElse { errors => + // typedAsAssign = false + // argWithTypedRhs + // } + // + // TODO: add an assignmentType field to NamedType, equal to: + // assignmentType = if (typedAsAssign) argTyped.tpe else NoType + + (argWithTypedRhs, NamedType(name, typedRhs.tpe.deconst)) case arg @ treeInfo.WildcardStarArg(repeated) => val arg1 = typedArg0(arg) (arg1, RepeatedType(arg1.tpe.deconst)) @@ -3933,7 +3948,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * - simplest solution: have two method calls * */ - def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { + def mkInvoke(context: Context, tree: Tree, qual: Tree, name: Name): Option[Tree] = { + val cxTree = context.enclosingNonImportContext.tree // SI-8364 debuglog(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") val treeInfo.Applied(treeSelection, _, _) = tree def isDesugaredApply = { @@ -4193,7 +4209,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val cases = tree.cases if (selector == EmptyTree) { if (pt.typeSymbol == PartialFunctionClass) - synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, tree, mode, pt) + synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, paramSynthetic = true, tree, mode, pt) else { val arity = if (isFunctionType(pt)) pt.dealiasWiden.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield @@ -4595,7 +4611,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper t } def typedSelectInternal(tree: Tree, qual: Tree, name: Name): Tree = { - def asDynamicCall = dyna.mkInvoke(context.tree, tree, qual, name) map { t => + def asDynamicCall = dyna.mkInvoke(context, tree, qual, name) map { t => dyna.wrapErrors(t, (_.typed1(t, mode, pt))) } @@ -4656,8 +4672,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case SilentTypeError(err: AccessTypeError) => (tree1, Some(err)) case SilentTypeError(err) => - context issue err - return setError(tree) + SelectWithUnderlyingError(tree, err) + return tree case SilentResultValue(treeAndPre) => (stabilize(treeAndPre._1, treeAndPre._2, mode, pt), None) } @@ -5095,7 +5111,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def isPlausible(m: Symbol) = m.alternatives exists (m => requiresNoArgs(m.info)) def maybeWarn(s: String): Unit = { - def warn(message: String) = context.unit.warning(lit.pos, s"$message Did you forget the interpolator?") + def warn(message: String) = context.warning(lit.pos, s"$message Did you forget the interpolator?") def suspiciousSym(name: TermName) = context.lookupSymbol(name, _ => true).symbol def suspiciousExpr = InterpolatorCodeRegex findFirstIn s def suspiciousIdents = InterpolatorIdentRegex findAllIn s map (s => suspiciousSym(s drop 1)) diff --git a/src/compiler/scala/tools/reflect/FormatInterpolator.scala b/src/compiler/scala/tools/reflect/FormatInterpolator.scala index 0258002850..e0f9bb6044 100644 --- a/src/compiler/scala/tools/reflect/FormatInterpolator.scala +++ b/src/compiler/scala/tools/reflect/FormatInterpolator.scala @@ -93,7 +93,8 @@ abstract class FormatInterpolator { case '\n' => "\\n" case '\f' => "\\f" case '\r' => "\\r" - case '\"' => "\\u0022" // $" in future + case '\"' => "${'\"'}" /* avoid lint warn */ + + " or a triple-quoted literal \"\"\"with embedded \" or \\u0022\"\"\"" // $" in future case '\'' => "'" case '\\' => """\\""" case x => "\\u%04x" format x diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala index 8376fca4ad..68cc728eb3 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala @@ -43,13 +43,13 @@ trait Holes { self: Quasiquotes => tpe <:< NothingClass.tpe || tpe <:< NullClass.tpe private def extractIterableTParam(tpe: Type) = IterableTParam.asSeenFrom(tpe, IterableClass) - private def stripIterable(tpe: Type, limit: Option[Rank] = None): (Rank, Type) = - if (limit.map { _ == NoDot }.getOrElse { false }) (NoDot, tpe) + private def stripIterable(tpe: Type, limit: Rank = DotDotDot): (Rank, Type) = + if (limit == NoDot) (NoDot, tpe) else if (tpe != null && !isIterableType(tpe)) (NoDot, tpe) else if (isBottomType(tpe)) (NoDot, tpe) else { val targ = extractIterableTParam(tpe) - val (rank, innerTpe) = stripIterable(targ, limit.map { _.pred }) + val (rank, innerTpe) = stripIterable(targ, limit.pred) (rank.succ, innerTpe) } private def iterableTypeFromRank(n: Rank, tpe: Type): Type = { @@ -76,10 +76,12 @@ trait Holes { self: Quasiquotes => class ApplyHole(annotatedRank: Rank, unquotee: Tree) extends Hole { val (strippedTpe, tpe): (Type, Type) = { - val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = Some(annotatedRank)) + val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = annotatedRank) if (isBottomType(strippedTpe)) cantSplice() - else if (isNativeType(strippedTpe)) (strippedTpe, iterableTypeFromRank(annotatedRank, strippedTpe)) - else if (isLiftableType(strippedTpe)) (strippedTpe, iterableTypeFromRank(annotatedRank, treeType)) + else if (isNativeType(strippedTpe)) { + if (strippedRank != NoDot && !(strippedTpe <:< treeType) && !isLiftableType(strippedTpe)) cantSplice() + else (strippedTpe, iterableTypeFromRank(annotatedRank, strippedTpe)) + } else if (isLiftableType(strippedTpe)) (strippedTpe, iterableTypeFromRank(annotatedRank, treeType)) else cantSplice() } @@ -191,7 +193,7 @@ trait Holes { self: Quasiquotes => val (iterableRank, _) = stripIterable(tpe) if (iterableRank.value < rank.value) c.abort(pat.pos, s"Can't extract $tpe with $rank, consider using $iterableRank") - val (_, strippedTpe) = stripIterable(tpe, limit = Some(rank)) + val (_, strippedTpe) = stripIterable(tpe, limit = rank) if (strippedTpe <:< treeType) treeNoUnlift else unlifters.spawn(strippedTpe, rank).map { diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 3b93a8933d..b68022afd9 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -22,7 +22,8 @@ trait Parsers { self: Quasiquotes => def parse(code: String): Tree = { try { val file = new BatchSourceFile(nme.QUASIQUOTE_FILE, code) - new QuasiquoteParser(file).parseRule(entryPoint) + val parser = new QuasiquoteParser(file) + parser.checkNoEscapingPlaceholders { parser.parseRule(entryPoint) } } catch { case mi: MalformedInput => c.abort(correspondingPosition(mi.offset), mi.msg) } @@ -30,15 +31,15 @@ trait Parsers { self: Quasiquotes => def correspondingPosition(offset: Int): Position = { val posMapList = posMap.toList - def containsOffset(start: Int, end: Int) = start <= offset && offset <= end + def containsOffset(start: Int, end: Int) = start <= offset && offset < end def fallbackPosition = posMapList match { case (pos1, (start1, end1)) :: _ if start1 > offset => pos1 - case _ :+ ((pos2, (start2, end2))) if offset > end2 => pos2.withPoint(pos2.point + (end2 - start2)) + case _ :+ ((pos2, (start2, end2))) if end2 <= offset => pos2.withPoint(pos2.point + (end2 - start2)) } posMapList.sliding(2).collect { - case (pos1, (start1, end1)) :: _ if containsOffset(start1, end1) => (pos1, offset - start1) - case (pos1, (_, end1)) :: (_, (start2, _)) :: _ if containsOffset(end1, start2) => (pos1, end1) - case _ :: (pos2, (start2, end2)) :: _ if containsOffset(start2, end2) => (pos2, offset - start2) + case (pos1, (start1, end1)) :: _ if containsOffset(start1, end1) => (pos1, offset - start1) + case (pos1, (start1, end1)) :: (pos2, (start2, _)) :: _ if containsOffset(end1, start2) => (pos1, end1 - start1) + case _ :: (pos2, (start2, end2)) :: _ if containsOffset(start2, end2) => (pos2, offset - start2) }.map { case (pos, offset) => pos.withPoint(pos.point + offset) }.toList.headOption.getOrElse(fallbackPosition) @@ -118,6 +119,8 @@ trait Parsers { self: Quasiquotes => override def isTemplateIntro: Boolean = super.isTemplateIntro || (isHole && lookingAhead { isTemplateIntro }) + override def isDefIntro: Boolean = super.isDefIntro || (isHole && lookingAhead { isDefIntro }) + override def isDclIntro: Boolean = super.isDclIntro || (isHole && lookingAhead { isDclIntro }) override def isStatSep(token: Int) = token == EOF || super.isStatSep(token) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index 5986758c2b..b287971815 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -17,7 +17,7 @@ trait Placeholders { self: Quasiquotes => // Step 1: Transform Scala source with holes into vanilla Scala source - lazy val posMap = mutable.ListMap[Position, (Int, Int)]() + lazy val posMap = mutable.LinkedHashMap[Position, (Int, Int)]() lazy val code = { val sb = new StringBuilder() val sessionSuffix = randomUUID().toString.replace("-", "").substring(0, 8) + "$" @@ -40,9 +40,7 @@ trait Placeholders { self: Quasiquotes => val iargs = method match { case nme.apply => args - case nme.unapply => - val (dummy @ Ident(nme.SELECTOR_DUMMY)) :: Nil = args - internal.subpatterns(dummy).get + case nme.unapply => internal.subpatterns(args.head).get case _ => global.abort("unreachable") } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala index 396688c437..b33069181c 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala @@ -51,7 +51,7 @@ abstract class Quasiquotes extends Parsers def sreified = reified .toString - .replace("scala.reflect.runtime.`package`.universe.build.", "") + .replace("scala.reflect.runtime.`package`.universe.internal.reificationSupport.", "") .replace("scala.reflect.runtime.`package`.universe.", "") .replace("scala.collection.immutable.", "") debug(s"reified tree:\n$sreified\n") diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 61fb22bc73..95113d5b00 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -131,6 +131,10 @@ trait Reifiers { self: Quasiquotes => case Placeholder(Hole(tree, NoDot)) if isReifyingPatterns => tree case Placeholder(hole @ Hole(_, rank @ Dot())) => c.abort(hole.pos, s"Can't $action with $rank here") case TuplePlaceholder(args) => reifyTuple(args) + // Due to greediness of syntactic applied we need to pre-emptively peek inside. + // `rest` will always be non-empty due to the rule on top of this one. + case SyntacticApplied(id @ Ident(nme.QUASIQUOTE_TUPLE), first :: rest) => + mirrorBuildCall(nme.SyntacticApplied, reifyTreePlaceholder(Apply(id, first)), reify(rest)) case TupleTypePlaceholder(args) => reifyTupleType(args) case FunctionTypePlaceholder(argtpes, restpe) => reifyFunctionType(argtpes, restpe) case CasePlaceholder(hole) => hole.tree @@ -151,21 +155,20 @@ trait Reifiers { self: Quasiquotes => mirrorCall(nme.This, tree) case SyntacticTraitDef(mods, name, tparams, earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticTraitDef, mods, name, tparams, earlyDefs, parents, selfdef, body) - case SyntacticClassDef(mods, name, tparams, constrmods, vparamss, earlyDefs, parents, selfdef, body) => - reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, vparamss, - earlyDefs, parents, selfdef, body) + case SyntacticClassDef(mods, name, tparams, constrmods, vparamss, + earlyDefs, parents, selfdef, body) => + mirrorBuildCall(nme.SyntacticClassDef, reify(mods), reify(name), reify(tparams), reify(constrmods), + reifyVparamss(vparamss), reify(earlyDefs), reify(parents), + reify(selfdef), reify(body)) case SyntacticPackageObjectDef(name, earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticPackageObjectDef, name, earlyDefs, parents, selfdef, body) case SyntacticObjectDef(mods, name, earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticObjectDef, mods, name, earlyDefs, parents, selfdef, body) case SyntacticNew(earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body) - case SyntacticDefDef(mods, name, tparams, build.ImplicitParams(vparamss, implparams), tpt, rhs) => - if (implparams.nonEmpty) - mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams), - reifyBuildCall(nme.ImplicitParams, vparamss, implparams), reify(tpt), reify(rhs)) - else - reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) + case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) => + mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams), + reifyVparamss(vparamss), reify(tpt), reify(rhs)) case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType => reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) case SyntacticVarDef(mods, name, tpt, rhs) => @@ -186,14 +189,32 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticApplied, fun, argss) case SyntacticTypeApplied(fun, targs) if targs.nonEmpty => reifyBuildCall(nme.SyntacticTypeApplied, fun, targs) + case SyntacticAppliedType(tpt, targs) if targs.nonEmpty => + reifyBuildCall(nme.SyntacticAppliedType, tpt, targs) case SyntacticFunction(args, body) => reifyBuildCall(nme.SyntacticFunction, args, body) - case SyntacticIdent(name, isBackquoted) => - reifyBuildCall(nme.SyntacticIdent, name, isBackquoted) case SyntacticEmptyTypeTree() => reifyBuildCall(nme.SyntacticEmptyTypeTree) case SyntacticImport(expr, selectors) => reifyBuildCall(nme.SyntacticImport, expr, selectors) + case SyntacticPartialFunction(cases) => + reifyBuildCall(nme.SyntacticPartialFunction, cases) + case SyntacticMatch(scrutinee, cases) => + reifyBuildCall(nme.SyntacticMatch, scrutinee, cases) + case SyntacticTermIdent(name, isBackquoted) => + reifyBuildCall(nme.SyntacticTermIdent, name, isBackquoted) + case SyntacticTypeIdent(name) => + reifyBuildCall(nme.SyntacticTypeIdent, name) + case SyntacticCompoundType(parents, defns) => + reifyBuildCall(nme.SyntacticCompoundType, parents, defns) + case SyntacticSingletonType(ref) => + reifyBuildCall(nme.SyntacticSingletonType, ref) + case SyntacticTypeProjection(qual, name) => + reifyBuildCall(nme.SyntacticTypeProjection, qual, name) + case SyntacticAnnotatedType(tpt, annot) => + reifyBuildCall(nme.SyntacticAnnotatedType, tpt, annot) + case SyntacticExistentialType(tpt, where) => + reifyBuildCall(nme.SyntacticExistentialType, tpt, where) case Q(tree) if fillListHole.isDefinedAt(tree) => mirrorBuildCall(nme.SyntacticBlock, fillListHole(tree)) case Q(other) => @@ -202,16 +223,21 @@ trait Reifiers { self: Quasiquotes => // not to cause infinite recursion. case block @ SyntacticBlock(stats) if block.isInstanceOf[Block] => reifyBuildCall(nme.SyntacticBlock, stats) + case SyntheticUnit() => + reifyBuildCall(nme.SyntacticBlock, Nil) case Try(block, catches, finalizer) => reifyBuildCall(nme.SyntacticTry, block, catches, finalizer) - case Match(selector, cases) => - reifyBuildCall(nme.SyntacticMatch, selector, cases) + case CaseDef(pat, guard, body) if fillListHole.isDefinedAt(body) => + mirrorCall(nme.CaseDef, reify(pat), reify(guard), mirrorBuildCall(nme.SyntacticBlock, fillListHole(body))) // parser emits trees with scala package symbol to ensure // that some names hygienically point to various scala package // members; we need to preserve this symbol to preserve // correctness of the trees produced by quasiquotes case Select(id @ Ident(nme.scala_), name) if id.symbol == ScalaPackage => reifyBuildCall(nme.ScalaDot, name) + case Select(qual, name) => + val ctor = if (name.isTypeName) nme.SyntacticSelectType else nme.SyntacticSelectTerm + reifyBuildCall(ctor, qual, name) case _ => super.reifyTreeSyntactically(tree) } @@ -266,6 +292,12 @@ trait Reifiers { self: Quasiquotes => def reifyPackageStat(hole: Hole) = reifyConstructionCheck(nme.mkPackageStat, hole) + def reifyVparamss(vparamss: List[List[ValDef]]) = { + val build.ImplicitParams(paramss, implparams) = vparamss + if (implparams.isEmpty) reify(paramss) + else reifyBuildCall(nme.ImplicitParams, paramss, implparams) + } + /** Splits list into a list of groups where subsequent elements are considered * similar by the corresponding function. * diff --git a/src/intellij/README b/src/intellij/README index ade87749cd..a39691f4f0 100644 --- a/src/intellij/README +++ b/src/intellij/README @@ -1,8 +1,12 @@ Use the latest IntelliJ IDEA release and install the Scala plugin from within the IDE. +Compilation withing IDEA is performed in "-Dlocker.skip=1" mode: the sources are built +directly using the STARR compiler. + The following steps are required to use IntelliJ IDEA on Scala trunk - - compile "locker" using "ant locker.done". This will also download some JARs from - Maven to ./build/deps, which are included in IntelliJ's classpath. + - Run "ant init". This will download some JARs from to ./build/deps, which are + included in IntelliJ's classpath. - Run src/intellij/setup.sh - Open ./src/intellij/scala-lang.ipr in IntelliJ - - File, Project Settings, Project, SDK. Create an SDK entry named "1.6" containing the java 1.6 SDK + - File, Project Settings, Project, SDK. Create an SDK entry named "1.6" containing the + java 1.6 SDK diff --git a/src/intellij/actors.iml.SAMPLE b/src/intellij/actors.iml.SAMPLE index 896c4966ff..b15af8b110 100644 --- a/src/intellij/actors.iml.SAMPLE +++ b/src/intellij/actors.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> diff --git a/src/intellij/compiler.iml.SAMPLE b/src/intellij/compiler.iml.SAMPLE index 9fb9cd55eb..50253000ab 100644 --- a/src/intellij/compiler.iml.SAMPLE +++ b/src/intellij/compiler.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> @@ -19,8 +20,8 @@ <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module" module-name="library" /> <orderEntry type="module" module-name="reflect" /> - <orderEntry type="module" module-name="asm" exported="" /> - <orderEntry type="library" exported="" name="ant" level="project" /> + <orderEntry type="module" module-name="asm" /> + <orderEntry type="library" name="ant" level="project" /> </component> </module> diff --git a/src/intellij/interactive.iml.SAMPLE b/src/intellij/interactive.iml.SAMPLE index c6c8ebb606..83178021d3 100644 --- a/src/intellij/interactive.iml.SAMPLE +++ b/src/intellij/interactive.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> @@ -23,3 +24,4 @@ <orderEntry type="module" module-name="scaladoc" /> </component> </module> + diff --git a/src/intellij/library.iml.SAMPLE b/src/intellij/library.iml.SAMPLE index cac53dff15..137ce6eb9c 100644 --- a/src/intellij/library.iml.SAMPLE +++ b/src/intellij/library.iml.SAMPLE @@ -4,8 +4,9 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> - <option name="compilerOptions" value="-sourcepath $BASE_DIR$/src/library" /> + <option name="compilerLibraryName" value="starr" /> + <option name="compilerOptions" value="-sourcepath $MODULE_DIR$/../library" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> diff --git a/src/intellij/manual.iml.SAMPLE b/src/intellij/manual.iml.SAMPLE index 3295a4a877..8babde73ea 100644 --- a/src/intellij/manual.iml.SAMPLE +++ b/src/intellij/manual.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> @@ -18,8 +19,8 @@ <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module" module-name="library" /> - <orderEntry type="module" module-name="xml" /> <orderEntry type="library" name="ant" level="project" /> + <orderEntry type="library" name="scaladoc-deps" level="project" /> </component> </module> diff --git a/src/intellij/partest-extras.iml.SAMPLE b/src/intellij/partest-extras.iml.SAMPLE new file mode 100644 index 0000000000..c2ada43493 --- /dev/null +++ b/src/intellij/partest-extras.iml.SAMPLE @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="FacetManager"> + <facet type="scala" name="Scala"> + <configuration> + <option name="compilerLibraryLevel" value="Project" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> + </configuration> + </facet> + </component> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$/../partest-extras"> + <sourceFolder url="file://$MODULE_DIR$/../partest-extras" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="asm" /> + <orderEntry type="module" module-name="library" /> + <orderEntry type="module" module-name="reflect" /> + <orderEntry type="module" module-name="compiler" /> + <orderEntry type="module" module-name="repl" /> + <orderEntry type="library" name="partest" level="project" /> + </component> +</module> + diff --git a/src/intellij/partest-javaagent.iml.SAMPLE b/src/intellij/partest-javaagent.iml.SAMPLE new file mode 100644 index 0000000000..e47e0f6349 --- /dev/null +++ b/src/intellij/partest-javaagent.iml.SAMPLE @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$/../partest-javaagent"> + <sourceFolder url="file://$MODULE_DIR$/../partest-javaagent" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="asm" /> + </component> +</module> + diff --git a/src/intellij/reflect.iml.SAMPLE b/src/intellij/reflect.iml.SAMPLE index 7d10522826..d206304896 100644 --- a/src/intellij/reflect.iml.SAMPLE +++ b/src/intellij/reflect.iml.SAMPLE @@ -4,8 +4,9 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> - <option name="compilerOptions" value="-sourcepath $BASE_DIR$/src/reflect" /> + <option name="compilerLibraryName" value="starr" /> + <option name="compilerOptions" value="-sourcepath $MODULE_DIR$/../reflect" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> @@ -19,7 +20,6 @@ <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module" module-name="library" /> - <orderEntry type="library" name="jline" level="project" /> </component> </module> diff --git a/src/intellij/repl.iml.SAMPLE b/src/intellij/repl.iml.SAMPLE index fc78ffe8c2..83791f4f6e 100644 --- a/src/intellij/repl.iml.SAMPLE +++ b/src/intellij/repl.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> @@ -23,3 +24,4 @@ <orderEntry type="library" name="repl-deps" level="project" /> </component> </module> + diff --git a/src/intellij/scala-lang.ipr.SAMPLE b/src/intellij/scala-lang.ipr.SAMPLE index a0765b3e99..c0614c946c 100644 --- a/src/intellij/scala-lang.ipr.SAMPLE +++ b/src/intellij/scala-lang.ipr.SAMPLE @@ -1,8 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="AntConfiguration"> - <defaultAnt bundledAnt="true" /> - </component> <component name="CompilerConfiguration"> <option name="DEFAULT_COMPILER" value="Javac" /> <resourceExtensions> @@ -21,11 +18,13 @@ <entry name="?*.tld" /> <entry name="?*.ftl" /> </wildcardResourcePatterns> - <annotationProcessing enabled="false" useClasspath="true" /> - </component> - <component name="CopyrightManager" default=""> - <module2copyright /> + <annotationProcessing> + <profile default="true" name="Default" enabled="false"> + <processorPath useClasspath="true" /> + </profile> + </annotationProcessing> </component> + <component name="CopyrightManager" default="" /> <component name="DependencyValidationManager"> <option name="SKIP_IMPORT_STATEMENTS" value="false" /> </component> @@ -41,11 +40,16 @@ <profile version="1.0" is_locked="false"> <option name="myName" value="Project Default" /> <option name="myLocal" value="false" /> + <inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" /> + <option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" /> + </inspection_tool> <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> <option name="processCode" value="true" /> <option name="processLiterals" value="true" /> <option name="processComments" value="true" /> </inspection_tool> + <inspection_tool class="UnitMethodIsParameterless" enabled="false" level="WARNING" enabled_by_default="false" /> </profile> </profiles> <option name="PROJECT_PROFILE" value="Project Default" /> @@ -53,7 +57,7 @@ <version value="1.0" /> </component> <component name="JavacSettings"> - <option name="ADDITIONAL_OPTIONS_STRING" value="-source 1.5 -target 1.5" /> + <option name="ADDITIONAL_OPTIONS_STRING" value="-source 1.6 -target 1.6" /> </component> <component name="JavadocGenerationManager"> <option name="OUTPUT_DIRECTORY" /> @@ -205,12 +209,15 @@ <module fileurl="file://$PROJECT_DIR$/interactive.iml" filepath="$PROJECT_DIR$/interactive.iml" /> <module fileurl="file://$PROJECT_DIR$/library.iml" filepath="$PROJECT_DIR$/library.iml" /> <module fileurl="file://$PROJECT_DIR$/manual.iml" filepath="$PROJECT_DIR$/manual.iml" /> + <module fileurl="file://$PROJECT_DIR$/partest-extras.iml" filepath="$PROJECT_DIR$/partest-extras.iml" /> + <module fileurl="file://$PROJECT_DIR$/partest-javaagent.iml" filepath="$PROJECT_DIR$/partest-javaagent.iml" /> <module fileurl="file://$PROJECT_DIR$/reflect.iml" filepath="$PROJECT_DIR$/reflect.iml" /> <module fileurl="file://$PROJECT_DIR$/repl.iml" filepath="$PROJECT_DIR$/repl.iml" /> <module fileurl="file://$PROJECT_DIR$/scala.iml" filepath="$PROJECT_DIR$/scala.iml" /> <module fileurl="file://$PROJECT_DIR$/scaladoc.iml" filepath="$PROJECT_DIR$/scaladoc.iml" /> <module fileurl="file://$PROJECT_DIR$/scalap.iml" filepath="$PROJECT_DIR$/scalap.iml" /> <module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" /> + <module fileurl="file://$PROJECT_DIR$/test-junit.iml" filepath="$PROJECT_DIR$/test-junit.iml" /> </modules> </component> <component name="ProjectResources"> @@ -234,45 +241,46 @@ <JAVADOC /> <SOURCES /> </library> - <library name="compiler-locker"> - <CLASSES> - <root url="file://$PROJECT_DIR$/../../build/locker/classes/library" /> - <root url="file://$PROJECT_DIR$/../../build/locker/classes/compiler" /> - <root url="file://$PROJECT_DIR$/../../build/locker/classes/reflect" /> - <root url="file://$PROJECT_DIR$/../../build/asm/classes" /> - </CLASSES> - <JAVADOC /> - <SOURCES /> - </library> <library name="junit"> <CLASSES> <root url="file://$PROJECT_DIR$/../../build/deps/junit" /> </CLASSES> <JAVADOC /> - <SOURCES> - <root url="file://$PROJECT_DIR$/../../build/deps/junit" /> - </SOURCES> + <SOURCES /> <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/junit" recursive="false" /> - <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/junit" recursive="false" type="SOURCES" /> </library> - <library name="partest-deps"> + <library name="partest"> <CLASSES> <root url="file://$PROJECT_DIR$/../../build/deps/partest" /> </CLASSES> <JAVADOC /> - <SOURCES> - <root url="file://$PROJECT_DIR$/../../build/deps/junit" /> - </SOURCES> + <SOURCES /> <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/partest" recursive="false" /> - <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/junit" recursive="false" type="SOURCES" /> </library> <library name="repl-deps"> - <CLASSES> + <CLASSES> <root url="file://$PROJECT_DIR$/../../build/deps/repl" /> - </CLASSES> - <JAVADOC /> - <SOURCES /> + </CLASSES> + <JAVADOC /> + <SOURCES /> <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/repl" recursive="false" /> - </library> + </library> + <library name="scaladoc-deps"> + <CLASSES> + <root url="file://$PROJECT_DIR$/../../build/deps/scaladoc" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/scaladoc" recursive="false" /> + </library> + <library name="starr"> + <CLASSES> + <root url="file://$PROJECT_DIR$/../../build/deps/starr" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + <jarDirectory url="file://$PROJECT_DIR$/../../build/deps/starr" recursive="false" /> + </library> </component> </project> + diff --git a/src/intellij/scaladoc.iml.SAMPLE b/src/intellij/scaladoc.iml.SAMPLE index 07bea5bf5d..8f9a0d8344 100644 --- a/src/intellij/scaladoc.iml.SAMPLE +++ b/src/intellij/scaladoc.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> @@ -20,8 +21,8 @@ <orderEntry type="module" module-name="library" /> <orderEntry type="module" module-name="reflect" /> <orderEntry type="module" module-name="compiler" /> - <orderEntry type="module" module-name="xml" /> - <orderEntry type="module" module-name="parser-combinators" /> - <orderEntry type="module" module-name="partest" /> + <orderEntry type="library" name="partest" level="project" /> + <orderEntry type="library" name="scaladoc-deps" level="project" /> </component> </module> + diff --git a/src/intellij/scalap.iml.SAMPLE b/src/intellij/scalap.iml.SAMPLE index 77eea7c38f..27ae451369 100644 --- a/src/intellij/scalap.iml.SAMPLE +++ b/src/intellij/scalap.iml.SAMPLE @@ -4,7 +4,8 @@ <facet type="scala" name="Scala"> <configuration> <option name="compilerLibraryLevel" value="Project" /> - <option name="compilerLibraryName" value="compiler-locker" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> <option name="maximumHeapSize" value="1536" /> <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" /> </configuration> diff --git a/src/intellij/setup.sh b/src/intellij/setup.sh index bd324ba5bd..ec303778ed 100755 --- a/src/intellij/setup.sh +++ b/src/intellij/setup.sh @@ -5,19 +5,10 @@ set -e export SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" -export BASE="$( cd "$( dirname "$0" )"/../.. && pwd )" echo "About to delete .ipr and .iml files and replace with the .SAMPLE files. Press enter to continue or CTRL-C to cancel." read -(rm -f *.ipr *.iml 2>/dev/null) -for f in $(ls "$SCRIPT_DIR"/*.SAMPLE); do - NEW_FILE=`echo $f | perl -pe 's/.SAMPLE//'`; - - cp $f $NEW_FILE - - # IntelliJ doesn't process the "compilerOptions" setting for variable - # replacement. If it did, we would just use "$PROJECT_DIR$". Instead, - # we do this replacement ourselves. - perl -pi -e 's/\$BASE_DIR\$/$ENV{"BASE"}/g' $NEW_FILE - echo "Created $NEW_FILE" +for f in "$SCRIPT_DIR"/*.SAMPLE; do + g=${f%.SAMPLE} + cp $f $g done diff --git a/src/intellij/test-junit.iml.SAMPLE b/src/intellij/test-junit.iml.SAMPLE new file mode 100644 index 0000000000..bb51c30a4f --- /dev/null +++ b/src/intellij/test-junit.iml.SAMPLE @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="FacetManager"> + <facet type="scala" name="Scala"> + <configuration> + <option name="compilerLibraryLevel" value="Project" /> + <option name="compilerLibraryName" value="starr" /> + </configuration> + </facet> + </component> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$/../../test/junit"> + <sourceFolder url="file://$MODULE_DIR$/../../test/junit" isTestSource="true" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="actors" /> + <orderEntry type="module" module-name="asm" /> + <orderEntry type="module" module-name="compiler" /> + <orderEntry type="module" module-name="library" /> + <orderEntry type="module" module-name="reflect" /> + <orderEntry type="module" module-name="repl" /> + <orderEntry type="module" module-name="partest-extras" /> + <orderEntry type="module" module-name="forkjoin" /> + <orderEntry type="library" name="junit" level="project" /> + <orderEntry type="library" name="scaladoc-deps" level="project" /> + </component> +</module> + diff --git a/src/intellij/test.iml.SAMPLE b/src/intellij/test.iml.SAMPLE index 423be2062c..cb4a8568a1 100644 --- a/src/intellij/test.iml.SAMPLE +++ b/src/intellij/test.iml.SAMPLE @@ -1,21 +1,31 @@ <?xml version="1.0" encoding="UTF-8"?> <module type="JAVA_MODULE" version="4"> + <component name="FacetManager"> + <facet type="scala" name="Scala"> + <configuration> + <option name="compilerLibraryLevel" value="Project" /> + <option name="compilerLibraryName" value="starr" /> + <option name="languageLevel" value="Scala 2.11" /> + </configuration> + </facet> + </component> <component name="NewModuleRootManager" inherit-compiler-output="true"> <exclude-output /> - <content url="file://$MODULE_DIR$/../../test" /> + <content url="file://$MODULE_DIR$/../../test"> + <excludeFolder url="file://$MODULE_DIR$/../../test/junit" /> + </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module" module-name="library" /> - <orderEntry type="module" module-name="xml" /> - <orderEntry type="module" module-name="parser-combinators" /> <orderEntry type="module" module-name="reflect" /> <orderEntry type="module" module-name="compiler" /> + <orderEntry type="module" module-name="repl" /> <orderEntry type="module" module-name="actors" /> - <orderEntry type="module" module-name="swing" /> - <orderEntry type="module" module-name="partest" /> <orderEntry type="module" module-name="asm" /> <orderEntry type="module" module-name="forkjoin" /> - <orderEntry type="library" name="junit" level="project" /> + <orderEntry type="module" module-name="partest-extras" /> + <orderEntry type="library" name="scaladoc-deps" level="project" /> + <orderEntry type="library" name="partest" level="project" /> </component> </module> diff --git a/src/intellij/update.sh b/src/intellij/update.sh new file mode 100755 index 0000000000..eb6fea782f --- /dev/null +++ b/src/intellij/update.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# +# Updates the .SAMPLE files with the current project files. +# + +set -e +export SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" + +echo "About to create overwrite the .ipr.SAMPLE and .iml.SAMPLE files with the current project files. Press enter to continue or CTRL-C to cancel." +read + +for f in "$SCRIPT_DIR"/*.{iml,ipr}; do + cp $f $f.SAMPLE +done + +for f in "$SCRIPT_DIR"/*.SAMPLE; do + g=${f%.SAMPLE} + if [[ ! -f $g ]]; then + echo "Stale sample file, deleting $f" + rm $f + fi +done diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index 9ff648a05a..7f4a9dc45d 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -94,7 +94,7 @@ trait PartialFunction[-A, +B] extends (A => B) { self => * Note that expression `pf.applyOrElse(x, default)` is equivalent to * {{{ if(pf isDefinedAt x) pf(x) else default(x) }}} * except that `applyOrElse` method can be implemented more efficiently. - * For all partial function literals compiler generates `applyOrElse` implementation which + * For all partial function literals the compiler generates an `applyOrElse` implementation which * avoids double evaluation of pattern matchers and guards. * This makes `applyOrElse` the basis for the efficient implementation for many operations and scenarios, such as: * diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 01d179aeb6..0cd91409cf 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -506,7 +506,6 @@ trait GenTraversableOnce[+A] extends Any { def toIndexedSeq: immutable.IndexedSeq[A] /** Converts this $coll to a stream. - * $willNotTerminateInf * @return a stream containing all elements of this $coll. */ def toStream: Stream[A] diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 01a0aa3b51..1b496383a3 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -165,11 +165,11 @@ object Iterator { /** Avoid stack overflows when applying ++ to lots of iterators by * flattening the unevaluated iterators out into a vector of closures. */ - private[scala] final class ConcatIterator[+A](initial: Vector[() => Iterator[A]]) extends Iterator[A] { - // current set to null when all iterators are exhausted - private[this] var current: Iterator[A] = Iterator.empty + private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] { + @deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility private[this] var queue: Vector[() => Iterator[A]] = initial // Advance current to the next non-empty iterator + // current is set to null when all iterators are exhausted private[this] def advance(): Boolean = { if (queue.isEmpty) { current = null @@ -185,7 +185,7 @@ object Iterator { def next() = if (hasNext) current.next else Iterator.empty.next override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = - new ConcatIterator(queue :+ (() => that.toIterator)) + new ConcatIterator(current, queue :+ (() => that.toIterator)) } private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] { @@ -194,7 +194,7 @@ object Iterator { def next = if (lhs.hasNext) lhs.next else rhs.next override def ++[B >: A](that: => GenTraversableOnce[B]) = - new ConcatIterator(Vector(() => this, () => that.toIterator)) + new ConcatIterator(this, Vector(() => that.toIterator)) } } diff --git a/src/library/scala/collection/LinearSeq.scala b/src/library/scala/collection/LinearSeq.scala index 1e4975a0a7..49fbb902ab 100644 --- a/src/library/scala/collection/LinearSeq.scala +++ b/src/library/scala/collection/LinearSeq.scala @@ -25,7 +25,7 @@ trait LinearSeq[+A] extends Seq[A] } /** $factoryInfo - * The current default implementation of a $Coll is a `Vector`. + * The current default implementation of a $Coll is a `List`. * @define coll linear sequence * @define Coll `LinearSeq` */ diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 14ae57c43a..7d1d6b3781 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -194,7 +194,7 @@ private[collection] trait Wrappers { def getKey = k def getValue = v def setValue(v1 : B) = self.put(k, v1) - override def hashCode = byteswap32(k.hashCode) + (byteswap32(v.hashCode) << 16) + override def hashCode = byteswap32(k.##) + (byteswap32(v.##) << 16) override def equals(other: Any) = other match { case e: ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue case _ => false diff --git a/src/library/scala/collection/generic/Sorted.scala b/src/library/scala/collection/generic/Sorted.scala index ab0d443a03..a0b0e1318b 100644 --- a/src/library/scala/collection/generic/Sorted.scala +++ b/src/library/scala/collection/generic/Sorted.scala @@ -62,7 +62,8 @@ trait Sorted[K, +This <: Sorted[K, This]] { /** Creates a ranged projection of this collection with both a lower-bound * and an upper-bound. * - * @param from The upper-bound (exclusive) of the ranged projection. + * @param from The lower-bound (inclusive) of the ranged projection. + * @param until The upper-bound (exclusive) of the ranged projection. */ def range(from: K, until: K): This = rangeImpl(Some(from), Some(until)) diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index e342e134b4..00491ef20e 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -114,10 +114,16 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza * @tparam T2 the type of the second half of the element pairs * @param asPair an implicit conversion which asserts that the element type * of this Array is a pair. + * @param ct1 a class tag for T1 type parameter that is required to create an instance + * of Array[T1] + * @param ct2 a class tag for T2 type parameter that is required to create an instance + * of Array[T2] * @return a pair of Arrays, containing, respectively, the first and second half * of each element pair of this Array. */ - def unzip[T1: ClassTag, T2: ClassTag](implicit asPair: T => (T1, T2)): (Array[T1], Array[T2]) = { + // implementation NOTE: ct1 and ct2 can't be written as context bounds because desugared + // implicits are put in front of asPair parameter that is supposed to guide type inference + def unzip[T1, T2](implicit asPair: T => (T1, T2), ct1: ClassTag[T1], ct2: ClassTag[T2]): (Array[T1], Array[T2]) = { val a1 = new Array[T1](length) val a2 = new Array[T2](length) var i = 0 @@ -137,10 +143,19 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza * @tparam T3 the type of the third of three elements in the triple * @param asTriple an implicit conversion which asserts that the element type * of this Array is a triple. + * @param ct1 a class tag for T1 type parameter that is required to create an instance + * of Array[T1] + * @param ct2 a class tag for T2 type parameter that is required to create an instance + * of Array[T2] + * @param ct3 a class tag for T3 type parameter that is required to create an instance + * of Array[T3] * @return a triple of Arrays, containing, respectively, the first, second, and third * elements from each element triple of this Array. */ - def unzip3[T1: ClassTag, T2: ClassTag, T3: ClassTag](implicit asTriple: T => (T1, T2, T3)): (Array[T1], Array[T2], Array[T3]) = { + // implementation NOTE: ct1, ct2, ct3 can't be written as context bounds because desugared + // implicits are put in front of asPair parameter that is supposed to guide type inference + def unzip3[T1, T2, T3](implicit asTriple: T => (T1, T2, T3), ct1: ClassTag[T1], ct2: ClassTag[T2], + ct3: ClassTag[T3]): (Array[T1], Array[T2], Array[T3]) = { val a1 = new Array[T1](length) val a2 = new Array[T2](length) val a3 = new Array[T3](length) diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index a55432fd71..a1e94c8876 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -14,8 +14,13 @@ import scala.annotation.implicitNotFound import scala.util.Try /** - * An `ExecutionContext` can execute program logic, typically but not - * necessarily on a thread pool. + * An `ExecutionContext` can execute program logic asynchronously, + * typically but not necessarily on a thread pool. + * + * A general purpose `ExecutionContext` must be asynchronous in executing + * any `Runnable` that is passed into its `execute`-method. A special purpose + * `ExecutionContext` may be synchronous but must only be passed to code that + * is explicitly safe to be run using a synchronously executing `ExecutionContext`. * * APIs such as `Future.onComplete` require you to provide a callback * and an implicit `ExecutionContext`. The implicit `ExecutionContext` diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 803c980058..2f7643bccf 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -64,6 +64,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals { // TODO undeprecated until Scala reflection becomes non-experimental // @deprecated("Use type tags and manually check the corresponding class or type instead", "2.10.0") +@SerialVersionUID(1L) abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Manifest.Any) || (that eq Manifest.AnyVal) @@ -72,6 +73,7 @@ abstract class AnyValManifest[T <: AnyVal](override val toString: String) extend case _ => false } override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + @transient override val hashCode = System.identityHashCode(this) } @@ -228,6 +230,7 @@ object ManifestFactory { private abstract class PhantomManifest[T](_runtimeClass: Predef.Class[_], override val toString: String) extends ClassTypeManifest[T](None, _runtimeClass, Nil) { override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + @transient override val hashCode = System.identityHashCode(this) } diff --git a/src/reflect/scala/reflect/api/Internals.scala b/src/reflect/scala/reflect/api/Internals.scala index 01700345d1..577cd09295 100644 --- a/src/reflect/scala/reflect/api/Internals.scala +++ b/src/reflect/scala/reflect/api/Internals.scala @@ -581,7 +581,7 @@ trait Internals { self: Universe => val ImplicitParams: ImplicitParamsExtractor trait ImplicitParamsExtractor { - def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] + def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]] def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] } @@ -600,10 +600,11 @@ trait Internals { self: Universe => } val SyntacticTypeApplied: SyntacticTypeAppliedExtractor + val SyntacticAppliedType: SyntacticTypeAppliedExtractor trait SyntacticTypeAppliedExtractor { def apply(tree: Tree, targs: List[Tree]): Tree - def unapply(tree: Tree): Some[(Tree, List[Tree])] + def unapply(tree: Tree): Option[(Tree, List[Tree])] } val SyntacticApplied: SyntacticAppliedExtractor @@ -761,9 +762,15 @@ trait Internals { self: Universe => def unapply(lst: List[List[Tree]]): Option[List[List[T]]] } + val SyntacticPartialFunction: SyntacticPartialFunctionExtractor + trait SyntacticPartialFunctionExtractor { + def apply(cases: List[Tree]): Match + def unapply(tree: Tree): Option[List[CaseDef]] + } + val SyntacticMatch: SyntacticMatchExtractor trait SyntacticMatchExtractor { - def apply(selector: Tree, cases: List[Tree]): Match + def apply(scrutinee: Tree, cases: List[Tree]): Match def unapply(tree: Match): Option[(Tree, List[CaseDef])] } @@ -773,10 +780,16 @@ trait Internals { self: Universe => def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)] } - val SyntacticIdent: SyntacticIdentExtractor - trait SyntacticIdentExtractor { - def apply(name: Name, isBackquoted: Boolean = false): Ident - def unapply(tree: Ident): Option[(Name, Boolean)] + val SyntacticTermIdent: SyntacticTermIdentExtractor + trait SyntacticTermIdentExtractor { + def apply(name: TermName, isBackquoted: Boolean = false): Ident + def unapply(id: Ident): Option[(TermName, Boolean)] + } + + val SyntacticTypeIdent: SyntacticTypeIdentExtractor + trait SyntacticTypeIdentExtractor { + def apply(name: TypeName): Ident + def unapply(tree: Tree): Option[TypeName] } val SyntacticImport: SyntacticImportExtractor @@ -784,6 +797,48 @@ trait Internals { self: Universe => def apply(expr: Tree, selectors: List[Tree]): Import def unapply(imp: Import): Some[(Tree, List[Tree])] } + + val SyntacticSelectType: SyntacticSelectTypeExtractor + trait SyntacticSelectTypeExtractor { + def apply(qual: Tree, name: TypeName): Select + def unapply(tree: Tree): Option[(Tree, TypeName)] + } + + val SyntacticSelectTerm: SyntacticSelectTermExtractor + trait SyntacticSelectTermExtractor { + def apply(qual: Tree, name: TermName): Select + def unapply(tree: Tree): Option[(Tree, TermName)] + } + + val SyntacticCompoundType: SyntacticCompoundTypeExtractor + trait SyntacticCompoundTypeExtractor { + def apply(parents: List[Tree], defns: List[Tree]): CompoundTypeTree + def unapply(tree: Tree): Option[(List[Tree], List[Tree])] + } + + val SyntacticSingletonType: SyntacitcSingletonTypeExtractor + trait SyntacitcSingletonTypeExtractor { + def apply(tree: Tree): SingletonTypeTree + def unapply(tree: Tree): Option[Tree] + } + + val SyntacticTypeProjection: SyntacticTypeProjectionExtractor + trait SyntacticTypeProjectionExtractor { + def apply(qual: Tree, name: TypeName): SelectFromTypeTree + def unapply(tree: Tree): Option[(Tree, TypeName)] + } + + val SyntacticAnnotatedType: SyntacticAnnotatedTypeExtractor + trait SyntacticAnnotatedTypeExtractor { + def apply(tpt: Tree, annot: Tree): Annotated + def unapply(tree: Tree): Option[(Tree, Tree)] + } + + val SyntacticExistentialType: SyntacticExistentialTypeExtractor + trait SyntacticExistentialTypeExtractor { + def apply(tpt: Tree, where: List[Tree]): ExistentialTypeTree + def unapply(tree: Tree): Option[(Tree, List[MemberDef])] + } } @deprecated("Use `internal.reificationSupport` instead", "2.11.0") diff --git a/src/reflect/scala/reflect/api/Liftables.scala b/src/reflect/scala/reflect/api/Liftables.scala index ec9d85b69e..673dbce6f5 100644 --- a/src/reflect/scala/reflect/api/Liftables.scala +++ b/src/reflect/scala/reflect/api/Liftables.scala @@ -6,7 +6,7 @@ trait Liftables { self: Universe => /** A type class that defines a representation of `T` as a `Tree`. * - * @see [[http://docs.scala-lang.org/overviews/macros/quasiquotes.html#lifting]] + * @see [[http://docs.scala-lang.org/overviews/quasiquotes/lifting.html]] */ trait Liftable[T] { def apply(value: T): Tree @@ -32,7 +32,7 @@ trait Liftables { self: Universe => * lifted: universe.Tree = O * }}} * - * @see [[http://docs.scala-lang.org/overviews/macros/quasiquotes.html#lifting]] + * @see [[http://docs.scala-lang.org/overviews/quasiquotes/lifting.html]] */ def apply[T](f: T => Tree): Liftable[T] = new Liftable[T] { def apply(value: T): Tree = f(value) } @@ -40,7 +40,7 @@ trait Liftables { self: Universe => /** A type class that defines a way to extract instance of `T` from a `Tree`. * - * @see [[http://docs.scala-lang.org/overviews/macros/quasiquotes.html#unlifting]] + * @see [[http://docs.scala-lang.org/overviews/quasiquotes/unlifting.html]] */ trait Unliftable[T] { def unapply(tree: Tree): Option[T] @@ -66,7 +66,7 @@ trait Liftables { self: Universe => * scala> val q"${_: O.type}" = q"$Oref" * }}} * - * @see [[http://docs.scala-lang.org/overviews/macros/quasiquotes.html#unlifting]] + * @see [[http://docs.scala-lang.org/overviews/quasiquotes/unlifting.html]] */ def apply[T](pf: PartialFunction[Tree, T]): Unliftable[T] = new Unliftable[T] { def unapply(value: Tree): Option[T] = pf.lift(value) diff --git a/src/reflect/scala/reflect/api/Mirror.scala b/src/reflect/scala/reflect/api/Mirror.scala index da3afd89ff..318fdb369a 100644 --- a/src/reflect/scala/reflect/api/Mirror.scala +++ b/src/reflect/scala/reflect/api/Mirror.scala @@ -118,4 +118,22 @@ abstract class Mirror[U <: Universe with Singleton] { * @group Mirror */ def staticPackage(fullName: String): U#ModuleSymbol + + /** + * Shortcut for `implicitly[WeakTypeTag[T]].tpe` + * @group TypeTags + */ + def weakTypeOf[T: universe.WeakTypeTag]: U#Type = universe.weakTypeTag[T].in(this).tpe + + /** + * Shortcut for `implicitly[TypeTag[T]].tpe` + * @group TypeTags + */ + def typeOf[T: universe.TypeTag]: U#Type = universe.typeTag[T].in(this).tpe + + /** + * Type symbol of `x` as derived from a type tag. + * @group TypeTags + */ + def symbolOf[T: universe.WeakTypeTag]: U#TypeSymbol } diff --git a/src/reflect/scala/reflect/api/Quasiquotes.scala b/src/reflect/scala/reflect/api/Quasiquotes.scala index 0065926e3b..e905aa4153 100644 --- a/src/reflect/scala/reflect/api/Quasiquotes.scala +++ b/src/reflect/scala/reflect/api/Quasiquotes.scala @@ -7,7 +7,7 @@ trait Quasiquotes { self: Universe => * that are also known as quasiquotes. With their help you can easily manipulate * Scala reflection ASTs. * - * @see [[http://docs.scala-lang.org/overviews/macros/quasiquotes.html]] + * @see [[http://docs.scala-lang.org/overviews/quasiquotes/intro.html]] */ implicit class Quasiquote(ctx: StringContext) { protected trait api { diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index af11de46ce..66ac62cc9e 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -27,6 +27,7 @@ trait StandardLiftables { self: Universe => callScala(stdnme.Symbol)(Literal(Constant(v.name)) :: Nil) } + implicit def liftTree[T <: Tree]: Liftable[T] = Liftable { identity } implicit def liftName[T <: Name]: Liftable[T] = Liftable { name => Ident(name) } implicit def liftExpr[T <: Expr[_]]: Liftable[T] = Liftable { expr => expr.tree } implicit def liftType[T <: Type]: Liftable[T] = Liftable { tpe => TypeTree(tpe) } diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index a5a50f1088..dddd3c0e61 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -919,6 +919,14 @@ trait Symbols { self: Universe => * For a Scala package class, NoSymbol. * For a Java class, NoSymbol. * + * Known issues: Due to SI-8367, primaryConstructor may return unexpected results + * when called for Java classes (for some vague definition of a "Java class", which apparently + * not only includes javac-produced classfiles, but also consists of classes defined in + * Scala programs under the java.lang package). What's even worse, for some Java classes + * we can't even guarantee stability of the return value - depending on your classloader configuration + * and/or JDK version you might get different primaryConstructor for the same ClassSymbol. + * We have logged these issues at SI-8193. + * * @group Class */ // TODO: SI-8193 I think we should only return a non-empty symbol if called for Scala classes diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 558e1aa611..bf560a21e5 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -410,7 +410,8 @@ trait Definitions extends api.StandardDefinitions { else if (isScalaRepeatedParamType(tp)) elementExtract(RepeatedParamClass, tp) orElse tp else tp ) - def repeatedToSingle(tp: Type): Type = elementExtract(RepeatedParamClass, tp) orElse tp + def repeatedToSingle(tp: Type): Type = elementExtract(RepeatedParamClass, tp) orElse elementExtract(JavaRepeatedParamClass, tp) orElse tp + // We don't need to deal with JavaRepeatedParamClass here, as `repeatedToSeq` is only called in the patmat translation for Scala sources. def repeatedToSeq(tp: Type): Type = elementTransform(RepeatedParamClass, tp)(seqType) orElse tp def seqToRepeated(tp: Type): Type = elementTransform(SeqClass, tp)(scalaRepeatedType) orElse tp def isReferenceArray(tp: Type) = elementTest(ArrayClass, tp)(_ <:< AnyRefTpe) @@ -489,8 +490,10 @@ trait Definitions extends api.StandardDefinitions { lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful - lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context") // defined in scala-reflect.jar, so we need to be careful - lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context") // defined in scala-reflect.jar, so we need to be careful + private def Context_210 = if (settings.isScala211) NoSymbol else getClassIfDefined("scala.reflect.macros.Context") // needed under -Xsource:2.10 + lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context").orElse(Context_210) // defined in scala-reflect.jar, so we need to be careful + + lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context").orElse(Context_210) // defined in scala-reflect.jar, so we need to be careful def MacroContextPrefix = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.prefix)) def MacroContextPrefixType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType)) def MacroContextUniverse = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.universe)) @@ -501,7 +504,9 @@ trait Definitions extends api.StandardDefinitions { lazy val StringContextClass = requiredClass[scala.StringContext] - lazy val QuasiquoteClass = if (ApiUniverseClass != NoSymbol) getMember(ApiUniverseClass, tpnme.Quasiquote) else NoSymbol + // SI-8392 a reflection universe on classpath may not have + // quasiquotes, if e.g. crosstyping with -Xsource on + lazy val QuasiquoteClass = if (ApiUniverseClass != NoSymbol) getMemberIfDefined(ApiUniverseClass, tpnme.Quasiquote) else NoSymbol lazy val QuasiquoteClass_api = if (QuasiquoteClass != NoSymbol) getMember(QuasiquoteClass, tpnme.api) else NoSymbol lazy val QuasiquoteClass_api_apply = if (QuasiquoteClass_api != NoSymbol) getMember(QuasiquoteClass_api, nme.apply) else NoSymbol lazy val QuasiquoteClass_api_unapply = if (QuasiquoteClass_api != NoSymbol) getMember(QuasiquoteClass_api, nme.unapply) else NoSymbol diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 7065a8cd6d..4a35e024de 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -30,6 +30,8 @@ trait Mirrors extends api.Mirrors { val EmptyPackageClass: ClassSymbol val EmptyPackage: ModuleSymbol + def symbolOf[T: universe.WeakTypeTag]: universe.TypeSymbol = universe.weakTypeTag[T].in(this).tpe.typeSymbolDirect.asType + def findMemberFromRoot(fullName: Name): Symbol = { val segs = nme.segments(fullName.toString, fullName.isTermName) if (segs.isEmpty) NoSymbol diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 680c19e426..fcc377ba32 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -567,8 +567,8 @@ trait Printers extends api.Printers { self: SymbolTable => override protected val commentsRequired = true - protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true, - insideTry: Boolean = true, insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true) = { + protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true, insideTry: Boolean = true, + insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true, insideAssign: Boolean = true) = { parent match { case _: If => insideIf case _: Match => insideMatch @@ -576,6 +576,7 @@ trait Printers extends api.Printers { self: SymbolTable => case _: Annotated => insideAnnotated case _: Block => insideBlock case _: LabelDef => insideLabelDef + case _: Assign => insideAssign case _ => false } } diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index ea230a215b..ad8a2594dd 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -6,7 +6,7 @@ import Flags._ import util._ trait ReificationSupport { self: SymbolTable => - import definitions.{TupleClass, FunctionClass, ScalaPackage, UnitClass} + import definitions._ import internal._ class ReificationSupportImpl extends ReificationSupportApi { @@ -94,10 +94,14 @@ trait ReificationSupport { self: SymbolTable => def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree } - def toStats(tree: Tree): List[Tree] = SyntacticBlock.unapply(tree).get + def toStats(tree: Tree): List[Tree] = tree match { + case EmptyTree => Nil + case SyntacticBlock(stats) => stats + case _ => throw new IllegalArgumentException(s"can't flatten $tree") + } def mkAnnotation(tree: Tree): Tree = tree match { - case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, noSelfType, Nil) => + case SyntacticNew(Nil, SyntacticApplied(SyntacticAppliedType(_, _), _) :: Nil, noSelfType, Nil) => tree case _ => throw new IllegalArgumentException(s"Tree ${showRaw(tree)} isn't a correct representation of annotation." + @@ -106,14 +110,14 @@ trait ReificationSupport { self: SymbolTable => def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation) - def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags): List[List[ValDef]] = - argss.map { args => args.map { mkParam(_, extraFlags) } } + def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags, excludeFlags: FlagSet = DEFERRED): List[List[ValDef]] = + argss.map { args => args.map { mkParam(_, extraFlags, excludeFlags) } } - def mkParam(tree: Tree, extraFlags: FlagSet): ValDef = tree match { + def mkParam(tree: Tree, extraFlags: FlagSet, excludeFlags: FlagSet): ValDef = tree match { case Typed(Ident(name: TermName), tpt) => - mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags) + mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags, excludeFlags) case vd: ValDef => - var newmods = vd.mods & (~DEFERRED) + var newmods = vd.mods & (~excludeFlags) if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM copyValDef(vd)(mods = newmods | extraFlags) case _ => @@ -123,7 +127,7 @@ trait ReificationSupport { self: SymbolTable => def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam) - def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM) + def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM, NoFlags) def mkTparams(tparams: List[Tree]): List[TypeDef] = tparams.map { @@ -183,7 +187,7 @@ trait ReificationSupport { self: SymbolTable => protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator object ImplicitParams extends ImplicitParamsExtractor { - def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] = + def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]] = if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match { @@ -197,17 +201,35 @@ trait ReificationSupport { self: SymbolTable => def unapply(flags: Long): Some[Long] = Some(flags) } + /** Construct/deconstruct type application term trees. + * Treats other term trees as zero-argument type applications. + */ object SyntacticTypeApplied extends SyntacticTypeAppliedExtractor { def apply(tree: Tree, targs: List[Tree]): Tree = if (targs.isEmpty) tree else if (tree.isTerm) TypeApply(tree, targs) - else if (tree.isType) AppliedTypeTree(tree, targs) - else throw new IllegalArgumentException(s"can't apply types to $tree") + else throw new IllegalArgumentException(s"can't apply type arguments to $tree") - def unapply(tree: Tree): Some[(Tree, List[Tree])] = tree match { + def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match { case TypeApply(fun, targs) => Some((fun, targs)) - case AppliedTypeTree(tpe, targs) => Some((tpe, targs)) - case _ => Some((tree, Nil)) + case _ if tree.isTerm => Some((tree, Nil)) + case _ => None + } + } + + /** Construct/deconstruct applied type trees. + * Treats other types as zero-arity applied types. + */ + object SyntacticAppliedType extends SyntacticTypeAppliedExtractor { + def apply(tree: Tree, targs: List[Tree]): Tree = + if (targs.isEmpty) tree + else if (tree.isType) AppliedTypeTree(tree, targs) + else throw new IllegalArgumentException(s"can't create applied type from non-type $tree") + + def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match { + case MaybeTypeTreeOriginal(AppliedTypeTree(tpe, targs)) => Some((tpe, targs)) + case _ if tree.isType => Some((tree, Nil)) + case _ => None } } @@ -219,7 +241,15 @@ trait ReificationSupport { self: SymbolTable => case UnApply(treeInfo.Unapplied(Select(fun, nme.unapply)), pats) => Some((fun, pats :: Nil)) case treeInfo.Applied(fun, targs, argss) => - Some((SyntacticTypeApplied(fun, targs), argss)) + fun match { + case Select(_: New, nme.CONSTRUCTOR) => + Some((tree, Nil)) + case _ => + val callee = + if (fun.isTerm) SyntacticTypeApplied(fun, targs) + else SyntacticAppliedType(fun, targs) + Some((callee, argss)) + } } } @@ -239,7 +269,7 @@ trait ReificationSupport { self: SymbolTable => def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = { val Template(parents, selfType, _) = templ val tbody = treeInfo.untypecheckedTemplBody(templ) - + def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) = Some((parents, selfType, ctorMods, vparamss, edefs, body)) def indexOfCtor(trees: List[Tree]) = @@ -296,7 +326,7 @@ trait ReificationSupport { self: SymbolTable => constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L) - val vparamss0 = mkParam(vparamss, extraFlags) + val vparamss0 = mkParam(vparamss, extraFlags, excludeFlags = DEFERRED | PARAM) val tparams0 = mkTparams(tparams) val parents0 = gen.mkParents(mods, if (mods.isCase) parents.filter { @@ -448,28 +478,25 @@ trait ReificationSupport { self: SymbolTable => * block as a list of elements rather than (stats, expr) pair * it also: * - * 1. Treats of q"" (empty tree) as zero-element block. - * - * 2. Strips trailing synthetic units which are inserted by the + * 1. Strips trailing synthetic units which are inserted by the * compiler if the block ends with a definition rather - * than an expression. + * than an expression or is empty. * - * 3. Matches non-block term trees and recognizes them as + * 2. Matches non-block term trees and recognizes them as * single-element blocks for sake of consistency with * compiler's default to treat single-element blocks with - * expressions as just expressions. + * expressions as just expressions. The only exception is q"" + * which is not considered to be a block. */ object SyntacticBlock extends SyntacticBlockExtractor { - def apply(stats: List[Tree]): Tree = - if (stats.isEmpty) EmptyTree - else gen.mkBlock(stats) + def apply(stats: List[Tree]): Tree = gen.mkBlock(stats) def unapply(tree: Tree): Option[List[Tree]] = tree match { case bl @ self.Block(stats, SyntheticUnit()) => Some(treeInfo.untypecheckedBlockBody(bl)) case bl @ self.Block(stats, expr) => Some(treeInfo.untypecheckedBlockBody(bl) :+ expr) - case EmptyTree => Some(Nil) - case _ if tree.isTerm => Some(tree :: Nil) - case _ => None + case SyntheticUnit() => Some(Nil) + case _ if tree.isTerm && tree.nonEmpty => Some(tree :: Nil) + case _ => None } } @@ -488,8 +515,10 @@ trait ReificationSupport { self: SymbolTable => gen.mkNew(parents, mkSelfType(selfType), earlyDefs ::: body, NoPosition, NoPosition) def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case SyntacticApplied(Select(New(SyntacticTypeApplied(ident, targs)), nme.CONSTRUCTOR), argss) => - Some((Nil, SyntacticApplied(SyntacticTypeApplied(ident, targs), argss) :: Nil, noSelfType, Nil)) + case treeInfo.Applied(Select(New(SyntacticAppliedType(ident, targs)), nme.CONSTRUCTOR), Nil, List(Nil)) => + Some((Nil, SyntacticAppliedType(ident, targs) :: Nil, noSelfType, Nil)) + case treeInfo.Applied(Select(New(SyntacticAppliedType(ident, targs)), nme.CONSTRUCTOR), Nil, argss) => + Some((Nil, SyntacticApplied(SyntacticAppliedType(ident, targs), argss) :: Nil, noSelfType, Nil)) case SyntacticBlock(SyntacticClassDef(_, tpnme.ANON_CLASS_NAME, Nil, _, ListOfNil, earlyDefs, parents, selfType, body) :: Apply(Select(New(Ident(tpnme.ANON_CLASS_NAME)), nme.CONSTRUCTOR), Nil) :: Nil) => Some((earlyDefs, parents, selfType, body)) @@ -501,11 +530,21 @@ trait ReificationSupport { self: SymbolTable => object SyntacticDefDef extends SyntacticDefDefExtractor { def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = { + val tparams0 = mkTparams(tparams) val vparamss0 = mkParam(vparamss, PARAM) - DefDef(mods, name, mkTparams(tparams), vparamss0, tpt, rhs) + val rhs0 = { + if (name != nme.CONSTRUCTOR) rhs + else rhs match { + case Block(_, _) => rhs + case _ => Block(List(rhs), gen.mkSyntheticUnit) + } + } + DefDef(mods, name, tparams0, vparamss0, tpt, rhs0) } def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] = tree match { + case DefDef(mods, nme.CONSTRUCTOR, tparams, vparamss, tpt, Block(List(expr), Literal(Constant(())))) => + Some((mods, nme.CONSTRUCTOR, tparams, vparamss, tpt, expr)) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => Some((mods, name, tparams, vparamss, tpt, rhs)) case _ => None @@ -807,10 +846,10 @@ trait ReificationSupport { self: SymbolTable => // drop potential @scala.unchecked annotation protected object MaybeUnchecked { def unapply(tree: Tree): Some[Tree] = tree match { - case Annotated(SyntacticNew(Nil, Apply(ScalaDot(tpnme.unchecked), Nil) :: Nil, noSelfType, Nil), annottee) => + case Annotated(SyntacticNew(Nil, ScalaDot(tpnme.unchecked) :: Nil, noSelfType, Nil), annottee) => Some(annottee) case Typed(annottee, MaybeTypeTreeOriginal( - Annotated(SyntacticNew(Nil, Apply(ScalaDot(tpnme.unchecked), Nil) :: Nil, noSelfType, Nil), _))) => + Annotated(SyntacticNew(Nil, ScalaDot(tpnme.unchecked) :: Nil, noSelfType, Nil), _))) => Some(annottee) case annottee => Some(annottee) } @@ -828,9 +867,40 @@ trait ReificationSupport { self: SymbolTable => case tree => throw new IllegalArgumentException("$tree is not valid representation of pattern match case") } + object SyntacticPartialFunction extends SyntacticPartialFunctionExtractor { + def apply(cases: List[Tree]): Match = Match(EmptyTree, mkCases(cases)) + def unapply(tree: Tree): Option[List[CaseDef]] = tree match { + case Match(EmptyTree, cases) => Some(cases) + case Typed( + Block( + List(ClassDef(clsMods, tpnme.ANON_FUN_NAME, Nil, Template( + List(abspf: TypeTree, ser: TypeTree), noSelfType, List( + DefDef(_, nme.CONSTRUCTOR, _, _, _, _), + DefDef(_, nme.applyOrElse, _, _, _, + Match(_, cases :+ + CaseDef(Bind(nme.DEFAULT_CASE, Ident(nme.WILDCARD)), _, _))), + DefDef(_, nme.isDefinedAt, _, _, _, _))))), + Apply(Select(New(Ident(tpnme.ANON_FUN_NAME)), termNames.CONSTRUCTOR), List())), + pf: TypeTree) + if pf.tpe != null && pf.tpe.typeSymbol.eq(PartialFunctionClass) && + abspf.tpe != null && abspf.tpe.typeSymbol.eq(AbstractPartialFunctionClass) && + ser.tpe != null && ser.tpe.typeSymbol.eq(SerializableClass) && + clsMods.hasFlag(FINAL) && clsMods.hasFlag(SYNTHETIC) => + Some(cases) + case _ => None + } + } + object SyntacticMatch extends SyntacticMatchExtractor { - def apply(selector: Tree, cases: List[Tree]) = Match(selector, mkCases(cases)) - def unapply(tree: Match): Option[(Tree, List[CaseDef])] = Match.unapply(tree) + def apply(scrutinee: Tree, cases: List[Tree]) = { + require(scrutinee.nonEmpty, "match's scrutinee may not be empty") + Match(scrutinee, mkCases(cases)) + } + + def unapply(tree: Match): Option[(Tree, List[CaseDef])] = tree match { + case Match(scrutinee, cases) if scrutinee.nonEmpty => Some((scrutinee, cases)) + case _ => None + } } object SyntacticTry extends SyntacticTryExtractor { @@ -838,13 +908,24 @@ trait ReificationSupport { self: SymbolTable => def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)] = Try.unapply(tree) } - object SyntacticIdent extends SyntacticIdentExtractor { - def apply(name: Name, isBackquoted: Boolean) = { + object SyntacticTermIdent extends SyntacticTermIdentExtractor { + def apply(name: TermName, isBackquoted: Boolean): Ident = { val id = self.Ident(name) if (isBackquoted) id updateAttachment BackquotedIdentifierAttachment id } - def unapply(tree: Ident): Some[(Name, Boolean)] = Some((tree.name, tree.hasAttachment[BackquotedIdentifierAttachment.type])) + def unapply(id: Ident): Option[(TermName, Boolean)] = id.name match { + case name: TermName => Some((name, id.hasAttachment[BackquotedIdentifierAttachment.type])) + case _ => None + } + } + + object SyntacticTypeIdent extends SyntacticTypeIdentExtractor { + def apply(name: TypeName): Ident = self.Ident(name) + def unapply(tree: Tree): Option[TypeName] = tree match { + case MaybeTypeTreeOriginal(Ident(name: TypeName)) => Some(name) + case _ => None + } } /** Facade over Imports and ImportSelectors that lets to structurally @@ -986,6 +1067,79 @@ trait ReificationSupport { self: SymbolTable => Some((imp.expr, selectors)) } } + + object SyntacticSelectType extends SyntacticSelectTypeExtractor { + def apply(qual: Tree, name: TypeName): Select = Select(qual, name) + def unapply(tree: Tree): Option[(Tree, TypeName)] = tree match { + case MaybeTypeTreeOriginal(Select(qual, name: TypeName)) => Some((qual, name)) + case _ => None + } + } + + object SyntacticSelectTerm extends SyntacticSelectTermExtractor { + def apply(qual: Tree, name: TermName): Select = Select(qual, name) + def unapply(tree: Tree): Option[(Tree, TermName)] = tree match { + case Select(qual, name: TermName) => Some((qual, name)) + case _ => None + } + } + + object SyntacticCompoundType extends SyntacticCompoundTypeExtractor { + def apply(parents: List[Tree], defns: List[Tree]) = + CompoundTypeTree(Template(gen.mkParents(NoMods, parents), noSelfType, defns)) + def unapply(tree: Tree): Option[(List[Tree], List[Tree])] = tree match { + case MaybeTypeTreeOriginal(CompoundTypeTree(Template(parents, _, defns))) => + Some((parents, defns)) + case _ => + None + } + } + + object SyntacticSingletonType extends SyntacitcSingletonTypeExtractor { + def apply(ref: Tree): SingletonTypeTree = SingletonTypeTree(ref) + def unapply(tree: Tree): Option[Tree] = tree match { + case MaybeTypeTreeOriginal(SingletonTypeTree(ref)) => + Some(ref) + case _ => + None + } + } + + object SyntacticTypeProjection extends SyntacticTypeProjectionExtractor { + def apply(qual: Tree, name: TypeName): SelectFromTypeTree = + SelectFromTypeTree(qual, name) + def unapply(tree: Tree): Option[(Tree, TypeName)] = tree match { + case MaybeTypeTreeOriginal(SelectFromTypeTree(qual, name)) => + Some((qual, name)) + case _ => + None + } + } + + object SyntacticAnnotatedType extends SyntacticAnnotatedTypeExtractor { + def apply(tpt: Tree, annot: Tree): Annotated = + Annotated(annot, tpt) + def unapply(tree: Tree): Option[(Tree, Tree)] = tree match { + case MaybeTypeTreeOriginal(Annotated(annot, tpt)) => + Some((tpt, annot)) + case _ => + None + } + } + + object SyntacticExistentialType extends SyntacticExistentialTypeExtractor { + def apply(tpt: Tree, where: List[Tree]): ExistentialTypeTree = + ExistentialTypeTree(tpt, where.map { + case md: MemberDef => md + case tree => throw new IllegalArgumentException("$tree is not legal forSome definition") + }) + def unapply(tree: Tree): Option[(Tree, List[MemberDef])] = tree match { + case MaybeTypeTreeOriginal(ExistentialTypeTree(tpt, where)) => + Some((tpt, where)) + case _ => + None + } + } } val build = new ReificationSupportImpl diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index f3467ff9f4..6848c357c5 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -580,6 +580,7 @@ trait StdNames { val AnyVal: NameType = "AnyVal" val Apply: NameType = "Apply" val ArrayAnnotArg: NameType = "ArrayAnnotArg" + val CaseDef: NameType = "CaseDef" val ClassInfoType: NameType = "ClassInfoType" val ConstantType: NameType = "ConstantType" val EmptyPackage: NameType = "EmptyPackage" @@ -611,33 +612,6 @@ trait StdNames { val SelectFromTypeTree: NameType = "SelectFromTypeTree" val SingleType: NameType = "SingleType" val SuperType: NameType = "SuperType" - val SyntacticApplied: NameType = "SyntacticApplied" - val SyntacticAssign: NameType = "SyntacticAssign" - val SyntacticBlock: NameType = "SyntacticBlock" - val SyntacticClassDef: NameType = "SyntacticClassDef" - val SyntacticDefDef: NameType = "SyntacticDefDef" - val SyntacticEmptyTypeTree: NameType = "SyntacticEmptyTypeTree" - val SyntacticFilter: NameType = "SyntacticFilter" - val SyntacticFor: NameType = "SyntacticFor" - val SyntacticForYield: NameType = "SyntacticForYield" - val SyntacticFunction: NameType = "SyntacticFunction" - val SyntacticFunctionType: NameType = "SyntacticFunctionType" - val SyntacticIdent: NameType = "SyntacticIdent" - val SyntacticImport: NameType = "SyntacticImport" - val SyntacticMatch: NameType = "SyntacticMatch" - val SyntacticNew: NameType = "SyntacticNew" - val SyntacticObjectDef: NameType = "SyntacticObjectDef" - val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef" - val SyntacticPatDef: NameType = "SyntacticPatDef" - val SyntacticTraitDef: NameType = "SyntacticTraitDef" - val SyntacticTry: NameType = "SyntacticTry" - val SyntacticTuple: NameType = "SyntacticTuple" - val SyntacticTupleType: NameType = "SyntacticTupleType" - val SyntacticTypeApplied: NameType = "SyntacticTypeApplied" - val SyntacticValDef: NameType = "SyntacticValDef" - val SyntacticValEq: NameType = "SyntacticValEq" - val SyntacticValFrom: NameType = "SyntacticValFrom" - val SyntacticVarDef: NameType = "SyntacticVarDef" val This: NameType = "This" val ThisType: NameType = "ThisType" val Tuple2: NameType = "Tuple2" @@ -805,11 +779,50 @@ trait StdNames { val zero: NameType = "zero" // quasiquote interpolators: - val q: NameType = "q" - val tq: NameType = "tq" - val cq: NameType = "cq" - val pq: NameType = "pq" - val fq: NameType = "fq" + val q: NameType = "q" + val tq: NameType = "tq" + val cq: NameType = "cq" + val pq: NameType = "pq" + val fq: NameType = "fq" + + // quasiquote's syntactic combinators + val SyntacticAnnotatedType: NameType = "SyntacticAnnotatedType" + val SyntacticApplied: NameType = "SyntacticApplied" + val SyntacticAppliedType: NameType = "SyntacticAppliedType" + val SyntacticAssign: NameType = "SyntacticAssign" + val SyntacticBlock: NameType = "SyntacticBlock" + val SyntacticClassDef: NameType = "SyntacticClassDef" + val SyntacticCompoundType: NameType = "SyntacticCompoundType" + val SyntacticDefDef: NameType = "SyntacticDefDef" + val SyntacticEmptyTypeTree: NameType = "SyntacticEmptyTypeTree" + val SyntacticExistentialType: NameType = "SyntacticExistentialType" + val SyntacticFilter: NameType = "SyntacticFilter" + val SyntacticFor: NameType = "SyntacticFor" + val SyntacticForYield: NameType = "SyntacticForYield" + val SyntacticFunction: NameType = "SyntacticFunction" + val SyntacticFunctionType: NameType = "SyntacticFunctionType" + val SyntacticImport: NameType = "SyntacticImport" + val SyntacticMatch: NameType = "SyntacticMatch" + val SyntacticNew: NameType = "SyntacticNew" + val SyntacticObjectDef: NameType = "SyntacticObjectDef" + val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef" + val SyntacticPartialFunction: NameType = "SyntacticPartialFunction" + val SyntacticPatDef: NameType = "SyntacticPatDef" + val SyntacticSelectTerm: NameType = "SyntacticSelectTerm" + val SyntacticSelectType: NameType = "SyntacticSelectType" + val SyntacticSingletonType: NameType = "SyntacticSingletonType" + val SyntacticTermIdent: NameType = "SyntacticTermIdent" + val SyntacticTraitDef: NameType = "SyntacticTraitDef" + val SyntacticTry: NameType = "SyntacticTry" + val SyntacticTuple: NameType = "SyntacticTuple" + val SyntacticTupleType: NameType = "SyntacticTupleType" + val SyntacticTypeApplied: NameType = "SyntacticTypeApplied" + val SyntacticTypeIdent: NameType = "SyntacticTypeIdent" + val SyntacticTypeProjection: NameType = "SyntacticTypeProjection" + val SyntacticValDef: NameType = "SyntacticValDef" + val SyntacticValEq: NameType = "SyntacticValEq" + val SyntacticValFrom: NameType = "SyntacticValFrom" + val SyntacticVarDef: NameType = "SyntacticVarDef" // unencoded operators object raw { diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index e50c65c9ca..c76dedbff4 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -51,6 +51,7 @@ abstract class SymbolTable extends macros.Universe val gen = new InternalTreeGen { val global: SymbolTable.this.type = SymbolTable.this } def log(msg: => AnyRef): Unit + def deprecationWarning(pos: Position, msg: String): Unit = warning(msg) def warning(msg: String): Unit = Console.err.println(msg) def inform(msg: String): Unit = Console.err.println(msg) def globalError(msg: String): Unit = abort(msg) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 03d8f97831..2ce54d2259 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -1904,6 +1904,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The next enclosing method. */ def enclMethod: Symbol = if (isSourceMethod) this else owner.enclMethod + /** The primary constructor of a class. */ def primaryConstructor: Symbol = NoSymbol /** The self symbol (a TermSymbol) of a class with explicit self type, or else the @@ -2342,7 +2343,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => def localName: TermName = name.localName /** The setter of this value or getter definition, or NoSymbol if none exists */ + @deprecated("Use `setterIn` instead", "2.11.0") final def setter(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol = + setterIn(base, hasExpandedName) + + final def setterIn(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol = base.info decl setterNameInBase(base, hasExpandedName) filter (_.hasAccessorFlag) def needsExpandedSetterName = ( @@ -3188,8 +3193,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def primaryConstructor = { val c = info decl primaryConstructorName - if (isJavaDefined) NoSymbol // need to force info before checking the flag - else if (c.isOverloaded) c.alternatives.head else c + if (c.isOverloaded) c.alternatives.head else c } override def associatedFile = ( diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 6011289baf..9066c73393 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -452,7 +452,7 @@ abstract class TreeGen { /** Create block of statements `stats` */ def mkBlock(stats: List[Tree]): Tree = - if (stats.isEmpty) Literal(Constant(())) + if (stats.isEmpty) mkSyntheticUnit() else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit()) else if (stats.length == 1) stats.head else Block(stats.init, stats.last) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index e9e5a89aa7..f26315c538 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -2271,7 +2271,7 @@ trait Types case _ => args.mkString("(", ", ", ")") } private def customToString = sym match { - case RepeatedParamClass => args.head + "*" + case RepeatedParamClass | JavaRepeatedParamClass => args.head + "*" case ByNameParamClass => "=> " + args.head case _ => if (isFunctionTypeDirect(this)) { @@ -4113,8 +4113,8 @@ trait Types def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol], depth: Depth): Boolean = { def isSubArg(t1: Type, t2: Type, variance: Variance) = ( - (variance.isContravariant || isSubType(t1, t2, depth)) - && (variance.isCovariant || isSubType(t2, t1, depth)) + (variance.isCovariant || isSubType(t2, t1, depth)) // The order of these two checks can be material for performance (SI-8478) + && (variance.isContravariant || isSubType(t1, t2, depth)) ) corresponds3(tps1, tps2, mapList(tparams)(_.variance))(isSubArg) diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index 3bcfed7d34..cfe2ad8b87 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -75,7 +75,14 @@ trait Variances { def nextVariance(sym: Symbol, v: Variance): Variance = ( if (shouldFlip(sym, tvar)) v.flip else if (isLocalOnly(sym)) Bivariant - else if (sym.isAliasType) Invariant + else if (sym.isAliasType) ( + // Unsound pre-2.11 behavior preserved under -Xsource:2.10 + if (settings.isScala211 || sym.isOverridingSymbol) Invariant + else { + deprecationWarning(sym.pos, s"Construct depends on unsound variance analysis and will not compile in scala 2.11 and beyond") + Bivariant + } + ) else v ) def loop(sym: Symbol, v: Variance): Variance = ( diff --git a/src/reflect/scala/reflect/internal/pickling/Translations.scala b/src/reflect/scala/reflect/internal/pickling/Translations.scala index e56cf796cb..d924cb3a0c 100644 --- a/src/reflect/scala/reflect/internal/pickling/Translations.scala +++ b/src/reflect/scala/reflect/internal/pickling/Translations.scala @@ -62,21 +62,22 @@ trait Translations { } def picklerTag(tpe: Type): Int = tpe match { - case NoType => NOtpe - case NoPrefix => NOPREFIXtpe - case _: ThisType => THIStpe - case _: SingleType => SINGLEtpe - case _: SuperType => SUPERtpe - case _: ConstantType => CONSTANTtpe - case _: TypeBounds => TYPEBOUNDStpe - case _: TypeRef => TYPEREFtpe - case _: RefinedType => REFINEDtpe - case _: ClassInfoType => CLASSINFOtpe - case _: MethodType => METHODtpe - case _: PolyType => POLYtpe - case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium! - case _: ExistentialType => EXISTENTIALtpe - case _: AnnotatedType => ANNOTATEDtpe + case NoType => NOtpe + case NoPrefix => NOPREFIXtpe + case _: ThisType => THIStpe + case _: SingleType => SINGLEtpe + case _: SuperType => SUPERtpe + case _: ConstantType => CONSTANTtpe + case _: TypeBounds => TYPEBOUNDStpe + case _: TypeRef => TYPEREFtpe + case _: RefinedType => REFINEDtpe + case _: ClassInfoType => CLASSINFOtpe + case _: MethodType => METHODtpe + case _: PolyType => POLYtpe + case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium! + case _: ExistentialType => EXISTENTIALtpe + case StaticallyAnnotatedType(_, _) => ANNOTATEDtpe + case _: AnnotatedType => picklerTag(tpe.underlying) } def picklerSubTag(tree: Tree): Int = tree match { diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 42f794736a..64a1a44722 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -229,6 +229,20 @@ abstract class UnPickler { NoSymbol } + def moduleAdvice(missing: String): String = { + val module = + if (missing.startsWith("scala.xml")) Some(("org.scala-lang.modules", "scala-xml")) + else if (missing.startsWith("scala.util.parsing")) Some(("org.scala-lang.modules", "scala-parser-combinators")) + else if (missing.startsWith("scala.swing")) Some(("org.scala-lang.modules", "scala-swing")) + else if (missing.startsWith("scala.util.continuations")) Some(("org.scala-lang.plugins", "scala-continuations-library")) + else None + + (module map { case (group, art) => + s"""\n(NOTE: It looks like the $art module is missing; try adding a dependency on "$group" : "$art". + | See http://docs.scala-lang.org/overviews/core/scala-2.11.html for more information.)""".stripMargin + } getOrElse "") + } + // (1) Try name. fromName(name) orElse { // (2) Try with expanded name. Can happen if references to private @@ -240,11 +254,12 @@ abstract class UnPickler { // (4) Call the mirror's "missing" hook. adjust(mirrorThatLoaded(owner).missingHook(owner, name)) orElse { // (5) Create a stub symbol to defer hard failure a little longer. + val fullName = s"${owner.fullName}.$name" val missingMessage = - s"""|bad symbolic reference. A signature in $filename refers to ${name.longString} - |in ${owner.kindString} ${owner.fullName} which is not available. - |It may be completely missing from the current classpath, or the version on - |the classpath might be incompatible with the version used when compiling $filename.""".stripMargin + s"""|bad symbolic reference to $fullName encountered in class file '$filename'. + |Cannot access ${name.longString} in ${owner.kindString} ${owner.fullName}. The current classpath may be + |missing a definition for $fullName, or $filename may have been compiled against a version that's + |incompatible with the one found on the current classpath.${moduleAdvice(fullName)}""".stripMargin owner.newStubSymbol(name, missingMessage) } } diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index 564cbb1ce3..c1c43178e5 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -16,8 +16,9 @@ private[internal] trait TypeConstraints { private lazy val _undoLog = new UndoLog def undoLog = _undoLog + import TypeConstraints.UndoPair class UndoLog extends Clearable { - private type UndoPairs = List[(TypeVar, TypeConstraint)] + type UndoPairs = List[UndoPair[TypeVar, TypeConstraint]] //OPT this method is public so we can do `manual inlining` var log: UndoPairs = List() @@ -29,7 +30,7 @@ private[internal] trait TypeConstraints { def undoTo(limit: UndoPairs) { assertCorrectThread() while ((log ne limit) && log.nonEmpty) { - val (tv, constr) = log.head + val UndoPair(tv, constr) = log.head tv.constr = constr log = log.tail } @@ -40,7 +41,7 @@ private[internal] trait TypeConstraints { * which is already synchronized. */ private[reflect] def record(tv: TypeVar) = { - log ::= ((tv, tv.constr.cloneInternal)) + log ::= UndoPair(tv, tv.constr.cloneInternal) } def clear() { @@ -266,3 +267,9 @@ private[internal] trait TypeConstraints { tvars forall (tv => tv.instWithinBounds || util.andFalse(logBounds(tv))) } } + +private[internal] object TypeConstraints { + // UndoPair is declared in companion object to not hold an outer pointer reference + final case class UndoPair[TypeVar <: SymbolTable#TypeVar, + TypeConstraint <: TypeConstraints#TypeConstraint](tv: TypeVar, tConstraint: TypeConstraint) +} diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index a96bed4696..ce0eadc04f 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -402,7 +402,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private val crashRecovery: PartialFunction[Throwable, Boolean] = { case ex: Throwable => - echo(intp.global.throwableAsString(ex)) + val (err, explain) = ( + if (intp.isInitializeComplete) + (intp.global.throwableAsString(ex), "") + else + (ex.getMessage, "The compiler did not initialize.\n") + ) + echo(err) ex match { case _: NoSuchMethodError | _: NoClassDefFoundError => @@ -410,7 +416,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) throw ex case _ => def fn(): Boolean = - try in.readYesOrNo(replayQuestionMessage, { echo("\nYou must enter y or n.") ; fn() }) + try in.readYesOrNo(explain + replayQuestionMessage, { echo("\nYou must enter y or n.") ; fn() }) catch { case _: RuntimeException => false } if (fn()) replay() diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 8bb5757bbb..47d97dd4dd 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -117,8 +117,10 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set private def _initSources = List(new BatchSourceFile("<init>", "class $repl_$init { }")) private def _initialize() = { try { - // todo. if this crashes, REPL will hang - new _compiler.Run() compileSources _initSources + // if this crashes, REPL will hang its head in shame + val run = new _compiler.Run() + assert(run.typerPhase != NoPhase, "REPL requires a typer phase.") + run compileSources _initSources _initializeComplete = true true } @@ -306,7 +308,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set */ override protected def findAbstractFile(name: String): AbstractFile = super.findAbstractFile(name) match { - case null => translatePath(name) map (super.findAbstractFile(_)) orNull + case null if _initializeComplete => translatePath(name) map (super.findAbstractFile(_)) orNull case file => file } } @@ -384,6 +386,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def compileSourcesKeepingRun(sources: SourceFile*) = { val run = new Run() + assert(run.typerPhase != NoPhase, "REPL requires a typer phase.") reporter.reset() run compileSources sources.toList (!reporter.hasErrors, run) diff --git a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala index 51fab3082e..07d619bca5 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala @@ -55,6 +55,8 @@ trait ReplGlobal extends Global { // newNamer(rootContext(unit)).enterSym(unit.body) } } + // add to initial or terminal phase to sanity check Run at construction + override val requires = List("typer") // ensure they didn't -Ystop-after:parser } override protected def computePhaseDescriptors: List[SubComponent] = { diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala index 4607684c0d..dce52af56a 100644 --- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala @@ -94,7 +94,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor val documentError: PartialFunction[Throwable, Unit] = { case NoCompilerRunException => - reporter.info(null, "No documentation generated with unsucessful compiler run", force = false) + reporter.info(null, "No documentation generated with unsuccessful compiler run", force = false) case _: ClassNotFoundException => () } diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala index 212f94c531..e5c64c6f45 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala @@ -37,7 +37,7 @@ trait ScaladocAnalyzer extends Analyzer { comment.defineVariables(sym) val typer1 = newTyper(context.makeNewScope(docDef, context.owner)) for (useCase <- comment.useCases) { - typer1.silent(_ => typer1 defineUseCases useCase) match { + typer1.silent(_.asInstanceOf[ScaladocTyper].defineUseCases(useCase)) match { case SilentTypeError(err) => unit.warning(useCase.pos, err.errMsg) case _ => diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala index d721a96ad7..a0dd154d2e 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -97,7 +97,9 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { "selected2.png", "selected-right-implicits.png", "selected-implicits.png", - "unselected.png" + "unselected.png", + + "permalink.png" ) /** Generates the Scaladoc site for a model into the site root. diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala index f6373e9e97..295bae5bef 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala @@ -14,6 +14,7 @@ import base.comment._ import model._ import scala.xml.NodeSeq +import scala.xml.Elem import scala.xml.dtd.{DocType, PublicID} import scala.collection._ import java.io.Writer @@ -219,4 +220,28 @@ abstract class HtmlPage extends Page { thisPage => else if (ety.isObject) "object_big.png" else if (ety.isPackage) "package_big.png" else "class_big.png" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not + + def permalink(template: Entity, isSelf: Boolean = true): Elem = + <span class="permalink"> + <a href={ memberToUrl(template, isSelf) } title="Permalink" target="_top"> + <img src={ relativeLinkTo(List("permalink.png", "lib")) } /> + </a> + </span> + + def memberToUrl(template: Entity, isSelf: Boolean = true): String = { + val (signature: Option[String], containingTemplate: TemplateEntity) = template match { + case dte: DocTemplateEntity if (!isSelf) => (Some(dte.signature), dte.inTemplate) + case dte: DocTemplateEntity => (None, dte) + case me: MemberEntity => (Some(me.signature), me.inTemplate) + case tpl => (None, tpl) + } + + def hashFromPath(templatePath: List[String]): String = + ((templatePath.head.replace(".html", "") :: templatePath.tail).reverse).mkString(".") + + val containingTemplatePath = templateToPath(containingTemplate) + val url = "../" * (containingTemplatePath.size - 1) + "index.html" + val hash = hashFromPath(containingTemplatePath) + s"$url#$hash" + signature.map("@" + _).getOrElse("") + } } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index 26ee005d3e..b5a8d1ac36 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -15,7 +15,7 @@ import base.comment._ import model._ import model.diagram._ -import scala.xml.{ NodeSeq, Text, UnprefixedAttribute } +import scala.xml.{Elem, NodeSeq, Text, UnprefixedAttribute} import scala.language.postfixOps import scala.collection.mutable. { Set, HashSet } @@ -110,7 +110,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <img src={ relativeLinkTo(List(docEntityKindToBigImage(tpl), "lib")) }/> }} { owner } - <h1>{ displayName }</h1> + <h1>{ displayName }</h1> { permalink(tpl) } </div> { signature(tpl, isSelf = true) } @@ -306,9 +306,6 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <xml:group> <div id="comment" class="fullcommenttop">{ memberToCommentBodyHtml(mbr, inTpl, isSelf = true) }</div> </xml:group> - case dte: DocTemplateEntity if mbr.comment.isDefined => - // comment of inner, documented class (only short comment, full comment is on the class' own page) - memberToInlineCommentHtml(mbr, isSelf) case _ => // comment of non-class member or non-documentented inner class val commentBody = memberToCommentBodyHtml(mbr, inTpl, isSelf = false) @@ -723,6 +720,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp /** name, tparams, params, result */ def signature(mbr: MemberEntity, isSelf: Boolean, isReduced: Boolean = false): NodeSeq = { + def inside(hasLinks: Boolean, nameLink: String = ""): NodeSeq = <xml:group> <span class="modifier_kind"> @@ -833,11 +831,11 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp </xml:group> mbr match { case dte: DocTemplateEntity if !isSelf => - <h4 class="signature">{ inside(hasLinks = true, nameLink = relativeLinkTo(dte)) }</h4> + <h4 class="signature">{ inside(hasLinks = true, nameLink = relativeLinkTo(dte)) }</h4> ++ permalink(dte, isSelf) case _ if isSelf => <h4 id="signature" class="signature">{ inside(hasLinks = true) }</h4> case _ => - <h4 class="signature">{ inside(hasLinks = true) }</h4> + <h4 class="signature">{ inside(hasLinks = true) }</h4> ++ permalink(mbr) } } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js index c201b324e7..3f5cfb4b52 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js @@ -1,5 +1,5 @@ // © 2009–2010 EPFL/LAMP -// code by Gilles Dubochet with contributions by Johannes Rudolph and "spiros" +// code by Gilles Dubochet with contributions by Johannes Rudolph, "spiros" and Marcin Kubala var topLevelTemplates = undefined; var topLevelPackages = undefined; @@ -11,7 +11,7 @@ var focusFilterState = undefined; var title = $(document).attr('title'); -var lastHash = ""; +var lastFragment = ""; $(document).ready(function() { $('body').layout({ @@ -24,9 +24,13 @@ $(document).ready(function() { ,north__paneSelector: ".ui-west-north" }); $('iframe').bind("load", function(){ - var subtitle = $(this).contents().find('title').text(); - $(document).attr('title', (title ? title + " - " : "") + subtitle); - + try { + var subtitle = $(this).contents().find('title').text(); + $(document).attr('title', (title ? title + " - " : "") + subtitle); + } catch (e) { + // Chrome doesn't allow reading the iframe's contents when + // used on the local file system. + } setUrlFragmentFromFrameSrc(); }); @@ -64,21 +68,43 @@ $(document).ready(function() { // Set the iframe's src according to the fragment of the current url. // fragment = "#scala.Either" => iframe url = "scala/Either.html" // fragment = "#scala.Either@isRight:Boolean" => iframe url = "scala/Either.html#isRight:Boolean" +// fragment = "#scalaz.iteratee.package@>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" => iframe url = "scalaz/iteratee/package.html#>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" function setFrameSrcFromUrlFragment() { - var fragment = location.hash.slice(1); - if(fragment) { - var loc = fragment.split("@")[0].replace(/\./g, "/"); - if(loc.indexOf(".html") < 0) loc += ".html"; - if(fragment.indexOf('@') > 0) loc += ("#" + fragment.split("@", 2)[1]); - frames["template"].location.replace(loc); - } - else - frames["template"].location.replace("package.html"); + + function extractLoc(fragment) { + var loc = fragment.split('@')[0].replace(/\./g, "/"); + if (loc.indexOf(".html") < 0) { + loc += ".html"; + } + return loc; + } + + function extractMemberSig(fragment) { + var splitIdx = fragment.indexOf('@'); + if (splitIdx < 0) { + return; + } + return fragment.substr(splitIdx + 1); + } + + var fragment = location.hash.slice(1); + if (fragment) { + var locWithMemeberSig = extractLoc(fragment); + var memberSig = extractMemberSig(fragment); + if (memberSig) { + locWithMemeberSig += "#" + memberSig; + } + frames["template"].location.replace(locWithMemeberSig); + } else { + console.log("empty fragment detected"); + frames["template"].location.replace("package.html"); + } } // Set the url fragment according to the src of the iframe "template". // iframe url = "scala/Either.html" => url fragment = "#scala.Either" // iframe url = "scala/Either.html#isRight:Boolean" => url fragment = "#scala.Either@isRight:Boolean" +// iframe url = "scalaz/iteratee/package.html#>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" => fragment = "#scalaz.iteratee.package@>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" function setUrlFragmentFromFrameSrc() { try { var commonLength = location.pathname.lastIndexOf("/"); diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/permalink.png b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/permalink.png Binary files differnew file mode 100644 index 0000000000..d54bc93f6a --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/permalink.png diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css index b066027f04..35f66cd5df 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css @@ -397,6 +397,37 @@ div.members > ol > li:last-child { margin-bottom: 5px; } +#template .members li .permalink { + position: absolute; + top: 5px; + right: 5px; +} + +#definition .permalink { + position: absolute; + top: 10px; + right: 15px; +} + +#definition .permalink a { + color: #EBEBEB; +} + +#template .members li .permalink, +#definition .permalink a { + display: none; +} + +#template .members li:hover .permalink, +#definition:hover .permalink a { + display: block; +} + +#template .members li .permalink a, +#definition .permalink a { + text-decoration: none; + font-weight: bold; +} /* Comments text formating */ diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js index 6d1caf6d50..1ebcb67f04 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js @@ -1,23 +1,57 @@ // © 2009–2010 EPFL/LAMP -// code by Gilles Dubochet with contributions by Pedro Furlanetto +// code by Gilles Dubochet with contributions by Pedro Furlanetto and Marcin Kubala $(document).ready(function(){ + var controls = { + visibility: { + publicOnly: $("#visbl").find("> ol > li.public"), + all: $("#visbl").find("> ol > li.all") + } + }; + // Escapes special characters and returns a valid jQuery selector function escapeJquery(str){ - return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); + return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=<>\|])/g, '\\$1'); } - // highlight and jump to selected member - if (window.location.hash) { - var temp = window.location.hash.replace('#', ''); - var elem = '#'+escapeJquery(temp); + function toggleVisibilityFilter(ctrlToEnable, ctrToDisable) { + if (ctrlToEnable.hasClass("out")) { + ctrlToEnable.removeClass("out").addClass("in"); + ctrToDisable.removeClass("in").addClass("out"); + filter(); + } + } + + controls.visibility.publicOnly.click(function () { + toggleVisibilityFilter(controls.visibility.publicOnly, controls.visibility.all); + }); - window.scrollTo(0, 0); - $(elem).parent().effect("highlight", {color: "#FFCC85"}, 3000); - $('html,body').animate({scrollTop:$(elem).parent().offset().top}, 1000); + controls.visibility.all.click(function () { + toggleVisibilityFilter(controls.visibility.all, controls.visibility.publicOnly); + }); + + function exposeMember(jqElem) { + var jqElemParent = jqElem.parent(), + parentName = jqElemParent.attr("name"), + linearizationName = /^([^#]*)(#.*)?$/gi.exec(parentName)[1]; + + // switch visibility filter if necessary + if (jqElemParent.attr("visbl") == "prt") { + toggleVisibilityFilter(controls.visibility.all, controls.visibility.publicOnly); + } + + // toggle appropriate linearization buttons + if (linearizationName) { + $("#linearization li.out[name='" + linearizationName + "']").removeClass("out").addClass("in"); + } + + filter(); + window.scrollTo(0, 0); + jqElemParent.effect("highlight", {color: "#FFCC85"}, 3000); + $('html,body').animate({scrollTop: jqElemParent.offset().top}, 1000); } - + var isHiddenClass = function (name) { return name == 'scala.Any' || name == 'scala.AnyRef'; @@ -97,7 +131,7 @@ $(document).ready(function(){ else if ($(this).hasClass("out")) { $(this).removeClass("out"); $(this).addClass("in"); - }; + } filter(); }); @@ -109,7 +143,7 @@ $(document).ready(function(){ else if ($(this).hasClass("out")) { $(this).removeClass("out"); $(this).addClass("in"); - }; + } filter(); }); @@ -147,32 +181,18 @@ $(document).ready(function(){ }); $("#visbl > ol > li.public").click(function() { if ($(this).hasClass("out")) { - $(this).removeClass("out").addClass("in"); - $("#visbl > ol > li.all").removeClass("in").addClass("out"); - filter(); - }; - }) - $("#visbl > ol > li.all").click(function() { - if ($(this).hasClass("out")) { - $(this).removeClass("out").addClass("in"); - $("#visbl > ol > li.public").removeClass("in").addClass("out"); - filter(); - }; - }); - $("#order > ol > li.alpha").click(function() { - if ($(this).hasClass("out")) { orderAlpha(); - }; + } }) $("#order > ol > li.inherit").click(function() { if ($(this).hasClass("out")) { orderInherit(); - }; + } }); $("#order > ol > li.group").click(function() { if ($(this).hasClass("out")) { orderGroup(); - }; + } }); $("#groupedMembers").hide(); @@ -181,7 +201,7 @@ $(document).ready(function(){ // Create tooltips $(".extype").add(".defval").tooltip({ tip: "#tooltip", - position:"top center", + position: "top center", predelay: 500, onBeforeShow: function(ev) { $(this.getTip()).text(this.getTrigger().attr("name")); @@ -233,6 +253,20 @@ $(document).ready(function(){ windowTitle(); if ($("#order > ol > li.group").length == 1) { orderGroup(); }; + + function findElementByHash(locationHash) { + var temp = locationHash.replace('#', ''); + var memberSelector = '#' + escapeJquery(temp); + return $(memberSelector); + } + + // highlight and jump to selected member + if (window.location.hash) { + var jqElem = findElementByHash(window.location.hash); + if (jqElem.length > 0) { + exposeMember(jqElem); + } + } }); function orderAlpha() { diff --git a/src/scalap/scala/tools/scalap/Arguments.scala b/src/scalap/scala/tools/scalap/Arguments.scala index cb0a92b6b3..c375a5bac4 100644 --- a/src/scalap/scala/tools/scalap/Arguments.scala +++ b/src/scalap/scala/tools/scalap/Arguments.scala @@ -5,6 +5,7 @@ ** */ + package scala.tools.scalap import scala.collection.mutable diff --git a/src/scalap/scala/tools/scalap/ByteArrayReader.scala b/src/scalap/scala/tools/scalap/ByteArrayReader.scala index 59f083ee76..cf160871dd 100644 --- a/src/scalap/scala/tools/scalap/ByteArrayReader.scala +++ b/src/scalap/scala/tools/scalap/ByteArrayReader.scala @@ -5,7 +5,10 @@ ** */ -package scala.tools.scalap + +package scala +package tools.scalap + class ByteArrayReader(content: Array[Byte]) { @@ -101,6 +104,9 @@ class ByteArrayReader(content: Array[Byte]) { def getDouble(bp: Int): Double = java.lang.Double.longBitsToDouble(getLong(bp)) /** skip next 'n' bytes - */ - def skip(n: Int): Unit = bp += n + */ + def skip(n: Int) { + bp += n + } + } diff --git a/src/scalap/scala/tools/scalap/Classfile.scala b/src/scalap/scala/tools/scalap/Classfile.scala index d9d264bbbf..f62df285f9 100644 --- a/src/scalap/scala/tools/scalap/Classfile.scala +++ b/src/scalap/scala/tools/scalap/Classfile.scala @@ -5,8 +5,10 @@ ** */ + package scala.tools.scalap + class Classfile(in: ByteArrayReader) { import Classfiles._ diff --git a/src/scalap/scala/tools/scalap/Classfiles.scala b/src/scalap/scala/tools/scalap/Classfiles.scala index 982a83cfa0..9295dd7aff 100644 --- a/src/scalap/scala/tools/scalap/Classfiles.scala +++ b/src/scalap/scala/tools/scalap/Classfiles.scala @@ -5,8 +5,10 @@ ** */ + package scala.tools.scalap + object Classfiles { final val JAVA_MAGIC = 0xCAFEBABE final val JAVA_MAJOR_VERSION = 45 diff --git a/src/scalap/scala/tools/scalap/CodeWriter.scala b/src/scalap/scala/tools/scalap/CodeWriter.scala index 21c4399d5c..168050096d 100644 --- a/src/scalap/scala/tools/scalap/CodeWriter.scala +++ b/src/scalap/scala/tools/scalap/CodeWriter.scala @@ -6,9 +6,13 @@ */ -package scala.tools.scalap +package scala +package tools.scalap -class CodeWriter(writer: java.io.Writer) { +import java.io._ + + +class CodeWriter(writer: Writer) { private val nl = scala.compat.Platform.EOL private var step = " " diff --git a/src/scalap/scala/tools/scalap/Decode.scala b/src/scalap/scala/tools/scalap/Decode.scala index 69325c1ec8..76ce3f4173 100644 --- a/src/scalap/scala/tools/scalap/Decode.scala +++ b/src/scalap/scala/tools/scalap/Decode.scala @@ -5,14 +5,17 @@ ** */ -package scala.tools.scalap +// $Id$ -import scala.tools.scalap.scalasig._ +package scala.tools.scalap -import scala.reflect.internal.util.ScalaClassLoader +import scala.tools.scalap.scalax.rules.scalasig._ +import scala.tools.nsc.util.ScalaClassLoader +import scala.tools.nsc.util.ScalaClassLoader.appLoader import scala.reflect.internal.pickling.ByteCodecs import ClassFileParser.{ ConstValueIndex, Annotation } +import Main.{ SCALA_SIG, SCALA_SIG_ANNOTATION, BYTES_VALUE } /** Temporary decoder. This would be better off in the scala.tools.nsc * but right now the compiler won't acknowledge scala.tools.scalap @@ -28,7 +31,7 @@ object Decode { /** Return the classfile bytes representing the scala sig classfile attribute. * This has been obsoleted by the switch to annotations. */ - def scalaSigBytes(name: String): Option[Array[Byte]] = scalaSigBytes(name, ScalaClassLoader.appLoader) + def scalaSigBytes(name: String): Option[Array[Byte]] = scalaSigBytes(name, appLoader) def scalaSigBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = { val bytes = classLoader.classBytes(name) val reader = new ByteArrayReader(bytes) @@ -36,16 +39,17 @@ object Decode { cf.scalaSigAttribute map (_.data) } - /** Return the bytes representing the annotation. */ - def scalaSigAnnotationBytes(name: String): Option[Array[Byte]] = scalaSigAnnotationBytes(name, ScalaClassLoader.appLoader) + /** Return the bytes representing the annotation + */ + def scalaSigAnnotationBytes(name: String): Option[Array[Byte]] = scalaSigAnnotationBytes(name, appLoader) def scalaSigAnnotationBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = { val bytes = classLoader.classBytes(name) val byteCode = ByteCode(bytes) val classFile = ClassFileParser.parse(byteCode) import classFile._ - classFile annotation Main.SCALA_SIG_ANNOTATION map { case Annotation(_, els) => - val bytesElem = els find (x => constant(x.elementNameIndex) == Main.BYTES_VALUE) getOrElse null + classFile annotation SCALA_SIG_ANNOTATION map { case Annotation(_, els) => + val bytesElem = els find (x => constant(x.elementNameIndex) == BYTES_VALUE) getOrElse null val _bytes = bytesElem.elementValue match { case ConstValueIndex(x) => constantWrapped(x) } val bytes = _bytes.asInstanceOf[StringBytesPair].bytes val length = ByteCodecs.decode(bytes) @@ -54,7 +58,8 @@ object Decode { } } - /** private[scala] so nobody gets the idea this is a supported interface. */ + /** private[scala] so nobody gets the idea this is a supported interface. + */ private[scala] def caseParamNames(path: String): Option[List[String]] = { val (outer, inner) = (path indexOf '$') match { case -1 => (path, "") @@ -62,7 +67,7 @@ object Decode { } for { - clazz <- ScalaClassLoader.appLoader.tryToLoadClass[AnyRef](outer) + clazz <- appLoader.tryToLoadClass[AnyRef](outer) ssig <- ScalaSigParser.parse(clazz) } yield { @@ -80,10 +85,11 @@ object Decode { } } - /** Returns a map of Alias -> Type for the given package. */ + /** Returns a map of Alias -> Type for the given package. + */ private[scala] def typeAliases(pkg: String) = { for { - clazz <- ScalaClassLoader.appLoader.tryToLoadClass[AnyRef](pkg + ".package") + clazz <- appLoader.tryToLoadClass[AnyRef](pkg + ".package") ssig <- ScalaSigParser.parse(clazz) } yield { diff --git a/src/scalap/scala/tools/scalap/JavaWriter.scala b/src/scalap/scala/tools/scalap/JavaWriter.scala index 1ba89e4702..772cf6eacd 100644 --- a/src/scalap/scala/tools/scalap/JavaWriter.scala +++ b/src/scalap/scala/tools/scalap/JavaWriter.scala @@ -5,11 +5,13 @@ ** */ + package scala.tools.scalap +import java.io._ import scala.reflect.NameTransformer -class JavaWriter(classfile: Classfile, writer: java.io.Writer) extends CodeWriter(writer) { +class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer) { val cf = classfile diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 44d7ef6a41..c72f416a89 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -5,17 +5,17 @@ ** */ -package scala.tools.scalap +package scala +package tools.scalap import java.io.{ PrintStream, OutputStreamWriter, ByteArrayOutputStream } - +import scala.reflect.NameTransformer +import scalax.rules.scalasig._ import scala.tools.nsc.util.{ ClassPath, JavaClassPath } -import scala.tools.nsc.util.ClassPath.DefaultJavaContext +import scala.tools.util.PathResolver +import ClassPath.DefaultJavaContext import scala.tools.nsc.io.AbstractFile -import scala.tools.scalap.scalasig._ - - /**The main object used to execute scalap on the command-line. * * @author Matthias Zenger, Stephane Micheloud, Burak Emir, Ilya Sergey @@ -104,7 +104,7 @@ class Main { // we have to encode every fragment of a name separately, otherwise the NameTransformer // will encode using unicode escaping dot separators as well // we can afford allocations because this is not a performance critical code - classname.split('.').map(scala.reflect.NameTransformer.encode).mkString(".") + classname.split('.').map(NameTransformer.encode).mkString(".") } val cls = path.findClass(encName) if (cls.isDefined && cls.get.binary.isDefined) { @@ -185,7 +185,7 @@ object Main extends Main { val cparg = List("-classpath", "-cp") map (arguments getArgument _) reduceLeft (_ orElse _) val path = cparg match { case Some(cp) => new JavaClassPath(DefaultJavaContext.classesInExpandedPath(cp), DefaultJavaContext) - case _ => scala.tools.util.PathResolver.fromPathString(".") // include '.' in the default classpath SI-6669 + case _ => PathResolver.fromPathString(".") // include '.' in the default classpath SI-6669 } // print the classpath if output is verbose if (verbose) diff --git a/src/scalap/scala/tools/scalap/MetaParser.scala b/src/scalap/scala/tools/scalap/MetaParser.scala index 324330466f..1ebf86268a 100644 --- a/src/scalap/scala/tools/scalap/MetaParser.scala +++ b/src/scalap/scala/tools/scalap/MetaParser.scala @@ -6,15 +6,17 @@ */ -package scala.tools.scalap +package scala +package tools.scalap +import java.util._ /** a parser class for parsing meta type information in classfiles * generated by pico. */ class MetaParser(meta: String) { - val scanner = new java.util.StringTokenizer(meta, "()[], \t<;", true) + val scanner = new StringTokenizer(meta, "()[], \t<;", true) var token: String = _ val res = new StringBuffer diff --git a/src/scalap/scala/tools/scalap/Properties.scala b/src/scalap/scala/tools/scalap/Properties.scala index 432dd495e9..8f9a9d8606 100644 --- a/src/scalap/scala/tools/scalap/Properties.scala +++ b/src/scalap/scala/tools/scalap/Properties.scala @@ -9,7 +9,8 @@ package scala.tools.scalap /** Loads decoder.properties from the jar. */ -object Properties extends scala.util.PropertiesTrait { +object Properties extends scala.util.PropertiesTrait +{ protected def propCategory = "decoder" protected def pickJarBasedOn = classOf[Classfile] } diff --git a/src/scalap/scala/tools/scalap/rules/package.scala b/src/scalap/scala/tools/scalap/rules/package.scala deleted file mode 100644 index dcd5f7ac00..0000000000 --- a/src/scalap/scala/tools/scalap/rules/package.scala +++ /dev/null @@ -1,6 +0,0 @@ -package scala.tools.scalap - -package object rules { - // make some language features in this package compile without warning - implicit def postfixOps = scala.language.postfixOps -} diff --git a/src/scalap/scala/tools/scalap/rules/Memoisable.scala b/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala index 418141bee7..bdd1761ed9 100644 --- a/src/scalap/scala/tools/scalap/rules/Memoisable.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala @@ -10,7 +10,9 @@ // // ----------------------------------------------------------------------------- -package scala.tools.scalap.rules +package scala.tools.scalap +package scalax +package rules import scala.collection.mutable @@ -20,7 +22,7 @@ trait MemoisableRules extends Rules { from[In] { in => in.memo(key, rule(in)) } } - override def ruleWithName[In, Out, A, X](name: String, f: In => Result[Out, A, X]) = super.ruleWithName(name, (in: In) => in match { + override def ruleWithName[In, Out, A, X](name: String, f: In => rules.Result[Out, A, X]) = super.ruleWithName(name, (in: In) => in match { case s: Memoisable => s.memo(name, f(in)) case _ => f(in) }) @@ -54,3 +56,6 @@ trait DefaultMemoisable extends Memoisable { if(DefaultMemoisable.debug) println(key + " -> " + t + " (" + out + ")") } } + + + diff --git a/src/scalap/scala/tools/scalap/rules/Result.scala b/src/scalap/scala/tools/scalap/scalax/rules/Result.scala index ae05416d7a..f37340e7b7 100644 --- a/src/scalap/scala/tools/scalap/rules/Result.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Result.scala @@ -10,7 +10,9 @@ // // ----------------------------------------------------------------------------- -package scala.tools.scalap.rules; +package scala.tools.scalap +package scalax +package rules; /** Represents the combined value of two rules applied in sequence. * diff --git a/src/scalap/scala/tools/scalap/rules/Rule.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala index 0a00111f7a..307458fc7d 100644 --- a/src/scalap/scala/tools/scalap/rules/Rule.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala @@ -10,7 +10,9 @@ // // ----------------------------------------------------------------------------- -package scala.tools.scalap.rules +package scala.tools.scalap +package scalax +package rules /** A Rule is a function from some input to a Result. The result may be: * <ul> @@ -170,3 +172,6 @@ trait Choice[-In, +Out, +A, +X] extends Rule[In, Out, A, X] { lazy val choices = Choice.this.choices ::: other :: Nil } } + + + diff --git a/src/scalap/scala/tools/scalap/rules/Rules.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala index bdcc81c22d..dd17c46f79 100644 --- a/src/scalap/scala/tools/scalap/rules/Rules.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala @@ -11,8 +11,11 @@ // ----------------------------------------------------------------------------- package scala.tools.scalap +package scalax package rules +import language.postfixOps + trait Name { def name: String override def toString = name diff --git a/src/scalap/scala/tools/scalap/rules/SeqRule.scala b/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala index e96a38b6be..f3c0235b23 100644 --- a/src/scalap/scala/tools/scalap/rules/SeqRule.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala @@ -10,7 +10,11 @@ // // ----------------------------------------------------------------------------- -package scala.tools.scalap.rules +package scala.tools.scalap +package scalax +package rules + +import language.postfixOps /** * A workaround for the difficulties of dealing with @@ -47,7 +51,7 @@ class SeqRule[S, +A, +X](rule: Rule[S, S, A, X]) { /** Creates a rule that always succeeds with a Boolean value. * Value is 'true' if this rule succeeds, 'false' otherwise */ - def -? = ? map { _.isDefined } + def -? = ? map { _ isDefined } def * = from[S] { // tail-recursive function with reverse list accumulator @@ -96,3 +100,4 @@ class SeqRule[S, +A, +X](rule: Rule[S, S, A, X]) { in => rep(0, in) } } + diff --git a/src/scalap/scala/tools/scalap/scalasig/ClassFileParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala index 9bd8402ccc..cfd750055b 100644 --- a/src/scalap/scala/tools/scalap/scalasig/ClassFileParser.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala @@ -1,6 +1,11 @@ -package scala.tools.scalap.scalasig +package scala.tools.scalap +package scalax +package rules +package scalasig -import scala.tools.scalap.rules.{ Success, Failure, ~, RulesWithState } +import language.postfixOps + +import java.io.IOException object ByteCode { def apply(bytes: Array[Byte]) = new ByteCode(bytes, 0, bytes.length) @@ -15,7 +20,7 @@ object ByteCode { val bytes = new Array[Byte](rest) while (rest > 0) { val res = in.read(bytes, bytes.length - rest, rest) - if (res == -1) throw new java.io.IOException("read error") + if (res == -1) throw new IOException("read error") rest -= res } ByteCode(bytes) @@ -26,7 +31,8 @@ object ByteCode { } } -/** Represents a chunk of raw bytecode. Used as input for the parsers. */ +/** Represents a chunk of raw bytecode. Used as input for the parsers + */ class ByteCode(val bytes: Array[Byte], val pos: Int, val length: Int) { assert(pos >= 0 && length >= 0 && pos + length <= bytes.length) @@ -78,11 +84,11 @@ trait ByteCodeReader extends RulesWithState { type S = ByteCode type Parser[A] = Rule[A, String] - val byte = apply(_.nextByte) + val byte = apply(_ nextByte) val u1 = byte ^^ (_ & 0xFF) - val u2 = bytes(2) ^^ (_.toInt) - val u4 = bytes(4) ^^ (_.toInt) // should map to Long?? + val u2 = bytes(2) ^^ (_ toInt) + val u4 = bytes(4) ^^ (_ toInt) // should map to Long?? def bytes(n: Int) = apply(_ next n) } @@ -93,7 +99,7 @@ object ClassFileParser extends ByteCodeReader { val magicNumber = (u4 filter (_ == 0xCAFEBABE)) | error("Not a valid class file") val version = u2 ~ u2 ^^ { case minor ~ major => (major, minor) } - val constantPool = (u2 ^^ ConstantPool) >> repeatUntil(constantPoolEntry)(_.isFull) + val constantPool = (u2 ^^ ConstantPool) >> repeatUntil(constantPoolEntry)(_ isFull) // NOTE currently most constants just evaluate to a string description // TODO evaluate to useful values @@ -238,3 +244,4 @@ case class ConstantPool(len: Int) { this } } + diff --git a/src/scalap/scala/tools/scalap/scalasig/Flags.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala index b9925150d2..050317cb82 100644 --- a/src/scalap/scala/tools/scalap/scalasig/Flags.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala @@ -1,4 +1,7 @@ -package scala.tools.scalap.scalasig +package scala.tools.scalap +package scalax +package rules +package scalasig trait Flags { def hasFlag(flag: Long): Boolean diff --git a/src/scalap/scala/tools/scalap/scalasig/ScalaSig.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala index 311e4acd6f..e3076322dd 100644 --- a/src/scalap/scala/tools/scalap/scalasig/ScalaSig.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala @@ -5,25 +5,27 @@ ** */ -package scala.tools.scalap.scalasig -import scala.language.implicitConversions - -import scala.reflect.internal.pickling.ByteCodecs +package scala.tools.scalap +package scalax +package rules +package scalasig -import scala.tools.scalap.Main -import scala.tools.scalap.rules._ +import scala.language.postfixOps +import scala.language.implicitConversions import ClassFileParser.{ ConstValueIndex, Annotation } +import scala.reflect.internal.pickling.ByteCodecs object ScalaSigParser { + import Main.{ SCALA_SIG, SCALA_SIG_ANNOTATION, BYTES_VALUE } def scalaSigFromAnnotation(classFile: ClassFile): Option[ScalaSig] = { import classFile._ - classFile.annotation(Main.SCALA_SIG_ANNOTATION) map { + classFile.annotation(SCALA_SIG_ANNOTATION) map { case Annotation(_, elements) => - val bytesElem = elements.find(elem => constant(elem.elementNameIndex) == Main.BYTES_VALUE).get + val bytesElem = elements.find(elem => constant(elem.elementNameIndex) == BYTES_VALUE).get val bytes = ((bytesElem.elementValue match {case ConstValueIndex(index) => constantWrapped(index)}) .asInstanceOf[StringBytesPair].bytes) val length = ByteCodecs.decode(bytes) @@ -33,7 +35,7 @@ object ScalaSigParser { } def scalaSigFromAttribute(classFile: ClassFile): Option[ScalaSig] = - classFile.attribute(Main.SCALA_SIG).map(_.byteCode).map(ScalaSigAttributeParsers.parse) + classFile.attribute(SCALA_SIG).map(_.byteCode).map(ScalaSigAttributeParsers.parse) def parse(classFile: ClassFile): Option[ScalaSig] = { val scalaSig = scalaSigFromAttribute(classFile) diff --git a/src/scalap/scala/tools/scalap/scalasig/ScalaSigPrinter.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala index 5929e0f59f..dd17c39d84 100644 --- a/src/scalap/scala/tools/scalap/scalasig/ScalaSigPrinter.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala @@ -5,14 +5,19 @@ ** */ -package scala.tools.scalap.scalasig -import scala.language.implicitConversions +package scala.tools.scalap +package scalax +package rules +package scalasig + +import language.postfixOps import java.io.{PrintStream, ByteArrayOutputStream} import java.util.regex.Pattern - -import scala.tools.scalap.rules.~ +import scala.tools.scalap.scalax.util.StringUtil +import scala.reflect.NameTransformer +import java.lang.String class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { import stream._ @@ -343,8 +348,8 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { } case "scala.<byname>" => "=> " + toString(typeArgs.head) case _ => { - val path = cutSubstring(symbol.path)(".package") //remove package object reference - trimStart(processName(path) + typeArgString(typeArgs), "<empty>.") + val path = StringUtil.cutSubstring(symbol.path)(".package") //remove package object reference + StringUtil.trimStart(processName(path) + typeArgString(typeArgs), "<empty>.") } }) case TypeBoundsType(lower, upper) => { @@ -389,7 +394,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { def typeArgString(typeArgs: Seq[Type]): String = if (typeArgs.isEmpty) "" - else typeArgs.map(toString).map(trimStart(_, "=> ")).mkString("[", ", ", "]") + else typeArgs.map(toString).map(StringUtil.trimStart(_, "=> ")).mkString("[", ", ", "]") def typeParamString(params: Seq[Symbol]): String = if (params.isEmpty) "" @@ -410,7 +415,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { if (i > 0) name.substring(i + 2) else name } - private def processName(name: String) = { + def processName(name: String) = { val stripped = stripPrivatePrefix(name) val m = pattern.matcher(stripped) var temp = stripped @@ -420,15 +425,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { temp = temp.replaceAll(re, _syms(re)) } val result = temp.replaceAll(placeholderPattern, "_") - scala.reflect.NameTransformer.decode(result) + NameTransformer.decode(result) } - private def trimStart(s: String, prefix: String) = - if (s != null && s.startsWith(prefix)) s.substring(prefix.length) else s - - private def decapitalize(s: String) = - java.beans.Introspector.decapitalize(s) - - private def cutSubstring(dom: String)(s: String) = - if (dom != null && s != null) dom.replace(s, "") else dom } diff --git a/src/scalap/scala/tools/scalap/scalasig/SourceFileAttributeParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/SourceFileAttributeParser.scala index 88d3d3b8b0..fc5a75c046 100644 --- a/src/scalap/scala/tools/scalap/scalasig/SourceFileAttributeParser.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/SourceFileAttributeParser.scala @@ -1,4 +1,7 @@ -package scala.tools.scalap.scalasig +package scala.tools.scalap +package scalax +package rules +package scalasig /** * @author ilyas @@ -13,12 +16,13 @@ object SourceFileAttributeParser extends ByteCodeReader { /** * * SourceFile_attribute { - u2 attribute_name_index; - u4 attribute_length; - u2 sourcefile_index; + u2 attribute_name_index; + u4 attribute_length; + u2 sourcefile_index; } * * Contains only file index in ConstantPool, first two fields are already treated * by {@link scalax.rules.scalasig.ClassFile.attribute#attribute} */ case class SourceFileInfo(sourceFileIndex: Int) + diff --git a/src/scalap/scala/tools/scalap/scalasig/Symbol.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Symbol.scala index 0656938150..6c38687649 100644 --- a/src/scalap/scala/tools/scalap/scalasig/Symbol.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Symbol.scala @@ -1,4 +1,7 @@ -package scala.tools.scalap.scalasig +package scala.tools.scalap +package scalax +package rules +package scalasig import ScalaSigEntryParsers._ diff --git a/src/scalap/scala/tools/scalap/scalasig/Type.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala index 97dc28d223..22d90325ce 100644 --- a/src/scalap/scala/tools/scalap/scalasig/Type.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala @@ -1,4 +1,7 @@ -package scala.tools.scalap.scalasig +package scala.tools.scalap +package scalax +package rules +package scalasig abstract class Type diff --git a/src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala b/src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala new file mode 100644 index 0000000000..6077eded0f --- /dev/null +++ b/src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala @@ -0,0 +1,19 @@ +package scala.tools.scalap +package scalax +package util + +import java.beans.Introspector + +/** + * @author ilyas + */ + +object StringUtil { + + def trimStart(s: String, prefix: String) = if (s != null && s.startsWith(prefix)) s.substring(prefix.length) else s + + def decapitalize(s: String) = Introspector.decapitalize(s) + + def cutSubstring(dom: String)(s: String) = if (dom != null && s != null) dom.replace(s, "") else dom + +} |