diff options
Diffstat (limited to 'src')
28 files changed, 220 insertions, 152 deletions
diff --git a/src/dotty/tools/backend/jvm/GenBCode.scala b/src/dotty/tools/backend/jvm/GenBCode.scala index 2d444d3be..8cec93977 100644 --- a/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/src/dotty/tools/backend/jvm/GenBCode.scala @@ -13,6 +13,9 @@ import dotty.tools.dotc import dotty.tools.dotc.backend.jvm.DottyPrimitives import dotty.tools.dotc.transform.Erasure +import dotty.tools.dotc.interfaces +import java.util.Optional + import scala.reflect.ClassTag import dotty.tools.dotc.core._ import Periods._ @@ -51,7 +54,17 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter var tree: Tree = _ - val sourceJFile: JFile = ctx.compilationUnit.source.file.file + val sourceFile = ctx.compilationUnit.source + + /** Convert a `scala.reflect.io.AbstractFile` into a + * `dotty.tools.dotc.interfaces.AbstractFile`. + */ + private[this] def convertAbstractFile(absfile: scala.reflect.io.AbstractFile): interfaces.AbstractFile = + new interfaces.AbstractFile { + override def name = absfile.name + override def path = absfile.path + override def jfile = Optional.ofNullable(absfile.file) + } final class PlainClassBuilder(cunit: CompilationUnit) extends SyncAndTryBuilder(cunit) @@ -307,7 +320,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter // Statistics.stopTimer(BackendStats.bcodeTimer, bcodeStart) if (ctx.compilerCallback != null) - ctx.compilerCallback.onSourceCompiled(sourceJFile) + ctx.compilerCallback.onSourceCompiled(sourceFile) /* TODO Bytecode can be verified (now that all classfiles have been written to disk) * @@ -373,10 +386,9 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter else getFileForClassfile(outFolder, jclassName, ".class") bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile) - val outJFile = outFile.file val className = jclassName.replace('/', '.') if (ctx.compilerCallback != null) - ctx.compilerCallback.onClassGenerated(sourceJFile, outJFile, className) + ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(outFile), className) } catch { case e: FileConflictException => diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 7c7648657..f12ab66c5 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -77,7 +77,7 @@ class Compiler { List(new LambdaLift, // in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here new ElimStaticThis, new Flatten, - new DropEmptyCompanions, + // new DropEmptyCompanions, new RestoreScopes), List(new ExpandPrivate, new CollectEntryPoints, diff --git a/src/dotty/tools/dotc/CompilerCallback.scala b/src/dotty/tools/dotc/CompilerCallback.scala deleted file mode 100644 index e2f56430b..000000000 --- a/src/dotty/tools/dotc/CompilerCallback.scala +++ /dev/null @@ -1,42 +0,0 @@ -package dotty.tools.dotc - -import java.io.File - -/** This trait contains methods that can be overriden to execute code during the - * compilation process. - * - * NOTE: This trait is experimental and may be subject to arbitrary changes. - * - * Example usage: - * {{{ - * val args: Array[String] = ... - * val callback = new CompilerCallback { - * override def onClassGenerated(source: File, generatedClass: File, className: String) = - * println(s"onClassGenerated($source, $generatedClass, $className)") - * override def onSourceCompiled(source: File) = - * println(s"onSourceCompiled($source)") - * } - * dotty.tools.dotc.process(args, callback) - * // Or, if you have a custom root context `rootCtx`: - * dotty.tools.dotc.process(args, rootCtx.fresh.setCompilerCallback(callback)) - * }}} - */ -trait CompilerCallback { - /** Called when a class has been generated. - * - * @param source The source file corresponding to this class. - * Example: ./src/library/scala/collection/Seq.scala - * @param generatedClass The generated classfile for this class. - * Example: ./scala/collection/Seq$.class - * @param className The name of this class. - * Example: scala.collection.Seq$ - */ - def onClassGenerated(source: File, generatedClass: File, className: String): Unit = {} - - /** Called when every class for this file has been generated. - * - * @param source The source file. - * Example: ./src/library/scala/collection/Seq.scala - */ - def onSourceCompiled(source: File): Unit = {} -} diff --git a/src/dotty/tools/dotc/Driver.scala b/src/dotty/tools/dotc/Driver.scala index 3437b86fc..887274fa8 100644 --- a/src/dotty/tools/dotc/Driver.scala +++ b/src/dotty/tools/dotc/Driver.scala @@ -1,11 +1,18 @@ package dotty.tools.dotc +import dotty.tools.FatalError import config.CompilerCommand import core.Contexts.{Context, ContextBase} import util.DotClass import reporting._ import scala.util.control.NonFatal +/** Run the Dotty compiler. + * + * Extending this class lets you customize many aspect of the compilation + * process, but in most cases you only need to call [[process]] on the + * existing object [[Main]]. + */ abstract class Driver extends DotClass { val prompt = "\ndotc> " @@ -40,12 +47,35 @@ abstract class Driver extends DotClass { (fileNames, ctx) } + /** Entry point to the compiler that can be conveniently used with Java reflection. + * + * This entry point can easily be used without depending on the `dotty` package, + * you only need to depend on `dotty-interfaces` and call this method using + * reflection. This allows you to write code that will work against multiple + * versions of dotty without recompilation. + * + * The trade-off is that you can only pass a SimpleReporter to this method + * and not a normal Reporter which is more powerful. + * + * Usage example: [[https://github.com/lampepfl/dotty/tree/master/test/test/InterfaceEntryPointTest.scala]] + * + * @param args Arguments to pass to the compiler. + * @param simple Used to log errors, warnings, and info messages. + * The default reporter is used if this is `null`. + * @param callback Used to execute custom code during the compilation + * process. No callbacks will be executed if this is `null`. + * @return + */ + final def process(args: Array[String], simple: interfaces.SimpleReporter, + callback: interfaces.CompilerCallback): interfaces.ReporterResult = { + val reporter = if (simple == null) null else Reporter.fromSimpleReporter(simple) + process(args, reporter, callback) + } /** Principal entry point to the compiler. - * Creates a new compiler instance and run it with arguments `args`. * - * The optional arguments of this method all have `null` as their default - * value, this makes it easier to call this method by reflection or from Java. + * Usage example: [[https://github.com/lampepfl/dotty/tree/master/test/test/OtherEntryPointsTest.scala]] + * in method `runCompiler` * * @param args Arguments to pass to the compiler. * @param reporter Used to log errors, warnings, and info messages. @@ -56,7 +86,7 @@ abstract class Driver extends DotClass { * if compilation succeeded. */ final def process(args: Array[String], reporter: Reporter = null, - callback: CompilerCallback = null): Reporter = { + callback: interfaces.CompilerCallback = null): Reporter = { val ctx = initCtx.fresh if (reporter != null) ctx.setReporter(reporter) @@ -74,7 +104,7 @@ abstract class Driver extends DotClass { * with sbt. */ final def process(args: Array[String]): Reporter = - process(args, null, null) + process(args, null: Reporter, null: interfaces.CompilerCallback) /** Entry point to the compiler using a custom `Context`. * @@ -83,6 +113,9 @@ abstract class Driver extends DotClass { * the other overloads cannot be overriden, instead you * should override this one which they call internally. * + * Usage example: [[https://github.com/lampepfl/dotty/tree/master/test/test/OtherEntryPointsTest.scala]] + * in method `runCompilerWithContext` + * * @param args Arguments to pass to the compiler. * @param rootCtx The root Context to use. * @return The `Reporter` used. Use `Reporter#hasErrors` to check @@ -101,6 +134,3 @@ abstract class Driver extends DotClass { sys.exit(if (process(args).hasErrors) 1 else 0) } } - -class FatalError(msg: String) extends Exception - diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index fcc055fc7..8ba155097 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -175,7 +175,7 @@ object desugar { vparamss = takeUpTo(normalizedVparamss, n), tpt = TypeTree(), rhs = vparam.rhs - ).withMods(vparam.mods & AccessFlags) + ).withMods(Modifiers(mods.flags & AccessFlags, mods.privateWithin)) val rest = defaultGetters(vparams :: vparamss1, n + 1) if (vparam.rhs.isEmpty) rest else defaultGetter :: rest case Nil :: vparamss1 => diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index c1132ce4b..f0537dffa 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -2,6 +2,7 @@ package dotty.tools package dotc package core +import interfaces.CompilerCallback import Decorators._ import Periods._ import Names._ diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 83ac64d53..b60f437d5 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -4,6 +4,7 @@ package core import Periods._ import Contexts._ import dotty.tools.backend.jvm.{LabelDefs, GenBCode} +import dotty.tools.dotc.core.Symbols.ClassSymbol import util.DotClass import DenotTransformers._ import Denotations._ @@ -347,6 +348,10 @@ object Phases { override def toString = phaseName } + trait NeedsCompanions { + def isCompanionNeeded(cls: ClassSymbol)(implicit ctx: Context): Boolean + } + /** Replace all instances of `oldPhaseClass` in `current` phases * by the result of `newPhases` applied to the old phase. */ diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index da3b76c57..91913b935 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -612,7 +612,7 @@ object Types { /** The set of members of this type having at least one of `requiredFlags` but none of `excludedFlags` set */ final def membersBasedOnFlags(requiredFlags: FlagSet, excludedFlags: FlagSet)(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") { memberDenots(takeAllFilter, - (name, buf) => buf ++= member(name).altsWith(x => x.is(requiredFlags, butNot = excludedFlags))) + (name, buf) => buf ++= memberExcluding(name, excludedFlags).altsWith(x => x.is(requiredFlags))) } /** The info of `sym`, seen as a member of this type. */ diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 8f1fbf797..f35293d8d 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -16,13 +16,13 @@ import scala.reflect.internal.util._ class ConsoleReporter( reader: BufferedReader = Console.in, writer: PrintWriter = new PrintWriter(Console.err, true)) - extends Reporter with UniqueMessagePositions { + extends Reporter with UniqueMessagePositions with HideNonSensicalMessages { /** maximal number of error messages to be printed */ protected def ErrorLimit = 100 def printSourceLine(pos: SourcePosition) = - printMessage(pos.lineContents.stripLineEnd) + printMessage(pos.lineContent.stripLineEnd) def printColumnMarker(pos: SourcePosition) = if (pos.exists) { printMessage(" " * pos.column + "^") } @@ -40,21 +40,17 @@ class ConsoleReporter( } } - override def doReport(d: Diagnostic)(implicit ctx: Context): Boolean = { - val issue = !(d.isSuppressed && hasErrors) - if (issue) d match { - case d: Error => - printMessageAndPos(s"error: ${d.msg}", d.pos) - if (ctx.settings.prompt.value) displayPrompt() - case d: ConditionalWarning if !d.enablingOption.value => - case d: MigrationWarning => - printMessageAndPos(s"migration warning: ${d.msg}", d.pos) - case d: Warning => - printMessageAndPos(s"warning: ${d.msg}", d.pos) - case _ => - printMessageAndPos(d.msg, d.pos) - } - issue + override def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match { + case d: Error => + printMessageAndPos(s"error: ${d.message}", d.pos) + if (ctx.settings.prompt.value) displayPrompt() + case d: ConditionalWarning if !d.enablingOption.value => + case d: MigrationWarning => + printMessageAndPos(s"migration warning: ${d.message}", d.pos) + case d: Warning => + printMessageAndPos(s"warning: ${d.message}", d.pos) + case _ => + printMessageAndPos(d.message, d.pos) } def displayPrompt(): Unit = { diff --git a/src/dotty/tools/dotc/reporting/Diagnostic.scala b/src/dotty/tools/dotc/reporting/Diagnostic.scala new file mode 100644 index 000000000..bcf55e993 --- /dev/null +++ b/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -0,0 +1,47 @@ +package dotty.tools +package dotc +package reporting + +import util.SourcePosition + +import java.util.Optional + +object Diagnostic { + val nonSensicalStartTag = "<nonsensical>" + val nonSensicalEndTag = "</nonsensical>" +} + +class Diagnostic(msgFn: => String, val pos: SourcePosition, val level: Int) + extends Exception with interfaces.Diagnostic { + import Diagnostic._ + private var myMsg: String = null + private var myIsNonSensical: Boolean = false + + override def position: Optional[interfaces.SourcePosition] = + if (pos.exists && pos.source.exists) Optional.of(pos) else Optional.empty() + + /** The message to report */ + def message: String = { + if (myMsg == null) { + myMsg = msgFn + if (myMsg.contains(nonSensicalStartTag)) { + myIsNonSensical = true + // myMsg might be composed of several d"..." invocations -> nested nonsensical tags possible + myMsg = myMsg.replaceAllLiterally(nonSensicalStartTag, "").replaceAllLiterally(nonSensicalEndTag, "") + } + } + myMsg + } + + /** A message is non-sensical if it contains references to <nonsensical> tags. + * Such tags are inserted by the error diagnostic framework if a message + * contains references to internally generated error types. Normally we + * want to suppress error messages referring to types like this because + * they look weird and are normally follow-up errors to something that + * was diagnosed before. + */ + def isNonSensical = { message; myIsNonSensical } + + override def toString = s"$getClass at $pos: $message" + override def getMessage() = message +} diff --git a/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala b/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala new file mode 100644 index 000000000..a325fe9f7 --- /dev/null +++ b/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala @@ -0,0 +1,20 @@ +package dotty.tools +package dotc +package reporting + +import core.Contexts.Context + +/** + * This trait implements `isHidden` so that we avoid reporting non-sensical messages. + */ +trait HideNonSensicalMessages extends Reporter { + /** Hides non-sensical messages, unless we haven't reported any error yet or + * `-Yshow-suppressed-errors` is set. + */ + override def isHidden(d: Diagnostic)(implicit ctx: Context): Boolean = + super.isHidden(d) || { + d.isNonSensical && + hasErrors && // if there are no errors yet, report even if diagnostic is non-sensical + !ctx.settings.YshowSuppressedErrors.value + } +} diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index 272b1880f..8236f93ef 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -10,46 +10,10 @@ import collection.mutable import config.Settings.Setting import config.Printers import java.lang.System.currentTimeMillis -import typer.ErrorReporting.DiagnosticString import typer.Mode +import interfaces.Diagnostic.{ERROR, WARNING, INFO} object Reporter { - - private val ERROR = 2 - private val WARNING = 1 - private val INFO = 0 - - class Diagnostic(msgFn: => String, val pos: SourcePosition, val level: Int) extends Exception { - import DiagnosticString._ - - private var myMsg: String = null - private var myIsNonSensical: Boolean = false - - /** The message to report */ - def msg: String = { - if (myMsg == null) { - myMsg = msgFn - if (myMsg.contains(nonSensicalStartTag)) { - myIsNonSensical = true - // myMsg might be composed of several d"..." invocations -> nested nonsensical tags possible - myMsg = myMsg.replaceAllLiterally(nonSensicalStartTag, "").replaceAllLiterally(nonSensicalEndTag, "") - } - } - myMsg - } - - /** Report in current reporter */ - def report(implicit ctx: Context) = ctx.reporter.report(this) - - def isNonSensical = { msg; myIsNonSensical } - def isSuppressed(implicit ctx: Context): Boolean = !ctx.settings.YshowSuppressedErrors.value && isNonSensical - - override def toString = s"$getClass at $pos: $msg" - override def getMessage() = msg - - def checkingStr: String = msgFn - } - class Error(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, ERROR) class Warning(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, WARNING) class Info(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, INFO) @@ -69,6 +33,16 @@ object Reporter { class MigrationWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) { def enablingOption(implicit ctx: Context) = ctx.settings.migration } + + /** Convert a SimpleReporter into a real Reporter */ + def fromSimpleReporter(simple: interfaces.SimpleReporter): Reporter = + new Reporter with UniqueMessagePositions with HideNonSensicalMessages { + override def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match { + case d: ConditionalWarning if !d.enablingOption.value => + case _ => + simple.report(d) + } + } } import Reporter._ @@ -193,12 +167,10 @@ trait Reporting { this: Context => * This interface provides methods to issue information, warning and * error messages. */ -abstract class Reporter { +abstract class Reporter extends interfaces.ReporterResult { - /** Report a diagnostic, unless it is suppressed because it is nonsensical - * @return a diagnostic was reported. - */ - def doReport(d: Diagnostic)(implicit ctx: Context): Boolean + /** Report a diagnostic */ + def doReport(d: Diagnostic)(implicit ctx: Context): Unit /** Whether very long lines can be truncated. This exists so important * debugging information (like printing the classpath) is not rendered @@ -239,7 +211,8 @@ abstract class Reporter { } def report(d: Diagnostic)(implicit ctx: Context): Unit = - if (!isHidden(d) && doReport(d)(ctx.addMode(Mode.Printing))) + if (!isHidden(d)) { + doReport(d)(ctx.addMode(Mode.Printing)) d match { case d: ConditionalWarning if !d.enablingOption.value => unreportedWarnings(d.enablingOption.name) += 1 case d: Warning => warningCount += 1 @@ -249,6 +222,7 @@ abstract class Reporter { case d: Info => // nothing to do here // match error if d is something else } + } def incomplete(d: Diagnostic)(implicit ctx: Context): Unit = incompleteHandler(d)(ctx) diff --git a/src/dotty/tools/dotc/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala index 8209839eb..954bff88e 100644 --- a/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -4,7 +4,7 @@ package reporting import core.Contexts.Context import collection.mutable -import Reporter.{Diagnostic, Error, Warning} +import Reporter.{Error, Warning} import config.Printers._ /** @@ -14,11 +14,10 @@ class StoreReporter(outer: Reporter) extends Reporter { private var infos: mutable.ListBuffer[Diagnostic] = null - def doReport(d: Diagnostic)(implicit ctx: Context): Boolean = { - typr.println(s">>>> StoredError: ${d.msg}") // !!! DEBUG + def doReport(d: Diagnostic)(implicit ctx: Context): Unit = { + typr.println(s">>>> StoredError: ${d.message}") // !!! DEBUG if (infos == null) infos = new mutable.ListBuffer infos += d - true } override def hasPending: Boolean = infos != null && { diff --git a/src/dotty/tools/dotc/reporting/ThrowingReporter.scala b/src/dotty/tools/dotc/reporting/ThrowingReporter.scala index 7c63383e9..026453036 100644 --- a/src/dotty/tools/dotc/reporting/ThrowingReporter.scala +++ b/src/dotty/tools/dotc/reporting/ThrowingReporter.scala @@ -11,7 +11,7 @@ import Reporter._ * info to the underlying reporter. */ class ThrowingReporter(reportInfo: Reporter) extends Reporter { - def doReport(d: Diagnostic)(implicit ctx: Context): Boolean = d match { + def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match { case _: Error => throw d case _ => reportInfo.doReport(d) } diff --git a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala index c1f240a23..32554e6b6 100644 --- a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala +++ b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -4,7 +4,6 @@ package reporting import scala.collection.mutable import util.{SourcePosition, SourceFile} -import Reporter.Diagnostic import core.Contexts.Context /** diff --git a/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala b/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala.disabled index 65362f199..65362f199 100644 --- a/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala +++ b/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala.disabled diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 90e105ee7..c5ab49c9c 100644 --- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.ast.{Trees, tpd} import scala.collection.{ mutable, immutable } import mutable.ListBuffer import core._ -import Phases.Phase +import dotty.tools.dotc.core.Phases.{NeedsCompanions, Phase} import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import TypeErasure.{ valueErasure, ErasedValueType } @@ -33,7 +33,7 @@ import SymUtils._ * This is different from the implementation of value classes in Scala 2 * (see SIP-15) which uses `asInstanceOf` which does not typecheck. */ -class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransformer => +class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with FullParameterization with NeedsCompanions { thisTransformer => import tpd._ import ExtensionMethods._ @@ -45,6 +45,10 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful override def runsAfterGroupsOf = Set(classOf[FirstTransform]) // need companion objects to exist + def isCompanionNeeded(cls: ClassSymbol)(implicit ctx: Context): Boolean = { + isDerivedValueClass(cls) + } + override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match { case moduleClassSym: ClassDenotation if moduleClassSym is ModuleClass => moduleClassSym.linkedClass match { diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 3b629f9b6..c24c5bbd9 100644 --- a/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -3,7 +3,9 @@ package transform import core._ import Names._ -import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer} +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.core.Phases.NeedsCompanions +import dotty.tools.dotc.transform.TreeTransforms._ import ast.Trees._ import Flags._ import Types._ @@ -32,6 +34,16 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi override def phaseName = "firstTransform" + private var addCompanionPhases: List[NeedsCompanions] = _ + + def needsCompanion(cls: ClassSymbol)(implicit ctx: Context) = + addCompanionPhases.exists(_.isCompanionNeeded(cls)) + + override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = { + addCompanionPhases = ctx.phasePlan.flatMap(_ collect { case p: NeedsCompanions => p }) + this + } + def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match { @@ -80,7 +92,7 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi } def addMissingCompanions(stats: List[Tree]): List[Tree] = stats map { - case stat: TypeDef if singleClassDefs contains stat.name => + case stat: TypeDef if (singleClassDefs contains stat.name) && needsCompanion(stat.symbol.asClass) => val objName = stat.name.toTermName val nameClash = stats.exists { case other: MemberDef => diff --git a/src/dotty/tools/dotc/transform/Getters.scala b/src/dotty/tools/dotc/transform/Getters.scala index 765791822..882e42d2f 100644 --- a/src/dotty/tools/dotc/transform/Getters.scala +++ b/src/dotty/tools/dotc/transform/Getters.scala @@ -12,6 +12,7 @@ import Constants._ import TreeTransforms._ import Flags._ import Decorators._ +import ValueClasses._ /** Performs the following rewritings for fields of a class: * @@ -34,7 +35,7 @@ import Decorators._ * * Omitted from the rewritings are * - * - private[this] fields in non-trait classes + * - private[this] fields in classes (excluding traits, value classes) * - fields generated for static modules (TODO: needed?) * - parameters, static fields, and fields coming from Java * @@ -53,7 +54,7 @@ class Getters extends MiniPhaseTransform with SymTransformer { thisTransform => override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = { def noGetterNeeded = d.is(NoGetterNeeded) || - d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) && !d.is(Flags.Lazy) || + d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) && !isDerivedValueClass(d.owner) && !d.is(Flags.Lazy) || d.is(Module) && d.isStatic || d.isSelfSym if (d.isTerm && (d.is(Lazy) || d.owner.isClass) && d.info.isValueType && !noGetterNeeded) { diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index 4a8ff83ca..2aece0663 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -1,6 +1,7 @@ package dotty.tools.dotc package transform +import dotty.tools.dotc.core.Phases.NeedsCompanions import dotty.tools.dotc.typer.Mode import scala.collection.mutable @@ -23,7 +24,7 @@ import dotty.tools.dotc.core.SymDenotations.SymDenotation import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer, DenotTransformer} import Erasure.Boxing.adaptToType -class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { +class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer with NeedsCompanions { import LazyVals._ import tpd._ @@ -46,6 +47,11 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { * before this phase starts processing same tree */ override def runsAfter = Set(classOf[Mixin]) + def isCompanionNeeded(cls: ClassSymbol)(implicit ctx: Context): Boolean = { + def hasLazyVal(x: ClassSymbol) = x.classInfo.membersBasedOnFlags(Flags.Lazy, excludedFlags = Flags.EmptyFlags).nonEmpty + hasLazyVal(cls) || cls.mixins.exists(hasLazyVal) + } + override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = transformLazyVal(tree) diff --git a/src/dotty/tools/dotc/transform/Literalize.scala b/src/dotty/tools/dotc/transform/Literalize.scala.disabled index f33baa52b..f33baa52b 100644 --- a/src/dotty/tools/dotc/transform/Literalize.scala +++ b/src/dotty/tools/dotc/transform/Literalize.scala.disabled diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index 4d626c67b..b4e32fa66 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -1543,7 +1543,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val spb = subPatBinders ExtractorTreeMaker(extractorApply, lengthGuard(binder), binder)( spb, - subPatRefs(binder, spb, binderTypeTested), + subPatRefs(binder, spb, resultType), aligner.isBool, checkedLength, patBinderOrCasted, diff --git a/src/dotty/tools/dotc/transform/PrivateToStatic.scala b/src/dotty/tools/dotc/transform/PrivateToStatic.scala.disabled index 218839d01..218839d01 100644 --- a/src/dotty/tools/dotc/transform/PrivateToStatic.scala +++ b/src/dotty/tools/dotc/transform/PrivateToStatic.scala.disabled diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index b3089c99c..d6a87acf6 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -8,6 +8,7 @@ import Trees._ import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._ import Applications._, Implicits._, Flags._ import util.Positions._ +import reporting.Diagnostic import printing.Showable import printing.Disambiguation.disambiguated @@ -127,7 +128,6 @@ object ErrorReporting { * message composition methods, this is crucial. */ implicit class DiagnosticString(val sc: StringContext) extends AnyVal { - import DiagnosticString._ def d(args: Any*)(implicit ctx: Context): String = { def isSensical(arg: Any): Boolean = arg match { case l: Seq[_] => l.forall(isSensical(_)) @@ -139,13 +139,8 @@ object ErrorReporting { } val s = new StringInterpolators(sc).i(args : _*) - if (args.forall(isSensical(_))) s else nonSensicalStartTag + s + nonSensicalEndTag + if (args.forall(isSensical(_))) s + else Diagnostic.nonSensicalStartTag + s + Diagnostic.nonSensicalEndTag } } - - object DiagnosticString { - final val nonSensicalStartTag = "<nonsensical>" - final val nonSensicalEndTag = "</nonsensical>" - } - } diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 9717b5625..99e8cd150 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -15,7 +15,6 @@ import util.{Stats, SimpleMap} import util.common._ import Decorators._ import Uniques._ -import ErrorReporting.{errorType, DiagnosticString} import config.Printers._ import annotation.tailrec import collection.mutable diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala index bb411c6b5..afbb43faf 100644 --- a/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/src/dotty/tools/dotc/typer/RefChecks.scala @@ -715,8 +715,6 @@ object RefChecks { case List(param) => if (param.is(Mutable)) ctx.error("value class parameter must not be a var", param.pos) - if (param.is(PrivateLocal)) - ctx.error("value class parameter must not be private[this]", param.pos) case _ => ctx.error("value class needs to have exactly one val parameter", clazz.pos) } diff --git a/src/dotty/tools/dotc/util/SourceFile.scala b/src/dotty/tools/dotc/util/SourceFile.scala index da2e54132..6b547203e 100644 --- a/src/dotty/tools/dotc/util/SourceFile.scala +++ b/src/dotty/tools/dotc/util/SourceFile.scala @@ -11,6 +11,8 @@ import Chars._ import ScriptSourceFile._ import Positions._ +import java.util.Optional + object ScriptSourceFile { @sharable private val headerPattern = Pattern.compile("""^(::)?!#.*(\r|\n|\r\n)""", Pattern.MULTILINE) private val headerStarts = List("#!", "::#!") @@ -32,7 +34,7 @@ object ScriptSourceFile { } } -case class SourceFile(file: AbstractFile, content: Array[Char]) { +case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfaces.SourceFile { def this(_file: AbstractFile) = this(_file, _file.toCharArray) def this(sourceName: String, cs: Seq[Char]) = this(new VirtualFile(sourceName), cs.toArray) @@ -41,6 +43,10 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) { /** Tab increment; can be overridden */ def tabInc = 8 + override def name = file.name + override def path = file.path + override def jfile = Optional.ofNullable(file.file) + override def equals(that : Any) = that match { case that : SourceFile => file.path == that.file.path && start == that.start case _ => false @@ -113,8 +119,8 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) { def nextLine(offset: Int): Int = lineToOffset(offsetToLine(offset) + 1 min lineIndices.length - 1) - /** The contents of the line containing position `offset` */ - def lineContents(offset: Int): String = + /** The content of the line containing position `offset` */ + def lineContent(offset: Int): String = content.slice(startOfLine(offset), nextLine(offset)).mkString /** The column corresponding to `offset`, starting at 0 */ diff --git a/src/dotty/tools/dotc/util/SourcePosition.scala b/src/dotty/tools/dotc/util/SourcePosition.scala index 9e02841f2..0b2b2aa0b 100644 --- a/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/src/dotty/tools/dotc/util/SourcePosition.scala @@ -1,23 +1,29 @@ package dotty.tools -package dotc.util +package dotc +package util import Positions.{Position, NoPosition} /** A source position is comprised of a position in a source file */ -case class SourcePosition(source: SourceFile, pos: Position) { - def point: Int = pos.point - def start: Int = pos.start - def end: Int = pos.end +case class SourcePosition(source: SourceFile, pos: Position) extends interfaces.SourcePosition { def exists = pos.exists - def lineContents: String = source.lineContents(point) + def lineContent: String = source.lineContent(point) + def point: Int = pos.point /** The line of the position, starting at 0 */ def line: Int = source.offsetToLine(point) - /** The column of the position, starting at 0 */ def column: Int = source.column(point) + def start: Int = pos.start + def startLine: Int = source.offsetToLine(start) + def startColumn: Int = source.column(start) + + def end: Int = pos.end + def endLine: Int = source.offsetToLine(end) + def endColumn: Int = source.column(end) + override def toString = if (source.exists) s"${source.file}:${line + 1}" else s"(no source file, offset = ${pos.point})" |