From ff95799af710cb19286a961ec01d1bbeffa4b1d9 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Wed, 17 Aug 2011 21:50:46 -0400 Subject: [PATCH] drop 2.7 support, fix fatal warnings support. fixes #153 --- compile/interface/API.scala | 49 +++--------- compile/interface/Analyzer.scala | 80 +++---------------- compile/interface/DelegatingReporter.scala | 2 +- project/Sbt.scala | 6 +- .../inherited_type_params/build.sbt | 2 +- .../sbt-test/source-dependencies/sealed/test | 2 + 6 files changed, 29 insertions(+), 112 deletions(-) diff --git a/compile/interface/API.scala b/compile/interface/API.scala index 86e75b769..241f38192 100644 --- a/compile/interface/API.scala +++ b/compile/interface/API.scala @@ -14,11 +14,7 @@ import xsbti.api.{ClassLike, DefinitionType, PathComponent, SimpleType} object API { val name = "xsbt-api" - // for 2.7 compatibility: this class was removed in 2.8 - type ImplicitMethodType = AnyRef } - // imports ImplicitMethodType, which will preserve source compatibility in 2.7 for defDef -import API._ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extends Compat { @@ -116,7 +112,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend if(pre == NoPrefix) { if(sym.isLocalClass || sym.isRoot || sym.isRootPackage) Constants.emptyType - else if(sym.isTypeParameterOrSkolem || isExistential(sym)) reference(sym) + else if(sym.isTypeParameterOrSkolem || sym.isExistentiallyBound) reference(sym) else { // this appears to come from an existential type in an inherited member- not sure why isExistential is false here /*println("Warning: Unknown prefixless type: " + sym + " in " + sym.owner + " in " + sym.enclClass) @@ -145,26 +141,19 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend { def build(t: Type, typeParams: Array[xsbti.api.TypeParameter], valueParameters: List[xsbti.api.ParameterList]): xsbti.api.Def = { - // 2.8 compatibility - implicit def symbolsToParameters(syms: List[Symbol]): xsbti.api.ParameterList = + def parameterList(syms: List[Symbol]): xsbti.api.ParameterList = { val isImplicitList = syms match { case head :: _ => isImplicit(head); case _ => false } new xsbti.api.ParameterList(syms.map(parameterS).toArray, isImplicitList) } - // 2.7 compatibility - implicit def typesToParameters(syms: List[Type]): xsbti.api.ParameterList = - { - val isImplicitList = t.isInstanceOf[ImplicitMethodType] - new xsbti.api.ParameterList(syms.map(parameterT).toArray, isImplicitList) - } t match { case PolyType(typeParams0, base) => assert(typeParams.isEmpty) assert(valueParameters.isEmpty) build(base, typeParameters(in, typeParams0), Nil) - case MethodType(params, resultType) => // in 2.7, params is of type List[Type], in 2.8 it is List[Symbol] - build(resultType, typeParams, (params: xsbti.api.ParameterList) :: valueParameters) + case MethodType(params, resultType) => + build(resultType, typeParams, parameterList(params) :: valueParameters) case Nullary(resultType) => // 2.9 and later build(resultType, typeParams, valueParameters) case returnType => @@ -175,9 +164,6 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend def parameterS(s: Symbol): xsbti.api.MethodParameter = makeParameter(s.nameString, s.info, s.info.typeSymbol, s) - def parameterT(t: Type): xsbti.api.MethodParameter = - makeParameter("", t, t.typeSymbol, NoSymbol) - // paramSym is only for 2.8 and is to determine if the parameter has a default def makeParameter(name: String, tpe: Type, ts: Symbol, paramSym: Symbol): xsbti.api.MethodParameter = { @@ -194,13 +180,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend val t = viewer(in).memberInfo(s) build(t, Array(), Nil) } - private def hasDefault(s: Symbol) = - { - // 2.7 compatibility - implicit def flagsWithDefault(f: AnyRef): WithDefault = new WithDefault - class WithDefault { val DEFAULTPARAM = 0x00000000 } - s != NoSymbol && s.hasFlag(Flags.DEFAULTPARAM) - } + private def hasDefault(s: Symbol) = s != NoSymbol && s.hasFlag(Flags.DEFAULTPARAM) private def fieldDef[T](in: Symbol, s: Symbol, keepConst: Boolean, create: (xsbti.api.Type, String, xsbti.api.Access, xsbti.api.Modifiers, Array[xsbti.api.Annotation]) => T): T = { val t = dropNullary(viewer(in).memberType(s)) @@ -266,7 +246,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend def mkVal = Some(fieldDef(in, sym, true, new xsbti.api.Val(_,_,_,_,_))) if(sym.isClass || sym.isModule) if(ignoreClass(sym)) None else Some(classLike(in, sym)) - else if(isNonClassType(sym)) + else if(sym.isNonClassType) Some(typeDef(in, sym)) else if(sym.isVariable) if(isSourceField(sym)) mkVar else None @@ -278,7 +258,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend None } private def ignoreClass(sym: Symbol): Boolean = - sym.isLocalClass || sym.isAnonymousClass || fullName(sym).endsWith(LocalChild) + sym.isLocalClass || sym.isAnonymousClass || sym.fullName.endsWith(LocalChild) // This filters private[this] vals/vars that were not in the original source. // The getter will be used for processing instead. @@ -305,7 +285,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend else { val within = c.privateWithin - val qualifier = if(within == NoSymbol) Constants.unqualified else new xsbti.api.IdQualifier(fullName(within)) + val qualifier = if(within == NoSymbol) Constants.unqualified else new xsbti.api.IdQualifier(within.fullName) if(c.hasFlag(Flags.PROTECTED)) new xsbti.api.Protected(qualifier) else new xsbti.api.Private(qualifier) } @@ -354,7 +334,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend private def classLike(in: Symbol, c: Symbol): ClassLike = classLikeCache.getOrElseUpdate( (in,c), mkClassLike(in, c)) private def mkClassLike(in: Symbol, c: Symbol): ClassLike = { - val name = fullName(c) + val name = c.fullName val isModule = c.isModuleClass || c.isModule val struct = if(isModule) c.moduleClass else c val defType = @@ -379,7 +359,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend () else { - packages += fullName(p) + packages += p.fullName `package`(p.enclosingPackage) } } @@ -414,10 +394,6 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend (sym ne null) && (sym != NoSymbol) && !sym.isImplClass && !sym.isNestedClass && sym.isStatic && !sym.hasFlag(Flags.SYNTHETIC) && !sym.hasFlag(Flags.JAVA) } - - // In 2.8, attributes is renamed to annotations - implicit def compat(a: AnyRef): WithAnnotations = new WithAnnotations(a) - class WithAnnotations(a: AnyRef) { def attributes = a.getClass.getMethod("annotations").invoke(a).asInstanceOf[List[AnnotationInfo]] } private def annotations(in: Symbol, s: Symbol): Array[xsbti.api.Annotation] = atPhase(currentRun.typerPhase) { @@ -427,14 +403,13 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend // a) they are recorded as normal source methods anyway // b) there is no way to distinguish them from user-defined methods val associated = List(b, b.getter(b.enclClass), b.setter(b.enclClass)).filter(_ != NoSymbol) - associated.flatMap( ss => annotations(in, ss.attributes) ).removeDuplicates.toArray ; + associated.flatMap( ss => annotations(in, ss.annotations) ).distinct.toArray ; } private def annotatedType(in: Symbol, at: AnnotatedType): xsbti.api.Type = { - val annots = at.attributes + val annots = at.annotations if(annots.isEmpty) processType(in, at.underlying) else annotated(in, annots, at.underlying) } - private def fullName(s: Symbol): String = nameString(s) private def simpleName(s: Symbol): String = { val n = s.originalName diff --git a/compile/interface/Analyzer.scala b/compile/interface/Analyzer.scala index 258857626..b4d2dd65d 100644 --- a/compile/interface/Analyzer.scala +++ b/compile/interface/Analyzer.scala @@ -46,7 +46,7 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends case Some((f,className)) => f match { - case ze: ZipArchive#Entry => binaryDependency(new File(archive(ze).getName), className) + case ze: ZipArchive#Entry => for(zip <- ze.underlyingSource; zipFile <- Option(zip.file) ) binaryDependency(zipFile, className) case pf: PlainFile => binaryDependency(pf.file, className) case _ => () } @@ -69,7 +69,7 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends } if(sym.isModuleClass && !sym.isImplClass) { - if(isTopLevelModule(sym) && linkedClass(sym) == NoSymbol) + if(isTopLevelModule(sym) && sym.companionClass == NoSymbol) addGenerated(false) addGenerated(true) } @@ -81,14 +81,16 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends } } - private def classFile(sym: Symbol): Option[(AbstractFile, String)] = + private[this] final val classSeparator = '.' + private[this] def findClass(name: String): Option[AbstractFile] = classPath.findClass(name).flatMap(_.binary.asInstanceOf[Option[AbstractFile]]) + private[this] def classFile(sym: Symbol): Option[(AbstractFile, String)] = { import scala.tools.nsc.symtab.Flags - val name = flatname(sym, finder.classSeparator) + moduleSuffix(sym) - finder.findClass(name).map(file => (file, name)) orElse { + val name = flatname(sym, classSeparator) + moduleSuffix(sym) + findClass(name).map(file => (file, name)) orElse { if(isTopLevelModule(sym)) { - val linked = linkedClass(sym) + val linked = sym.companionClass if(linked == NoSymbol) None else @@ -102,7 +104,7 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends private def moduleSuffix(sym: Symbol) = if (sym.hasFlag(Flags.MODULE) && !sym.isMethod && !sym.isImplClass && !sym.hasFlag(Flags.JAVA)) "$" else ""; private def flatname(s: Symbol, separator: Char) = - atPhase(currentRun.flattenPhase.next) { nameString(s, separator) } + atPhase(currentRun.flattenPhase.next) { s fullName separator } private def isTopLevelModule(sym: Symbol): Boolean = atPhase (currentRun.picklerPhase.next) { @@ -112,70 +114,14 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends flatname(s, sep) + (if(dollarRequired) "$" else "") private def fileForClass(outputDirectory: File, s: Symbol, separatorRequired: Boolean): File = new File(outputDirectory, className(s, File.separatorChar, separatorRequired) + ".class") - - // required because the 2.8 way to find a class is: - // classPath.findClass(name).flatMap(_.binary) - // and the 2.7 way is: - // val entry = classPath.root.find(name, false) - // if(entry eq null) None else Some(entry.classFile) - private lazy val finder = try { new LegacyFinder } catch { case _ => new NewFinder } - private trait ClassFinder - { - def classSeparator: Char - def findClass(name: String): Option[AbstractFile] - } - private class NewFinder extends ClassFinder - { - private class Compat27 { def findClass(name: String) = this; def flatMap(f: Compat27 => AnyRef) = Predef.error("Should never be called"); def binary = None } - private implicit def compat27(any: AnyRef): Compat27 = new Compat27 - - def classSeparator = '.' // 2.8 uses . when searching for classes - def findClass(name: String): Option[AbstractFile] = - classPath.findClass(name).flatMap(_.binary.asInstanceOf[Option[AbstractFile]]) - } - private class LegacyFinder extends ClassFinder - { - private class Compat28 { def root: Compat28 = invalid; def find(n: String, b: Boolean) = this; def classFile = invalid; def invalid = Predef.error("Should never be called") } - private implicit def compat28(any: AnyRef): Compat28 = new Compat28 - - def classSeparator = File.separatorChar // 2.7 uses / or \ when searching for classes - private val root = classPath.root - def findClass(name: String): Option[AbstractFile] = - { - val entry = root.find(name, false) - if(entry eq null) None else Some(entry.classFile) - } - } } abstract class Compat { val global: Global import global._ - def archive(s: ZipArchive#Entry): ZipFile = s.getArchive - def nameString(s: Symbol): String = s.fullNameString - def nameString(s: Symbol, sep: Char): String = s.fullNameString(sep) - def isExistential(s: Symbol): Boolean = s.isExistential - def isNonClassType(s: Symbol): Boolean = s.isTypeMember val LocalChild = global.tpnme.LOCAL_CHILD val Nullary = global.NullaryMethodType - def linkedClass(s: Symbol): Symbol = s.linkedClassOfModule - - /** After 2.8.0.Beta1, fullNameString was renamed fullName. - * linkedClassOfModule was renamed companionClass. */ - private[this] implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym) - private[this] final class SymCompat(s: Symbol) - { - def fullNameString = s.fullName; def fullName = sourceCompatibilityOnly - def fullNameString(sep: Char) = s.fullName(sep); def fullName(sep: Char) = sourceCompatibilityOnly - - def isExistential: Boolean = s.isExistentiallyBound; def isExistentiallyBound = sourceCompatibilityOnly - def isTypeMember: Boolean = s.isNonClassType; def isNonClassType = sourceCompatibilityOnly - - def linkedClassOfModule = s.companionClass; def companionClass = sourceCompatibilityOnly - // In 2.8, hasAttribute is renamed to hasAnnotation - def hasAnnotation(a: Symbol) = s.hasAttribute(a); def hasAttribute(a: Symbol) = sourceCompatibilityOnly - } private[this] final class MiscCompat { // in 2.9, nme.LOCALCHILD was renamed to tpnme.LOCAL_CHILD @@ -190,14 +136,6 @@ abstract class Compat def unapply(t: Type): Option[Type] = None } - final def hasAnnotation(s: Symbol)(ann: Symbol) = atPhase(currentRun.typerPhase) { s.hasAnnotation(ann) } - - /** After 2.8.0.Beta1, getArchive was renamed archive.*/ - private[this] implicit def zipCompat(z: ZipArchive#Entry): ZipCompat = new ZipCompat(z) - private[this] final class ZipCompat(z: ZipArchive#Entry) - { - def getArchive = z.archive; def archive = sourceCompatibilityOnly - } private[this] def sourceCompatibilityOnly: Nothing = throw new RuntimeException("For source compatibility only: should not get here.") private[this] final implicit def miscCompat(n: AnyRef): MiscCompat = new MiscCompat diff --git a/compile/interface/DelegatingReporter.scala b/compile/interface/DelegatingReporter.scala index d791f95fe..04ef11d35 100644 --- a/compile/interface/DelegatingReporter.scala +++ b/compile/interface/DelegatingReporter.scala @@ -44,7 +44,7 @@ private final class DelegatingReporter(warnFatal: Boolean, delegate: xsbti.Repor protected def info0(pos: Position, msg: String, rawSeverity: Severity, force: Boolean) { val severity = if(warnFatal && rawSeverity == WARNING) ERROR else rawSeverity - delegate.log(convert(pos), msg, convert(rawSeverity)) + delegate.log(convert(pos), msg, convert(severity)) } private[this] def convert(posIn: Position): xsbti.Position = { diff --git a/project/Sbt.scala b/project/Sbt.scala index be90a3933..add13c031 100644 --- a/project/Sbt.scala +++ b/project/Sbt.scala @@ -85,7 +85,9 @@ object Sbt extends Build // Compiler-side interface to compiler that is compiled against the compiler being used either in advance or on the fly. // Includes API and Analyzer phases that extract source API and relationships. lazy val compileInterfaceSub = baseProject(compilePath / "interface", "Compiler Interface") dependsOn(interfaceSub, ioSub % "test->test", logSub % "test->test", launchSub % "test->test") settings( compileInterfaceSettings : _*) - lazy val precompiled28 = precompiled("2.8.1") + lazy val precompiled290 = precompiled("2.9.0") + lazy val precompiled281 = precompiled("2.8.1") + lazy val precompiled280 = precompiled("2.8.0") // lazy val precompiled27 = precompiled("2.7.7") // Implements the core functionality of detecting and propagating changes incrementally. @@ -115,7 +117,7 @@ object Sbt extends Build // Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object // technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project // with the sole purpose of providing certain identifiers without qualification (with a package object) - lazy val sbtSub = baseProject(sbtPath, "Simple Build Tool") dependsOn(mainSub, compileInterfaceSub, precompiled28, scriptedSbtSub % "test->test") settings(sbtSettings : _*) + lazy val sbtSub = baseProject(sbtPath, "Simple Build Tool") dependsOn(mainSub, compileInterfaceSub, precompiled281, precompiled280, precompiled290, scriptedSbtSub % "test->test") settings(sbtSettings : _*) /* Nested subproject paths */ def sbtPath = file("sbt") diff --git a/sbt/src/sbt-test/source-dependencies/inherited_type_params/build.sbt b/sbt/src/sbt-test/source-dependencies/inherited_type_params/build.sbt index 1182796da..d95ea6d23 100644 --- a/sbt/src/sbt-test/source-dependencies/inherited_type_params/build.sbt +++ b/sbt/src/sbt-test/source-dependencies/inherited_type_params/build.sbt @@ -1,4 +1,4 @@ -name :== "test" +name := "test" TaskKey[Unit]("check-same") <<= compile in Configurations.Compile map { analysis => analysis.apis.internal foreach { case (_, api) => diff --git a/sbt/src/sbt-test/source-dependencies/sealed/test b/sbt/src/sbt-test/source-dependencies/sealed/test index 1aecb667e..69c8ebe98 100644 --- a/sbt/src/sbt-test/source-dependencies/sealed/test +++ b/sbt/src/sbt-test/source-dependencies/sealed/test @@ -1,3 +1,5 @@ +> 'set scalacOptions += "-Xfatal-warnings"' + > compile # have new class E extend A