diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc')
28 files changed, 448 insertions, 384 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index e3102fda2..deb239143 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -559,7 +559,7 @@ object desugar { * ValDef or DefDef. */ def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match { - case VarPattern(named, tpt) => + case IdPattern(named, tpt) => derivedValDef(original, named, tpt, rhs, mods) case _ => val rhsUnchecked = makeAnnotated("scala.unchecked", rhs) @@ -816,7 +816,7 @@ object desugar { * Otherwise this gives { case pat => body } */ def makeLambda(pat: Tree, body: Tree): Tree = pat match { - case VarPattern(named, tpt) => + case IdPattern(named, tpt) => Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body) case _ => makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false) @@ -898,7 +898,9 @@ object desugar { } def isIrrefutableGenFrom(gen: GenFrom): Boolean = - gen.isInstanceOf[IrrefutableGenFrom] || isIrrefutable(gen.pat, gen.expr) + gen.isInstanceOf[IrrefutableGenFrom] || + IdPattern.unapply(gen.pat).isDefined || + isIrrefutable(gen.pat, gen.expr) /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when * matched against `rhs`. @@ -1062,9 +1064,9 @@ object desugar { TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait) } - /** If tree is a variable pattern, return its name and type, otherwise return None. + /** If tree is of the form `id` or `id: T`, return its name and type, otherwise return None. */ - private object VarPattern { + private object IdPattern { def unapply(tree: Tree)(implicit ctx: Context): Option[VarInfo] = tree match { case id: Ident => Some(id, TypeTree()) case Typed(id: Ident, tpt) => Some((id, tpt)) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index bf11a442e..27be8c9d6 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1077,6 +1077,13 @@ object Trees { /** Hook to indicate that a transform of some subtree should be skipped */ protected def skipTransform(tree: Tree)(implicit ctx: Context): Boolean = false + /** For untyped trees, this is just the identity. + * For typed trees, a context derived form `ctx` that records `call` as the + * innermost enclosing call for which the inlined version is currently + * processed. + */ + protected def inlineContext(call: Tree)(implicit ctx: Context): Context = ctx + abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { def transform(tree: Tree)(implicit ctx: Context): Tree = @@ -1121,7 +1128,7 @@ object Trees { case SeqLiteral(elems, elemtpt) => cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) case Inlined(call, bindings, expansion) => - cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)) + cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(inlineContext(call))) case TypeTree() => tree case SingletonTypeTree(ref) => @@ -1225,7 +1232,7 @@ object Trees { case SeqLiteral(elems, elemtpt) => this(this(x, elems), elemtpt) case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion) + this(this(x, bindings), expansion)(inlineContext(call)) case TypeTree() => x case SingletonTypeTree(ref) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index ed268fda7..e5904156f 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -342,7 +342,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { private def followOuterLinks(t: Tree)(implicit ctx: Context) = t match { case t: This if ctx.erasedTypes && !(t.symbol == ctx.owner.enclosingClass || t.symbol.isStaticOwner) => // after erasure outer paths should be respected - new ExplicitOuter.OuterOps(ctx).path(t.tpe.widen.classSymbol) + new ExplicitOuter.OuterOps(ctx).path(toCls = t.tpe.widen.classSymbol) case t => t } @@ -933,10 +933,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = new Property.Key[List[Tree]] - /** A context derived form `ctx` that records `call` as innermost enclosing - * call for which the inlined version is currently processed. - */ - def inlineContext(call: Tree)(implicit ctx: Context): Context = + override def inlineContext(call: Tree)(implicit ctx: Context): Context = ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds) /** All enclosing calls that are currently inlined, from innermost to outermost */ diff --git a/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala b/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala index 19ede3cec..c2301a3aa 100644 --- a/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala +++ b/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala @@ -93,21 +93,20 @@ object CompilerCommand extends DotClass { def shouldStopWithInfo = { import settings._ - Set(help, Xhelp, Yhelp, showPlugins, showPhases) exists (_.value) + Set(help, Xhelp, Yhelp) exists (_.value) } def infoMessage: String = { import settings._ - if (help.value) usageMessage - else if (Xhelp.value) xusageMessage - else if (Yhelp.value) yusageMessage -// else if (showPlugins.value) global.pluginDescriptions -// else if (showPhases.value) global.phaseDescriptions + ( -// if (debug.value) "\n" + global.phaseFlagDescriptions else "" -// ) - else "" + if (help.value) usageMessage + else if (Xhelp.value) xusageMessage + else if (Yhelp.value) yusageMessage + else "" } + // Print all warnings encountered during arguments parsing + summary.warnings.foreach(ctx.warning(_)) + if (summary.errors.nonEmpty) { summary.errors foreach (ctx.error(_)) ctx.echo(" dotc -help gives more information") diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index 184b3718a..159989e6f 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -144,7 +144,7 @@ object PathResolver { } else { implicit val ctx = (new ContextBase).initialCtx - val ArgsSummary(sstate, rest, errors) = + val ArgsSummary(sstate, rest, errors, warnings) = ctx.settings.processArguments(args.toList, true) errors.foreach(println) val pr = new PathResolver()(ctx.fresh.setSettings(sstate)) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index e4c90789c..fd79fcaa6 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -8,152 +8,74 @@ class ScalaSettings extends Settings.SettingGroup { protected def defaultClasspath = sys.env.getOrElse("CLASSPATH", ".") - /** Path related settings. - */ + /** Path related settings */ val bootclasspath = PathSetting("-bootclasspath", "Override location of bootstrap class files.", Defaults.scalaBootClassPath) val extdirs = PathSetting("-extdirs", "Override location of installed extensions.", Defaults.scalaExtDirs) val javabootclasspath = PathSetting("-javabootclasspath", "Override java boot classpath.", Defaults.javaBootClassPath) val javaextdirs = PathSetting("-javaextdirs", "Override java extdirs classpath.", Defaults.javaExtDirs) val sourcepath = PathSetting("-sourcepath", "Specify location(s) of source files.", "") // Defaults.scalaSourcePath - val argfiles = BooleanSetting("@<file>", "A text file containing compiler arguments (options and source files)") val classpath = PathSetting("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp" val d = StringSetting("-d", "directory|jar", "destination for generated classfiles.", ".") val priorityclasspath = PathSetting("-priorityclasspath", "class path that takes precedence over all other paths (or testing only)", "") - /** Other settings. - */ - val dependencyfile = StringSetting("-dependencyfile", "file", "Set dependency tracking file.", ".scala_dependencies") + /** Other settings */ val deprecation = BooleanSetting("-deprecation", "Emit warning and location for usages of deprecated APIs.") val migration = BooleanSetting("-migration", "Emit warning and location for migration issues from Scala 2.") val encoding = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding) val explaintypes = BooleanSetting("-explaintypes", "Explain type errors in more detail.") val explain = BooleanSetting("-explain", "Explain errors in more detail.") val feature = BooleanSetting("-feature", "Emit warning and location for usages of features that should be imported explicitly.") - val g = ChoiceSetting("-g", "level", "Set level of generated debugging info.", List("none", "source", "line", "vars", "notailcalls"), "vars") val help = BooleanSetting("-help", "Print a synopsis of standard options") - val nowarn = BooleanSetting("-nowarn", "Generate no warnings.") val color = ChoiceSetting("-color", "mode", "Colored output", List("always", "never"/*, "auto"*/), "always"/* "auto"*/) val target = ChoiceSetting("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.", - List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "jvm-1.8", "msil"), - "jvm-1.8") - val scalajs = BooleanSetting("-scalajs", "Compile in Scala.js mode (requires scalajs-library.jar on the classpath).") + List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "jvm-1.8", "msil"), "jvm-1.8") val unchecked = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.") val uniqid = BooleanSetting("-uniqid", "Uniquely tag all identifiers in debugging output.") val usejavacp = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.") val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing.") val version = BooleanSetting("-version", "Print product version and exit.") val pageWidth = IntSetting("-pagewidth", "Set page width", 80) - - val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.") - val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.") - val toolcp = PathSetting("-toolcp", "Add to the runner classpath.", "") - val nobootcp = BooleanSetting("-nobootcp", "Do not use the boot classpath for the scala jars.") val strict = BooleanSetting("-strict", "Use strict type rules, which means some formerly legal code does not typecheck anymore.") - - val nospecialization = BooleanSetting("-no-specialization", "Ignore @specialize annotations.") val language = MultiStringSetting("-language", "feature", "Enable one or more language features.") val rewrite = OptionSetting[Rewrites]("-rewrite", "When used in conjunction with -language:Scala2 rewrites sources to migrate to new syntax") /** -X "Advanced" settings */ val Xhelp = BooleanSetting("-X", "Print a synopsis of advanced options.") - val assemname = StringSetting("-Xassem-name", "file", "(Requires -target:msil) Name of the output assembly.", "").dependsOn(target, "msil") - val assemrefs = StringSetting("-Xassem-path", "path", "(Requires -target:msil) List of assemblies referenced by the program.", ".").dependsOn(target, "msil") - val assemextdirs = StringSetting("-Xassem-extdirs", "dirs", "(Requires -target:msil) List of directories containing assemblies. default:lib", Defaults.scalaLibDir.path).dependsOn(target, "msil") - val sourcedir = StringSetting("-Xsourcedir", "directory", "(Requires -target:msil) Mirror source folder structure in output directory.", ".").dependsOn(target, "msil") - val checkInit = BooleanSetting("-Xcheckinit", "Wrap field accessors to throw an exception on uninitialized access.") - val noassertions = BooleanSetting("-Xdisable-assertions", "Generate no assertions or assumptions.") -// val elidebelow = IntSetting("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument", -// elidable.MINIMUM, None, elidable.byName get _) val noForwarders = BooleanSetting("-Xno-forwarders", "Do not generate static forwarders in mirror classes.") - val genPhaseGraph = StringSetting("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") - val XlogImplicits = BooleanSetting("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") val XminImplicitSearchDepth = IntSetting("-Xmin-implicit-search-depth", "Set number of levels of implicit searches undertaken before checking for divergence.", 5) val xmaxInlines = IntSetting("-Xmax-inlines", "Maximal number of successive inlines", 32) - val logImplicitConv = BooleanSetting("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.") - val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated") - val logFreeTerms = BooleanSetting("-Xlog-free-terms", "Print a message when reification creates a free term.") - val logFreeTypes = BooleanSetting("-Xlog-free-types", "Print a message when reification resorts to generating a free type.") val maxClassfileName = IntSetting("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, 72 to 255) val Xmigration = VersionSetting("-Xmigration", "Warn about constructs whose behavior may have changed since version.") - val Xsource = VersionSetting("-Xsource", "Treat compiler input as Scala source for the specified version.") - val Xverify = BooleanSetting("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)") - val plugin = MultiStringSetting("-Xplugin", "file", "Load one or more plugins from files.") - val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable the given plugin(s).") - val showPlugins = BooleanSetting("-Xplugin-list", "Print a synopsis of loaded plugins.") - val require = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless the given plugin(s) are available.") - val pluginsDir = StringSetting("-Xpluginsdir", "path", "Path to search compiler plugins.", Defaults.scalaPluginPath) val Xprint = PhasesSetting("-Xprint", "Print out program after") - val writeICode = PhasesSetting("-Xprint-icode", "Log internal icode to *.icode files after", "icode") - val Xprintpos = BooleanSetting("-Xprint-pos", "Print tree positions, as offsets.") val printtypes = BooleanSetting("-Xprint-types", "Print tree types (debugging option).") val XprintDiff = BooleanSetting("-Xprint-diff", "Print changed parts of the tree since last print.") val XprintDiffDel = BooleanSetting("-Xprint-diff-del", "Print chaged parts of the tree since last print including deleted parts.") val prompt = BooleanSetting("-Xprompt", "Display a prompt after each error (debugging option).") - val script = StringSetting("-Xscript", "object", "Treat the source file as a script and wrap it in a main method.", "") val mainClass = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d <jar>)", "") - val Xshowcls = StringSetting("-Xshow-class", "class", "Show internal representation of class.", "") - val Xshowobj = StringSetting("-Xshow-object", "object", "Show internal representation of object.", "") - val showPhases = BooleanSetting("-Xshow-phases", "Print a synopsis of compiler phases.") - val sourceReader = StringSetting("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") val XnoValueClasses = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.") val XreplLineWidth = IntSetting("-Xrepl-line-width", "Maximial number of columns per line for REPL output", 390) - val XoldPatmat = BooleanSetting("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.") - val XnoPatmatAnalysis = BooleanSetting("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") - val XfullLubs = BooleanSetting("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.") - val wikiSyntax = BooleanSetting("-Xwiki-syntax", "Retains the Scala2 behavior of using Wiki Syntax in Scaladoc") - /** -Y "Private" settings - */ - val overrideObjects = BooleanSetting("-Yoverride-objects", "Allow member objects to be overridden.") + /** -Y "Private" settings */ val overrideVars = BooleanSetting("-Yoverride-vars", "Allow vars to be overridden.") val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.") - val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after") val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of") val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync") - val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness") - val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after") - val Ycloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.") - val Ycompacttrees = BooleanSetting("-Ycompact-trees", "Use compact tree printer when displaying trees.") - val noCompletion = BooleanSetting("-Yno-completion", "Disable tab-completion in the REPL.") - val Ydce = BooleanSetting("-Ydead-code", "Perform dead code elimination.") val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.") val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names") val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations") val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions") val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)") - //val doc = BooleanSetting ("-Ydoc", "Generate documentation") val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") - val inlineHandlers = BooleanSetting("-Yinline-handlers", "Perform exception handler inlining when possible.") - val YinlinerWarnings = BooleanSetting("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)") - val Ylinearizer = ChoiceSetting("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") val log = PhasesSetting("-Ylog", "Log operations during") val Ylogcp = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.") - val Ynogenericsig = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.") val YnoImports = BooleanSetting("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.") val YnoPredef = BooleanSetting("-Yno-predef", "Compile without importing Predef.") - val noAdaptedArgs = BooleanSetting("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.") - val selfInAnnots = BooleanSetting("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.") - val Yshowtrees = BooleanSetting("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.") - val YshowtreesCompact = BooleanSetting("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.") - val YshowtreesStringified = BooleanSetting("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.") - val Yshowsyms = BooleanSetting("-Yshow-syms", "Print the AST symbol hierarchy after each phase.") - val Yshowsymkinds = BooleanSetting("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.") val Yskip = PhasesSetting("-Yskip", "Skip") - val Ygenjavap = StringSetting("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "") val Ydumpclasses = StringSetting("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "") - val Ynosqueeze = BooleanSetting("-Yno-squeeze", "Disable creation of compact code in matching.") val YstopAfter = PhasesSetting("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat val YstopBefore = PhasesSetting("-Ystop-before", "Stop before") // stop before erasure as long as we have not debugged it fully - val refinementMethodDispatch = ChoiceSetting("-Ystruct-dispatch", "policy", "structural method dispatch policy", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") - val Yrangepos = BooleanSetting("-Yrangepos", "Use range positions for syntax trees.") - val Ybuilderdebug = ChoiceSetting("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none") - val Yreifycopypaste = BooleanSetting("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") - val Yreplsync = BooleanSetting("-Yrepl-sync", "Do not use asynchronous code for repl startup") val YmethodInfer = BooleanSetting("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") - val etaExpandKeepsStar = BooleanSetting("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") - val Yinvalidate = StringSetting("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "") - val noSelfCheck = BooleanSetting("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") val YtraceContextCreation = BooleanSetting("-Ytrace-context-creation", "Store stack trace of context creations.") val YshowSuppressedErrors = BooleanSetting("-Yshow-suppressed-errors", "Also show follow-on errors and warnings that are normally supressed.") val Yheartbeat = BooleanSetting("-Yheartbeat", "show heartbeat stack trace of compiler operations.") @@ -167,52 +89,17 @@ class ScalaSettings extends Settings.SettingGroup { val YforceSbtPhases = BooleanSetting("-Yforce-sbt-phases", "Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging.") val YdumpSbtInc = BooleanSetting("-Ydump-sbt-inc", "For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases.") val YcheckAllPatmat = BooleanSetting("-Ycheck-all-patmat", "Check exhaustivity and redundancy of all pattern matching (used for testing the algorithm)") - def stop = YstopAfter - /** Area-specific debug output. - */ - val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.") - val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.") - val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.") - val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.") - val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.") - val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.") - val YmacrodebugLite = BooleanSetting("-Ymacro-debug-lite", "Trace essential macro-related activities.") - val YmacrodebugVerbose = BooleanSetting("-Ymacro-debug-verbose", "Trace all macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.") - val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.") - val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.") - val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.") - val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.") - val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.") - val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.") + /** Area-specific debug output */ val Yexplainlowlevel = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.") val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).") val YshowVarBounds = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds") val YnoInline = BooleanSetting("-Yno-inline", "Suppress inlining.") + /** Linker specific flags */ val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize" - /** IDE-specific settings - */ - val YpresentationVerbose = BooleanSetting("-Ypresentation-verbose", "Print information about presentation compiler tasks.") - val YpresentationDebug = BooleanSetting("-Ypresentation-debug", "Enable debugging output for the presentation compiler.") - val YpresentationStrict = BooleanSetting("-Ypresentation-strict", "Do not report type errors in sources with syntax errors.") - - val YpresentationLog = StringSetting("-Ypresentation-log", "file", "Log presentation compiler events into file", "") - val YpresentationReplay = StringSetting("-Ypresentation-replay", "file", "Replay presentation compiler events from file", "") - val YpresentationDelay = IntSetting("-Ypresentation-delay", "Wait number of ms after typing before starting typechecking", 0, 0 to 999) - - /** Doc specific settings */ - val template = OptionSetting[String]( - "-template", - "A mustache template for rendering each top-level entity in the API" - ) - - val resources = OptionSetting[String]( - "-resources", - "A directory containing static resources needed for the API documentation" - ) - + /** Dottydoc specific settings */ val siteRoot = StringSetting( "-siteroot", "site root", @@ -227,49 +114,5 @@ class ScalaSettings extends Settings.SettingGroup { sys.props("user.dir").split(sys.props("file.separator")).last ) - val DocVersion = StringSetting ( - "-Ydoc-version", - "version", - "An optional version number, to be appended to the title", - "" - ) - - val DocOutput = StringSetting ( - "-Ydoc-output", - "outdir", - "The output directory in which to place the documentation", - "." - ) - - val DocFooter = StringSetting ( - "-Ydoc-footer", - "footer", - "A footer on every Scaladoc page, by default the EPFL/Lightbend copyright notice. Can be overridden with a custom footer.", - "" - ) - - val DocUncompilable = StringSetting ( - "-Ydoc-no-compile", - "path", - "A directory containing sources which should be parsed, no more (e.g. AnyRef.scala)", - "" - ) - - //def DocUncompilableFiles(implicit ctx: Context) = DocUncompilable.value match { - // case "" => Nil - // case path => io.Directory(path).deepFiles.filter(_ hasExtension "scala").toList - //} - - val DocExternalDoc = MultiStringSetting ( - "-Ydoc-external-doc", - "external-doc", - "comma-separated list of classpath_entry_path#doc_URL pairs describing external dependencies." - ) - - val DocAuthor = BooleanSetting("-Ydoc-author", "Include authors.", true) - - val DocGroups = BooleanSetting ( - "-Ydoc:groups", - "Group similar functions together (based on the @group annotation)" - ) + val wikiSyntax = BooleanSetting("-Xwiki-syntax", "Retains the Scala2 behavior of using Wiki Syntax in Scaladoc") } diff --git a/compiler/src/dotty/tools/dotc/config/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index cffa047fe..58fa6d366 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -44,10 +44,14 @@ object Settings { case class ArgsSummary( sstate: SettingsState, arguments: List[String], - errors: List[String]) { + errors: List[String], + warnings: List[String]) { def fail(msg: String) = - ArgsSummary(sstate, arguments, errors :+ msg) + ArgsSummary(sstate, arguments.tail, errors :+ msg, warnings) + + def warn(msg: String) = + ArgsSummary(sstate, arguments.tail, errors, warnings :+ msg) } case class Setting[T: ClassTag] private[Settings] ( @@ -106,11 +110,11 @@ object Settings { } def tryToSet(state: ArgsSummary): ArgsSummary = { - val ArgsSummary(sstate, arg :: args, errors) = state + val ArgsSummary(sstate, arg :: args, errors, warnings) = state def update(value: Any, args: List[String]) = - ArgsSummary(updateIn(sstate, value), args, errors) + ArgsSummary(updateIn(sstate, value), args, errors, warnings) def fail(msg: String, args: List[String]) = - ArgsSummary(sstate, args, errors :+ msg) + ArgsSummary(sstate, args, errors :+ msg, warnings) def missingArg = fail(s"missing argument for option $name", args) def doSet(argRest: String) = ((implicitly[ClassTag[T]], args): @unchecked) match { @@ -206,7 +210,7 @@ object Settings { * to get their arguments. */ protected def processArguments(state: ArgsSummary, processAll: Boolean, skipped: List[String]): ArgsSummary = { - def stateWithArgs(args: List[String]) = ArgsSummary(state.sstate, args, state.errors) + def stateWithArgs(args: List[String]) = ArgsSummary(state.sstate, args, state.errors, state.warnings) state.arguments match { case Nil => checkDependencies(stateWithArgs(skipped)) @@ -219,7 +223,7 @@ object Settings { if (state1 ne state) processArguments(state1, processAll, skipped) else loop(settings1) case Nil => - state.fail(s"bad option: '$x'") + processArguments(state.warn(s"bad option '$x' was ignored"), processAll, skipped) } loop(allSettings.toList) case arg :: args => @@ -229,7 +233,7 @@ object Settings { } def processArguments(arguments: List[String], processAll: Boolean)(implicit ctx: Context): ArgsSummary = - processArguments(ArgsSummary(ctx.sstate, arguments, Nil), processAll, Nil) + processArguments(ArgsSummary(ctx.sstate, arguments, Nil, Nil), processAll, Nil) def publish[T](settingf: Int => Setting[T]): Setting[T] = { val setting = settingf(_allSettings.length) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index c61e92f3a..847177e2f 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -528,6 +528,8 @@ class Definitions { lazy val EqType = ctx.requiredClassRef("scala.Eq") def EqClass(implicit ctx: Context) = EqType.symbol.asClass + lazy val XMLTopScopeModuleRef = ctx.requiredModuleRef("scala.xml.TopScope") + // Annotation base classes lazy val AnnotationType = ctx.requiredClassRef("scala.annotation.Annotation") def AnnotationClass(implicit ctx: Context) = AnnotationType.symbol.asClass @@ -636,13 +638,9 @@ class Definitions { FunctionType(args.length, isImplicit).appliedTo(args ::: resultType :: Nil) def unapply(ft: Type)(implicit ctx: Context) = { val tsym = ft.typeSymbol - val isImplicitFun = isImplicitFunctionClass(tsym) - if (isImplicitFun || isFunctionClass(tsym)) { - val targs = ft.argInfos - val numArgs = targs.length - 1 - if (numArgs >= 0 && FunctionType(numArgs, isImplicitFun).symbol == tsym) - Some(targs.init, targs.last, isImplicitFun) - else None + if (isFunctionClass(tsym)) { + val targs = ft.dealias.argInfos + Some(targs.init, targs.last, tsym.name.isImplicitFunction) } else None } @@ -695,20 +693,17 @@ class Definitions { lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2) lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0) - def FunctionClass(n: Int)(implicit ctx: Context) = - if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n) + def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) = + if (isImplicit) ctx.requiredClass("scala.ImplicitFunction" + n.toString) + else if (n <= MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n) else ctx.requiredClass("scala.Function" + n.toString) lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply) def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol - def ImplicitFunctionClass(n: Int)(implicit ctx: Context) = - ctx.requiredClass("scala.ImplicitFunction" + n.toString) - def FunctionType(n: Int, isImplicit: Boolean = false)(implicit ctx: Context): TypeRef = - if (isImplicit && !ctx.erasedTypes) ImplicitFunctionClass(n).typeRef - else if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n) - else FunctionClass(n).typeRef + if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes)) ImplementedFunctionType(n) + else FunctionClass(n, isImplicit).typeRef private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet @@ -732,14 +727,61 @@ class Definitions { def isBottomType(tp: Type) = tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass) - def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function) - def isImplicitFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.ImplicitFunction) - /** Is a class that will be erased to FunctionXXL */ - def isXXLFunctionClass(cls: Symbol) = cls.name.functionArity > MaxImplementedFunctionArity + /** Is a function class. + * - FunctionN for N >= 0 + * - ImplicitFunctionN for N >= 0 + */ + def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction + + /** Is an implicit function class. + * - ImplicitFunctionN for N >= 0 + */ + def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction + + /** Is a class that will be erased to FunctionXXL + * - FunctionN for N >= 22 + * - ImplicitFunctionN for N >= 22 + */ + def isXXLFunctionClass(cls: Symbol) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity + + /** Is a synthetic function class + * - FunctionN for N > 22 + * - ImplicitFunctionN for N >= 0 + */ + def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction + def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction) def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple) def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product) + /** Returns the erased class of the function class `cls` + * - FunctionN for N > 22 becomes FunctionXXL + * - FunctionN for 22 > N >= 0 remains as FunctionN + * - ImplicitFunctionN for N > 22 becomes FunctionXXL + * - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN + * - anything else becomes a NoSymbol + */ + def erasedFunctionClass(cls: Symbol): Symbol = { + val arity = scalaClassName(cls).functionArity + if (arity > 22) defn.FunctionXXLClass + else if (arity >= 0) defn.FunctionClass(arity) + else NoSymbol + } + + /** Returns the erased type of the function class `cls` + * - FunctionN for N > 22 becomes FunctionXXL + * - FunctionN for 22 > N >= 0 remains as FunctionN + * - ImplicitFunctionN for N > 22 becomes FunctionXXL + * - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN + * - anything else becomes a NoType + */ + def erasedFunctionType(cls: Symbol): Type = { + val arity = scalaClassName(cls).functionArity + if (arity > 22) defn.FunctionXXLType + else if (arity >= 0) defn.FunctionType(arity) + else NoType + } + val predefClassNames: Set[Name] = Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName) @@ -810,16 +852,13 @@ class Definitions { def isFunctionType(tp: Type)(implicit ctx: Context) = { val arity = functionArity(tp) val sym = tp.dealias.typeSymbol - arity >= 0 && ( - isFunctionClass(sym) && tp.isRef(FunctionType(arity, isImplicit = false).typeSymbol) || - isImplicitFunctionClass(sym) && tp.isRef(FunctionType(arity, isImplicit = true).typeSymbol) - ) + arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction).typeSymbol) } def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1 def isImplicitFunctionType(tp: Type)(implicit ctx: Context) = - isFunctionType(tp) && tp.dealias.typeSymbol.name.startsWith(tpnme.ImplicitFunction) + isFunctionType(tp) && tp.dealias.typeSymbol.name.isImplicitFunction // ----- primitive value class machinery ------------------------------------------ @@ -893,9 +932,6 @@ class Definitions { // ----- Initialization --------------------------------------------------- - private def maxImplemented(name: Name) = - if (name `startsWith` tpnme.Function) MaxImplementedFunctionArity else 0 - /** Give the scala package a scope where a FunctionN trait is automatically * added when someone looks for it. */ @@ -905,7 +941,7 @@ class Definitions { val newDecls = new MutableScope(oldDecls) { override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { val res = super.lookupEntry(name) - if (res == null && name.isTypeName && name.functionArity > maxImplemented(name)) + if (res == null && name.isTypeName && name.isSyntheticFunction) newScopeEntry(newFunctionNTrait(name.asTypeName)) else res } diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index c037d1ce7..aac313892 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -8,6 +8,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._ import Decorators.StringDecorator import util.{Chars, NameTransformer} import Chars.isOperatorPart +import Definitions._ object NameOps { @@ -231,13 +232,50 @@ object NameOps { } } - def functionArity: Int = { - def test(prefix: Name): Int = - if (name.startsWith(prefix)) - try name.drop(prefix.length).toString.toInt - catch { case ex: NumberFormatException => -1 } - else -1 - test(tpnme.Function) max test(tpnme.ImplicitFunction) + /** Is a synthetic function name + * - N for FunctionN + * - N for ImplicitFunctionN + * - (-1) otherwise + */ + def functionArity: Int = + functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction) + + /** Is a function name + * - FunctionN for N >= 0 + * - ImplicitFunctionN for N >= 0 + * - false otherwise + */ + def isFunction: Boolean = functionArity >= 0 + + /** Is a implicit function name + * - ImplicitFunctionN for N >= 0 + * - false otherwise + */ + def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0 + + /** Is a synthetic function name + * - FunctionN for N > 22 + * - ImplicitFunctionN for N >= 0 + * - false otherwise + */ + def isSyntheticFunction: Boolean = { + functionArityFor(tpnme.Function) > MaxImplementedFunctionArity || + functionArityFor(tpnme.ImplicitFunction) >= 0 + } + + /** Parsed function arity for function with some specific prefix */ + private def functionArityFor(prefix: Name): Int = { + if (name.startsWith(prefix)) + try name.toString.substring(prefix.length).toInt + catch { case _: NumberFormatException => -1 } + else -1 + } + + + /** The number of hops specified in an outer-select name */ + def outerSelectHops: Int = { + require(isOuterSelect) + name.dropRight(nme.OUTER_SELECT.length).toString.toInt } /** The name of the generic runtime operation corresponding to an array operation */ diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 4a9c50dad..c424c6182 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -533,6 +533,7 @@ object StdNames { val nullRuntimeClass: N = "scala.runtime.Null$" val synthSwitch: N = "$synthSwitch" + val _scope: N = "$scope" // unencoded operators object raw { diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 2a341390b..ff99008bb 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -44,7 +44,7 @@ object TypeErasure { val sym = tp.symbol sym.isClass && sym != defn.AnyClass && sym != defn.ArrayClass && - !defn.isXXLFunctionClass(sym) && !defn.isImplicitFunctionClass(sym) + !defn.isSyntheticFunctionClass(sym) case _: TermRef => true case JavaArrayType(elem) => @@ -358,8 +358,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean if (!sym.isClass) this(tp.info) else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp) else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type. - else if (defn.isXXLFunctionClass(sym)) defn.FunctionXXLType - else if (defn.isImplicitFunctionClass(sym)) apply(defn.FunctionType(sym.name.functionArity)) + else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym) else eraseNormalClassRef(tp) case tp: RefinedType => val parent = tp.parent @@ -370,7 +369,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean case SuperType(thistpe, supertpe) => SuperType(this(thistpe), this(supertpe)) case ExprType(rt) => - defn.FunctionClass(0).typeRef + defn.FunctionType(0) case AndType(tp1, tp2) => erasedGlb(this(tp1), this(tp2), isJava) case OrType(tp1, tp2) => @@ -496,8 +495,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean val erasedVCRef = eraseDerivedValueClassRef(tp) if (erasedVCRef.exists) return sigName(erasedVCRef) } - if (defn.isImplicitFunctionClass(sym)) - sigName(defn.FunctionType(sym.name.functionArity)) + if (defn.isSyntheticFunctionClass(sym)) + sigName(defn.erasedFunctionType(sym)) else normalizeClass(sym.asClass).fullName.asTypeName case defn.ArrayOf(elem) => diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 9f4cdbd35..b46bc401d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -110,7 +110,8 @@ object Parsers { */ def syntaxError(msg: => Message, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { - syntaxError(msg, Position(offset)) + val length = if (in.name != null) in.name.show.length else 0 + syntaxError(msg, Position(offset, offset + length)) lastErrorOffset = in.offset } @@ -249,11 +250,6 @@ object Parsers { lastErrorOffset = in.offset } // DEBUG - private def expectedMsg(token: Int): String = - expectedMessage(showToken(token)) - private def expectedMessage(what: String): String = - s"$what expected but ${showToken(in.token)} found" - /** Consume one token of the specified type, or * signal an error if it is not there. * @@ -262,7 +258,7 @@ object Parsers { def accept(token: Int): Int = { val offset = in.offset if (in.token != token) { - syntaxErrorOrIncomplete(expectedMsg(token)) + syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token, in.name)) } if (in.token == token) in.nextToken() offset @@ -408,14 +404,13 @@ object Parsers { var opStack: List[OpInfo] = Nil - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = - if (isLeftAssoc(op) != leftAssoc) - syntaxError( - "left- and right-associative operators with same precedence may not be mixed", offset) + def checkAssoc(offset: Token, op1: Name, op2: Name, op2LeftAssoc: Boolean): Unit = + if (isLeftAssoc(op1) != op2LeftAssoc) + syntaxError(MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc), offset) - def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean): Tree = { + def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean, op2: Name): Tree = { if (opStack != base && precedence(opStack.head.operator.name) == prec) - checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc) + checkAssoc(opStack.head.offset, opStack.head.operator.name, op2, leftAssoc) def recur(top: Tree): Tree = { if (opStack == base) top else { @@ -449,20 +444,20 @@ object Parsers { var top = first while (isIdent && in.name != notAnOperator) { val op = if (isType) typeIdent() else termIdent() - top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name)) + top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name), op.name) opStack = OpInfo(top, op, in.offset) :: opStack newLineOptWhenFollowing(canStartOperand) if (maybePostfix && !canStartOperand(in.token)) { val topInfo = opStack.head opStack = opStack.tail - val od = reduceStack(base, topInfo.operand, 0, true) + val od = reduceStack(base, topInfo.operand, 0, true, in.name) return atPos(startOffset(od), topInfo.offset) { PostfixOp(od, topInfo.operator) } } top = operand() } - reduceStack(base, top, 0, true) + reduceStack(base, top, 0, true, in.name) } /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ @@ -474,7 +469,7 @@ object Parsers { in.nextToken() name } else { - syntaxErrorOrIncomplete(expectedMsg(IDENTIFIER)) + syntaxErrorOrIncomplete(ExpectedTokenButFound(IDENTIFIER, in.token, in.name)) nme.ERROR } @@ -1055,7 +1050,7 @@ object Parsers { case Block(Nil, EmptyTree) => assert(handlerStart != -1) syntaxError( - new EmptyCatchBlock(body), + EmptyCatchBlock(body), Position(handlerStart, endOffset(handler)) ) case _ => diff --git a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala index 20b655a19..09d1b20b1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala +++ b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala @@ -55,7 +55,6 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont val _buf: TermName = "$buf" val _md: TermName = "$md" val _plus: TermName = "$amp$plus" - val _scope: TermName = "$scope" val _tmpscope: TermName = "$tmpscope" val _xml: TermName = "xml" } diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 280832ef3..8d42e525a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -17,7 +17,7 @@ abstract class TokensCommon { def showToken(token: Int) = { val str = tokenString(token) - if (keywords contains token) s"'$str'" else str + if (isKeyword(token)) s"'$str'" else str } val tokenString, debugString = new Array[String](maxToken + 1) @@ -114,6 +114,8 @@ abstract class TokensCommon { val keywords: TokenSet + def isKeyword(token: Token): Boolean = keywords contains token + /** parentheses */ final val LPAREN = 90; enter(LPAREN, "'('") final val RPAREN = 91; enter(RPAREN, "')'") diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 5b75df6b2..3d952f425 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -126,8 +126,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case AppliedType(tycon, args) => val cls = tycon.typeSymbol if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*" - if (defn.isFunctionClass(cls)) return toTextFunction(args, isImplicit = false) - if (defn.isImplicitFunctionClass(cls)) return toTextFunction(args, isImplicit = true) + if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction) if (defn.isTupleClass(cls)) return toTextTuple(args) return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case tp: TypeRef => diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 24d583b19..190445d60 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -5,7 +5,7 @@ package reporting import core.Contexts.Context import core.Decorators._ import printing.Highlighting.{Blue, Red} -import diagnostic.{Message, MessageContainer, NoExplanation} +import diagnostic.{ErrorMessageID, Message, MessageContainer, NoExplanation} import diagnostic.messages._ import util.SourcePosition @@ -95,9 +95,10 @@ trait MessageRendering { if (pos.exists) Blue({ val file = pos.source.file.toString val errId = - if (message.errorId != NoExplanation.ID) - s"[E${"0" * (3 - message.errorId.toString.length) + message.errorId}] " - else "" + if (message.errorId ne ErrorMessageID.NoExplanationID) { + val errorNumber = message.errorId.errorNumber() + s"[E${"0" * (3 - errorNumber.toString.length) + errorNumber}] " + } else "" val kind = if (message.kind == "") diagnosticLevel else s"${message.kind} $diagnosticLevel" diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 26c1e5ebc..b2c7abec9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -171,22 +171,6 @@ trait Reporting { this: Context => throw ex } } - - /** Implements a fold that applies the function `f` to the result of `op` if - * there are no new errors in the reporter - * - * @param op operation checked for errors - * @param f function applied to result of op - * @return either the result of `op` if it had errors or the result of `f` - * applied to it - */ - def withNoError[A, B >: A](op: => A)(f: A => B): B = { - val before = reporter.errorCount - val op0 = op - - if (reporter.errorCount > before) op0 - else f(op0) - } } /** diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java new file mode 100644 index 000000000..c74130b44 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -0,0 +1,58 @@ +package dotty.tools.dotc.reporting.diagnostic; + +/** Unique IDs identifying the messages */ +public enum ErrorMessageID { + + // IMPORTANT: Add new IDs only at the end and never remove IDs + + LazyErrorId, // // errorNumber: -2 + NoExplanationID, // errorNumber: -1 + + EmptyCatchOrFinallyBlockID, // errorNumber: 0 + EmptyCatchBlockID, // errorNumber: 1 + EmptyCatchAndFinallyBlockID, // errorNumber: 2 + DeprecatedWithOperatorID, + CaseClassMissingParamListID, + DuplicateBindID, + MissingIdentID, + TypeMismatchID, + NotAMemberID, + EarlyDefinitionsNotSupportedID, + TopLevelImplicitClassID, + ImplicitCaseClassID, + ObjectMayNotHaveSelfTypeID, + TupleTooLongID, + RepeatedModifierID, + InterpolatedStringErrorID, + UnboundPlaceholderParameterID, + IllegalStartSimpleExprID, + MissingReturnTypeID, + YieldOrDoExpectedInForComprehensionID, + ProperDefinitionNotFoundID, + ByNameParameterNotSupportedID, + WrongNumberOfTypeArgsID, + IllegalVariableInPatternAlternativeID, + TypeParamsTypeExpectedID, + IdentifierExpectedID, + AuxConstructorNeedsNonImplicitParameterID, + IncorrectRepeatedParameterSyntaxID, + IllegalLiteralID, + PatternMatchExhaustivityID, + MatchCaseUnreachableID, + SeqWildcardPatternPosID, + IllegalStartOfSimplePatternID, + PkgDuplicateSymbolID, + ExistentialTypesNoLongerSupportedID, + UnboundWildcardTypeID, + DanglingThisInPathID, + OverridesNothingID, + OverridesNothingButNameExistsID, + ForwardReferenceExtendsOverDefinitionID, + ExpectedTokenButFoundID, + MixedLeftAndRightAssociativeOpsID; + + public int errorNumber() { + return ordinal() - 2; + } + +} diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index 2497fb216..09d7ae975 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -30,11 +30,10 @@ object Message { * Instead use the `persist` method to create an instance that does not keep a * reference to these contexts. * - * @param errorId a unique number identifying the message, this will later be + * @param errorId a unique id identifying the message, this will later be * used to reference documentation online */ -abstract class Message(val errorId: Int) { self => - import messages._ +abstract class Message(val errorId: ErrorMessageID) { self => /** The `msg` contains the diagnostic message e.g: * @@ -116,17 +115,17 @@ class ExtendMessage(_msg: () => Message)(f: String => String) { self => } /** The fallback `Message` containing no explanation and having no `kind` */ -class NoExplanation(val msg: String) extends Message(NoExplanation.ID) { +class NoExplanation(val msg: String) extends Message(ErrorMessageID.NoExplanationID) { val explanation = "" val kind = "" + + override def toString(): String = s"NoExplanation($msg)" } /** The extractor for `NoExplanation` can be used to check whether any error * lacks an explanation */ object NoExplanation { - final val ID = -1 - def unapply(m: Message): Option[Message] = if (m.explanation == "") Some(m) else None diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 4d61f21cf..7fccebef9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -4,12 +4,20 @@ package reporting package diagnostic import dotc.core._ -import Contexts.Context, Decorators._, Symbols._, Names._, NameOps._, Types._ +import Contexts.Context +import Decorators._ +import Symbols._ +import Names._ +import NameOps._ +import Types._ import util.SourcePosition import config.Settings.Setting -import interfaces.Diagnostic.{ERROR, WARNING, INFO} +import interfaces.Diagnostic.{ERROR, INFO, WARNING} +import dotc.parsing.Scanners.Token +import dotc.parsing.Tokens import printing.Highlighting._ import printing.Formatting +import ErrorMessageID._ object messages { @@ -87,8 +95,8 @@ object messages { // Syntax Errors ---------------------------------------------------------- // - abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: Int)(implicit ctx: Context) - extends Message(errNo) { + abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) + extends Message(EmptyCatchOrFinallyBlockID) { val explanation = { val tryString = tryBody match { case Block(Nil, untpd.EmptyTree) => "{}" @@ -124,7 +132,7 @@ object messages { } case class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) - extends EmptyCatchOrFinallyBlock(tryBody, 1) { + extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) { val kind = "Syntax" val msg = hl"""|The ${"catch"} block does not contain a valid expression, try @@ -132,7 +140,7 @@ object messages { } case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) - extends EmptyCatchOrFinallyBlock(tryBody, 2) { + extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchAndFinallyBlockID) { val kind = "Syntax" val msg = hl"""|A ${"try"} without ${"catch"} or ${"finally"} is equivalent to putting @@ -140,7 +148,7 @@ object messages { } case class DeprecatedWithOperator()(implicit ctx: Context) - extends Message(3) { + extends Message(DeprecatedWithOperatorID) { val kind = "Syntax" val msg = hl"""${"with"} as a type operator has been deprecated; use `&' instead""" @@ -151,7 +159,7 @@ object messages { } case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(4) { + extends Message(CaseClassMissingParamListID) { val kind = "Syntax" val msg = hl"""|A ${"case class"} must have at least one parameter list""" @@ -165,7 +173,7 @@ object messages { // Type Errors ------------------------------------------------------------ // case class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) - extends Message(5) { + extends Message(DuplicateBindID) { val kind = "Naming" val msg = em"duplicate pattern variable: `${bind.name}`" @@ -192,7 +200,7 @@ object messages { } case class MissingIdent(tree: untpd.Ident, treeKind: String, name: String)(implicit ctx: Context) - extends Message(6) { + extends Message(MissingIdentID) { val kind = "Unbound Identifier" val msg = em"not found: $treeKind$name" @@ -205,7 +213,7 @@ object messages { } case class TypeMismatch(found: Type, expected: Type, whyNoMatch: String = "", implicitFailure: String = "")(implicit ctx: Context) - extends Message(7) { + extends Message(TypeMismatchID) { val kind = "Type Mismatch" val msg = { val (where, printCtx) = Formatting.disambiguateTypes(found, expected) @@ -220,7 +228,7 @@ object messages { } case class NotAMember(site: Type, name: Name, selected: String)(implicit ctx: Context) - extends Message(8) { + extends Message(NotAMemberID) { val kind = "Member Not Found" //println(i"site = $site, decls = ${site.decls}, source = ${site.widen.typeSymbol.sourceFile}") //DEBUG @@ -286,7 +294,7 @@ object messages { } case class EarlyDefinitionsNotSupported()(implicit ctx: Context) - extends Message(9) { + extends Message(EarlyDefinitionsNotSupportedID) { val kind = "Syntax" val msg = "early definitions are not supported; use trait parameters instead" @@ -332,7 +340,7 @@ object messages { } case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(10) { + extends Message(TopLevelImplicitClassID) { val kind = "Syntax" val msg = hl"""An ${"implicit class"} may not be top-level""" @@ -362,7 +370,7 @@ object messages { } case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(11) { + extends Message(ImplicitCaseClassID) { val kind = "Syntax" val msg = hl"""A ${"case class"} may not be defined as ${"implicit"}""" @@ -375,7 +383,7 @@ object messages { } case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) - extends Message(12) { + extends Message(ObjectMayNotHaveSelfTypeID) { val kind = "Syntax" val msg = hl"""${"object"}s must not have a self ${"type"}""" @@ -393,7 +401,7 @@ object messages { } case class TupleTooLong(ts: List[untpd.Tree])(implicit ctx: Context) - extends Message(13) { + extends Message(TupleTooLongID) { import Definitions.MaxTupleArity val kind = "Syntax" val msg = hl"""A ${"tuple"} cannot have more than ${MaxTupleArity} members""" @@ -409,7 +417,7 @@ object messages { } case class RepeatedModifier(modifier: String)(implicit ctx:Context) - extends Message(14) { + extends Message(RepeatedModifierID) { val kind = "Syntax" val msg = hl"""repeated modifier $modifier""" @@ -431,7 +439,7 @@ object messages { } case class InterpolatedStringError()(implicit ctx:Context) - extends Message(15) { + extends Message(InterpolatedStringErrorID) { val kind = "Syntax" val msg = "error in interpolated string: identifier or block expected" val explanation = { @@ -449,7 +457,7 @@ object messages { } case class UnboundPlaceholderParameter()(implicit ctx:Context) - extends Message(16) { + extends Message(UnboundPlaceholderParameterID) { val kind = "Syntax" val msg = "unbound placeholder parameter; incorrect use of `_`" val explanation = @@ -482,7 +490,7 @@ object messages { } case class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) - extends Message(17) { + extends Message(IllegalStartSimpleExprID) { val kind = "Syntax" val msg = "illegal start of simple expression" val explanation = { @@ -500,7 +508,8 @@ object messages { } } - case class MissingReturnType()(implicit ctx:Context) extends Message(18) { + case class MissingReturnType()(implicit ctx:Context) + extends Message(MissingReturnTypeID) { val kind = "Syntax" val msg = "missing return type" val explanation = @@ -512,7 +521,7 @@ object messages { } case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) - extends Message(19) { + extends Message(YieldOrDoExpectedInForComprehensionID) { val kind = "Syntax" val msg = hl"${"yield"} or ${"do"} expected" @@ -545,7 +554,7 @@ object messages { } case class ProperDefinitionNotFound()(implicit ctx: Context) - extends Message(20) { + extends Message(ProperDefinitionNotFoundID) { val kind = "Definition Not Found" val msg = hl"""Proper definition was not found in ${"@usecase"}""" @@ -584,7 +593,7 @@ object messages { } case class ByNameParameterNotSupported()(implicit ctx: Context) - extends Message(21) { + extends Message(ByNameParameterNotSupportedID) { val kind = "Syntax" val msg = "By-name parameter type not allowed here." @@ -608,7 +617,7 @@ object messages { } case class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) - extends Message(22) { + extends Message(WrongNumberOfTypeArgsID) { val kind = "Syntax" private val expectedCount = expectedArgs.length @@ -654,7 +663,7 @@ object messages { } case class IllegalVariableInPatternAlternative()(implicit ctx: Context) - extends Message(23) { + extends Message(IllegalVariableInPatternAlternativeID) { val kind = "Syntax" val msg = "Variables are not allowed in alternative patterns" val explanation = { @@ -683,7 +692,7 @@ object messages { } case class TypeParamsTypeExpected(mods: untpd.Modifiers, identifier: TermName)(implicit ctx: Context) - extends Message(24) { + extends Message(TypeParamsTypeExpectedID) { val kind = "Syntax" val msg = hl"""Expected ${"type"} keyword for type parameter $identifier""" val explanation = @@ -696,7 +705,7 @@ object messages { } case class IdentifierExpected(identifier: String)(implicit ctx: Context) - extends Message(25) { + extends Message(IdentifierExpectedID) { val kind = "Syntax" val msg = "identifier expected" val explanation = { @@ -717,7 +726,7 @@ object messages { } case class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) - extends Message(26) { + extends Message(AuxConstructorNeedsNonImplicitParameterID) { val kind = "Syntax" val msg = "auxiliary constructor needs non-implicit parameter list" val explanation = @@ -732,7 +741,8 @@ object messages { |""" } - case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) extends Message(27) { + case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) + extends Message(IncorrectRepeatedParameterSyntaxID) { val kind = "Syntax" val msg = "'*' expected" val explanation = @@ -758,7 +768,8 @@ object messages { |""".stripMargin } - case class IllegalLiteral()(implicit ctx: Context) extends Message(28) { + case class IllegalLiteral()(implicit ctx: Context) + extends Message(IllegalLiteralID) { val kind = "Syntax" val msg = "illegal literal" val explanation = @@ -773,7 +784,7 @@ object messages { } case class PatternMatchExhaustivity(uncovered: String)(implicit ctx: Context) - extends Message(29) { + extends Message(PatternMatchExhaustivityID) { val kind = "Pattern Match Exhaustivity" val msg = hl"""|match may not be exhaustive. @@ -785,14 +796,14 @@ object messages { } case class MatchCaseUnreachable()(implicit ctx: Context) - extends Message(30) { + extends Message(MatchCaseUnreachableID) { val kind = s"""Match ${hl"case"} Unreachable""" val msg = "unreachable code" val explanation = "" } case class SeqWildcardPatternPos()(implicit ctx: Context) - extends Message(31) { + extends Message(SeqWildcardPatternPosID) { val kind = "Syntax" val msg = "`_*' can be used only for last argument" val explanation = { @@ -815,7 +826,8 @@ object messages { } } - case class IllegalStartOfSimplePattern()(implicit ctx: Context) extends Message(32) { + case class IllegalStartOfSimplePattern()(implicit ctx: Context) + extends Message(IllegalStartOfSimplePatternID) { val kind = "Syntax" val msg = "illegal start of simple pattern" val explanation = { @@ -895,13 +907,14 @@ object messages { } case class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) - extends Message(33) { + extends Message(PkgDuplicateSymbolID) { val kind = "Duplicate Symbol" val msg = hl"trying to define package with same name as `$existing`" val explanation = "" } - case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) extends Message(34) { + case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) + extends Message(ExistentialTypesNoLongerSupportedID) { val kind = "Syntax" val msg = hl"""|Existential types are no longer supported - @@ -923,7 +936,8 @@ object messages { |""" } - case class UnboundWildcardType()(implicit ctx: Context) extends Message(35) { + case class UnboundWildcardType()(implicit ctx: Context) + extends Message(UnboundWildcardTypeID) { val kind = "Syntax" val msg = "Unbound wildcard type" val explanation = @@ -967,7 +981,7 @@ object messages { |""" } - case class DanglingThisInPath()(implicit ctx: Context) extends Message(36) { + case class DanglingThisInPath()(implicit ctx: Context) extends Message(DanglingThisInPathID) { val kind = "Syntax" val msg = hl"""Expected an additional member selection after the keyword ${"this"}""" @@ -1004,7 +1018,7 @@ object messages { } case class OverridesNothing(member: Symbol)(implicit ctx: Context) - extends Message(37) { + extends Message(OverridesNothingID) { val kind = "Reference" val msg = hl"""${member} overrides nothing""" @@ -1016,7 +1030,7 @@ object messages { } case class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) - extends Message(38) { + extends Message(OverridesNothingButNameExistsID) { val kind = "Reference" val msg = hl"""${member} has a different signature than the overridden declaration""" @@ -1035,7 +1049,7 @@ object messages { } case class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) - extends Message(39) { + extends Message(ForwardReferenceExtendsOverDefinitionID) { val kind = "Reference" val msg = hl"`${definition.name}` is a forward reference extending over the definition of `${value.name}`" @@ -1053,4 +1067,64 @@ object messages { |""".stripMargin } + case class ExpectedTokenButFound(expected: Token, found: Token, foundName: TermName)(implicit ctx: Context) + extends Message(ExpectedTokenButFoundID) { + val kind = "Syntax" + + private val expectedText = + if (Tokens.isIdentifier(expected)) "an identifier" + else Tokens.showToken(expected) + + private val foundText = + if (foundName != null) hl"`${foundName.show}`" + else Tokens.showToken(found) + + val msg = hl"""${expectedText} expected, but ${foundText} found""" + + private val ifKeyword = + if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found)) + s""" + |If you necessarily want to use $foundText as identifier, you may put it in backticks.""".stripMargin + else + "" + + val explanation = + s"""|The text ${foundText} may not occur at that position, the compiler expected ${expectedText}.$ifKeyword + |""".stripMargin + } + + case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) + extends Message(MixedLeftAndRightAssociativeOpsID) { + val kind = "Syntax" + val op1Asso = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" + val op2Asso = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" + val msg = s"`${op1}` (${op1Asso}) and `${op2}` ($op2Asso) have same precedence and may not be mixed" + val explanation = + s"""|The operators ${op1} and ${op2} are used as infix operators in the same expression, + |but they bind to different sides: + |${op1} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} + |${op2} is applied to the operand to its ${if (op2LeftAssoc) "left" else "right"} + |As both have the same precedence the compiler can't decide which to apply first. + | + |You may use parenthesis to make the application order explicit, + |or use method application syntax `operand1.${op1}(operand2)`. + | + |Operators ending in a colon `:` are right-associative. All other operators are left-associative. + | + |Infix operator precedence is determined by the operator's first character. Characters are listed + |below in increasing order of precedence, with characters on the same line having the same precedence. + | (all letters) + | | + | ^ + | & + | = ! + | < > + | : + | + - + | * / % + | (all other special characters) + |Operators starting with a letter have lowest precedence, followed by operators starting with `|`, etc. + |""".stripMargin + } + } diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index bba97c4c2..3857b405f 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -349,10 +349,8 @@ object Erasure extends TypeTestsCasts{ if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) { assert(sym.isConstructor, s"${sym.showLocated}") defn.ObjectClass - } else if (defn.isXXLFunctionClass(owner)) - defn.FunctionXXLClass - else if (defn.isImplicitFunctionClass(owner)) - recur(defn.FunctionClass(owner.name.functionArity)) + } else if (defn.isSyntheticFunctionClass(owner)) + defn.erasedFunctionClass(owner) else owner recur(sym.owner) @@ -417,7 +415,7 @@ object Erasure extends TypeTestsCasts{ if (tree.symbol == ctx.owner.lexicallyEnclosingClass || tree.symbol.isStaticOwner) promote(tree) else { ctx.log(i"computing outer path from ${ctx.owner.ownersIterator.toList}%, % to ${tree.symbol}, encl class = ${ctx.owner.enclosingClass}") - outer.path(tree.symbol) + outer.path(toCls = tree.symbol) } private def runtimeCallWithProtoArgs(name: Name, pt: Type, args: Tree*)(implicit ctx: Context): Tree = { diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index c2aacf826..d75c32fcc 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -60,7 +60,8 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf /** Convert a selection of the form `qual.C_<OUTER>` to an outer path from `qual` to `C` */ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = if (tree.name.isOuterSelect) - outer.path(tree.tpe.widen.classSymbol, tree.qualifier).ensureConforms(tree.tpe) + outer.path(start = tree.qualifier, count = tree.name.outerSelectHops) + .ensureConforms(tree.tpe) else tree /** First, add outer accessors if a class does not have them yet and it references an outer this. @@ -354,24 +355,32 @@ object ExplicitOuter { } else Nil } - /** The path of outer accessors that references `toCls.this` starting from - * the context owner's this node. + /** A path of outer accessors starting from node `start`. `start` defaults to the + * context owner's this node. There are two alternative conditions that determine + * where the path ends: + * + * - if the initial `count` parameter is non-negative: where the number of + * outer accessors reaches count. + * - if the initial `count` parameter is negative: where the class symbol of + * the type of the reached tree matches `toCls`. */ - def path(toCls: Symbol, start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass)): Tree = try { - def loop(tree: Tree): Tree = { + def path(start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass), + toCls: Symbol = NoSymbol, + count: Int = -1): Tree = try { + def loop(tree: Tree, count: Int): Tree = { val treeCls = tree.tpe.widen.classSymbol val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)(outerAccessorCtx)} in $treeCls") - if (treeCls == toCls) tree + if (count == 0 || count < 0 && treeCls == toCls) tree else { val acc = outerAccessor(treeCls.asClass)(outerAccessorCtx) assert(acc.exists, i"failure to construct path from ${ctx.owner.ownersIterator.toList}%/% to `this` of ${toCls.showLocated};\n${treeCls.showLocated} does not have an outer accessor") - loop(tree.select(acc).ensureApplied) + loop(tree.select(acc).ensureApplied, count - 1) } } ctx.log(i"computing outerpath to $toCls from ${ctx.outersIterator.map(_.owner).toList}") - loop(start) + loop(start, count) } catch { case ex: ClassCastException => throw new ClassCastException(i"no path exists from ${ctx.owner.enclosingClass} to $toCls") diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 19fb3dd0c..b603a53dc 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -440,10 +440,10 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform singleton(clazz.thisType) else if (ctx.owner.isConstructor) outerParam.get(ctx.owner) match { - case Some(param) => outer.path(clazz, Ident(param.termRef)) - case _ => outer.path(clazz) + case Some(param) => outer.path(start = Ident(param.termRef), toCls = clazz) + case _ => outer.path(toCls = clazz) } - else outer.path(clazz) + else outer.path(toCls = clazz) transformFollowingDeep(qual.select(sym)) } diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index eee429a87..7a4af647f 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -12,6 +12,7 @@ import core.Types._ import core.Flags._ import core.Constants._ import core.StdNames._ +import core.NameOps._ import core.Decorators._ import core.TypeErasure.isErasedType import core.Phases.Phase @@ -81,7 +82,7 @@ class TreeChecker extends Phase with SymTransformer { val sym = symd.symbol if (sym.isClass && !sym.isAbsent) { - val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) || + val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) || (sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists) if (!validSuperclass) printError(s"$sym has no superclass set") @@ -336,7 +337,10 @@ class TreeChecker extends Phase with SymTransformer { assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) val tpe = tree.typeOpt val sym = tree.symbol - if (!tpe.isInstanceOf[WithFixedSym] && sym.exists && !sym.is(Private)) { + if (!tpe.isInstanceOf[WithFixedSym] && + sym.exists && !sym.is(Private) && + !tree.name.isOuterSelect // outer selects have effectively fixed symbols + ) { val qualTpe = tree.qualifier.typeOpt val member = if (sym.is(Private)) qualTpe.member(tree.name) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 42c24ffb7..0ed6ed6b4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -916,7 +916,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val result = assignType(cpy.UnApply(tree)(unapplyFn, unapplyImplicits, unapplyPatterns), ownType) unapp.println(s"unapply patterns = $unapplyPatterns") if ((ownType eq selType) || ownType.isError) result - else Typed(result, TypeTree(ownType)) + else tryWithClassTag(Typed(result, TypeTree(ownType)), selType) case tp => val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn) val typedArgsErr = args mapconserve (typed(_, defn.AnyType)) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 27b0f28ca..fb0497c2b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -356,8 +356,7 @@ object Checking { */ def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = { class NotPrivate extends TypeMap { - type Errors = List[(String, Position)] - var errors: Errors = Nil + var errors: List[String] = Nil def accessBoundary(sym: Symbol): Symbol = if (sym.is(Private) || !sym.owner.isClass) sym.owner @@ -383,8 +382,8 @@ object Checking { val prevErrors = errors var tp1 = if (isLeaked(tp.symbol)) { - errors = (em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", - sym.pos) :: errors + errors = + em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}" :: errors tp } else mapOver(tp) @@ -408,7 +407,7 @@ object Checking { } val notPrivate = new NotPrivate val info = notPrivate(sym.info) - notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) } + notPrivate.errors.foreach(ctx.errorOrMigrationWarning(_, pos)) info } diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index cfc0003c6..27c7d0c2f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -27,7 +27,7 @@ import transform.TypeUtils._ object Inliner { import tpd._ - /** Adds accessors accessors for all non-public term members accessed + /** Adds accessors for all non-public term members accessed * from `tree`. Non-public type members are currently left as they are. * This means that references to a private type will lead to typing failures * on the code when it is inlined. Less than ideal, but hard to do better (see below). @@ -190,7 +190,8 @@ object Inliner { val inlineCtx = ctx sym.updateAnnotation(LazyBodyAnnotation { _ => implicit val ctx = inlineCtx - ctx.withNoError(treeExpr(ctx))(makeInlineable) + val body = treeExpr(ctx) + if (ctx.reporter.hasErrors) body else makeInlineable(body) }) } } @@ -233,8 +234,10 @@ object Inliner { * and body that replace it. */ def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = - if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) - new Inliner(tree, bodyToInline(tree.symbol)).inlined(pt) + if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) { + val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors + if (ctx.reporter.hasErrors) tree else new Inliner(tree, body).inlined(pt) + } else errorTree( tree, i"""|Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded, @@ -396,24 +399,29 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol // The name of the outer selector that computes the rhs of `selfSym` - def outerSelector(selfSym: Symbol): TermName = classOf(selfSym).name.toTermName ++ nme.OUTER_SELECT + def outerSelector(n: Int): TermName = n.toString.toTermName ++ nme.OUTER_SELECT // The total nesting depth of the class represented by `selfSym`. def outerLevel(selfSym: Symbol): Int = classOf(selfSym).ownersIterator.length - // All needed this-proxies, sorted by nesting depth of the classes they represent (innermost first) - val accessedSelfSyms = thisProxy.values.toList.map(_.symbol).sortBy(-outerLevel(_)) + // All needed this-proxies, paired-with and sorted-by nesting depth of + // the classes they represent (innermost first) + val sortedProxies = thisProxy.toList.map { + case (cls, proxy) => (outerLevel(cls), proxy.symbol) + } sortBy (-_._1) // Compute val-definitions for all this-proxies and append them to `bindingsBuf` var lastSelf: Symbol = NoSymbol - for (selfSym <- accessedSelfSyms) { + var lastLevel: Int = 0 + for ((level, selfSym) <- sortedProxies) { val rhs = if (!lastSelf.exists) prefix else - untpd.Select(ref(lastSelf), outerSelector(selfSym)).withType(selfSym.info) + untpd.Select(ref(lastSelf), outerSelector(lastLevel - level)).withType(selfSym.info) bindingsBuf += ValDef(selfSym.asTerm, rhs) lastSelf = selfSym + lastLevel = level } // The type map to apply to the inlined tree. This maps references to this-types diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ded8993fb..26f7bc65b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -351,6 +351,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val ownType = if (rawType.exists) ensureAccessible(rawType, superAccess = false, tree.pos) + else if (name == nme._scope) { + // gross hack to support current xml literals. + // awaiting a better implicits based solution for library-supported xml + return ref(defn.XMLTopScopeModuleRef) + } else errorType(new MissingIdent(tree, kind, name.show), tree.pos) @@ -518,18 +523,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def handlePattern: Tree = { val tpt1 = typedTpt // special case for an abstract type that comes with a class tag - tpt1.tpe.dealias match { - case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper => - inferImplicit(defn.ClassTagType.appliedTo(tref), - EmptyTree, tpt1.pos)(ctx.retractMode(Mode.Pattern)) match { - case SearchSuccess(arg, _, _, _) => - return typed(untpd.Apply(untpd.TypedSplice(arg), tree.expr), pt) - case _ => - } - case _ => - if (!ctx.isAfterTyper) tpt1.tpe.<:<(pt)(ctx.addMode(Mode.GADTflexible)) - } - ascription(tpt1, isWildcard = true) + if (!ctx.isAfterTyper) tpt1.tpe.<:<(pt)(ctx.addMode(Mode.GADTflexible)) + tryWithClassTag(ascription(tpt1, isWildcard = true), pt) } cases( ifPat = handlePattern, @@ -538,6 +533,23 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } + /** For a typed tree `e: T`, if `T` is an abstract type for which an implicit class tag `ctag` + * exists, rewrite to `ctag(e)`. + * @pre We are in pattern-matching mode (Mode.Pattern) + */ + def tryWithClassTag(tree: Typed, pt: Type)(implicit ctx: Context) = tree.tpt.tpe.dealias match { + case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper => + require(ctx.mode.is(Mode.Pattern)) + inferImplicit(defn.ClassTagType.appliedTo(tref), + EmptyTree, tree.tpt.pos)(ctx.retractMode(Mode.Pattern)) match { + case SearchSuccess(clsTag, _, _, _) => + typed(untpd.Apply(untpd.TypedSplice(clsTag), untpd.TypedSplice(tree.expr)), pt) + case _ => + tree + } + case _ => tree + } + def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = track("typedNamedArg") { val arg1 = typed(tree.arg, pt) assignType(cpy.NamedArg(tree)(tree.name, arg1), arg1) @@ -664,9 +676,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") { val untpd.Function(args, body) = tree if (ctx.mode is Mode.Type) { - val funCls = - if (tree.isInstanceOf[untpd.ImplicitFunction]) defn.ImplicitFunctionClass(args.length) - else defn.FunctionClass(args.length) + val funCls = defn.FunctionClass(args.length, tree.isInstanceOf[untpd.ImplicitFunction]) typed(cpy.AppliedTypeTree(tree)( untpd.TypeTree(funCls.typeRef), args :+ body), pt) } @@ -1118,15 +1128,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Tree = track("typedBind") { val pt1 = fullyDefinedType(pt, "pattern variable", tree.pos) val body1 = typed(tree.body, pt1) - typr.println(i"typed bind $tree pt = $pt1 bodytpe = ${body1.tpe}") body1 match { - case UnApply(fn, Nil, arg :: Nil) if tree.body.isInstanceOf[untpd.Typed] => - // A typed pattern `x @ (_: T)` with an implicit `ctag: ClassTag[T]` - // was rewritten to `x @ ctag(_)`. - // Rewrite further to `ctag(x @ _)` - assert(fn.symbol.owner == defn.ClassTagClass) + case UnApply(fn, Nil, arg :: Nil) if fn.symbol.owner == defn.ClassTagClass && !body1.tpe.isError => + // A typed pattern `x @ (e: T)` with an implicit `ctag: ClassTag[T]` + // was rewritten to `x @ ctag(e)` by `tryWithClassTag`. + // Rewrite further to `ctag(x @ e)` tpd.cpy.UnApply(body1)(fn, Nil, - typed(untpd.Bind(tree.name, arg).withPos(tree.pos), arg.tpe) :: Nil) + typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withPos(tree.pos), arg.tpe) :: Nil) case _ => val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos) assignType(cpy.Bind(tree)(tree.name, body1), sym) @@ -1937,7 +1945,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit !untpd.isImplicitClosure(tree) && !isApplyProto(pt) && !ctx.isAfterTyper) { - typr.println("insert apply on implicit $tree") + typr.println(i"insert apply on implicit $tree") typed(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt) } else if (ctx.mode is Mode.Pattern) { @@ -1956,7 +1964,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (Inliner.hasBodyToInline(tree.symbol) && !ctx.owner.ownersIterator.exists(_.isInlineMethod) && !ctx.settings.YnoInline.value && - !ctx.isAfterTyper) + !ctx.isAfterTyper && + !ctx.reporter.hasErrors) adapt(Inliner.inlineCall(tree, pt), pt) else if (ctx.typeComparer.GADTused && pt.isValueType) // Insert an explicit cast, so that -Ycheck in later phases succeeds. |