diff options
130 files changed, 1497 insertions, 1047 deletions
diff --git a/bridge/src/main/scala/xsbt/CompilerInterface.scala b/bridge/src/main/scala/xsbt/CompilerInterface.scala index ee272b8b1..bf1488dad 100644 --- a/bridge/src/main/scala/xsbt/CompilerInterface.scala +++ b/bridge/src/main/scala/xsbt/CompilerInterface.scala @@ -50,12 +50,14 @@ class CachedCompilerImpl(args: Array[String], output: Output, resident: Boolean) (outputArgs ++ args.toList ++ sources.map(_.getAbsolutePath).sortWith(_ < _)).toArray[String] def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, progress: CompileProgress): Unit = synchronized { - run(sources.toList, changes, callback, log, progress) + run(sources.toList, changes, callback, log, delegate, progress) } - private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, compileProgress: CompileProgress): Unit = { + private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, compileProgress: CompileProgress): Unit = { debug(log, args.mkString("Calling Dotty compiler with arguments (CompilerInterface):\n\t", "\n\t", "")) val ctx = (new ContextBase).initialCtx.fresh .setSbtCallback(callback) + .setReporter(new DelegatingReporter(delegate)) + val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader] val reporter = DottyMain.process(commandArguments(sources.toArray), ctx) diff --git a/bridge/src/main/scala/xsbt/DelegatingReporter.scala b/bridge/src/main/scala/xsbt/DelegatingReporter.scala new file mode 100644 index 000000000..726570d71 --- /dev/null +++ b/bridge/src/main/scala/xsbt/DelegatingReporter.scala @@ -0,0 +1,58 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import dotty.tools._ +import dotc._ +import reporting._ +import core.Contexts._ + +import xsbti.{Maybe, Position} + +final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter + with UniqueMessagePositions + with HideNonSensicalMessages { + + override def printSummary(implicit ctx: Context): Unit = delegate.printSummary() + + def doReport(d: Diagnostic)(implicit ctx: Context): Unit = { + val severity = + d match { + case _: Reporter.Error => xsbti.Severity.Error + case _: Reporter.Warning => xsbti.Severity.Warn + case _ => xsbti.Severity.Info + } + val pos = + if (d.pos.exists) Some(d.pos) + else None + + val file = + if (d.pos.source.file.exists) Option(d.pos.source.file.file) + else None + + val offset0 = pos.map(_.point) + + val position = new Position { + def line: Maybe[Integer] = maybe(pos.map(_.line)) + def lineContent: String = pos.map(_.lineContent).getOrElse("") + def offset: Maybe[Integer] = maybeInt(offset0) + def pointer: Maybe[Integer] = offset + def pointerSpace: Maybe[String] = maybe(offset0.map(" " * _)) + def sourceFile: Maybe[java.io.File] = maybe(file) + def sourcePath: Maybe[String] = maybe(file.map(_.getPath)) + } + + delegate.log(position, d.message, severity) + } + + private[this] def maybe[T](opt: Option[T]): Maybe[T] = opt match { + case None => Maybe.nothing[T] + case Some(s) => Maybe.just[T](s) + } + import java.lang.{ Integer => I } + private[this] def maybeInt(opt: Option[Int]): Maybe[I] = opt match { + case None => Maybe.nothing[I] + case Some(s) => Maybe.just[I](s) + } +}
\ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/Source.scala b/bridge/src/sbt-test/compilerReporter/simple/Source.scala new file mode 100644 index 000000000..6f0678599 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/Source.scala @@ -0,0 +1,10 @@ +trait A +trait B + +trait Wr { + val z: A with B +} + +object Er { + val a = er1 +}
\ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/build.sbt b/bridge/src/sbt-test/compilerReporter/simple/build.sbt new file mode 100644 index 000000000..017846f5e --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/build.sbt @@ -0,0 +1 @@ +Reporter.checkSettings
\ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/project/DottyInjectedPlugin.scala b/bridge/src/sbt-test/compilerReporter/simple/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000..3433779b6 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/project/DottyInjectedPlugin.scala @@ -0,0 +1,17 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := "0.1-SNAPSHOT", + scalaOrganization := "ch.epfl.lamp", + scalacOptions += "-language:Scala2", + scalaBinaryVersion := "2.11", + autoScalaLibrary := false, + libraryDependencies ++= Seq("org.scala-lang" % "scala-library" % "2.11.5"), + scalaCompilerBridgeSource := ("ch.epfl.lamp" % "dotty-bridge" % "0.1.1-SNAPSHOT" % "component").sources() + ) +} diff --git a/bridge/src/sbt-test/compilerReporter/simple/project/Reporter.scala b/bridge/src/sbt-test/compilerReporter/simple/project/Reporter.scala new file mode 100644 index 000000000..c0a56ec82 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/project/Reporter.scala @@ -0,0 +1,44 @@ +import sbt._ +import Keys._ +import KeyRanks.DTask + +object Reporter { + import xsbti.{Reporter, Problem, Position, Severity, Maybe} + + lazy val check = TaskKey[Unit]("check", "make sure compilation info are forwared to sbt") + + // compilerReporter is marked private in sbt + lazy val compilerReporter = TaskKey[Option[xsbti.Reporter]]("compilerReporter", "Experimental hook to listen (or send) compilation failure messages.", DTask) + + lazy val reporter = + Some(new xsbti.Reporter { + private val buffer = collection.mutable.ArrayBuffer.empty[Problem] + def reset(): Unit = buffer.clear() + def hasErrors: Boolean = buffer.exists(_.severity == Severity.Error) + def hasWarnings: Boolean = buffer.exists(_.severity == Severity.Warn) + def printSummary(): Unit = println(problems.mkString(System.lineSeparator)) + def problems: Array[Problem] = buffer.toArray + def log(pos: Position, msg: String, sev: Severity): Unit = { + object MyProblem extends Problem { + def category: String = null + def severity: Severity = sev + def message: String = msg + def position: Position = pos + override def toString = s"custom: $position:$severity: $message" + } + buffer.append(MyProblem) + } + def comment(pos: xsbti.Position, msg: String): Unit = () + }) + + lazy val checkSettings = Seq( + compilerReporter in (Compile, compile) := reporter, + check <<= (compile in Compile).mapFailure( _ => { + val problems = reporter.get.problems + println(problems.toList) + assert(problems.size == 2) + assert(problems.count(_.severity == Severity.Error) == 1) // not found: er1, + assert(problems.count(_.severity == Severity.Warn) == 1) // `with' as a type operator has been deprecated; use `&' instead, + }) + ) +}
\ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/test b/bridge/src/sbt-test/compilerReporter/simple/test new file mode 100644 index 000000000..a5912a391 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/test @@ -0,0 +1 @@ +> check
\ No newline at end of file diff --git a/docs/SyntaxSummary.txt b/docs/SyntaxSummary.txt index f07335d1d..6c83c71ab 100644 --- a/docs/SyntaxSummary.txt +++ b/docs/SyntaxSummary.txt @@ -105,7 +105,7 @@ grammar. WithType ::= AnnotType {`with' AnnotType} (deprecated) AnnotType ::= SimpleType {Annotation} Annotated(t, annot) SimpleType ::= SimpleType (TypeArgs | NamedTypeArgs) AppliedTypeTree(t, args) - | SimpleType `#' id SelectFromTypeTree(t, name) + | SimpleType `#' id Select(t, name) | StableId | Path `.' `type' SingletonTypeTree(p) | `(' ArgTypes ')' Tuple(ts) diff --git a/project/Build.scala b/project/Build.scala index 88ee7dca7..7c57bd862 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -207,11 +207,31 @@ object DottyBuild extends Build { ). settings(publishing) + // until sbt/sbt#2402 is fixed (https://github.com/sbt/sbt/issues/2402) + lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") + lazy val `dotty-bridge` = project.in(file("bridge")). dependsOn(dotty). settings( overrideScalaVersionSetting, + cleanSbtBridge := { + val dottyBridgeVersion = version.value + val dottyVersion = (version in dotty).value + val classVersion = System.getProperty("java.class.version") + + val sbtV = sbtVersion.value + val sbtOrg = "org.scala-sbt" + val sbtScalaVersion = "2.10.6" + + val home = System.getProperty("user.home") + val org = organization.value + val artifact = moduleName.value + + IO.delete(file(home) / ".ivy2" / "cache" / sbtOrg / s"$org-$artifact-$dottyBridgeVersion-bin_${dottyVersion}__$classVersion") + IO.delete(file(home) / ".sbt" / "boot" / s"scala-$sbtScalaVersion" / sbtOrg / "sbt" / sbtV / s"$org-$artifact-$dottyBridgeVersion-bin_${dottyVersion}__$classVersion") + }, + publishLocal := (publishLocal.dependsOn(cleanSbtBridge)).value, description := "sbt compiler bridge for Dotty", resolvers += Resolver.typesafeIvyRepo("releases"), libraryDependencies ++= Seq( diff --git a/project/plugins.sbt b/project/plugins.sbt index 8ac4d69bf..57bd46581 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -8,5 +8,3 @@ addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0") addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.8") - -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.3.5") diff --git a/src/dotty/tools/backend/jvm/CollectSuperCalls.scala b/src/dotty/tools/backend/jvm/CollectSuperCalls.scala index 8f9b067ba..8285bfe4b 100644 --- a/src/dotty/tools/backend/jvm/CollectSuperCalls.scala +++ b/src/dotty/tools/backend/jvm/CollectSuperCalls.scala @@ -4,9 +4,13 @@ import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.ast.Trees._ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Symbols._ +import dotty.tools.dotc.core.Flags.Trait import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo} -/** Collect all super calls except to the parent class. +/** Collect all super calls to trait members. + * + * For each super reference to trait member, register a call from the current class to the + * owner of the referenced member. * * This information is used to know if it is safe to remove a redundant mixin class. * A redundant mixin class is one that is implemented by another mixin class. As the @@ -20,9 +24,9 @@ class CollectSuperCalls extends MiniPhaseTransform { override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = { tree.qualifier match { - case Super(qual: This, mix) if mix.nonEmpty => - val classSymbol = qual.symbol.asClass.classSymbol - registerSuperCall(classSymbol, tree.symbol.owner.asClass) + case sup: Super => + if (tree.symbol.owner.is(Trait)) + registerSuperCall(ctx.owner.enclosingClass.asClass, tree.symbol.owner.asClass) case _ => } tree diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 30934605b..2d60d851c 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -70,7 +70,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma type Bind = tpd.Bind type New = tpd.New type Super = tpd.Super - type Modifiers = tpd.Modifiers + type Modifiers = Null type Annotation = Annotations.Annotation type ArrayValue = tpd.JavaSeqLiteral type ApplyDynamic = Null @@ -747,9 +747,13 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma */ def superInterfaces: List[Symbol] = { val directlyInheritedTraits = decorateSymbol(sym).directlyInheritedTraits + val directlyInheritedTraitsSet = directlyInheritedTraits.toSet val allBaseClasses = directlyInheritedTraits.iterator.flatMap(_.symbol.asClass.baseClasses.drop(1)).toSet val superCalls = superCallsMap.getOrElse(sym, Set.empty) - directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t)) + val additional = (superCalls -- directlyInheritedTraitsSet).filter(_.is(Flags.Trait)) +// if (additional.nonEmpty) +// println(s"$fullName: adding supertraits $additional") + directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t)) ++ additional } /** @@ -940,7 +944,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object ValDef extends ValDefDeconstructor { - def _1: Modifiers = field.mods + def _1: Modifiers = null def _2: Name = field.name def _3: Tree = field.tpt def _4: Tree = field.rhs @@ -1051,7 +1055,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object DefDef extends DefDefDeconstructor { - def _1: Modifiers = field.mods + def _1: Modifiers = null def _2: Name = field.name def _3: List[TypeDef] = field.tparams def _4: List[List[ValDef]] = field.vparamss @@ -1077,7 +1081,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } object ClassDef extends ClassDefDeconstructor { - def _1: Modifiers = field.mods + def _1: Modifiers = null def _2: Name = field.name def _4: Template = field.rhs.asInstanceOf[Template] def _3: List[TypeDef] = Nil diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index d1f126860..2120fa73e 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -25,7 +25,7 @@ class Compiler { /** Meta-ordering constraint: * - * DenotTransformers that change the signature of their denotation's info must go + * DenotTransformers that change the signature of their denotation's info must go * after erasure. The reason is that denotations are permanently referred to by * TermRefs which contain a signature. If the signature of a symbol would change, * all refs to it would become outdated - they could not be dereferenced in the @@ -83,7 +83,7 @@ class Compiler { new CapturedVars, // Represent vars captured by closures as heap objects new Constructors, // Collect initialization code in primary constructors // Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it - new FunctionalInterfaces,// Rewrites closures to implement @specialized types of Functions. + new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions. new GetClass), // Rewrites getClass calls on primitive types. List(new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments // Note: in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 500b28233..edd6da5c9 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -9,13 +9,8 @@ import Decorators._ import language.higherKinds import collection.mutable.ListBuffer import util.Attachment -import config.Printers._ object desugar { - - /** Are we using the new unboxed pair scheme? */ - private final val unboxedPairs = false - import untpd._ /** Tags a .withFilter call generated by desugaring a for expression. @@ -27,7 +22,7 @@ object desugar { private type VarInfo = (NameTree, Tree) /** Names of methods that are added unconditionally to case classes */ - def isDesugaredCaseClassMethodName(name: Name)(implicit ctx: Context) = + def isDesugaredCaseClassMethodName(name: Name)(implicit ctx: Context): Boolean = name == nme.isDefined || name == nme.copy || name == nme.productArity || @@ -506,7 +501,7 @@ object desugar { val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body) val cls = TypeDef(clsName, clsTmpl) .withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags) - Thicket(modul, classDef(cls)) + Thicket(modul, classDef(cls).withPos(mdef.pos)) } } @@ -517,7 +512,7 @@ object desugar { def patDef(pdef: PatDef)(implicit ctx: Context): Tree = { val PatDef(mods, pats, tpt, rhs) = pdef val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) - flatTree(pats1 map (makePatDef(mods, _, rhs))) + flatTree(pats1 map (makePatDef(pdef, mods, _, rhs))) } /** If `pat` is a variable pattern, @@ -535,9 +530,9 @@ object desugar { * If the original pattern variable carries a type annotation, so does the corresponding * ValDef or DefDef. */ - def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match { + def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match { case VarPattern(named, tpt) => - derivedValDef(named, tpt, rhs, mods) + derivedValDef(original, named, tpt, rhs, mods) case _ => val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs) val vars = getVariables(pat) @@ -554,7 +549,7 @@ object desugar { case Nil => matchExpr case (named, tpt) :: Nil => - derivedValDef(named, tpt, matchExpr, mods) + derivedValDef(original, named, tpt, matchExpr, mods) case _ => val tmpName = ctx.freshName().toTermName val patMods = mods & (AccessFlags | Lazy) | Synthetic @@ -565,8 +560,8 @@ object desugar { val restDefs = for (((named, tpt), n) <- vars.zipWithIndex) yield - if (mods is Lazy) derivedDefDef(named, tpt, selector(n), mods &~ Lazy) - else derivedValDef(named, tpt, selector(n), mods) + if (mods is Lazy) derivedDefDef(original, named, tpt, selector(n), mods &~ Lazy) + else derivedValDef(original, named, tpt, selector(n), mods) flatTree(firstDef :: restDefs) } } @@ -633,7 +628,7 @@ object desugar { val selector = makeTuple(params.map(p => Ident(p.name))) if (unchecked) - Function(params, Match(Annotated(New(ref(defn.UncheckedAnnotType)), selector), cases)) + Function(params, Match(Annotated(selector, New(ref(defn.UncheckedAnnotType))), cases)) else Function(params, Match(selector, cases)) } @@ -662,16 +657,20 @@ object desugar { * tree @cls */ def makeAnnotated(cls: Symbol, tree: Tree)(implicit ctx: Context) = - Annotated(untpd.New(untpd.TypeTree(cls.typeRef), Nil), tree) + Annotated(tree, untpd.New(untpd.TypeTree(cls.typeRef), Nil)) - private def derivedValDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = { - val vdef = ValDef(named.name.asTermName, tpt, rhs).withMods(mods).withPos(named.pos) + private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = { + val vdef = ValDef(named.name.asTermName, tpt, rhs) + .withMods(mods) + .withPos(original.pos.withPoint(named.pos.start)) val mayNeedSetter = valDef(vdef) mayNeedSetter } - private def derivedDefDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) = - DefDef(named.name.asTermName, Nil, Nil, tpt, rhs).withMods(mods).withPos(named.pos) + private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) = + DefDef(named.name.asTermName, Nil, Nil, tpt, rhs) + .withMods(mods) + .withPos(original.pos.withPoint(named.pos.start)) /** Main desugaring method */ def apply(tree: Tree)(implicit ctx: Context): Tree = { @@ -699,7 +698,7 @@ object desugar { Apply(Select(left, op), args) } else { val x = ctx.freshName().toTermName - Block( + new InfixOpBlock( ValDef(x, TypeTree(), left).withMods(synthetic), Apply(Select(right, op), Ident(x))) } @@ -761,7 +760,7 @@ object desugar { */ def makeLambda(pat: Tree, body: Tree): Tree = pat match { case VarPattern(named, tpt) => - Function(derivedValDef(named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body) + Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body) case _ => makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false) } @@ -864,7 +863,7 @@ object desugar { val rhss = valeqs map { case GenAlias(_, rhs) => rhs } val (defpat0, id0) = makeIdPat(pat) val (defpats, ids) = (pats map makeIdPat).unzip - val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _)) + val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _)) val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids))) val allpats = pat :: pats val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1) @@ -886,7 +885,15 @@ object desugar { Apply( ref(defn.SymbolClass.companionModule.termRef), Literal(Constant(str)) :: Nil) - case InterpolatedString(id, strs, elems) => + case InterpolatedString(id, segments) => + val strs = segments map { + case ts: Thicket => ts.trees.head + case t => t + } + val elems = segments flatMap { + case ts: Thicket => ts.trees.tail + case t => Nil + } Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems) case InfixOp(l, op, r) => if (ctx.mode is Mode.Type) @@ -901,8 +908,8 @@ object desugar { if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) { val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType Annotated( - New(ref(defn.RepeatedAnnotType), Nil :: Nil), - AppliedTypeTree(ref(seqType), t)) + AppliedTypeTree(ref(seqType), t), + New(ref(defn.RepeatedAnnotType), Nil :: Nil)) } else { assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode) Select(t, op) @@ -912,25 +919,15 @@ object desugar { case Parens(t) => t case Tuple(ts) => - if (unboxedPairs) { - def PairTypeTree(l: Tree, r: Tree) = - AppliedTypeTree(ref(defn.PairType), l :: r :: Nil) - if (ctx.mode is Mode.Type) ts.reduceRight(PairTypeTree) - else if (ts.isEmpty) unitLiteral - else ts.reduceRight(Pair(_, _)) - } - else { - val arity = ts.length - def tupleTypeRef = defn.TupleType(arity) - if (arity > Definitions.MaxTupleArity) { - ctx.error(s"tuple too long (max allowed: ${Definitions.MaxTupleArity})", tree.pos) - unitLiteral - } - else if (arity == 1) ts.head - else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts) - else if (arity == 0) unitLiteral - else Apply(ref(tupleTypeRef.classSymbol.companionModule.valRef), ts) - } + val arity = ts.length + def tupleTypeRef = defn.TupleType(arity) + if (arity > Definitions.MaxTupleArity) { + ctx.error(s"tuple too long (max allowed: ${Definitions.MaxTupleArity})", tree.pos) + unitLiteral + } else if (arity == 1) ts.head + else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts) + else if (arity == 0) unitLiteral + else Apply(ref(tupleTypeRef.classSymbol.companionModule.valRef), ts) case WhileDo(cond, body) => // { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() } val call = Apply(Ident(nme.WHILE_PREFIX), Nil) @@ -947,7 +944,7 @@ object desugar { makeFor(nme.map, nme.flatMap, enums, body) orElse tree case PatDef(mods, pats, tpt, rhs) => val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) - flatTree(pats1 map (makePatDef(mods, _, rhs))) + flatTree(pats1 map (makePatDef(tree, mods, _, rhs))) case ParsedTry(body, handler, finalizer) => handler match { case Match(EmptyTree, cases) => Try(body, cases, finalizer) @@ -1037,9 +1034,6 @@ object desugar { add(id, TypeTree()) case Apply(_, args) => args foreach collect - case Pair(left, right) => - collect(left) - collect(right) case Typed(expr, _) => collect(expr) case NamedArg(_, arg) => @@ -1049,10 +1043,10 @@ object desugar { case Alternative(trees) => for (tree <- trees; (vble, _) <- getVariables(tree)) ctx.error("illegal variable in pattern alternative", vble.pos) - case Annotated(annot, arg) => + case Annotated(arg, _) => collect(arg) - case InterpolatedString(_, _, elems) => - elems foreach collect + case InterpolatedString(_, segments) => + segments foreach collect case InfixOp(left, _, right) => collect(left) collect(right) diff --git a/src/dotty/tools/dotc/ast/NavigateAST.scala b/src/dotty/tools/dotc/ast/NavigateAST.scala index 2b11f81f3..33aa87d8e 100644 --- a/src/dotty/tools/dotc/ast/NavigateAST.scala +++ b/src/dotty/tools/dotc/ast/NavigateAST.scala @@ -19,10 +19,9 @@ object NavigateAST { case _ => val loosePath = untypedPath(tree, exactMatch = false) throw new - Error(i"""no untyped tree for $tree, pos = ${tree.pos}, envelope = ${tree.envelope} + Error(i"""no untyped tree for $tree, pos = ${tree.pos} |best matching path =\n$loosePath%\n====\n% - |path positions = ${loosePath.map(_.pos)} - |path envelopes = ${loosePath.map(_.envelope)}""") + |path positions = ${loosePath.map(_.pos)}""") } /** The reverse path of untyped trees starting with a tree that closest matches @@ -40,7 +39,7 @@ object NavigateAST { def untypedPath(tree: tpd.Tree, exactMatch: Boolean = false)(implicit ctx: Context): List[Positioned] = tree match { case tree: MemberDef[_] => - untypedPath(tree.envelope) match { + untypedPath(tree.pos) match { case path @ (last: DefTree[_]) :: _ => path case path if !exactMatch => path case _ => Nil @@ -76,7 +75,7 @@ object NavigateAST { path } def singlePath(p: Positioned, path: List[Positioned]): List[Positioned] = - if (p.envelope contains pos) childPath(p.productIterator, p :: path) + if (p.pos contains pos) childPath(p.productIterator, p :: path) else path singlePath(from, Nil) } diff --git a/src/dotty/tools/dotc/ast/Positioned.scala b/src/dotty/tools/dotc/ast/Positioned.scala index e7f5de591..8d364d439 100644 --- a/src/dotty/tools/dotc/ast/Positioned.scala +++ b/src/dotty/tools/dotc/ast/Positioned.scala @@ -3,6 +3,10 @@ package ast import util.Positions._ import util.DotClass +import core.Contexts.Context +import core.Decorators._ +import core.Flags.JavaDefined +import core.StdNames.nme /** A base class for things that have positions (currently: modifiers and trees) */ @@ -16,7 +20,7 @@ abstract class Positioned extends DotClass with Product { */ def pos: Position = curPos - /** Destructively update `curPos` to given position. Also, set any missing + /** Destructively update `curPos` to given position. Also, set any missing * positions in children. */ protected def setPos(pos: Position): Unit = { @@ -24,11 +28,6 @@ abstract class Positioned extends DotClass with Product { if (pos.exists) setChildPositions(pos.toSynthetic) } - /** The envelope containing the item in its entirety. Envelope is different from - * `pos` for definitions (instances of MemberDef). - */ - def envelope: Position = pos.toSynthetic - /** A positioned item like this one with the position set to `pos`. * if the positioned item is source-derived, a clone is returned. * If the positioned item is synthetic, the position is updated @@ -106,8 +105,7 @@ abstract class Positioned extends DotClass with Product { } } - /** The initial, synthetic position. This is usually the union of all positioned children's - * envelopes. + /** The initial, synthetic position. This is usually the union of all positioned children's positions. */ protected def initialPos: Position = { var n = productArity @@ -115,7 +113,7 @@ abstract class Positioned extends DotClass with Product { while (n > 0) { n -= 1 productElement(n) match { - case p: Positioned => pos = pos union p.envelope + case p: Positioned => pos = pos union p.pos case xs: List[_] => pos = unionPos(pos, xs) case _ => } @@ -124,7 +122,7 @@ abstract class Positioned extends DotClass with Product { } private def unionPos(pos: Position, xs: List[_]): Position = xs match { - case (p: Positioned) :: xs1 => unionPos(pos union p.envelope, xs1) + case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1) case _ => pos } @@ -138,7 +136,7 @@ abstract class Positioned extends DotClass with Product { false } (this eq that) || - (this.envelope contains that.pos) && { + (this.pos contains that.pos) && { var n = productArity var found = false while (n > 0 && !found) { @@ -148,4 +146,68 @@ abstract class Positioned extends DotClass with Product { found } } + + /** Check that all positioned items in this tree satisfy the following conditions: + * - Parent positions contain child positions + * - If item is a non-empty tree, it has a position + */ + def checkPos(nonOverlapping: Boolean)(implicit ctx: Context): Unit = try { + import untpd._ + var lastPositioned: Positioned = null + var lastPos = NoPosition + def check(p: Any): Unit = p match { + case p: Positioned => + assert(pos contains p.pos, + s"""position error, parent position does not contain child positon + |parent = $this, + |parent position = $pos, + |child = $p, + |child position = ${p.pos}""".stripMargin) + p match { + case tree: Tree if !tree.isEmpty => + assert(tree.pos.exists, + s"position error: position not set for $tree # ${tree.uniqueId}") + case _ => + } + if (nonOverlapping) { + this match { + case _: WildcardFunction + if lastPositioned.isInstanceOf[ValDef] && !p.isInstanceOf[ValDef] => + // ignore transition from last wildcard parameter to body + case _ => + assert(!lastPos.exists || !p.pos.exists || lastPos.end <= p.pos.start, + s"""position error, child positions overlap or in wrong order + |parent = $this + |1st child = $lastPositioned + |1st child position = $lastPos + |2nd child = $p + |2nd child position = ${p.pos}""".stripMargin) + } + lastPositioned = p + lastPos = p.pos + } + p.checkPos(nonOverlapping) + case xs: List[_] => + xs.foreach(check) + case _ => + } + this match { + case tree: DefDef if tree.name == nme.CONSTRUCTOR && tree.mods.is(JavaDefined) => + // Special treatment for constructors coming from Java: + // Leave out tparams, they are copied with wrong positions from parent class + check(tree.mods) + check(tree.vparamss) + case _ => + val end = productArity + var n = 0 + while (n < end) { + check(productElement(n)) + n += 1 + } + } + } catch { + case ex: AssertionError => + println(i"error while checking $this") + throw ex + } } diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index a48651ebf..725838ef6 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -182,8 +182,8 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case OrTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind]) case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind]) - case SelectFromTypeTree(tpt, _) => mayBeTypePat(tpt) - case Annotated(_, tpt) => mayBeTypePat(tpt) + case Select(tpt, _) => mayBeTypePat(tpt) + case Annotated(tpt, _) => mayBeTypePat(tpt) case _ => false } @@ -249,17 +249,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** Is this case guarded? */ def isGuardedCase(cdef: CaseDef) = cdef.guard ne EmptyTree - /** True iff definition is a val or def with no right-hand-side, or it - * is an abstract typoe declaration - */ - def lacksDefinition(mdef: MemberDef)(implicit ctx: Context) = mdef match { - case mdef: ValOrDefDef => - mdef.unforcedRhs == EmptyTree && !mdef.name.isConstructorName && !mdef.mods.is(ParamAccessor) - case mdef: TypeDef => - mdef.rhs.isEmpty || mdef.rhs.isInstanceOf[TypeBoundsTree] - case _ => false - } - /** The underlying pattern ignoring any bindings */ def unbind(x: Tree): Tree = unsplice(x) match { case Bind(_, y) => unbind(y) @@ -279,9 +268,21 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] => import TreeInfo._ + import untpd._ + + /** True iff definition is a val or def with no right-hand-side, or it + * is an abstract typoe declaration + */ + def lacksDefinition(mdef: MemberDef)(implicit ctx: Context) = mdef match { + case mdef: ValOrDefDef => + mdef.unforcedRhs == EmptyTree && !mdef.name.isConstructorName && !mdef.mods.is(ParamAccessor) + case mdef: TypeDef => + mdef.rhs.isEmpty || mdef.rhs.isInstanceOf[TypeBoundsTree] + case _ => false + } def isFunctionWithUnknownParamType(tree: Tree) = tree match { - case untpd.Function(args, _) => + case Function(args, _) => args.exists { case ValDef(_, tpt, _) => tpt.isEmpty case _ => false @@ -307,7 +308,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => | DefDef(_, _, _, _, _) => Pure case vdef @ ValDef(_, _, _) => - if (vdef.mods is Mutable) Impure else exprPurity(vdef.rhs) + if (vdef.symbol.flags is Mutable) Impure else exprPurity(vdef.rhs) case _ => Impure } @@ -480,7 +481,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => require(sym.pos.exists) object accum extends TreeAccumulator[List[Tree]] { def apply(x: List[Tree], tree: Tree)(implicit ctx: Context): List[Tree] = { - if (tree.envelope.contains(sym.pos)) + if (tree.pos.contains(sym.pos)) if (definedSym(tree) == sym) tree :: x else { val x1 = foldOver(x, tree) @@ -630,20 +631,6 @@ object TreeInfo { } } - def isApplyDynamicName(name: Name) = (name == nme.updateDynamic) || (name == nme.selectDynamic) || (name == nme.applyDynamic) || (name == nme.applyDynamicNamed) - - class DynamicApplicationExtractor(nameTest: Name => Boolean) { - def unapply(tree: Tree) = tree match { - case Apply(TypeApply(Select(qual, oper), _), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name)) - case Apply(Select(qual, oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name)) - case Apply(Ident(oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((EmptyTree(), name)) - case _ => None - } - } - object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic) - object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName) - object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed) - object MacroImplReference { private def refPart(tree: Tree): Tree = tree match { case TypeApply(fun, _) => refPart(fun) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index cf11c27fa..bb6fbd5ba 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -33,51 +33,7 @@ object Trees { /** Attachment key for trees with documentation strings attached */ val DocComment = new Attachment.Key[Comment] - /** Modifiers and annotations for definitions - * @param flags The set flags - * @param privateWithin If a private or protected has is followed by a - * qualifier [q], the name q, "" as a typename otherwise. - * @param annotations The annotations preceding the modifiers - */ - case class Modifiers[-T >: Untyped] ( - flags: FlagSet = EmptyFlags, - privateWithin: TypeName = tpnme.EMPTY, - annotations: List[Tree[T]] = Nil) extends Positioned with Cloneable { - - def is(fs: FlagSet): Boolean = flags is fs - def is(fc: FlagConjunction): Boolean = flags is fc - - def | (fs: FlagSet): Modifiers[T] = withFlags(flags | fs) - def & (fs: FlagSet): Modifiers[T] = withFlags(flags & fs) - def &~(fs: FlagSet): Modifiers[T] = withFlags(flags &~ fs) - - def toTypeFlags: Modifiers[T] = withFlags(flags.toTypeFlags) - def toTermFlags: Modifiers[T] = withFlags(flags.toTermFlags) - - def withFlags(flags: FlagSet) = - if (this.flags == flags) this - else copy(flags = flags) - - def withAddedAnnotation[U >: Untyped <: T](annot: Tree[U]): Modifiers[U] = - if (annotations.exists(_ eq annot)) this - else withAnnotations(annotations :+ annot) - - def withAnnotations[U >: Untyped <: T](annots: List[Tree[U]]): Modifiers[U] = - if (annots eq annotations) this - else copy(annotations = annots) - - def withPrivateWithin(pw: TypeName) = - if (pw.isEmpty) this - else copy(privateWithin = pw) - - def hasFlags = flags != EmptyFlags - def hasAnnotations = annotations.nonEmpty - def hasPrivateWithin = privateWithin != tpnme.EMPTY - - def tokenPos: Seq[(Token, Position)] = ??? - } - - @sharable private var nextId = 0 // for debugging + @sharable private var nextId = 0 // for debugging type LazyTree = AnyRef /* really: Tree | Lazy[Tree] */ type LazyTreeList = AnyRef /* really: List[Tree] | Lazy[List[Tree]] */ @@ -320,29 +276,41 @@ object Trees { abstract class MemberDef[-T >: Untyped] extends NameTree[T] with DefTree[T] { type ThisTree[-T >: Untyped] <: MemberDef[T] - private[this] var myMods: Modifiers[T] = null + private[this] var myMods: untpd.Modifiers = null - private[ast] def rawMods: Modifiers[T] = - if (myMods == null) genericEmptyModifiers else myMods + private[dotc] def rawMods: untpd.Modifiers = + if (myMods == null) untpd.EmptyModifiers else myMods def rawComment: Option[Comment] = getAttachment(DocComment) - def withMods(mods: Modifiers[Untyped]): ThisTree[Untyped] = { + def withMods(mods: untpd.Modifiers): ThisTree[Untyped] = { val tree = if (myMods == null || (myMods == mods)) this else clone.asInstanceOf[MemberDef[Untyped]] tree.setMods(mods) tree.asInstanceOf[ThisTree[Untyped]] } - def withFlags(flags: FlagSet): ThisTree[Untyped] = withMods(Modifiers(flags)) + def withFlags(flags: FlagSet): ThisTree[Untyped] = withMods(untpd.Modifiers(flags)) def setComment(comment: Option[Comment]): ThisTree[Untyped] = { comment.map(putAttachment(DocComment, _)) asInstanceOf[ThisTree[Untyped]] } - protected def setMods(mods: Modifiers[T @uncheckedVariance]) = myMods = mods + protected def setMods(mods: untpd.Modifiers) = myMods = mods + + /** The position of the name defined by this definition. + * This is a point position if the definition is synthetic, or a range position + * if the definition comes from source. + * It might also be that the definition does not have a position (for instance when synthesized by + * a calling chain from `viewExists`), in that case the return position is NoPosition. + */ + def namePos = + if (pos.exists) + if (rawMods.is(Synthetic)) Position(pos.point, pos.point) + else Position(pos.point, pos.point + name.length, pos.point) + else pos + - override def envelope: Position = rawMods.pos.union(pos).union(initialPos) } /** A ValDef or DefDef tree */ @@ -366,7 +334,7 @@ object Trees { override def toString = s"BackquotedIdent($name)" } - /** qualifier.name */ + /** qualifier.name, or qualifier#name, if qualifier is a type */ case class Select[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name) extends RefTree[T] { type ThisTree[-T >: Untyped] = Select[T] @@ -430,15 +398,6 @@ object Trees { type ThisTree[-T >: Untyped] = New[T] } - /** (left, right) */ - case class Pair[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) - extends TermTree[T] { - type ThisTree[-T >: Untyped] = Pair[T] - override def isTerm = left.isTerm && right.isTerm - override def isType = left.isType && right.isType - override def isPattern = !isTerm && (left.isPattern || left.isTerm) && (right.isPattern || right.isTerm) - } - /** expr : tpt */ case class Typed[-T >: Untyped] private[ast] (expr: Tree[T], tpt: Tree[T]) extends ProxyTree[T] with TermTree[T] { @@ -560,15 +519,6 @@ object Trees { type ThisTree[-T >: Untyped] = SingletonTypeTree[T] } - /** qualifier # name - * In Scala, this always refers to a type, but in a Java - * compilation unit this might refer to a term. - */ - case class SelectFromTypeTree[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name) - extends RefTree[T] { - type ThisTree[-T >: Untyped] = SelectFromTypeTree[T] - } - /** left & right */ case class AndTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) extends TypTree[T] { @@ -619,7 +569,6 @@ object Trees { type ThisTree[-T >: Untyped] = Bind[T] override def isType = name.isTypeName override def isTerm = name.isTermName - override def envelope: Position = pos union initialPos } /** tree_1 | ... | tree_n */ @@ -697,7 +646,7 @@ object Trees { /** import expr.selectors * where a selector is either an untyped `Ident`, `name` or - * an untyped `Pair` `name => rename` + * an untyped thicket consisting of `name` and `rename`. */ case class Import[-T >: Untyped] private[ast] (expr: Tree[T], selectors: List[Tree[Untyped]]) extends DenotingTree[T] { @@ -712,7 +661,7 @@ object Trees { } /** arg @annot */ - case class Annotated[-T >: Untyped] private[ast] (annot: Tree[T], arg: Tree[T]) + case class Annotated[-T >: Untyped] private[ast] (arg: Tree[T], annot: Tree[T]) extends ProxyTree[T] { type ThisTree[-T >: Untyped] = Annotated[T] def forwardTo = arg @@ -740,6 +689,7 @@ object Trees { val newTrees = trees.map(_.withPos(pos)) new Thicket[T](newTrees).asInstanceOf[this.type] } + override def pos = (NoPosition /: trees) ((pos, t) => pos union t.pos) override def foreachInThicket(op: Tree[T] => Unit): Unit = trees foreach (_.foreachInThicket(op)) } @@ -747,16 +697,14 @@ object Trees { class EmptyValDef[T >: Untyped] extends ValDef[T]( nme.WILDCARD, genericEmptyTree[T], genericEmptyTree[T]) with WithoutTypeOrPos[T] { override def isEmpty: Boolean = true - setMods(Modifiers[T](PrivateLocal)) + setMods(untpd.Modifiers(PrivateLocal)) } @sharable val theEmptyTree: Thicket[Type] = Thicket(Nil) @sharable val theEmptyValDef = new EmptyValDef[Type] - @sharable val theEmptyModifiers = new Modifiers() def genericEmptyValDef[T >: Untyped]: ValDef[T] = theEmptyValDef.asInstanceOf[ValDef[T]] def genericEmptyTree[T >: Untyped]: Thicket[T] = theEmptyTree.asInstanceOf[Thicket[T]] - def genericEmptyModifiers[T >: Untyped]: Modifiers[T] = theEmptyModifiers.asInstanceOf[Modifiers[T]] def flatten[T >: Untyped](trees: List[Tree[T]]): List[Tree[T]] = { var buf: ListBuffer[Tree[T]] = null @@ -815,7 +763,6 @@ object Trees { abstract class Instance[T >: Untyped <: Type] extends DotClass { inst => - type Modifiers = Trees.Modifiers[T] type Tree = Trees.Tree[T] type TypTree = Trees.TypTree[T] type TermTree = Trees.TermTree[T] @@ -838,7 +785,6 @@ object Trees { type TypeApply = Trees.TypeApply[T] type Literal = Trees.Literal[T] type New = Trees.New[T] - type Pair = Trees.Pair[T] type Typed = Trees.Typed[T] type NamedArg = Trees.NamedArg[T] type Assign = Trees.Assign[T] @@ -853,7 +799,6 @@ object Trees { type JavaSeqLiteral = Trees.JavaSeqLiteral[T] type TypeTree = Trees.TypeTree[T] type SingletonTypeTree = Trees.SingletonTypeTree[T] - type SelectFromTypeTree = Trees.SelectFromTypeTree[T] type AndTypeTree = Trees.AndTypeTree[T] type OrTypeTree = Trees.OrTypeTree[T] type RefinedTypeTree = Trees.RefinedTypeTree[T] @@ -875,14 +820,9 @@ object Trees { @sharable val EmptyTree: Thicket = genericEmptyTree @sharable val EmptyValDef: ValDef = genericEmptyValDef - @sharable val EmptyModifiers: Modifiers = genericEmptyModifiers // ----- Auxiliary creation methods ------------------ - def Modifiers(flags: FlagSet = EmptyFlags, - privateWithin: TypeName = tpnme.EMPTY, - annotations: List[Tree] = Nil) = new Modifiers(flags, privateWithin, annotations) - def Thicket(trees: List[Tree]): Thicket = new Thicket(trees) def Thicket(): Thicket = EmptyTree def Thicket(x1: Tree, x2: Tree): Thicket = Thicket(x1 :: x2 :: Nil) @@ -892,11 +832,6 @@ object Trees { case ys => Thicket(ys) } - // ----- Accessing modifiers ---------------------------------------------------- - - abstract class ModsDeco { def mods: Modifiers } - implicit def modsDeco(mdef: MemberDef)(implicit ctx: Context): ModsDeco - // ----- Helper classes for copying, transforming, accumulating ----------------- val cpy: TreeCopier @@ -957,10 +892,6 @@ object Trees { case tree: New if tpt eq tree.tpt => tree case _ => finalize(tree, untpd.New(tpt)) } - def Pair(tree: Tree)(left: Tree, right: Tree)(implicit ctx: Context): Pair = tree match { - case tree: Pair if (left eq tree.left) && (right eq tree.right) => tree - case _ => finalize(tree, untpd.Pair(left, right)) - } def Typed(tree: Tree)(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = tree match { case tree: Typed if (expr eq tree.expr) && (tpt eq tree.tpt) => tree case _ => finalize(tree, untpd.Typed(expr, tpt)) @@ -1016,10 +947,6 @@ object Trees { case tree: SingletonTypeTree if ref eq tree.ref => tree case _ => finalize(tree, untpd.SingletonTypeTree(ref)) } - def SelectFromTypeTree(tree: Tree)(qualifier: Tree, name: Name): SelectFromTypeTree = tree match { - case tree: SelectFromTypeTree if (qualifier eq tree.qualifier) && (name == tree.name) => tree - case _ => finalize(tree, untpd.SelectFromTypeTree(qualifier, name)) - } def AndTypeTree(tree: Tree)(left: Tree, right: Tree): AndTypeTree = tree match { case tree: AndTypeTree if (left eq tree.left) && (right eq tree.right) => tree case _ => finalize(tree, untpd.AndTypeTree(left, right)) @@ -1084,9 +1011,9 @@ object Trees { case tree: PackageDef if (pid eq tree.pid) && (stats eq tree.stats) => tree case _ => finalize(tree, untpd.PackageDef(pid, stats)) } - def Annotated(tree: Tree)(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = tree match { - case tree: Annotated if (annot eq tree.annot) && (arg eq tree.arg) => tree - case _ => finalize(tree, untpd.Annotated(annot, arg)) + def Annotated(tree: Tree)(arg: Tree, annot: Tree)(implicit ctx: Context): Annotated = tree match { + case tree: Annotated if (arg eq tree.arg) && (annot eq tree.annot) => tree + case _ => finalize(tree, untpd.Annotated(arg, annot)) } def Thicket(tree: Tree)(trees: List[Tree]): Thicket = tree match { case tree: Thicket if trees eq tree.trees => tree @@ -1134,8 +1061,6 @@ object Trees { tree case New(tpt) => cpy.New(tree)(transform(tpt)) - case Pair(left, right) => - cpy.Pair(tree)(transform(left), transform(right)) case Typed(expr, tpt) => cpy.Typed(tree)(transform(expr), transform(tpt)) case NamedArg(name, arg) => @@ -1162,8 +1087,6 @@ object Trees { tree case SingletonTypeTree(ref) => cpy.SingletonTypeTree(tree)(transform(ref)) - case SelectFromTypeTree(qualifier, name) => - cpy.SelectFromTypeTree(tree)(transform(qualifier), name) case AndTypeTree(left, right) => cpy.AndTypeTree(tree)(transform(left), transform(right)) case OrTypeTree(left, right) => @@ -1200,8 +1123,8 @@ object Trees { cpy.Import(tree)(transform(expr), selectors) case PackageDef(pid, stats) => cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)) - case Annotated(annot, arg) => - cpy.Annotated(tree)(transform(annot), transform(arg)) + case Annotated(arg, annot) => + cpy.Annotated(tree)(transform(arg), transform(annot)) case Thicket(trees) => val trees1 = transform(trees) if (trees1 eq trees) tree else Thicket(trees1) @@ -1240,8 +1163,6 @@ object Trees { x case New(tpt) => this(x, tpt) - case Pair(left, right) => - this(this(x, left), right) case Typed(expr, tpt) => this(this(x, expr), tpt) case NamedArg(name, arg) => @@ -1268,8 +1189,6 @@ object Trees { x case SingletonTypeTree(ref) => this(x, ref) - case SelectFromTypeTree(qualifier, name) => - this(x, qualifier) case AndTypeTree(left, right) => this(this(x, left), right) case OrTypeTree(left, right) => @@ -1306,8 +1225,8 @@ object Trees { this(x, expr) case PackageDef(pid, stats) => this(this(x, pid), stats)(localCtx) - case Annotated(annot, arg) => - this(this(x, annot), arg) + case Annotated(arg, annot) => + this(this(x, arg), annot) case Thicket(ts) => this(x, ts) } @@ -1345,7 +1264,6 @@ object Trees { case tree: DefDef => cpy.DefDef(tree)(name = newName.asTermName) case tree: untpd.PolyTypeDef => untpd.cpy.PolyTypeDef(tree)(newName.asTypeName, tree.tparams, tree.rhs).withMods(tree.rawMods) case tree: TypeDef => cpy.TypeDef(tree)(name = newName.asTypeName) - case tree: SelectFromTypeTree => cpy.SelectFromTypeTree(tree)(tree.qualifier, newName) } }.asInstanceOf[tree.ThisTree[T]] } diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 2b0e63a19..f59bb7a47 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -9,7 +9,6 @@ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._ import Denotations._, Decorators._, DenotTransformers._ -import config.Printers._ import collection.mutable import typer.ErrorReporting._ @@ -20,22 +19,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { private def ta(implicit ctx: Context) = ctx.typeAssigner - def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Modifiers( - sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags else ModifierFlags), - if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, - sym.annotations map (_.tree)) - def Ident(tp: NamedType)(implicit ctx: Context): Ident = ta.assignType(untpd.Ident(tp.name), tp) def Select(qualifier: Tree, name: Name)(implicit ctx: Context): Select = ta.assignType(untpd.Select(qualifier, name), qualifier) - def SelectFromTypeTree(qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree = - ta.assignType(untpd.SelectFromTypeTree(qualifier, name), qualifier) - - def SelectFromTypeTree(qualifier: Tree, tp: NamedType)(implicit ctx: Context): SelectFromTypeTree = - untpd.SelectFromTypeTree(qualifier, tp.name).withType(tp) + def Select(qualifier: Tree, tp: NamedType)(implicit ctx: Context): Select = + untpd.Select(qualifier, tp.name).withType(tp) def This(cls: ClassSymbol)(implicit ctx: Context): This = untpd.This(cls.name).withType(cls.thisType) @@ -60,9 +51,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def New(tp: Type)(implicit ctx: Context): New = New(TypeTree(tp)) - def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair = - ta.assignType(untpd.Pair(left, right), left, right) - def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = ta.assignType(untpd.Typed(expr, tpt), tpt) @@ -293,8 +281,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef = ta.assignType(untpd.PackageDef(pid, stats), pid) - def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = - ta.assignType(untpd.Annotated(annot, arg), annot, arg) + def Annotated(arg: Tree, annot: Tree)(implicit ctx: Context): Annotated = + ta.assignType(untpd.Annotated(arg, annot), arg, annot) def Throw(expr: Tree)(implicit ctx: Context): Tree = ref(defn.throwMethod).appliedTo(expr) @@ -337,7 +325,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { Ident(tp) else tp.prefix match { case pre: SingletonType => followOuterLinks(singleton(pre)).select(tp) - case pre => SelectFromTypeTree(TypeTree(pre), tp) + case pre => Select(TypeTree(pre), tp) } // no checks necessary def ref(sym: Symbol)(implicit ctx: Context): Tree = @@ -453,10 +441,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } else foldOver(sym, tree) } - implicit class modsDeco(mdef: MemberDef)(implicit ctx: Context) extends ModsDeco { - def mods = if (mdef.hasType) Modifiers(mdef.symbol) else mdef.rawMods - } - override val cpy = new TypedTreeCopier class TypedTreeCopier extends TreeCopier { @@ -494,14 +478,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { override def New(tree: Tree)(tpt: Tree)(implicit ctx: Context): New = ta.assignType(untpd.cpy.New(tree)(tpt), tpt) - override def Pair(tree: Tree)(left: Tree, right: Tree)(implicit ctx: Context): Pair = { - val tree1 = untpd.cpy.Pair(tree)(left, right) - tree match { - case tree: Pair if (left.tpe eq tree.left.tpe) && (right.tpe eq tree.right.tpe) => tree1.withTypeUnchecked(tree.tpe) - case _ => ta.assignType(tree1, left, right) - } - } - override def Typed(tree: Tree)(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = ta.assignType(untpd.cpy.Typed(tree)(expr, tpt), tpt) @@ -569,11 +545,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } - override def Annotated(tree: Tree)(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = { - val tree1 = untpd.cpy.Annotated(tree)(annot, arg) + override def Annotated(tree: Tree)(arg: Tree, annot: Tree)(implicit ctx: Context): Annotated = { + val tree1 = untpd.cpy.Annotated(tree)(arg, annot) tree match { case tree: Annotated if (arg.tpe eq tree.arg.tpe) && (annot eq tree.annot) => tree1.withTypeUnchecked(tree.tpe) - case _ => ta.assignType(tree1, annot, arg) + case _ => ta.assignType(tree1, arg, annot) } } diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index cef78c6e6..61c3a79a4 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -35,11 +35,24 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree case class SymbolLit(str: String) extends TermTree - case class InterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) extends TermTree + + /** An interpolated string + * @param segments a list of two element tickets consisting of string literal and argument tree, + * possibly with a simple string literal as last element of the list + */ + case class InterpolatedString(id: TermName, segments: List[Tree]) extends TermTree + case class Function(args: List[Tree], body: Tree) extends Tree { override def isTerm = body.isTerm override def isType = body.isType } + /** A function created from a wildcard expression + * @param placeHolderParams a list of definitions of synthetic parameters + * @param body the function body where wildcards are replaced by + * references to synthetic parameters. + */ + class WildcardFunction(placeholderParams: List[ValDef], body: Tree) extends Function(placeholderParams, body) + case class InfixOp(left: Tree, op: Name, right: Tree) extends OpTree case class PostfixOp(od: Tree, op: Name) extends OpTree case class PrefixOp(op: Name, od: Tree) extends OpTree @@ -63,6 +76,62 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { class PolyTypeDef(name: TypeName, override val tparams: List[TypeDef], rhs: Tree) extends TypeDef(name, rhs) + /** A block arising from a right-associative infix operation, where, e.g. + * + * a +: b + * + * is expanded to + * + * { val x = a; b.+:(x) } + */ + class InfixOpBlock(leftOperand: Tree, rightOp: Tree) extends Block(leftOperand :: Nil, rightOp) + + // ----- Modifiers ----------------------------------------------------- + + /** Modifiers and annotations for definitions + * @param flags The set flags + * @param privateWithin If a private or protected has is followed by a + * qualifier [q], the name q, "" as a typename otherwise. + * @param annotations The annotations preceding the modifiers + */ + case class Modifiers ( + flags: FlagSet = EmptyFlags, + privateWithin: TypeName = tpnme.EMPTY, + annotations: List[Tree] = Nil) extends Positioned with Cloneable { + + def is(fs: FlagSet): Boolean = flags is fs + def is(fc: FlagConjunction): Boolean = flags is fc + + def | (fs: FlagSet): Modifiers = withFlags(flags | fs) + def & (fs: FlagSet): Modifiers = withFlags(flags & fs) + def &~(fs: FlagSet): Modifiers = withFlags(flags &~ fs) + + def toTypeFlags: Modifiers = withFlags(flags.toTypeFlags) + def toTermFlags: Modifiers = withFlags(flags.toTermFlags) + + def withFlags(flags: FlagSet) = + if (this.flags == flags) this + else copy(flags = flags) + + def withAddedAnnotation(annot: Tree): Modifiers = + if (annotations.exists(_ eq annot)) this + else withAnnotations(annotations :+ annot) + + def withAnnotations(annots: List[Tree]): Modifiers = + if (annots eq annotations) this + else copy(annotations = annots) + + def withPrivateWithin(pw: TypeName) = + if (pw.isEmpty) this + else copy(privateWithin = pw) + + def hasFlags = flags != EmptyFlags + def hasAnnotations = annotations.nonEmpty + def hasPrivateWithin = privateWithin != tpnme.EMPTY + } + + @sharable val EmptyModifiers: Modifiers = new Modifiers() + // ----- TypeTrees that refer to other tree's symbols ------------------- /** A type tree that gets its type from some other tree's symbol. Enters the @@ -116,7 +185,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def TypeApply(fun: Tree, args: List[Tree]): TypeApply = new TypeApply(fun, args) def Literal(const: Constant): Literal = new Literal(const) def New(tpt: Tree): New = new New(tpt) - def Pair(left: Tree, right: Tree): Pair = new Pair(left, right) def Typed(expr: Tree, tpt: Tree): Typed = new Typed(expr, tpt) def NamedArg(name: Name, arg: Tree): NamedArg = new NamedArg(name, arg) def Assign(lhs: Tree, rhs: Tree): Assign = new Assign(lhs, rhs) @@ -132,7 +200,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def TypeTree(original: Tree): TypeTree = new TypeTree(original) def TypeTree() = new TypeTree(EmptyTree) def SingletonTypeTree(ref: Tree): SingletonTypeTree = new SingletonTypeTree(ref) - def SelectFromTypeTree(qualifier: Tree, name: Name): SelectFromTypeTree = new SelectFromTypeTree(qualifier, name) def AndTypeTree(left: Tree, right: Tree): AndTypeTree = new AndTypeTree(left, right) def OrTypeTree(left: Tree, right: Tree): OrTypeTree = new OrTypeTree(left, right) def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) @@ -149,7 +216,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = new Template(constr, parents, self, body) def Import(expr: Tree, selectors: List[untpd.Tree]): Import = new Import(expr, selectors) def PackageDef(pid: RefTree, stats: List[Tree]): PackageDef = new PackageDef(pid, stats) - def Annotated(annot: Tree, arg: Tree): Annotated = new Annotated(annot, arg) + def Annotated(arg: Tree, annot: Tree): Annotated = new Annotated(arg, annot) // ------ Additional creation methods for untyped only ----------------- @@ -243,22 +310,11 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { /** A repeated argument such as `arg: _*` */ def repeated(arg: Tree)(implicit ctx: Context) = Typed(arg, Ident(tpnme.WILDCARD_STAR)) -// ------- Decorators ------------------------------------------------- +// ----- Accessing modifiers ---------------------------------------------------- - implicit class UntypedTreeDecorator(val self: Tree) extends AnyVal { - def locateEnclosing(base: List[Tree], pos: Position): List[Tree] = { - def encloses(elem: Any) = elem match { - case t: Tree => t.envelope contains pos - case _ => false - } - base.productIterator find encloses match { - case Some(tree: Tree) => locateEnclosing(tree :: base, pos) - case none => base - } - } - } + abstract class ModsDecorator { def mods: Modifiers } - implicit class modsDeco(val mdef: MemberDef)(implicit ctx: Context) extends ModsDeco { + implicit class modsDeco(val mdef: MemberDef)(implicit ctx: Context) { def mods = mdef.rawMods } @@ -295,9 +351,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case tree: SymbolLit if str == tree.str => tree case _ => untpd.SymbolLit(str).withPos(tree.pos) } - def InterpolatedString(tree: Tree)(id: TermName, strings: List[Literal], elems: List[Tree]) = tree match { - case tree: InterpolatedString if (id eq tree.id) && (strings eq tree.strings) && (elems eq tree.elems) => tree - case _ => untpd.InterpolatedString(id, strings, elems).withPos(tree.pos) + def InterpolatedString(tree: Tree)(id: TermName, segments: List[Tree]) = tree match { + case tree: InterpolatedString if (id eq tree.id) && (segments eq tree.segments) => tree + case _ => untpd.InterpolatedString(id, segments).withPos(tree.pos) } def Function(tree: Tree)(args: List[Tree], body: Tree) = tree match { case tree: Function if (args eq tree.args) && (body eq tree.body) => tree @@ -369,8 +425,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { cpy.ParsedTry(tree)(transform(expr), transform(handler), transform(finalizer)) case SymbolLit(str) => cpy.SymbolLit(tree)(str) - case InterpolatedString(id, strings, elems) => - cpy.InterpolatedString(tree)(id, transformSub(strings), transform(elems)) + case InterpolatedString(id, segments) => + cpy.InterpolatedString(tree)(id, transform(segments)) case Function(args, body) => cpy.Function(tree)(transform(args), transform(body)) case InfixOp(left, op, right) => @@ -416,8 +472,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { this(this(this(x, expr), handler), finalizer) case SymbolLit(str) => x - case InterpolatedString(id, strings, elems) => - this(this(x, strings), elems) + case InterpolatedString(id, segments) => + this(x, segments) case Function(args, body) => this(this(x, args), body) case InfixOp(left, op, right) => diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index 0949d7fee..c188bfab4 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -63,6 +63,9 @@ object Config { */ final val checkNoDoubleBindings = true + /** Check positions for consistency after parsing */ + final val checkPositions = true + /** Show subtype traces for all deep subtype recursions */ final val traceDeepSubTypeRecursions = false diff --git a/src/dotty/tools/dotc/config/Printers.scala b/src/dotty/tools/dotc/config/Printers.scala index fa36ad12c..322bc82d9 100644 --- a/src/dotty/tools/dotc/config/Printers.scala +++ b/src/dotty/tools/dotc/config/Printers.scala @@ -4,12 +4,10 @@ object Printers { class Printer { def println(msg: => String): Unit = System.out.println(msg) - def echo[T](msg: => String, value: T): T = { println(msg + value); value } } object noPrinter extends Printer { override def println(msg: => String): Unit = () - override def echo[T](msg: => String, value: T): T = value } val default: Printer = new Printer diff --git a/src/dotty/tools/dotc/core/CheckRealizable.scala b/src/dotty/tools/dotc/core/CheckRealizable.scala index 11fd6786a..78ec685fc 100644 --- a/src/dotty/tools/dotc/core/CheckRealizable.scala +++ b/src/dotty/tools/dotc/core/CheckRealizable.scala @@ -4,7 +4,6 @@ package core import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._ import SymDenotations._, Denotations.SingleDenotation -import config.Printers._ import util.Positions._ import Decorators._ import StdNames._ diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala index 99b4af0a9..91e70b7b5 100644 --- a/src/dotty/tools/dotc/core/Constraint.scala +++ b/src/dotty/tools/dotc/core/Constraint.scala @@ -8,7 +8,7 @@ import collection.mutable import printing.{Printer, Showable} import printing.Texts._ import config.Config -import config.Printers._ +import config.Printers.constr /** Constraint over undetermined type parameters. Constraints are built * over values of the following types: diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index 18e47a7f2..5911af72c 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -5,7 +5,7 @@ package core import Types._, Contexts._, Symbols._ import Decorators._ import config.Config -import config.Printers._ +import config.Printers.{constr, typr} import TypeApplications.EtaExpansion import collection.mutable diff --git a/src/dotty/tools/dotc/core/ConstraintRunInfo.scala b/src/dotty/tools/dotc/core/ConstraintRunInfo.scala index 4b7e22653..e0f659cc6 100644 --- a/src/dotty/tools/dotc/core/ConstraintRunInfo.scala +++ b/src/dotty/tools/dotc/core/ConstraintRunInfo.scala @@ -1,7 +1,8 @@ package dotty.tools.dotc package core -import Contexts._, config.Printers._ +import Contexts._ +import config.Printers.typr trait ConstraintRunInfo { self: RunInfo => private var maxSize = 0 diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala index e7e388be9..458f8b82f 100644 --- a/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -8,7 +8,6 @@ import collection.mutable import printing.{Printer, Showable} import printing.Texts._ import config.Config -import config.Printers._ import collection.immutable.BitSet import reflect.ClassTag import annotation.tailrec diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 4b2861452..222e2235d 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -9,7 +9,7 @@ import util.DotClass import DenotTransformers._ import Denotations._ import Decorators._ -import config.Printers._ +import config.Printers.config import scala.collection.mutable.{ListBuffer, ArrayBuffer} import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, TreeTransform} import dotty.tools.dotc.transform._ diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 47ec541ab..ab45550a4 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -16,7 +16,7 @@ import CheckRealizable._ import util.SimpleMap import util.Stats import config.Config -import config.Printers._ +import config.Printers.{completions, incremental, noPrinter} trait SymDenotations { this: Context => import SymDenotations._ @@ -46,7 +46,7 @@ trait SymDenotations { this: Context => val initial = denot.initial val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id) if ((initial ne denot) || ctx.phaseId != firstPhaseId) - ctx.withPhase(firstPhaseId).stillValidInOwner(initial.asSymDenotation) + ctx.withPhase(firstPhaseId).stillValidInOwner(initial) else stillValidInOwner(denot) } @@ -56,6 +56,7 @@ trait SymDenotations { this: Context => stillValid(owner) && ( !owner.isClass || owner.isRefinementClass + || owner.is(Scala2x) || (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) || denot.isSelfSym) } catch { @@ -77,7 +78,7 @@ trait SymDenotations { this: Context => implicit val ctx: Context = this val initial = denot.initial if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) { - ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial.asSymDenotation) + ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial) } else try { val owner = denot.owner.denot if (!traceInvalid(owner)) explainSym("owner is invalid") @@ -346,14 +347,14 @@ object SymDenotations { else { def legalize(name: Name): Name = // JVM method names may not contain `<' or `>' characters if (is(Method)) name.replace('<', '(').replace('>', ')') else name - legalize(name.expandedName(initial.asSymDenotation.owner)) + legalize(name.expandedName(initial.owner)) } // need to use initial owner to disambiguate, as multiple private symbols with the same name // might have been moved from different origins into the same class /** The name with which the denoting symbol was created */ final def originalName(implicit ctx: Context) = { - val d = initial.asSymDenotation + val d = initial if (d is ExpandedName) d.name.unexpandedName else d.name // !!!DEBUG, was: effectiveName } @@ -435,13 +436,13 @@ object SymDenotations { /** Is this symbol an anonymous class? */ final def isAnonymousClass(implicit ctx: Context): Boolean = - isClass && (initial.asSymDenotation.name startsWith tpnme.ANON_CLASS) + isClass && (initial.name startsWith tpnme.ANON_CLASS) final def isAnonymousFunction(implicit ctx: Context) = - this.symbol.is(Method) && (initial.asSymDenotation.name startsWith nme.ANON_FUN) + this.symbol.is(Method) && (initial.name startsWith nme.ANON_FUN) final def isAnonymousModuleVal(implicit ctx: Context) = - this.symbol.is(ModuleVal) && (initial.asSymDenotation.name startsWith nme.ANON_CLASS) + this.symbol.is(ModuleVal) && (initial.name startsWith nme.ANON_CLASS) /** Is this a companion class method or companion object method? * These methods are generated by Symbols#synthesizeCompanionMethod @@ -606,7 +607,7 @@ object SymDenotations { /** Is this symbol a class that extends `AnyVal`? */ final def isValueClass(implicit ctx: Context): Boolean = { - val di = this.initial.asSymDenotation + val di = initial di.isClass && di.derivesFrom(defn.AnyValClass)(ctx.withPhase(di.validFor.firstPhaseId)) // We call derivesFrom at the initial phase both because AnyVal does not exist @@ -1164,6 +1165,8 @@ object SymDenotations { d } + override def initial: SymDenotation = super.initial.asSymDenotation + /** Install this denotation as the result of the given denotation transformer. */ override def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit = super.installAfter(phase) @@ -1226,10 +1229,13 @@ object SymDenotations { if (myTypeParams == null) myTypeParams = if (ctx.erasedTypes || is(Module)) Nil // fast return for modules to avoid scanning package decls - else if (this ne initial) initial.asSymDenotation.typeParams - else infoOrCompleter match { - case info: TypeParamsCompleter => info.completerTypeParams(symbol) - case _ => typeParamsFromDecls + else { + val di = initial + if (this ne di) di.typeParams + else infoOrCompleter match { + case info: TypeParamsCompleter => info.completerTypeParams(symbol) + case _ => typeParamsFromDecls + } } myTypeParams } diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index af362f4da..f32a591a6 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -13,7 +13,7 @@ import NameOps._ import Flags._ import StdNames.tpnme import util.Positions.Position -import config.Printers._ +import config.Printers.core import collection.mutable import dotty.tools.dotc.config.Config import java.util.NoSuchElementException diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 538a74198..991dd2664 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -8,7 +8,7 @@ import StdNames.{nme, tpnme} import collection.mutable import util.{Stats, DotClass, SimpleMap} import config.Config -import config.Printers._ +import config.Printers.{typr, constr, subtyping} import TypeErasure.{erasedLub, erasedGlb} import TypeApplications._ import scala.util.control.NonFatal diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index b69ce2536..5ba9a3351 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -4,7 +4,7 @@ package core import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._ import SymDenotations._, Denotations.SingleDenotation -import config.Printers._ +import config.Printers.typr import util.Positions._ import NameOps._ import Decorators._ diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 87d94dcbe..30d1c0136 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -28,11 +28,11 @@ import Hashable._ import Uniques._ import collection.{mutable, Seq, breakOut} import config.Config -import config.Printers._ import annotation.tailrec import Flags.FlagSet import language.implicitConversions import scala.util.hashing.{ MurmurHash3 => hashing } +import config.Printers.{core, typr, cyclicErrors} object Types { @@ -927,7 +927,7 @@ object Types { def narrow(implicit ctx: Context): TermRef = TermRef(NoPrefix, ctx.newSkolem(this)) - /** Useful for diagnsotics: The underlying type if this type is a type proxy, + /** Useful for diagnostics: The underlying type if this type is a type proxy, * otherwise NoType */ def underlyingIfProxy(implicit ctx: Context) = this match { @@ -935,6 +935,9 @@ object Types { case _ => NoType } + /** If this is a FunProto or PolyProto, WildcardType, otherwise this. */ + def notApplied: Type = this + // ----- Normalizing typerefs over refined types ---------------------------- /** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed @@ -2532,8 +2535,8 @@ object Types { /** A type for polymorphic methods */ class PolyType(val paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) extends CachedGroundType with GenericType with MethodOrPoly { - val paramBounds = paramBoundsExp(this) - val resType = resultTypeExp(this) + val paramBounds: List[TypeBounds] = paramBoundsExp(this) + val resType: Type = resultTypeExp(this) def variances = Nil protected def computeSignature(implicit ctx: Context) = resultSignature diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 394d8f11a..e9de68e7f 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -74,7 +74,6 @@ Standard-Section: "ASTs" TopLevelStat* SELECT possiblySigned_NameRef qual_Term NEW cls_Type SUPER Length this_Term mixinTrait_Type? - PAIR Length left_Term right_Term TYPED Length expr_Term ascription_Type NAMEDARG Length paramName_NameRef arg_Term ASSIGN Length lhs_Term rhs_Term @@ -300,7 +299,8 @@ object TastyFormat { final val RENAMED = 138 final val APPLY = 139 final val TYPEAPPLY = 140 - final val PAIR = 142 + + final val TYPED = 143 final val NAMEDARG = 144 final val ASSIGN = 145 @@ -452,7 +452,6 @@ object TastyFormat { case APPLY => "APPLY" case TYPEAPPLY => "TYPEAPPLY" case NEW => "NEW" - case PAIR => "PAIR" case TYPED => "TYPED" case NAMEDARG => "NAMEDARG" case ASSIGN => "ASSIGN" diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index be3999533..e5cacfc00 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -392,9 +392,6 @@ class TreePickler(pickler: TastyPickler) { case New(tpt) => writeByte(NEW) pickleTpt(tpt) - case Pair(left, right) => - writeByte(PAIR) - withLength { pickleTree(left); pickleTree(right) } case Typed(expr, tpt) => writeByte(TYPED) withLength { pickleTree(expr); pickleTpt(tpt) } @@ -496,7 +493,7 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleTree(expr) selectors foreach { - case Pair(Ident(from), Ident(to)) => + case Thicket(Ident(from) :: Ident(to) :: Nil) => writeByte(RENAMED) withLength { pickleName(from); pickleName(to) } case Ident(name) => diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 31247c005..56bb8498a 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -729,9 +729,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { } } val mods = - if (sym.annotations.isEmpty) EmptyModifiers - else Modifiers(annotations = sym.annotations.map(_.tree)) - tree.withMods(mods) // record annotations in tree so that tree positions can be filled in. + if (sym.annotations.isEmpty) untpd.EmptyModifiers + else untpd.Modifiers(annotations = sym.annotations.map(_.tree)) + tree.withMods(mods) + // record annotations in tree so that tree positions can be filled in. + // Note: Once the inline PR with its changes to positions is in, this should be + // no longer necessary. goto(end) setPos(start, tree) } @@ -831,7 +834,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case RENAMED => readByte() readEnd() - untpd.Pair(untpd.Ident(readName()), untpd.Ident(readName())) :: readSelectors() + untpd.Thicket(untpd.Ident(readName()), untpd.Ident(readName())) :: readSelectors() case IMPORTED => readByte() untpd.Ident(readName()) :: readSelectors() @@ -915,8 +918,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { tpd.Apply(fn, until(end)(readArg())) case TYPEAPPLY => tpd.TypeApply(readTerm(), until(end)(readTpt())) - case PAIR => - Pair(readTerm(), readTerm()) case TYPED => val expr = readTerm() val tpt = readTpt() diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 0d91e8cd6..70148b3e2 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -12,6 +12,7 @@ import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto} import util.Positions._ import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._ +import ast.untpd.Modifiers import printing.Texts._ import printing.Printer import io.AbstractFile @@ -1044,7 +1045,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val toName = readNameRef() val from = untpd.Ident(fromName) val to = untpd.Ident(toName) - if (toName.isEmpty) from else untpd.Pair(from, untpd.Ident(toName)) + if (toName.isEmpty) from else untpd.Thicket(from, untpd.Ident(toName)) }) Import(expr, selectors) @@ -1186,7 +1187,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case ANNOTATEDtree => val annot = readTreeRef() val arg = readTreeRef() - Annotated(annot, arg) + Annotated(arg, annot) case SINGLETONTYPEtree => SingletonTypeTree(readTreeRef()) @@ -1194,7 +1195,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case SELECTFROMTYPEtree => val qualifier = readTreeRef() val selector = readTypeNameRef() - SelectFromTypeTree(qualifier, symbol.namedType) + Select(qualifier, symbol.namedType) case COMPOUNDTYPEtree => readTemplateRef() @@ -1236,7 +1237,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val pflags = (pflagsHi.toLong << 32) + pflagsLo val flags = unpickleScalaFlags(pflags, isType) val privateWithin = readNameRef().asTypeName - Trees.Modifiers[Type](flags, privateWithin, Nil) + Modifiers(flags, privateWithin, Nil) } protected def readTemplateRef()(implicit ctx: Context): Template = diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index fbb362354..ed7cf9e3f 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -10,6 +10,7 @@ import scala.language.implicitConversions import JavaTokens._ import JavaScanners._ +import Scanners.Offset import Parsers._ import core._ import Contexts._ @@ -107,9 +108,6 @@ object JavaParsers { def unimplementedExpr = Ident("???".toTermName) - def makePackaging(pkg: RefTree, stats: List[Tree]): PackageDef = - atPos(pkg.pos) { PackageDef(pkg, stats) } - def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean) = { def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match { case (meth: DefDef) :: rest if meth.name == CONSTRUCTOR => (meth, rest) @@ -229,7 +227,7 @@ object JavaParsers { def convertToTypeId(tree: Tree): Tree = convertToTypeName(tree) match { case Some(t) => t withPos tree.pos case _ => tree match { - case AppliedTypeTree(_, _) | SelectFromTypeTree(_, _) => + case AppliedTypeTree(_, _) | Select(_, _) => tree case _ => syntaxError("identifier expected", tree.pos) @@ -250,14 +248,14 @@ object JavaParsers { var t: RefTree = atPos(in.offset) { Ident(ident()) } while (in.token == DOT) { in.nextToken() - t = atPos(in.offset) { Select(t, ident()) } + t = atPos(t.pos.start, in.offset) { Select(t, ident()) } } t } def optArrayBrackets(tpt: Tree): Tree = if (in.token == LBRACKET) { - val tpt1 = atPos(in.offset) { arrayOf(tpt) } + val tpt1 = atPos(tpt.pos.start, in.offset) { arrayOf(tpt) } in.nextToken() accept(RBRACKET) optArrayBrackets(tpt1) @@ -283,18 +281,15 @@ object JavaParsers { if (in.token == FINAL) in.nextToken() if (in.token == IDENTIFIER) { var t = typeArgs(atPos(in.offset)(Ident(ident()))) - // typeSelect generates Select nodes is the lhs is an Ident or Select, - // SelectFromTypeTree otherwise. See #3567. - // Select nodes can be later - // converted in the typechecker to SelectFromTypeTree if the class - // turns out to be an instance ionner class instead of a static inner class. + // typeSelect generates Select nodes if the lhs is an Ident or Select, + // For other nodes it always assumes that the selected item is a type. def typeSelect(t: Tree, name: Name) = t match { case Ident(_) | Select(_, _) => Select(t, name) - case _ => SelectFromTypeTree(t, name.toTypeName) + case _ => Select(t, name.toTypeName) } while (in.token == DOT) { in.nextToken() - t = typeArgs(atPos(in.offset)(typeSelect(t, ident()))) + t = typeArgs(atPos(t.pos.start, in.offset)(typeSelect(t, ident()))) } convertToTypeId(t) } else { @@ -328,7 +323,7 @@ object JavaParsers { val t1 = convertToTypeId(t) val args = repsep(typeArg, COMMA) acceptClosingAngle() - atPos(t1.pos) { + atPos(t1.pos.start) { AppliedTypeTree(t1, args) } } else t @@ -356,7 +351,11 @@ object JavaParsers { // assumed true unless we see public/private/protected var isPackageAccess = true var annots: List[Tree] = Nil - def addAnnot(sym: ClassSymbol) = annots :+= New(TypeTree(sym.typeRef)).withPos(Position(in.offset)) + def addAnnot(sym: ClassSymbol) = + annots :+= atPos(in.offset) { + in.nextToken() + New(TypeTree(sym.typeRef)) + } while (true) { in.token match { @@ -387,13 +386,10 @@ object JavaParsers { in.nextToken() case NATIVE => addAnnot(NativeAnnot) - in.nextToken() case TRANSIENT => addAnnot(TransientAnnot) - in.nextToken() case VOLATILE => addAnnot(VolatileAnnot) - in.nextToken() case SYNCHRONIZED | STRICTFP => in.nextToken() case _ => @@ -443,16 +439,19 @@ object JavaParsers { } def formalParam(): ValDef = { + val start = in.offset if (in.token == FINAL) in.nextToken() annotations() var t = typ() if (in.token == DOTDOTDOT) { in.nextToken() - t = atPos(t.pos) { + t = atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) } } - varDecl(Position(in.offset), Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName) + atPos(start, in.offset) { + varDecl(Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName) + } } def optThrows(): Unit = { @@ -462,7 +461,7 @@ object JavaParsers { } } - def methodBody(): Tree = { + def methodBody(): Tree = atPos(in.offset) { skipAhead() accept(RBRACE) // skip block unimplementedExpr @@ -470,16 +469,18 @@ object JavaParsers { def definesInterface(token: Int) = token == INTERFACE || token == AT - def termDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = { + def termDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = { val inInterface = definesInterface(parentToken) val tparams = if (in.token == LT) typeParams(Flags.JavaDefined | Flags.Param) else List() val isVoid = in.token == VOID var rtpt = - if (isVoid) { - in.nextToken() - TypeTree(UnitType) withPos Position(in.offset) - } else typ() - var offset = in.offset + if (isVoid) + atPos(in.offset) { + in.nextToken() + TypeTree(UnitType) + } + else typ() + var nameOffset = in.offset val rtptName = rtpt match { case Ident(name) => name case _ => nme.EMPTY @@ -489,14 +490,15 @@ object JavaParsers { val vparams = formalParams() optThrows() List { - atPos(offset) { - DefDef(nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()).withMods(mods) + atPos(start) { + DefDef(nme.CONSTRUCTOR, parentTParams, + List(vparams), TypeTree(), methodBody()).withMods(mods) } } } else { var mods1 = mods if (mods is Flags.Abstract) mods1 = mods &~ Flags.Abstract - offset = in.offset + nameOffset = in.offset val name = ident() if (in.token == LPAREN) { // method declaration @@ -510,13 +512,14 @@ object JavaParsers { } else { if (parentToken == AT && in.token == DEFAULT) { val annot = - atPos(offset) { + atPos(nameOffset) { New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil) } mods1 = mods1 withAddedAnnotation annot + val unimplemented = unimplementedExpr skipTo(SEMI) accept(SEMI) - unimplementedExpr + unimplemented } else { accept(SEMI) EmptyTree @@ -524,13 +527,13 @@ object JavaParsers { } //if (inInterface) mods1 |= Flags.Deferred List { - atPos(offset) { + atPos(start, nameOffset) { DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method) } } } else { if (inInterface) mods1 |= Flags.Final | Flags.JavaStatic - val result = fieldDecls(Position(offset), mods1, rtpt, name) + val result = fieldDecls(start, nameOffset, mods1, rtpt, name) accept(SEMI) result } @@ -546,19 +549,21 @@ object JavaParsers { * Once we have reached the end of the statement, we know whether * these potential definitions are real or not. */ - def fieldDecls(pos: Position, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = { - val buf = ListBuffer[Tree](varDecl(pos, mods, tpt, name.toTermName)) + def fieldDecls(start: Offset, firstNameOffset: Offset, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = { + val buf = ListBuffer[Tree]( + atPos(start, firstNameOffset) { varDecl(mods, tpt, name.toTermName) }) val maybe = new ListBuffer[Tree] // potential variable definitions. while (in.token == COMMA) { in.nextToken() if (in.token == IDENTIFIER) { // if there's an ident after the comma ... + val nextNameOffset = in.offset val name = ident() if (in.token == EQUALS || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition buf ++= maybe - buf += varDecl(Position(in.offset), mods, tpt, name.toTermName) + buf += atPos(start, nextNameOffset) { varDecl(mods, tpt, name.toTermName) } maybe.clear() } else if (in.token == COMMA) { // ... if there's a comma after the ident, it could be a real vardef or not. - maybe += varDecl(Position(in.offset), mods, tpt, name.toTermName) + maybe += atPos(start, nextNameOffset) { varDecl(mods, tpt, name.toTermName) } } else { // ... if there's something else we were still in the initializer of the // previous var def; skip to next comma or semicolon. skipTo(COMMA, SEMI) @@ -576,35 +581,29 @@ object JavaParsers { buf.toList } - def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = { + def varDecl(mods: Modifiers, tpt: Tree, name: TermName): ValDef = { val tpt1 = optArrayBrackets(tpt) if (in.token == EQUALS && !(mods is Flags.Param)) skipTo(COMMA, SEMI) val mods1 = if (mods is Flags.Final) mods else mods | Flags.Mutable - atPos(pos) { - ValDef(name, tpt1, if (mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1) - } + ValDef(name, tpt1, if (mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1) } - def memberDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match { + def memberDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match { case CLASS | ENUM | INTERFACE | AT => - typeDecl(if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods) + typeDecl(start, if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods) case _ => - termDecl(mods, parentToken, parentTParams) + termDecl(start, mods, parentToken, parentTParams) } def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = atPos(cdef.pos) { + assert(cdef.pos.exists) ModuleDef(cdef.name.toTermName, makeTemplate(List(), statics, List(), false)).withMods((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags) } - private val wild = Ident(nme.WILDCARD) withPos Position(-1) - private val wildList = List(wild) // OPT This list is shared for performance. - def importCompanionObject(cdef: TypeDef): Tree = - atPos(cdef.pos) { - Import(Ident(cdef.name.toTermName), wildList) - } + Import(Ident(cdef.name.toTermName).withPos(NoPosition), Ident(nme.WILDCARD) :: Nil) // Importing the companion object members cannot be done uncritically: see // ticket #2377 wherein a class contains two static inner classes, each of which @@ -633,8 +632,8 @@ object JavaParsers { } def importDecl(): List[Tree] = { + val start = in.offset accept(IMPORT) - val offset = in.offset val buf = new ListBuffer[Name] def collectIdents() : Int = { if (in.token == ASTERISK) { @@ -657,7 +656,7 @@ object JavaParsers { accept(SEMI) val names = buf.toList if (names.length < 2) { - syntaxError(offset, "illegal import", skipIt = false) + syntaxError(start, "illegal import", skipIt = false) List() } else { val qual = ((Ident(names.head): Tree) /: names.tail.init) (Select(_, _)) @@ -667,7 +666,8 @@ object JavaParsers { // case nme.WILDCARD => Pair(ident, Ident(null) withPos Position(-1)) // case _ => Pair(ident, ident) // } - List(atPos(offset)(Import(qual, List(ident)))) + val imp = atPos(start) { Import(qual, List(ident)) } + imp :: Nil } } @@ -679,9 +679,9 @@ object JavaParsers { List() } - def classDecl(mods: Modifiers): List[Tree] = { + def classDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(CLASS) - val offset = in.offset + val nameOffset = in.offset val name = identForType() val tparams = typeParams() val superclass = @@ -693,14 +693,15 @@ object JavaParsers { } val interfaces = interfacesOpt() val (statics, body) = typeBody(CLASS, name, tparams) - addCompanionObject(statics, atPos(offset) { + val cls = atPos(start, nameOffset) { TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods) - }) + } + addCompanionObject(statics, cls) } - def interfaceDecl(mods: Modifiers): List[Tree] = { + def interfaceDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(INTERFACE) - val offset = in.offset + val nameOffset = in.offset val name = identForType() val tparams = typeParams() val parents = @@ -711,11 +712,12 @@ object JavaParsers { List(javaLangObject()) } val (statics, body) = typeBody(INTERFACE, name, tparams) - addCompanionObject(statics, atPos(offset) { + val iface = atPos(start, nameOffset) { TypeDef( name, tparams, makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract) - }) + } + addCompanionObject(statics, iface) } def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = { @@ -730,7 +732,8 @@ object JavaParsers { val statics = new ListBuffer[Tree] val members = new ListBuffer[Tree] while (in.token != RBRACE && in.token != EOF) { - var mods = modifiers(inInterface) + val start = in.offset + var mods = atPos(start) { modifiers(inInterface) } if (in.token == LBRACE) { skipAhead() // skip init block, we just assume we have seen only static accept(RBRACE) @@ -738,7 +741,7 @@ object JavaParsers { in.nextToken() } else { if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.JavaStatic - val decls = memberDecl(mods, parentToken, parentTParams) + val decls = memberDecl(start, mods, parentToken, parentTParams) (if ((mods is Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef]))) statics else @@ -761,10 +764,10 @@ object JavaParsers { Select(javaLangDot(nme.annotation), tpnme.Annotation), scalaAnnotationDot(tpnme.ClassfileAnnotation) ) - def annotationDecl(mods: Modifiers): List[Tree] = { + def annotationDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(AT) accept(INTERFACE) - val offset = in.offset + val nameOffset = in.offset val name = identForType() val (statics, body) = typeBody(AT, name, List()) val constructorParams = body.collect { @@ -774,14 +777,15 @@ object JavaParsers { List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined)) val body1 = body.filterNot(_.isInstanceOf[DefDef]) val templ = makeTemplate(annotationParents, constr :: body1, List(), false) - addCompanionObject(statics, atPos(offset) { + val annot = atPos(start, nameOffset) { TypeDef(name, templ).withMods(mods | Flags.Abstract) - }) + } + addCompanionObject(statics, annot) } - def enumDecl(mods: Modifiers): List[Tree] = { + def enumDecl(start: Offset, mods: Modifiers): List[Tree] = { accept(ENUM) - val offset = in.offset + val nameOffset = in.offset val name = identForType() def enumType = Ident(name) val interfaces = interfacesOpt() @@ -824,10 +828,11 @@ object JavaParsers { val superclazz = Apply(TypeApply( Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)), List(Literal(Constant(null)),Literal(Constant(0)))) - addCompanionObject(consts ::: statics ::: predefs, atPos(offset) { + val enum = atPos(start, nameOffset) { TypeDef(name, List(), makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.Enum) - }) + } + addCompanionObject(consts ::: statics ::: predefs, enum) } def enumConst(enumType: Tree) = { @@ -848,22 +853,21 @@ object JavaParsers { } } - def typeDecl(mods: Modifiers): List[Tree] = in.token match { - case ENUM => enumDecl(mods) - case INTERFACE => interfaceDecl(mods) - case AT => annotationDecl(mods) - case CLASS => classDecl(mods) + def typeDecl(start: Offset, mods: Modifiers): List[Tree] = in.token match { + case ENUM => enumDecl(start, mods) + case INTERFACE => interfaceDecl(start, mods) + case AT => annotationDecl(start, mods) + case CLASS => classDecl(start, mods) case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree) } /** CompilationUnit ::= [package QualId semi] TopStatSeq */ def compilationUnit(): Tree = { - var offset = in.offset + val start = in.offset val pkg: RefTree = if (in.token == AT || in.token == PACKAGE) { annotations() - offset = in.offset accept(PACKAGE) val pkg = qualId() accept(SEMI) @@ -880,13 +884,15 @@ object JavaParsers { buf ++= importDecl() while (in.token != EOF && in.token != RBRACE) { while (in.token == SEMI) in.nextToken() - if (in.token != EOF) - buf ++= typeDecl(modifiers(inInterface = false)) + if (in.token != EOF) { + val start = in.offset + val mods = atPos(start) { modifiers(inInterface = false) } + buf ++= typeDecl(start, mods) + } } + val unit = atPos(start) { PackageDef(pkg, buf.toList) } accept(EOF) - atPos(offset) { - makePackaging(pkg, buf.toList) - } + unit } } } diff --git a/src/dotty/tools/dotc/parsing/JavaScanners.scala b/src/dotty/tools/dotc/parsing/JavaScanners.scala index faac8e163..83e16627c 100644 --- a/src/dotty/tools/dotc/parsing/JavaScanners.scala +++ b/src/dotty/tools/dotc/parsing/JavaScanners.scala @@ -27,6 +27,7 @@ object JavaScanners { def nextToken(): Unit = { if (next.token == EMPTY) { + lastOffset = lastCharOffset fetchToken() } else { diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 378aa6ed7..86330f3ab 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -59,19 +59,30 @@ object Parsers { /* ------------- POSITIONS ------------------------------------------- */ + /** Positions tree. + * If `t` does not have a position yet, set its position to the given one. + */ + def atPos[T <: Positioned](pos: Position)(t: T): T = + if (t.pos.isSourceDerived) t else t.withPos(pos) + def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T = atPos(Position(start, end, point))(t) + /** If the last read offset is strictly greater than `start`, position tree + * to position spanning from `start` to last read offset, with given point. + * If the last offset is less than or equal to start, the tree `t` did not + * consume any source for its construction. In this case, don't position it yet, + * but wait for its position to be determined by `setChildPositions` when the + * parent node is positioned. + */ def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T = - atPos(start, point, in.lastOffset max start)(t) + if (in.lastOffset > start) atPos(start, point, in.lastOffset)(t) else t def atPos[T <: Positioned](start: Offset)(t: T): T = atPos(start, start)(t) - def atPos[T <: Positioned](pos: Position)(t: T): T = - if (t.pos.isSourceDerived) t else t.withPos(pos) - - def tokenRange = Position(in.offset, in.lastCharOffset, in.offset) + def nameStart: Offset = + if (in.token == BACKQUOTED_IDENT) in.offset + 1 else in.offset def sourcePos(off: Int = in.offset): SourcePosition = source atPos Position(off) @@ -313,8 +324,6 @@ object Parsers { tree } - def emptyConstructor() = atPos(in.offset) { ast.untpd.emptyConstructor } - /* --------------- PLACEHOLDERS ------------------------------------------- */ /** The implicit parameters introduced by `_` in the current expression. @@ -601,30 +610,30 @@ object Parsers { } private def interpolatedString(inPattern: Boolean = false): Tree = atPos(in.offset) { - val partsBuf = new ListBuffer[Literal] - val exprBuf = new ListBuffer[Tree] + val segmentBuf = new ListBuffer[Tree] val interpolator = in.name in.nextToken() while (in.token == STRINGPART) { - partsBuf += literal().asInstanceOf[Literal] - exprBuf += atPos(in.offset) { - if (in.token == IDENTIFIER) - termIdent() - else if (in.token == THIS) { - in.nextToken() - This(tpnme.EMPTY) - } - else if (in.token == LBRACE) - if (inPattern) Block(Nil, inBraces(pattern())) - else expr() - else { - syntaxErrorOrIncomplete("error in interpolated string: identifier or block expected") - EmptyTree - } - } + segmentBuf += Thicket( + literal(), + atPos(in.offset) { + if (in.token == IDENTIFIER) + termIdent() + else if (in.token == THIS) { + in.nextToken() + This(tpnme.EMPTY) + } + else if (in.token == LBRACE) + if (inPattern) Block(Nil, inBraces(pattern())) + else expr() + else { + syntaxErrorOrIncomplete("error in interpolated string: identifier or block expected") + EmptyTree + } + }) } - if (in.token == STRINGLIT) partsBuf += literal().asInstanceOf[Literal] - InterpolatedString(interpolator, partsBuf.toList, exprBuf.toList) + if (in.token == STRINGLIT) segmentBuf += literal() + InterpolatedString(interpolator, segmentBuf.toList) } /* ------------- NEW LINES ------------------------------------------------- */ @@ -694,9 +703,10 @@ object Parsers { } } else if (in.token == LBRACKET) { + val start = in.offset val tparams = typeParamClause(ParamOwner.TypeParam) if (isIdent && in.name.toString == "->") - atPos(in.skipToken())(TypeLambdaTree(tparams, typ())) + atPos(start, in.skipToken())(TypeLambdaTree(tparams, typ())) else { syntaxErrorOrIncomplete(expectedMessage("`->'")); typ() } } else infixType() @@ -742,7 +752,7 @@ object Parsers { def annotType(): Tree = annotTypeRest(simpleType()) def annotTypeRest(t: Tree): Tree = - if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(annot(), t) }) + if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(t, annot()) }) else t /** SimpleType ::= SimpleType TypeArgs @@ -762,7 +772,7 @@ object Parsers { else if (isSimpleLiteral) { SingletonTypeTree(literal()) } else if (in.token == USCORE) { val start = in.skipToken() - typeBounds().withPos(Position(start, in.offset, start)) + typeBounds().withPos(Position(start, in.lastOffset, start)) } else path(thisOK = false, handleSingletonType) match { case r @ SingletonTypeTree(_) => r @@ -785,7 +795,7 @@ object Parsers { private def typeProjection(t: Tree): Tree = { accept(HASH) val id = typeIdent() - atPos(t.pos.start, id.pos.start) { SelectFromTypeTree(t, id.name) } + atPos(t.pos.start, id.pos.start) { Select(t, id.name) } } /** NamedTypeArg ::= id `=' Type @@ -866,7 +876,8 @@ object Parsers { def typeParamBounds(pname: TypeName): Tree = { val t = typeBounds() val cbs = contextBounds(pname) - if (cbs.isEmpty) t else atPos(t.pos.start) { ContextBounds(t, cbs) } + if (cbs.isEmpty) t + else atPos((t.pos union cbs.head.pos).start) { ContextBounds(t, cbs) } } def contextBounds(pname: TypeName): List[Tree] = in.token match { @@ -899,7 +910,7 @@ object Parsers { private final def findWildcardType(t: Tree): Option[Position] = t match { case TypeBoundsTree(_, _) => Some(t.pos) case Parens(t1) => findWildcardType(t1) - case Annotated(_, t1) => findWildcardType(t1) + case Annotated(t1, _) => findWildcardType(t1) case _ => None } @@ -972,7 +983,7 @@ object Parsers { else try if (placeholderParams.isEmpty) t - else Function(placeholderParams.reverse, t) + else new WildcardFunction(placeholderParams.reverse, t) finally placeholderParams = saved } @@ -1009,9 +1020,23 @@ object Parsers { in.nextToken() expr() } else EmptyTree + + handler match { + case Block(Nil, EmptyTree) => syntaxError( + "`catch` block does not contain a valid expression, try adding a case like - `case e: Exception =>` to the block", + handler.pos + ) + case _ => + } + val finalizer = - if (handler.isEmpty || in.token == FINALLY) { accept(FINALLY); expr() } - else EmptyTree + if (in.token == FINALLY) { accept(FINALLY); expr() } + else { + if (handler.isEmpty) + warning("A try without `catch` or `finally` is equivalent to putting its body in a block; no exceptions are handled.") + + EmptyTree + } ParsedTry(body, handler, finalizer) } case THROW => @@ -1056,12 +1081,13 @@ object Parsers { syntaxErrorOrIncomplete("`*' expected"); t } case AT if location != Location.InPattern => - (t /: annotations()) ((t, annot) => Annotated(annot, t)) + (t /: annotations())(Annotated) case _ => val tpt = typeDependingOn(location) if (isWildcard(t) && location != Location.InPattern) { val vd :: rest = placeholderParams - placeholderParams = cpy.ValDef(vd)(tpt = tpt) :: rest + placeholderParams = + cpy.ValDef(vd)(tpt = tpt).withPos(vd.pos union tpt.pos) :: rest } Typed(t, tpt) } @@ -1140,12 +1166,12 @@ object Parsers { case NEW => canApply = false val start = in.skipToken() - val (impl, missingBody) = template(emptyConstructor()) + val (impl, missingBody) = template(emptyConstructor) impl.parents match { case parent :: Nil if missingBody => if (parent.isType) ensureApplied(wrapNew(parent)) else parent case _ => - New(impl) + New(impl.withPos(Position(start, in.lastOffset))) } case _ => if (isLiteral) literal() @@ -1348,15 +1374,15 @@ object Parsers { */ val pattern2 = () => infixPattern() match { case p @ Ident(name) if isVarPattern(p) && in.token == AT => - val pos = in.skipToken() + val offset = in.skipToken() // compatibility for Scala2 `x @ _*` syntax infixPattern() match { case pt @ Ident(tpnme.WILDCARD_STAR) => migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", p.pos.start) - atPos(p.pos.start, pos) { Typed(p, pt) } + atPos(p.pos.start, offset) { Typed(p, pt) } case p => - atPos(p.pos.start, pos) { Bind(name, p) } + atPos(p.pos.start, offset) { Bind(name, p) } } case p @ Ident(tpnme.WILDCARD_STAR) => // compatibility for Scala2 `_*` syntax @@ -1576,12 +1602,12 @@ object Parsers { def typeParamClause(ownerKind: ParamOwner.Value): List[TypeDef] = inBrackets { def typeParam(): TypeDef = { val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def - val modStart = in.offset + val start = in.offset var mods = annotsAsMods() if (ownerKind == ParamOwner.Class) { mods = modifiers(start = mods) mods = - atPos(modStart, in.offset) { + atPos(start, in.offset) { if (in.token == TYPE) { in.nextToken() mods | Param | ParamAccessor @@ -1591,13 +1617,13 @@ object Parsers { } } } - else mods = atPos(modStart) (mods | Param) + else mods = atPos(start) (mods | Param) if (ownerKind != ParamOwner.Def) { if (isIdent(nme.raw.PLUS)) mods |= Covariant else if (isIdent(nme.raw.MINUS)) mods |= Contravariant if (mods is VarianceFlags) in.nextToken() } - atPos(tokenRange) { + atPos(start, nameStart) { val name = if (isConcreteOwner || in.token != USCORE) ident().toTypeName else { @@ -1631,12 +1657,12 @@ object Parsers { var firstClauseOfCaseClass = ofCaseClass var implicitOffset = -1 // use once def param(): ValDef = { - val modStart = in.offset + val start = in.offset var mods = annotsAsMods() if (owner.isTypeName) { mods = modifiers(start = mods) | ParamAccessor mods = - atPos(modStart, in.offset) { + atPos(start, in.offset) { if (in.token == VAL) { in.nextToken() mods @@ -1649,8 +1675,8 @@ object Parsers { } } } - else mods = atPos(modStart) { mods | Param } - atPos(tokenRange) { + else mods = atPos(start) { mods | Param } + atPos(start, nameStart) { val name = ident() val tpt = if (ctx.settings.YmethodInfer.value && owner.isTermName && in.token != COLON) { @@ -1669,7 +1695,7 @@ object Parsers { if (in.token == EQUALS) { in.nextToken(); expr() } else EmptyTree if (implicitOffset >= 0) { - mods = mods.withPos(mods.pos.withStart(implicitOffset)) + mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset))) implicitOffset = -1 } ValDef(name, tpt, default).withMods(addFlag(mods, implicitFlag)) @@ -1760,12 +1786,16 @@ object Parsers { val from = termIdentOrWildcard() if (from.name != nme.WILDCARD && in.token == ARROW) atPos(from.pos.start, in.skipToken()) { - Pair(from, termIdentOrWildcard()) + Thicket(from, termIdentOrWildcard()) } else from } - def posMods(start: Int, mods: Modifiers) = atPos(start, in.skipToken())(mods) + def posMods(start: Int, mods: Modifiers) = { + val mods1 = atPos(start)(mods) + in.nextToken() + mods1 + } /** Def ::= val PatDef * | var VarDef @@ -1779,13 +1809,13 @@ object Parsers { */ def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match { case VAL => - patDefOrDcl(posMods(start, mods), in.getDocComment(start)) + patDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case VAR => - patDefOrDcl(posMods(start, addFlag(mods, Mutable)), in.getDocComment(start)) + patDefOrDcl(start, posMods(start, addFlag(mods, Mutable)), in.getDocComment(start)) case DEF => - defDefOrDcl(posMods(start, mods), in.getDocComment(start)) + defDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case TYPE => - typeDefOrDcl(posMods(start, mods), in.getDocComment(start)) + typeDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case _ => tmplDef(start, mods) } @@ -1795,7 +1825,7 @@ object Parsers { * ValDcl ::= Id {`,' Id} `:' Type * VarDcl ::= Id {`,' Id} `:' Type */ - def patDefOrDcl(mods: Modifiers, docstring: Option[Comment] = None): Tree = { + def patDefOrDcl(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): Tree = atPos(start, nameStart) { val lhs = commaSeparated(pattern2) val tpt = typedOpt() val rhs = @@ -1810,7 +1840,7 @@ object Parsers { } else EmptyTree lhs match { case (id @ Ident(name: TermName)) :: Nil => { - cpy.ValDef(id)(name, tpt, rhs).withMods(mods).setComment(docstring) + ValDef(name, tpt, rhs).withMods(mods).setComment(docstring) } case _ => PatDef(mods, lhs, tpt, rhs) } @@ -1821,7 +1851,7 @@ object Parsers { * DefDcl ::= DefSig `:' Type * DefSig ::= id [DefTypeParamClause] ParamClauses */ - def defDefOrDcl(mods: Modifiers, docstring: Option[Comment] = None): Tree = atPos(tokenRange) { + def defDefOrDcl(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): Tree = atPos(start, nameStart) { def scala2ProcedureSyntax(resultTypeStr: String) = { val toInsert = if (in.token == LBRACE) s"$resultTypeStr =" @@ -1896,9 +1926,9 @@ object Parsers { /** TypeDef ::= type Id [TypeParamClause] `=' Type * TypeDcl ::= type Id [TypeParamClause] TypeBounds */ - def typeDefOrDcl(mods: Modifiers, docstring: Option[Comment] = None): Tree = { + def typeDefOrDcl(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): Tree = { newLinesOpt() - atPos(tokenRange) { + atPos(start, nameStart) { val name = ident().toTypeName val tparams = typeParamClauseOpt(ParamOwner.Type) in.token match { @@ -1921,15 +1951,15 @@ object Parsers { val docstring = in.getDocComment(start) in.token match { case TRAIT => - classDef(posMods(start, addFlag(mods, Trait)), docstring) + classDef(start, posMods(start, addFlag(mods, Trait)), docstring) case CLASS => - classDef(posMods(start, mods), docstring) + classDef(start, posMods(start, mods), docstring) case CASECLASS => - classDef(posMods(start, mods | Case), docstring) + classDef(start, posMods(start, mods | Case), docstring) case OBJECT => - objectDef(posMods(start, mods | Module), docstring) + objectDef(start, posMods(start, mods | Module), docstring) case CASEOBJECT => - objectDef(posMods(start, mods | Case | Module), docstring) + objectDef(start, posMods(start, mods | Case | Module), docstring) case _ => syntaxErrorOrIncomplete("expected start of definition") EmptyTree @@ -1939,9 +1969,9 @@ object Parsers { /** ClassDef ::= Id [ClsTypeParamClause] * [ConstrMods] ClsParamClauses TemplateOpt */ - def classDef(mods: Modifiers, docstring: Option[Comment]): TypeDef = atPos(tokenRange) { + def classDef(start: Offset, mods: Modifiers, docstring: Option[Comment]): TypeDef = atPos(start, nameStart) { val name = ident().toTypeName - val constr = atPos(in.offset) { + val constr = atPos(in.lastOffset) { val tparams = typeParamClauseOpt(ParamOwner.Class) val cmods = constrModsOpt() val vparamss = paramClauses(name, mods is Case) @@ -1966,9 +1996,9 @@ object Parsers { /** ObjectDef ::= Id TemplateOpt */ - def objectDef(mods: Modifiers, docstring: Option[Comment] = None): ModuleDef = { + def objectDef(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): ModuleDef = atPos(start, nameStart) { val name = ident() - val template = templateOpt(emptyConstructor()) + val template = templateOpt(emptyConstructor) ModuleDef(name, template).withMods(mods).setComment(docstring) } @@ -2007,12 +2037,12 @@ object Parsers { else { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) template(constr)._1 - else Template(constr, Nil, EmptyValDef, Nil).withPos(constr.pos.toSynthetic) + else Template(constr, Nil, EmptyValDef, Nil) } /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ - def templateBodyOpt(constr: DefDef, parents: List[Tree]) = atPos(constr.pos.start) { + def templateBodyOpt(constr: DefDef, parents: List[Tree]) = { val (self, stats) = if (in.token == LBRACE) templateBody() else (EmptyValDef, Nil) Template(constr, parents, self, stats) @@ -2023,7 +2053,7 @@ object Parsers { if (in.token == WITH) { syntaxError("early definitions are not supported; use trait parameters instead") in.nextToken() - template(emptyConstructor()) + template(emptyConstructor) } r } @@ -2058,7 +2088,7 @@ object Parsers { if (in.token == PACKAGE) { val start = in.skipToken() if (in.token == OBJECT) - stats += objectDef(atPos(start, in.skipToken()) { Modifiers(Package) }) + stats += objectDef(start, atPos(start, in.skipToken()) { Modifiers(Package) }) else stats += packaging(start) } else if (in.token == IMPORT) @@ -2192,7 +2222,7 @@ object Parsers { in.nextToken() if (in.token == OBJECT) { val docstring = in.getDocComment(start) - ts += objectDef(atPos(start, in.skipToken()) { Modifiers(Package) }, docstring) + ts += objectDef(start, atPos(start, in.skipToken()) { Modifiers(Package) }, docstring) if (in.token != EOF) { acceptStatSep() ts ++= topStatSeq() diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 7e2a2893e..205d2b6b9 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -161,8 +161,15 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { import untpd.{modsDeco => _, _} /** Print modifiers from symbols if tree has type, overriding the untpd behavior. */ - implicit def modsDeco(mdef: untpd.MemberDef)(implicit ctx: Context): untpd.ModsDeco = - tpd.modsDeco(mdef.asInstanceOf[tpd.MemberDef]).asInstanceOf[untpd.ModsDeco] + implicit def modsDeco(mdef: untpd.MemberDef)(implicit ctx: Context): untpd.ModsDecorator = + new untpd.ModsDecorator { + def mods = if (mdef.hasType) Modifiers(mdef.symbol) else mdef.rawMods + } + + def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = untpd.Modifiers( + sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags else ModifierFlags), + if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, + sym.annotations map (_.tree)) def isLocalThis(tree: Tree) = tree.typeOpt match { case tp: ThisType => tp.cls == ctx.owner.enclosingClass @@ -253,6 +260,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (vparamss.isEmpty || primaryConstrs.nonEmpty) tparamsTxt else { var modsText = modText(constr.mods, "") + if (!modsText.isEmpty) modsText = " " ~ modsText if (constr.mods.hasAnnotations && !constr.mods.hasFlags) modsText = modsText ~~ " this" withEnclosingDef(constr) { addVparamssText(tparamsTxt ~~ modsText, vparamss) } } @@ -280,7 +288,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case _ => toText(name) } case tree @ Select(qual, name) => - toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR) + if (qual.isType) toTextLocal(qual) ~ "#" ~ toText(name) + else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR) case tree: This => optDotPrefix(tree) ~ "this" ~ idText(tree) case Super(qual: This, mix) => @@ -310,8 +319,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { toTextLocal(tpt) } } - case Pair(l, r) => - "(" ~ toTextGlobal(l) ~ ", " ~ toTextGlobal(r) ~ ")" case Typed(expr, tpt) => changePrec(InfixPrec) { toText(expr) ~ ": " ~ toText(tpt) } case NamedArg(name, arg) => @@ -350,8 +357,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tree.hasType) toText(tree.typeOpt) else toText(orig) case SingletonTypeTree(ref) => toTextLocal(ref) ~ ".type" - case SelectFromTypeTree(qual, name) => - toTextLocal(qual) ~ "#" ~ toText(name) case AndTypeTree(l, r) => changePrec(AndPrec) { toText(l) ~ " & " ~ toText(r) } case OrTypeTree(l, r) => @@ -415,7 +420,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } case Import(expr, selectors) => def selectorText(sel: Tree): Text = sel match { - case Pair(l, r) => toTextGlobal(l) ~ " => " ~ toTextGlobal(r) + case Thicket(l :: r :: Nil) => toTextGlobal(l) ~ " => " ~ toTextGlobal(r) case _ => toTextGlobal(sel) } val selectorsText: Text = selectors match { @@ -433,7 +438,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { "package " ~ toTextPackageId(pid) ~ bodyText case tree: Template => toTextTemplate(tree) - case Annotated(annot, arg) => + case Annotated(arg, annot) => toTextLocal(arg) ~~ annotText(annot) case EmptyTree => "<empty>" @@ -445,15 +450,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } case SymbolLit(str) => "'" + str - case InterpolatedString(id, strings, elems) => - def interleave(strs: List[Text], elems: List[Text]): Text = ((strs, elems): @unchecked) match { - case (Nil, Nil) => "" - case (str :: Nil, Nil) => str - case (str :: strs1, elem :: elems1) => str ~ elem ~ interleave(strs1, elems1) + case InterpolatedString(id, segments) => + def strText(str: Literal) = Str(escapedString(str.const.stringValue)) + def segmentText(segment: Tree) = segment match { + case Thicket(List(str: Literal, expr)) => strText(str) ~ "{" ~ toTextGlobal(expr) ~ "}" + case str: Literal => strText(str) } - val strTexts = strings map (str => Str(escapedString(str.const.stringValue))) - val elemsTexts = elems map (elem => "{" ~ toTextGlobal(elem) ~ "}") - toText(id) ~ "\"" ~ interleave(strTexts, elemsTexts) ~ "\"" + toText(id) ~ "\"" ~ Text(segments map segmentText, "") ~ "\"" case Function(args, body) => var implicitSeen: Boolean = false def argToText(arg: Tree) = arg match { diff --git a/src/dotty/tools/dotc/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala index 954bff88e..b7b7c1af0 100644 --- a/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -5,7 +5,7 @@ package reporting import core.Contexts.Context import collection.mutable import Reporter.{Error, Warning} -import config.Printers._ +import config.Printers.typr /** * This class implements a Reporter that stores all messages diff --git a/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 026a518ce..a36b47aa8 100644 --- a/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -184,7 +184,7 @@ private class ExtractDependenciesCollector(implicit val ctx: Context) extends tp selectors foreach { case Ident(name) => addImported(name) - case Pair(Ident(name), Ident(rename)) => + case Thicket(Ident(name) :: Ident(rename) :: Nil) => addImported(name) if (rename ne nme.WILDCARD) addUsedName(rename) diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 24dea5118..a503d55e5 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -388,9 +388,6 @@ object Erasure extends TypeTestsCasts{ recur(typed(tree.qualifier, AnySelectionProto)) } - override def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context) = - untpd.Ident(tree.name).withPos(tree.pos).withType(erasedType(tree)) - override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = if (tree.symbol == ctx.owner.enclosingClass || tree.symbol.isStaticOwner) promote(tree) else { diff --git a/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 04c6864b1..91399f91a 100644 --- a/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -74,7 +74,7 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => Bind(defaultSym, Underscore(selector.tpe.widen)), EmptyTree, Literal(Constant(false))) - val annotated = Annotated(New(ref(defn.UncheckedAnnotType)), paramRef) + val annotated = Annotated(paramRef, New(ref(defn.UncheckedAnnotType))) cpy.Match(applyRhs)(annotated, cases.map(translateCase) :+ defaultCase) case _ => tru diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index 504f9250b..e63a7c3a7 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -210,7 +210,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { def transformMemberDefNonVolatile(x: ValOrDefDef)(implicit ctx: Context) = { val claz = x.symbol.owner.asClass val tpe = x.tpe.widen.resultType.widen - assert(!(x.mods is Flags.Mutable)) + assert(!(x.symbol is Flags.Mutable)) val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName val containerSymbol = ctx.newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags | Flags.Private, @@ -220,14 +220,14 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { val containerTree = ValDef(containerSymbol, defaultValue(tpe)) if (x.tpe.isNotNull && tpe <:< defn.ObjectType) { // can use 'null' value instead of flag val slowPath = DefDef(x.symbol.asTerm, mkDefNonThreadSafeNonNullable(containerSymbol, x.rhs)) - Thicket(List(containerTree, slowPath)) + Thicket(containerTree, slowPath) } else { val flagName = ctx.freshName(x.name ++ StdNames.nme.BITMAP_PREFIX).toTermName val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags.Private, defn.BooleanType).enteredAfter(this) val flag = ValDef(flagSymbol, Literal(Constants.Constant(false))) val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs)) - Thicket(List(containerTree, flag, slowPath)) + Thicket(containerTree, flag, slowPath) } } @@ -331,7 +331,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { } def transformMemberDefVolatile(x: ValOrDefDef)(implicit ctx: Context) = { - assert(!(x.mods is Flags.Mutable)) + assert(!(x.symbol is Flags.Mutable)) val tpe = x.tpe.widen.resultType.widen val claz = x.symbol.owner.asClass @@ -377,7 +377,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { } val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName - val containerSymbol = ctx.newSymbol(claz, containerName, (x.mods &~ containerFlagsMask | containerFlags).flags, tpe, coord = x.symbol.coord).enteredAfter(this) + val containerSymbol = ctx.newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags, tpe, coord = x.symbol.coord).enteredAfter(this) val containerTree = ValDef(containerSymbol, defaultValue(tpe)) @@ -390,8 +390,8 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait) if (flag eq EmptyTree) - Thicket(List(containerTree, accessor)) - else Thicket(List(containerTree, flag, accessor)) + Thicket(containerTree, accessor) + else Thicket(containerTree, flag, accessor) } } diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index 21b56959b..490feb7d0 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -37,7 +37,7 @@ import scala.reflect.internal.util.Collections * elimRepeated is required * TODO: outer tests are not generated yet. */ -class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTransformer => +class PatternMatcher extends MiniPhaseTransform with DenotTransformer { import dotty.tools.dotc.ast.tpd._ override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref @@ -80,7 +80,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans ctx.newSymbol(owner, ctx.freshName(prefix + ctr).toTermName, Flags.Synthetic | Flags.Case, tp, coord = pos) } - def newSynthCaseLabel(name: String, tpe:Type, owner: Symbol = ctx.owner) = + def newSynthCaseLabel(name: String, tpe: Type, owner: Symbol = ctx.owner) = ctx.newSymbol(owner, ctx.freshName(name).toTermName, Flags.Label | Flags.Synthetic | Flags.Method, tpe).asTerm //NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS @@ -148,30 +148,28 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans } } + object Rebindings { + def apply(from: Symbol, to: Symbol) = new Rebindings(List(from), List(ref(to))) + // requires sameLength(from, to) + def apply(from: List[Symbol], to: List[Tree]) = + if (from nonEmpty) new Rebindings(from, to) else NoRebindings + } - object Rebindings { - def apply(from: Symbol, to: Symbol) = new Rebindings(List(from), List(ref(to))) - // requires sameLength(from, to) - def apply(from: List[Symbol], to: List[Tree]) = - if (from nonEmpty) new Rebindings(from, to) else NoRebindings - } - - class Rebindings(val lhs: List[Symbol], val rhs: List[Tree]) { - def >>(other: Rebindings) = { - if (other eq NoRebindings) this - else if (this eq NoRebindings) other - else { - assert((lhs.toSet ++ other.lhs.toSet).size == lhs.length + other.lhs.length, "no double assignments") - new Rebindings(this.lhs ++ other.lhs, this.rhs ++ other.rhs) - } - } - - def emitValDefs: List[ValDef] = { - Collections.map2(lhs, rhs)((symbol, tree) => ValDef(symbol.asTerm, tree.ensureConforms(symbol.info))) + class Rebindings(val lhs: List[Symbol], val rhs: List[Tree]) { + def >>(other: Rebindings) = { + if (other eq NoRebindings) this + else if (this eq NoRebindings) other + else { + assert((lhs.toSet ++ other.lhs.toSet).size == lhs.length + other.lhs.length, "no double assignments") + new Rebindings(this.lhs ++ other.lhs, this.rhs ++ other.rhs) } } - object NoRebindings extends Rebindings(Nil, Nil) + def emitValDefs: List[ValDef] = { + Collections.map2(lhs, rhs)((symbol, tree) => ValDef(symbol.asTerm, tree.ensureConforms(symbol.info))) + } + } + object NoRebindings extends Rebindings(Nil, Nil) trait OptimizedCodegen extends CodegenCore { override def codegen: AbsCodegen = optimizedCodegen @@ -192,12 +190,13 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans //val matchRes = ctx.newSymbol(NoSymbol, ctx.freshName("matchRes").toTermName, Flags.Synthetic | Flags.Param | Flags.Label | Flags.Method, restpe /*withoutAnnotations*/) //NoSymbol.newValueParameter(newTermName("x"), NoPosition, newFlags = SYNTHETIC) setInfo restpe.withoutAnnotations - val caseSyms = cases.scanLeft(ctx.owner.asTerm)((curOwner, nextTree) => newSynthCaseLabel(ctx.freshName("case"), MethodType(Nil, restpe), curOwner)).tail + + val caseSyms: List[TermSymbol] = cases.scanLeft(ctx.owner.asTerm)((curOwner, nextTree) => newSynthCaseLabel(ctx.freshName("case"), MethodType(Nil, restpe), curOwner)).tail // must compute catchAll after caseLabels (side-effects nextCase) // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) // if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd - val catchAllDef = matchFailGen.map { _(scrutSym)} + val catchAllDef = matchFailGen.map { _(scrutSym) } .getOrElse(Throw(New(defn.MatchErrorType, List(ref(scrutSym))))) val matchFail = newSynthCaseLabel(ctx.freshName("matchFail"), MethodType(Nil, restpe)) @@ -207,14 +206,13 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val caseDefs = (cases zip caseSyms zip nextCases).foldRight[Tree](catchAllDefBody) { // dotty deviation //case (((mkCase, sym), nextCase), acc) => - (x:(((Casegen => Tree), TermSymbol), Tree), acc: Tree) => x match { - - case ((mkCase, sym), nextCase) => - val body = mkCase(new OptimizedCasegen(nextCase)).ensureConforms(restpe) - - DefDef(sym, _ => Block(List(acc), body)) - }} + (x: (((Casegen => Tree), TermSymbol), Tree), acc: Tree) => x match { + case ((mkCase, sym), nextCase) => + val body = mkCase(new OptimizedCasegen(nextCase)).ensureConforms(restpe) + DefDef(sym, _ => Block(List(acc), body)) + } + } // scrutSym == NoSymbol when generating an alternatives matcher // val scrutDef = scrutSym.fold(List[Tree]())(ValDef(_, scrut) :: Nil) // for alternatives @@ -255,9 +253,13 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans ) } else { assert(defn.isProductSubType(prev.tpe)) - Block( - List(ValDef(b.asTerm, prev)), - next //Substitution(b, ref(prevSym))(next) + val nullCheck: Tree = prev.select(defn.Object_ne).appliedTo(Literal(Constant(null))) + ifThenElseZero( + nullCheck, + Block( + List(ValDef(b.asTerm, prev)), + next //Substitution(b, ref(prevSym))(next) + ) ) } } @@ -285,7 +287,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans next )) } - } } final case class Suppression(exhaustive: Boolean, unreachable: Boolean) @@ -642,7 +643,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val checkedLength: Option[Int], val prevBinder: Symbol, val ignoredSubPatBinders: Set[Symbol] - ) extends FunTreeMaker with PreserveSubPatBinders { + ) extends FunTreeMaker with PreserveSubPatBinders { def extraStoredBinders: Set[Symbol] = Set() @@ -664,9 +665,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans bindSubPats(next) } - if (extractorReturnsBoolean) casegen.flatMapCond(extractor, unitLiteral, nextBinder, condAndNext) - else casegen.flatMap(extractor, nextBinder, condAndNext) // getType? - + if (extractorReturnsBoolean) casegen.flatMapCond(extractor, unitLiteral, nextBinder, condAndNext) + else casegen.flatMap(extractor, nextBinder, condAndNext) // getType? } override def toString = "X" + ((extractor, nextBinder.name)) @@ -700,7 +700,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val mutableBinders: List[Symbol], binderKnownNonNull: Boolean, val ignoredSubPatBinders: Set[Symbol] - ) extends FunTreeMaker with PreserveSubPatBinders { + ) extends FunTreeMaker with PreserveSubPatBinders { val nextBinder = prevBinder // just passing through @@ -709,6 +709,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans def chainBefore(next: Tree)(casegen: Casegen): Tree = { val nullCheck: Tree = ref(prevBinder).select(defn.Object_ne).appliedTo(Literal(Constant(null))) + val cond: Option[Tree] = if (binderKnownNonNull) extraCond else extraCond.map(nullCheck.select(defn.Boolean_&&).appliedTo).orElse(Some(nullCheck)) @@ -782,9 +783,9 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val expectedClass = expectedTp.dealias.classSymbol.asClass val test = codegen._asInstanceOf(testedBinder, expectedTp) val outerAccessorTested = ctx.atPhase(ctx.explicitOuterPhase.next) { implicit ctx => - ExplicitOuter.ensureOuterAccessors(expectedClass) - test.select(ExplicitOuter.outerAccessor(expectedClass)).select(defn.Object_eq).appliedTo(expectedOuter) - } + ExplicitOuter.ensureOuterAccessors(expectedClass) + test.select(ExplicitOuter.outerAccessor(expectedClass)).select(defn.Object_eq).appliedTo(expectedOuter) + } outerAccessorTested } } @@ -848,7 +849,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val nextBinder = afterTest.asTerm - def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { + def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol): Boolean = { // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` // generates an outer test based on `patType.prefix` with automatically dealises. patType.dealias match { @@ -866,7 +867,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val np = expectedTp.normalizedPrefix val ts = np.termSymbol (ts ne NoSymbol) && needsOuterTest(expectedTp, testedBinder.info, ctx.owner) - } // the logic to generate the run-time test that follows from the fact that @@ -906,7 +906,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans if (isExpectedReferenceType) mkNullTest else mkTypeTest ) - ) + ) // true when called to type-test the argument to an extractor // don't do any fancy equality checking, just test the type @@ -920,7 +920,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans and(mkEqualsTest(ref(tref.symbol.companionModule)), mkTypeTest) // must use == to support e.g. List() == Nil case ConstantType(Constant(null)) if isAnyRef => mkEqTest(expTp(Literal(Constant(null)))) case ConstantType(const) => mkEqualsTest(expTp(Literal(const))) - case t:SingletonType => mkEqTest(singleton(expectedTp)) // SI-4577, SI-4897 + case t: SingletonType => mkEqTest(singleton(expectedTp)) // SI-4577, SI-4897 //case ThisType(sym) => mkEqTest(expTp(This(sym))) case _ => mkDefault } @@ -1050,7 +1050,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val (cases, toHoist) = optimizeCases(scrutSym, casesRebindingPropagated, pt) - val matchRes = codegen.matcher(scrut, scrutSym, pt)(cases.map(x => combineExtractors(x) _), synthCatchAll) if (toHoist isEmpty) matchRes else Block(toHoist, matchRes) @@ -1092,7 +1091,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans def unapply(pat: Tree): Boolean = pat match { case Typed(_, arg) if arg.tpe.isRepeatedParam => true case Bind(nme.WILDCARD, WildcardPattern()) => true // don't skip when binding an interesting symbol! - case t if (tpd.isWildcardArg(t)) => true + case t if (tpd.isWildcardArg(t)) => true case x: Ident => isVarPattern(x) case Alternative(ps) => ps forall unapply case EmptyTree => true @@ -1113,7 +1112,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans object SymbolBound { def unapply(tree: Tree): Option[(Symbol, Tree)] = tree match { case Bind(_, expr) if tree.symbol.exists => Some(tree.symbol -> expr) - case _ => None + case _ => None } } @@ -1126,13 +1125,13 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans final case class BoundTree(binder: Symbol, tree: Tree) { private lazy val extractor = ExtractorCall(tree, binder) - def pos = tree.pos - def tpe = binder.info.widenDealias - def pt = unbound match { - // case Star(tpt) => this glbWith seqType(tpt.tpe) dd todo: - case TypeBound(tpe) => tpe - case tree => tree.tpe - } + def pos = tree.pos + def tpe = binder.info.widenDealias + def pt = unbound match { + // case Star(tpt) => this glbWith seqType(tpt.tpe) dd todo: + case TypeBound(tpe) => tpe + case tree => tree.tpe + } def glbWith(other: Type) = ctx.typeComparer.glb(tpe :: other :: Nil)// .normalize @@ -1200,7 +1199,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans // Statically conforms to paramType if (tpe <:< paramType) treeMaker(binder, false, pos, tpe) :: Nil else typeTest :: extraction :: Nil - ) + ) step(makers: _*)(extractor.subBoundTrees: _*) } @@ -1219,7 +1218,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans // [7] symbol-less bind patterns - this happens in certain ill-formed programs, there'll be an error later // don't fail here though (or should we?) def nextStep(): TranslationStep = tree match { - case _: UnApply | _: Apply| Typed(_: UnApply | _: Apply, _) => extractorStep() + case _: UnApply | _: Apply | Typed(_: UnApply | _: Apply, _) => extractorStep() case SymbolAndTypeBound(sym, tpe) => typeTestStep(sym, tpe) case TypeBound(tpe) => typeTestStep(binder, tpe) case SymbolBound(sym, expr) => bindingStep(sym, expr) @@ -1230,7 +1229,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans } def translate(): List[TreeMaker] = nextStep() merge (_.translate()) - private def concreteType = tpe.bounds.hi private def unbound = unbind(tree) private def tpe_s = if (pt <:< concreteType) "" + pt else s"$pt (binder: $tpe)" @@ -1260,7 +1258,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans * * NOTE: the resulting tree is not type checked, nor are nested pattern matches transformed * thus, you must typecheck the result (and that will in turn translate nested matches) - * this could probably optimized... (but note that the matchStrategy must be solved for each nested patternmatch) + * this could probably be optimized... (but note that the matchStrategy must be solved for each nested patternmatch) */ def translateMatch(match_ : Match): Tree = { val Match(sel, cases) = match_ @@ -1271,7 +1269,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val (nonSyntheticCases, defaultOverride) = cases match { case init :+ last if isSyntheticDefaultCase(last) => (init, Some(((scrut: Symbol) => last.body))) - case _ => (cases, None) + case _ => (cases, None) } @@ -1331,7 +1329,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans * a function that will take care of binding and substitution of the next ast (to the right). * */ - def translateCase(scrutSym: Symbol, pt: Type)(caseDef: CaseDef) = { + def translateCase(scrutSym: Symbol, pt: Type)(caseDef: CaseDef): List[TreeMaker] = { val CaseDef(pattern, guard, body) = caseDef translatePattern(BoundTree(scrutSym, pattern)) ++ translateGuard(guard) :+ translateBody(body, pt) } @@ -1400,7 +1398,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans object ExtractorCall { // TODO: check unargs == args - def apply(tree: Tree, binder: Symbol): ExtractorCall = { + def apply(tree: Tree, binder: Symbol): ExtractorCall = { tree match { case UnApply(unfun, implicits, args) => val castedBinder = ref(binder).ensureConforms(tree.tpe) @@ -1479,8 +1477,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans productSelectors(binder.info) else binder.caseAccessors val res = - if (accessors.isDefinedAt(i - 1)) ref(binder).select(accessors(i - 1).name) - else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN + if (accessors.isDefinedAt(i - 1)) ref(binder).select(accessors(i - 1).name) + else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN val rsym = res.symbol // just for debugging res } @@ -1492,7 +1490,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans if (!aligner.isStar) Nil else if (expectedLength == 0) seqTree(binder) :: Nil else genDrop(binder, expectedLength) - ) + ) // this error-condition has already been checked by checkStarPatOK: // if (isSeq) assert(firstIndexingBinder + nbIndexingIndices + (if (lastIsStar) 1 else 0) == totalArity, "(resultInMonad, ts, subPatTypes, subPats)= " +(resultInMonad, ts, subPatTypes, subPats)) @@ -1503,7 +1501,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans ( productElemsToN(binder, firstIndexingBinder) ++ genTake(binder, expectedLength) ++ lastTrees - ).toList + ).toList } // the trees that select the subpatterns on the extractor's result, referenced by `binder` @@ -1511,7 +1509,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans protected def subPatRefs(binder: Symbol): List[Tree] = { val refs = if (totalArity > 0 && isSeq) subPatRefsSeq(binder) else if (binder.info.member(nme._1).exists && !isSeq) productElemsToN(binder, totalArity) - else ref(binder):: Nil + else ref(binder) :: Nil refs } @@ -1601,7 +1599,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans // can't simplify this when subPatBinders.isEmpty, since UnitTpe is definitely // wrong when isSeq, and resultInMonad should always be correct since it comes // directly from the extractor's result type - val binder = freshSym(pos, resultInMonad) + val binder = freshSym(pos, resultInMonad) val spb = subPatBinders ExtractorTreeMaker(extractorApply, lengthGuard(binder), binder)( spb, @@ -1819,6 +1817,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans def expectedTypes = typedPatterns map (_.tpe) def unexpandedFormals = extractor.varargsTypes } + trait ScalacPatternExpander extends PatternExpander[Tree, Type] { def NoPattern = EmptyTree def NoType = core.Types.NoType @@ -1836,7 +1835,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans ( typeOfMemberNamedHead(seq) orElse typeOfMemberNamedApply(seq) orElse seq.elemType - ) + ) } def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated): Extractor = { ctx.log(s"newExtractor($whole, $fixed, $repeated") @@ -1863,7 +1862,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans method.paramTypess.head match { case init :+ last if last.isRepeatedParam => newExtractor(whole, init, repeatedFromVarargs(last)) - case tps => newExtractor(whole, tps, NoRepeated) + case tps => newExtractor(whole, tps, NoRepeated) } } @@ -1874,15 +1873,14 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans * Unfortunately the MethodType does not carry the information of whether * it was unapplySeq, so we have to funnel that information in separately. */ - def unapplyMethodTypes(tree:Tree, fun: Tree, args:List[Tree], resultType:Type, isSeq: Boolean): Extractor = { + def unapplyMethodTypes(tree: Tree, fun: Tree, args: List[Tree], resultType: Type, isSeq: Boolean): Extractor = { _id = _id + 1 - val whole = tree.tpe// see scaladoc for Trees.Unapply + val whole = tree.tpe // see scaladoc for Trees.Unapply // fun.tpe.widen.paramTypess.headOption.flatMap(_.headOption).getOrElse(NoType)//firstParamType(method) val resultOfGet = extractorMemberType(resultType, nme.get) - //println(s"${_id}unapplyArgs(${result.widen}") - val expanded:List[Type] = /*( + val expanded: List[Type] = /*( if (result =:= defn.BooleanType) Nil else if (defn.isProductSubType(result)) productSelectorTypes(result) else if (result.classSymbol is Flags.CaseClass) result.decls.filter(x => x.is(Flags.CaseAccessor) && x.is(Flags.Method)).map(_.info).toList @@ -1917,7 +1915,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans def offering = extractor.offeringString def symString = tree.symbol.showLocated def offerString = if (extractor.isErroneous) "" else s" offering $offering" - def arityExpected = ( if (extractor.hasSeq) "at least " else "" ) + prodArity + def arityExpected = (if (extractor.hasSeq) "at least " else "") + prodArity def err(msg: String) = ctx.error(msg, tree.pos) def warn(msg: String) = ctx.warning(msg, tree.pos) @@ -1944,10 +1942,10 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans } } - def apply(tree:Tree, sel: Tree, args: List[Tree], resultType: Type): Aligned = { + def apply(tree: Tree, sel: Tree, args: List[Tree], resultType: Type): Aligned = { val fn = sel match { case Applied(fn) => fn - case _ => sel + case _ => sel } val patterns = newPatterns(args) val isSeq = sel.symbol.name == nme.unapplySeq @@ -1977,8 +1975,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans } def apply(tree: Tree, resultType: Type): Aligned = tree match { - case Typed(tree, _) => apply(tree, resultType) - case Apply(fn, args) => apply(tree, fn, args, resultType) + case Typed(tree, _) => apply(tree, resultType) + case Apply(fn, args) => apply(tree, fn, args, resultType) case UnApply(fn, implicits, args) => apply(tree, fn, args, resultType) } } diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala index fd22a0ad9..6af225035 100644 --- a/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/src/dotty/tools/dotc/transform/PostTyper.scala @@ -13,7 +13,7 @@ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTrans import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import util.Positions._ import Decorators._ -import config.Printers._ +import config.Printers.typr import Symbols._, TypeUtils._ /** A macro transform that runs immediately after typer and that performs the following functions: @@ -93,7 +93,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran * * should behave differently. * - * O1.x should have the same effect as { println("43"; 42 } + * O1.x should have the same effect as { println("43"); 42 } * * whereas * @@ -103,10 +103,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran * purity of the prefix unless the selection goes to an inline val. */ private def normalizeTree(tree: Tree)(implicit ctx: Context): Tree = tree match { - case tree: TypeTree => tree - case TypeApply(fn, args) => - Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType]) - tree + case _: TypeTree | _: TypeApply => tree case _ => if (tree.isType) { Checking.typeChecker.traverse(tree) @@ -265,8 +262,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran case tree: New if !inJavaAnnot && !parentNews.contains(tree) => Checking.checkInstantiable(tree.tpe, tree.pos) super.transform(tree) - case tree @ Annotated(annot, annotated) => - cpy.Annotated(tree)(transformAnnot(annot), transform(annotated)) + case tree @ Annotated(annotated, annot) => + cpy.Annotated(tree)(transform(annotated), transformAnnot(annot)) case tree: TypeTree => tree.withType( tree.tpe match { diff --git a/src/dotty/tools/dotc/transform/SelectStatic.scala b/src/dotty/tools/dotc/transform/SelectStatic.scala index 504a66c2f..5d60bb984 100644 --- a/src/dotty/tools/dotc/transform/SelectStatic.scala +++ b/src/dotty/tools/dotc/transform/SelectStatic.scala @@ -19,25 +19,21 @@ class SelectStatic extends MiniPhaseTransform with IdentityDenotTransformer { th import ast.tpd._ override def phaseName: String = "selectStatic" - private val isPackage = FlagConjunction(PackageCreationFlags.bits) override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { val sym = tree.symbol - val r1 = - if (!sym.is(isPackage) && !sym.maybeOwner.is(isPackage) && - ( - ((sym is Flags.Module) && sym.maybeOwner.isStaticOwner) || - (sym is Flags.JavaStatic) || - (sym.maybeOwner is Flags.ImplClass) || - sym.hasAnnotation(ctx.definitions.ScalaStaticAnnot) - ) - ) - if (!tree.qualifier.symbol.is(JavaModule) && !tree.qualifier.isType) - Block(List(tree.qualifier), ref(sym)) - else tree + def isStaticMember = + (sym is Flags.Module) && sym.initial.maybeOwner.initial.isStaticOwner || + (sym is Flags.JavaStatic) || + (sym.maybeOwner is Flags.ImplClass) || + sym.hasAnnotation(ctx.definitions.ScalaStaticAnnot) + val isStaticRef = !sym.is(Package) && !sym.maybeOwner.is(Package) && isStaticMember + val tree1 = + if (isStaticRef && !tree.qualifier.symbol.is(JavaModule) && !tree.qualifier.isType) + Block(List(tree.qualifier), ref(sym)) else tree - normalize(r1) + normalize(tree1) } private def normalize(t: Tree)(implicit ctx: Context) = t match { diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 18e3a6c8a..e7342aec9 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -164,7 +164,6 @@ class TreeChecker extends Phase with SymTransformer { tree match { case t: MemberDef => if (t.name ne sym.name) ctx.warning(s"symbol ${sym.fullName} name doesn't correspond to AST: ${t}") - if (sym.flags != t.mods.flags) ctx.warning(s"symbol ${sym.fullName} flags ${sym.flags} doesn't match AST definition flags ${t.mods.flags}") // todo: compare trees inside annotations case _ => } @@ -200,7 +199,6 @@ class TreeChecker extends Phase with SymTransformer { def checkIdentNotJavaClass(tree: Tree)(implicit ctx: Context): Unit = tree match { // case tree: untpd.Ident => // case tree: untpd.Select => - // case tree: untpd.SelectFromTypeTree => // case tree: untpd.Bind => case vd : ValDef => assertIdentNotJavaClass(vd.forceIfLazy) @@ -213,9 +211,6 @@ class TreeChecker extends Phase with SymTransformer { // case tree: untpd.This => // case tree: untpd.Literal => // case tree: untpd.New => - case Pair(left, right) => - assertIdentNotJavaClass(left) - assertIdentNotJavaClass(right) case Typed(expr, _) => assertIdentNotJavaClass(expr) case NamedArg(_, arg) => @@ -252,7 +247,7 @@ class TreeChecker extends Phase with SymTransformer { // case tree: TypeBoundsTree => // case tree: Alternative => // case tree: PackageDef => - case Annotated(_, arg) => + case Annotated(arg, _) => assertIdentNotJavaClass(arg) case _ => } diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 89ae927b7..05961508a 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -70,7 +70,6 @@ object TreeTransforms { def prepareForApply(tree: Apply)(implicit ctx: Context) = this def prepareForTypeApply(tree: TypeApply)(implicit ctx: Context) = this def prepareForLiteral(tree: Literal)(implicit ctx: Context) = this - def prepareForPair(tree: Pair)(implicit ctx: Context) = this def prepareForNew(tree: New)(implicit ctx: Context) = this def prepareForTyped(tree: Typed)(implicit ctx: Context) = this def prepareForAssign(tree: Assign)(implicit ctx: Context) = this @@ -83,7 +82,6 @@ object TreeTransforms { def prepareForTry(tree: Try)(implicit ctx: Context) = this def prepareForSeqLiteral(tree: SeqLiteral)(implicit ctx: Context) = this def prepareForTypeTree(tree: TypeTree)(implicit ctx: Context) = this - def prepareForSelectFromTypeTree(tree: SelectFromTypeTree)(implicit ctx: Context) = this def prepareForBind(tree: Bind)(implicit ctx: Context) = this def prepareForAlternative(tree: Alternative)(implicit ctx: Context) = this def prepareForTypeDef(tree: TypeDef)(implicit ctx: Context) = this @@ -104,7 +102,6 @@ object TreeTransforms { def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformLiteral(tree: Literal)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformNew(tree: New)(implicit ctx: Context, info: TransformerInfo): Tree = tree - def transformPair(tree: Pair)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = tree @@ -116,7 +113,6 @@ object TreeTransforms { def transformTry(tree: Try)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformSeqLiteral(tree: SeqLiteral)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformTypeTree(tree: TypeTree)(implicit ctx: Context, info: TransformerInfo): Tree = tree - def transformSelectFromTypeTree(tree: SelectFromTypeTree)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformBind(tree: Bind)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformAlternative(tree: Alternative)(implicit ctx: Context, info: TransformerInfo): Tree = tree def transformUnApply(tree: UnApply)(implicit ctx: Context, info: TransformerInfo): Tree = tree @@ -267,7 +263,6 @@ object TreeTransforms { nxPrepTypeApply = index(transformations, "prepareForTypeApply") nxPrepLiteral = index(transformations, "prepareForLiteral") nxPrepNew = index(transformations, "prepareForNew") - nxPrepPair = index(transformations, "prepareForPair") nxPrepTyped = index(transformations, "prepareForTyped") nxPrepAssign = index(transformations, "prepareForAssign") nxPrepBlock = index(transformations, "prepareForBlock") @@ -279,7 +274,6 @@ object TreeTransforms { nxPrepTry = index(transformations, "prepareForTry") nxPrepSeqLiteral = index(transformations, "prepareForSeqLiteral") nxPrepTypeTree = index(transformations, "prepareForTypeTree") - nxPrepSelectFromTypeTree = index(transformations, "prepareForSelectFromTypeTree") nxPrepBind = index(transformations, "prepareForBind") nxPrepAlternative = index(transformations, "prepareForAlternative") nxPrepUnApply = index(transformations, "prepareForUnApply") @@ -299,7 +293,6 @@ object TreeTransforms { nxTransTypeApply = index(transformations, "transformTypeApply") nxTransLiteral = index(transformations, "transformLiteral") nxTransNew = index(transformations, "transformNew") - nxTransPair = index(transformations, "transformPair") nxTransTyped = index(transformations, "transformTyped") nxTransAssign = index(transformations, "transformAssign") nxTransBlock = index(transformations, "transformBlock") @@ -311,7 +304,6 @@ object TreeTransforms { nxTransTry = index(transformations, "transformTry") nxTransSeqLiteral = index(transformations, "transformSeqLiteral") nxTransTypeTree = index(transformations, "transformTypeTree") - nxTransSelectFromTypeTree = index(transformations, "transformSelectFromTypeTree") nxTransBind = index(transformations, "transformBind") nxTransAlternative = index(transformations, "transformAlternative") nxTransUnApply = index(transformations, "transformUnApply") @@ -341,7 +333,6 @@ object TreeTransforms { nxPrepTypeApply = indexUpdate(prev.nxPrepTypeApply, changedTransformationClass, transformationIndex, "prepareForTypeApply", copy) nxPrepLiteral = indexUpdate(prev.nxPrepLiteral, changedTransformationClass, transformationIndex, "prepareForLiteral", copy) nxPrepNew = indexUpdate(prev.nxPrepNew, changedTransformationClass, transformationIndex, "prepareForNew", copy) - nxPrepPair = indexUpdate(prev.nxPrepPair, changedTransformationClass, transformationIndex, "prepareForPair", copy) nxPrepTyped = indexUpdate(prev.nxPrepTyped, changedTransformationClass, transformationIndex, "prepareForTyped", copy) nxPrepAssign = indexUpdate(prev.nxPrepAssign, changedTransformationClass, transformationIndex, "prepareForAssign", copy) nxPrepBlock = indexUpdate(prev.nxPrepBlock, changedTransformationClass, transformationIndex, "prepareForBlock", copy) @@ -353,7 +344,6 @@ object TreeTransforms { nxPrepTry = indexUpdate(prev.nxPrepTry, changedTransformationClass, transformationIndex, "prepareForTry", copy) nxPrepSeqLiteral = indexUpdate(prev.nxPrepSeqLiteral, changedTransformationClass, transformationIndex, "prepareForSeqLiteral", copy) nxPrepTypeTree = indexUpdate(prev.nxPrepTypeTree, changedTransformationClass, transformationIndex, "prepareForTypeTree", copy) - nxPrepSelectFromTypeTree = indexUpdate(prev.nxPrepSelectFromTypeTree, changedTransformationClass, transformationIndex, "prepareForSelectFromTypeTree", copy) nxPrepBind = indexUpdate(prev.nxPrepBind, changedTransformationClass, transformationIndex, "prepareForBind", copy) nxPrepAlternative = indexUpdate(prev.nxPrepAlternative, changedTransformationClass, transformationIndex, "prepareForAlternative", copy) nxPrepUnApply = indexUpdate(prev.nxPrepUnApply, changedTransformationClass, transformationIndex, "prepareForUnApply", copy) @@ -372,7 +362,6 @@ object TreeTransforms { nxTransTypeApply = indexUpdate(prev.nxTransTypeApply, changedTransformationClass, transformationIndex, "transformTypeApply", copy) nxTransLiteral = indexUpdate(prev.nxTransLiteral, changedTransformationClass, transformationIndex, "transformLiteral", copy) nxTransNew = indexUpdate(prev.nxTransNew, changedTransformationClass, transformationIndex, "transformNew", copy) - nxTransPair = indexUpdate(prev.nxTransPair, changedTransformationClass, transformationIndex, "transformPair", copy) nxTransTyped = indexUpdate(prev.nxTransTyped, changedTransformationClass, transformationIndex, "transformTyped", copy) nxTransAssign = indexUpdate(prev.nxTransAssign, changedTransformationClass, transformationIndex, "transformAssign", copy) nxTransBlock = indexUpdate(prev.nxTransBlock, changedTransformationClass, transformationIndex, "transformBlock", copy) @@ -384,7 +373,6 @@ object TreeTransforms { nxTransTry = indexUpdate(prev.nxTransTry, changedTransformationClass, transformationIndex, "transformTry", copy) nxTransSeqLiteral = indexUpdate(prev.nxTransSeqLiteral, changedTransformationClass, transformationIndex, "transformSeqLiteral", copy) nxTransTypeTree = indexUpdate(prev.nxTransTypeTree, changedTransformationClass, transformationIndex, "transformTypeTree", copy) - nxTransSelectFromTypeTree = indexUpdate(prev.nxTransSelectFromTypeTree, changedTransformationClass, transformationIndex, "transformSelectFromTypeTree", copy) nxTransBind = indexUpdate(prev.nxTransBind, changedTransformationClass, transformationIndex, "transformBind", copy) nxTransAlternative = indexUpdate(prev.nxTransAlternative, changedTransformationClass, transformationIndex, "transformAlternative", copy) nxTransUnApply = indexUpdate(prev.nxTransUnApply, changedTransformationClass, transformationIndex, "transformUnApply", copy) @@ -409,7 +397,6 @@ object TreeTransforms { var nxPrepTypeApply: Array[Int] = _ var nxPrepLiteral: Array[Int] = _ var nxPrepNew: Array[Int] = _ - var nxPrepPair: Array[Int] = _ var nxPrepTyped: Array[Int] = _ var nxPrepAssign: Array[Int] = _ var nxPrepBlock: Array[Int] = _ @@ -421,7 +408,6 @@ object TreeTransforms { var nxPrepTry: Array[Int] = _ var nxPrepSeqLiteral: Array[Int] = _ var nxPrepTypeTree: Array[Int] = _ - var nxPrepSelectFromTypeTree: Array[Int] = _ var nxPrepBind: Array[Int] = _ var nxPrepAlternative: Array[Int] = _ var nxPrepUnApply: Array[Int] = _ @@ -441,7 +427,6 @@ object TreeTransforms { var nxTransTypeApply: Array[Int] = _ var nxTransLiteral: Array[Int] = _ var nxTransNew: Array[Int] = _ - var nxTransPair: Array[Int] = _ var nxTransTyped: Array[Int] = _ var nxTransAssign: Array[Int] = _ var nxTransBlock: Array[Int] = _ @@ -453,7 +438,6 @@ object TreeTransforms { var nxTransTry: Array[Int] = _ var nxTransSeqLiteral: Array[Int] = _ var nxTransTypeTree: Array[Int] = _ - var nxTransSelectFromTypeTree: Array[Int] = _ var nxTransBind: Array[Int] = _ var nxTransAlternative: Array[Int] = _ var nxTransUnApply: Array[Int] = _ @@ -520,7 +504,6 @@ object TreeTransforms { val prepForApply: Mutator[Apply] = (trans, tree, ctx) => trans.prepareForApply(tree)(ctx) val prepForTypeApply: Mutator[TypeApply] = (trans, tree, ctx) => trans.prepareForTypeApply(tree)(ctx) val prepForNew: Mutator[New] = (trans, tree, ctx) => trans.prepareForNew(tree)(ctx) - val prepForPair: Mutator[Pair] = (trans, tree, ctx) => trans.prepareForPair(tree)(ctx) val prepForTyped: Mutator[Typed] = (trans, tree, ctx) => trans.prepareForTyped(tree)(ctx) val prepForAssign: Mutator[Assign] = (trans, tree, ctx) => trans.prepareForAssign(tree)(ctx) val prepForLiteral: Mutator[Literal] = (trans, tree, ctx) => trans.prepareForLiteral(tree)(ctx) @@ -533,7 +516,6 @@ object TreeTransforms { val prepForTry: Mutator[Try] = (trans, tree, ctx) => trans.prepareForTry(tree)(ctx) val prepForSeqLiteral: Mutator[SeqLiteral] = (trans, tree, ctx) => trans.prepareForSeqLiteral(tree)(ctx) val prepForTypeTree: Mutator[TypeTree] = (trans, tree, ctx) => trans.prepareForTypeTree(tree)(ctx) - val prepForSelectFromTypeTree: Mutator[SelectFromTypeTree] = (trans, tree, ctx) => trans.prepareForSelectFromTypeTree(tree)(ctx) val prepForBind: Mutator[Bind] = (trans, tree, ctx) => trans.prepareForBind(tree)(ctx) val prepForAlternative: Mutator[Alternative] = (trans, tree, ctx) => trans.prepareForAlternative(tree)(ctx) val prepForUnApply: Mutator[UnApply] = (trans, tree, ctx) => trans.prepareForUnApply(tree)(ctx) @@ -638,17 +620,6 @@ object TreeTransforms { } @tailrec - final private[TreeTransforms] def goPair(tree: Pair, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { - if (cur < info.transformers.length) { - val trans = info.transformers(cur) - trans.transformPair(tree)(ctx.withPhase(trans.treeTransformPhase), info) match { - case t: Pair => goPair(t, info.nx.nxTransPair(cur + 1)) - case t => transformSingle(t, cur + 1) - } - } else tree - } - - @tailrec final private[TreeTransforms] def goTyped(tree: Typed, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) @@ -781,17 +752,6 @@ object TreeTransforms { } @tailrec - final private[TreeTransforms] def goSelectFromTypeTree(tree: SelectFromTypeTree, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { - if (cur < info.transformers.length) { - val trans = info.transformers(cur) - trans.transformSelectFromTypeTree(tree)(ctx.withPhase(trans.treeTransformPhase), info) match { - case t: SelectFromTypeTree => goSelectFromTypeTree(t, info.nx.nxTransSelectFromTypeTree(cur + 1)) - case t => transformSingle(t, cur + 1) - } - } else tree - } - - @tailrec final private[TreeTransforms] def goBind(tree: Bind, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) @@ -900,8 +860,6 @@ object TreeTransforms { tree match { case tree: Ident => goIdent(tree, info.nx.nxTransIdent(cur)) case tree: Select => goSelect(tree, info.nx.nxTransSelect(cur)) - case tree: SelectFromTypeTree => - goSelectFromTypeTree(tree, info.nx.nxTransSelectFromTypeTree(cur)) case tree: Bind => goBind(tree, cur) case tree: ValDef if !tree.isEmpty => goValDef(tree, info.nx.nxTransValDef(cur)) case tree: DefDef => goDefDef(tree, info.nx.nxTransDefDef(cur)) @@ -917,7 +875,6 @@ object TreeTransforms { case tree: TypeApply => goTypeApply(tree, info.nx.nxTransTypeApply(cur)) case tree: Literal => goLiteral(tree, info.nx.nxTransLiteral(cur)) case tree: New => goNew(tree, info.nx.nxTransNew(cur)) - case tree: Pair => goPair(tree, info.nx.nxTransPair(cur)) case tree: Typed => goTyped(tree, info.nx.nxTransTyped(cur)) case tree: Assign => goAssign(tree, info.nx.nxTransAssign(cur)) case tree: Block => goBlock(tree, info.nx.nxTransBlock(cur)) @@ -967,13 +924,6 @@ object TreeTransforms { val qual = transform(tree.qualifier, mutatedInfo, cur) goSelect(cpy.Select(tree)(qual, tree.name), mutatedInfo.nx.nxTransSelect(cur)) } - case tree: SelectFromTypeTree => - implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSelectFromTypeTree, info.nx.nxPrepSelectFromTypeTree, tree, cur) - if (mutatedInfo eq null) tree - else { - val qual = transform(tree.qualifier, mutatedInfo, cur) - goSelectFromTypeTree(cpy.SelectFromTypeTree(tree)(qual, tree.name), mutatedInfo.nx.nxTransSelectFromTypeTree(cur)) - } case tree: Bind => implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForBind, info.nx.nxPrepBind, tree, cur) if (mutatedInfo eq null) tree @@ -1052,14 +1002,6 @@ object TreeTransforms { val tpt = transform(tree.tpt, mutatedInfo, cur) goNew(cpy.New(tree)(tpt), mutatedInfo.nx.nxTransNew(cur)) } - case tree: Pair => - implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForPair, info.nx.nxPrepPair, tree, cur) - if (mutatedInfo eq null) tree - else { - val left = transform(tree.left, mutatedInfo, cur) - val right = transform(tree.right, mutatedInfo, cur) - goPair(cpy.Pair(tree)(left, right), mutatedInfo.nx.nxTransPair(cur)) - } case tree: Typed => implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTyped, info.nx.nxPrepTyped, tree, cur) if (mutatedInfo eq null) tree diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 099105de3..55d9fc990 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -24,14 +24,14 @@ import ProtoTypes._ import EtaExpansion._ import Inferencing._ import collection.mutable -import config.Printers._ +import config.Printers.{typr, unapp, overload} import TypeApplications._ import language.implicitConversions object Applications { import tpd._ - def extractorMemberType(tp: Type, name: Name, errorPos: Position = NoPosition)(implicit ctx:Context) = { + def extractorMemberType(tp: Type, name: Name, errorPos: Position = NoPosition)(implicit ctx: Context) = { val ref = tp.member(name).suchThat(_.info.isParameterless) if (ref.isOverloaded) errorType(i"Overloaded reference to $ref is not allowed in extractor", errorPos) @@ -41,12 +41,12 @@ object Applications { ref.info.widenExpr.dealias } - def productSelectorTypes(tp: Type, errorPos: Position = NoPosition)(implicit ctx:Context): List[Type] = { + def productSelectorTypes(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context): List[Type] = { val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos) sels.takeWhile(_.exists).toList } - def productSelectors(tp: Type)(implicit ctx:Context): List[Symbol] = { + def productSelectors(tp: Type)(implicit ctx: Context): List[Symbol] = { val sels = for (n <- Iterator.from(0)) yield tp.member(nme.selectorName(n)).symbol sels.takeWhile(_.exists).toList } @@ -58,7 +58,7 @@ object Applications { else tp :: Nil } else tp :: Nil - def unapplyArgs(unapplyResult: Type, unapplyFn:Tree, args:List[untpd.Tree], pos: Position = NoPosition)(implicit ctx: Context): List[Type] = { + def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: Position = NoPosition)(implicit ctx: Context): List[Type] = { def seqSelector = defn.RepeatedParamType.appliedTo(unapplyResult.elemType :: Nil) def getTp = extractorMemberType(unapplyResult, nme.get, pos) @@ -591,13 +591,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => fun1.tpe match { case ErrorType => tree.withType(ErrorType) - case TryDynamicCallType => - tree match { - case tree @ Apply(Select(qual, name), args) if !isDynamicMethod(name) => - typedDynamicApply(qual, name, args, pt)(tree) - case _ => - handleUnexpectedFunType(tree, fun1) - } + case TryDynamicCallType => typedDynamicApply(tree, pt) case _ => tryEither { implicit ctx => simpleApply(fun1, proto) @@ -658,7 +652,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => /** Overridden in ReTyper to handle primitive operations that can be generated after erasure */ protected def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree = - throw new Error(s"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}") + throw new Error(i"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}") def typedNamedArgs(args: List[untpd.Tree])(implicit ctx: Context) = for (arg @ NamedArg(id, argtpt) <- args) yield { @@ -679,7 +673,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic => } case _ => } - assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs) + def tryDynamicTypeApply(): Tree = typedFn match { + case typedFn: Select if !pt.isInstanceOf[FunProto] => typedDynamicSelect(typedFn, typedArgs, pt) + case _ => tree.withType(TryDynamicCallType) + } + if (typedFn.tpe eq TryDynamicCallType) tryDynamicTypeApply() + else assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs) } /** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray. diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index d77520c77..415cd5d6a 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -26,7 +26,7 @@ import transform.SymUtils._ import Decorators._ import Uniques._ import ErrorReporting.{err, errorType} -import config.Printers._ +import config.Printers.typr import collection.mutable import SymDenotations.NoCompleter @@ -37,7 +37,7 @@ object Checking { * well as for AppliedTypeTree nodes. Also checks that type arguments to * *-type parameters are fully applied. */ - def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type)(implicit ctx: Context) = { + def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type)(implicit ctx: Context): Unit = { (args, boundss).zipped.foreach { (arg, bound) => if (!bound.isHK && arg.tpe.isHK) ctx.error(ex"missing type parameter(s) for $arg", arg.pos) @@ -99,8 +99,6 @@ object Checking { checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply)) case Select(qual, name) if name.isTypeName => checkRealizable(qual.tpe, qual.pos) - case SelectFromTypeTree(qual, name) if name.isTypeName => - checkRealizable(qual.tpe, qual.pos) case SingletonTypeTree(ref) => checkRealizable(ref.tpe, ref.pos) case _ => diff --git a/src/dotty/tools/dotc/typer/Dynamic.scala b/src/dotty/tools/dotc/typer/Dynamic.scala index aeb3cca8c..b5ace87d3 100644 --- a/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/src/dotty/tools/dotc/typer/Dynamic.scala @@ -2,15 +2,14 @@ package dotty.tools package dotc package typer -import dotty.tools.dotc.ast.Trees.NamedArg -import dotty.tools.dotc.ast.tpd._ +import dotty.tools.dotc.ast.Trees._ +import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Names.Name import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Types._ -import dotty.tools.dotc.core.Mode import dotty.tools.dotc.core.Decorators._ object Dynamic { @@ -28,44 +27,78 @@ object Dynamic { * The first matching rule of is applied. */ trait Dynamic { self: Typer with Applications => + import Dynamic._ + import tpd._ /** Translate selection that does not typecheck according to the normal rules into a applyDynamic/applyDynamicNamed. - * foo.bar(baz0, baz1, ...) ~~> foo.applyDynamic(bar)(baz0, baz1, ...) - * foo.bar(x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed("bar")(("x", bazX), ("y", bazY), ("", baz), ...) + * foo.bar(baz0, baz1, ...) ~~> foo.applyDynamic(bar)(baz0, baz1, ...) + * foo.bar[T0, ...](baz0, baz1, ...) ~~> foo.applyDynamic[T0, ...](bar)(baz0, baz1, ...) + * foo.bar(x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed("bar")(("x", bazX), ("y", bazY), ("", baz), ...) + * foo.bar[T0, ...](x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed[T0, ...]("bar")(("x", bazX), ("y", bazY), ("", baz), ...) */ - def typedDynamicApply(qual: untpd.Tree, name: Name, args: List[untpd.Tree], pt: Type)(original: untpd.Apply)( - implicit ctx: Context): Tree = { - def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false } - val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic - if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args)) { - ctx.error("applyDynamicNamed does not support passing a vararg parameter", original.pos) - original.withType(ErrorType) - } else { - def namedArgTuple(name: String, arg: untpd.Tree) = untpd.Tuple(List(Literal(Constant(name)), arg)) - def namedArgs = args.map { - case NamedArg(argName, arg) => namedArgTuple(argName.toString, arg) - case arg => namedArgTuple("", arg) + def typedDynamicApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { + def typedDynamicApply(qual: untpd.Tree, name: Name, targs: List[untpd.Tree]): Tree = { + def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false } + val args = tree.args + val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic + if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args)) { + ctx.error("applyDynamicNamed does not support passing a vararg parameter", tree.pos) + tree.withType(ErrorType) + } else { + def namedArgTuple(name: String, arg: untpd.Tree) = untpd.Tuple(List(Literal(Constant(name)), arg)) + def namedArgs = args.map { + case NamedArg(argName, arg) => namedArgTuple(argName.toString, arg) + case arg => namedArgTuple("", arg) + } + val args1 = if (dynName == nme.applyDynamic) args else namedArgs + typedApply(untpd.Apply(coreDynamic(qual, dynName, name, targs), args1), pt) } - val args1 = if (dynName == nme.applyDynamic) args else namedArgs - typedApply(untpd.Apply(coreDynamic(qual, dynName, name), args1), pt) + } + + tree.fun match { + case Select(qual, name) if !isDynamicMethod(name) => + typedDynamicApply(qual, name, Nil) + case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) => + typedDynamicApply(qual, name, targs) + case TypeApply(fun, targs) => + typedDynamicApply(fun, nme.apply, targs) + case fun => + typedDynamicApply(fun, nme.apply, Nil) } } /** Translate selection that does not typecheck according to the normal rules into a selectDynamic. - * foo.bar ~~> foo.selectDynamic(bar) + * foo.bar ~~> foo.selectDynamic(bar) + * foo.bar[T0, ...] ~~> foo.selectDynamic[T0, ...](bar) * * Note: inner part of translation foo.bar(baz) = quux ~~> foo.selectDynamic(bar).update(baz, quux) is achieved * through an existing transformation of in typedAssign [foo.bar(baz) = quux ~~> foo.bar.update(baz, quux)]. */ - def typedDynamicSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = - typedApply(coreDynamic(tree.qualifier, nme.selectDynamic, tree.name), pt) + def typedDynamicSelect(tree: untpd.Select, targs: List[Tree], pt: Type)(implicit ctx: Context): Tree = + typedApply(coreDynamic(tree.qualifier, nme.selectDynamic, tree.name, targs), pt) /** Translate selection that does not typecheck according to the normal rules into a updateDynamic. * foo.bar = baz ~~> foo.updateDynamic(bar)(baz) */ - def typedDynamicAssign(qual: untpd.Tree, name: Name, rhs: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = - typedApply(untpd.Apply(coreDynamic(qual, nme.updateDynamic, name), rhs), pt) + def typedDynamicAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context): Tree = { + def typedDynamicAssign(qual: untpd.Tree, name: Name, targs: List[untpd.Tree]): Tree = + typedApply(untpd.Apply(coreDynamic(qual, nme.updateDynamic, name, targs), tree.rhs), pt) + tree.lhs match { + case Select(qual, name) if !isDynamicMethod(name) => + typedDynamicAssign(qual, name, Nil) + case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) => + typedDynamicAssign(qual, name, targs) + case _ => + ctx.error("reassignment to val", tree.pos) + tree.withType(ErrorType) + } + } - private def coreDynamic(qual: untpd.Tree, dynName: Name, name: Name)(implicit ctx: Context): untpd.Apply = - untpd.Apply(untpd.Select(qual, dynName), Literal(Constant(name.toString))) + private def coreDynamic(qual: untpd.Tree, dynName: Name, name: Name, targs: List[untpd.Tree])(implicit ctx: Context): untpd.Apply = { + val select = untpd.Select(qual, dynName) + val selectWithTypes = + if (targs.isEmpty) select + else untpd.TypeApply(select, targs) + untpd.Apply(selectWithTypes, Literal(Constant(name.toString))) + } } diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala index e193b126a..4ce24b633 100644 --- a/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -7,7 +7,8 @@ import Contexts._ import Symbols._ import dotty.tools.dotc.parsing.JavaParsers.JavaParser import parsing.Parsers.Parser -import config.Printers._ +import config.Config +import config.Printers.{typr, default} import util.Stats._ import scala.util.control.NonFatal import ast.Trees._ @@ -34,6 +35,8 @@ class FrontEnd extends Phase { else new Parser(unit.source).parse() val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr printer.println("parsed:\n" + unit.untpdTree.show) + if (Config.checkPositions) + unit.untpdTree.checkPos(nonOverlapping = !unit.isJava && !ctx.reporter.hasErrors) } def enterSyms(implicit ctx: Context) = monitor("indexing") { diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 0a3307140..ef32e0ba6 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -28,7 +28,7 @@ import Inferencing.fullyDefinedType import Trees._ import Hashable._ import config.Config -import config.Printers._ +import config.Printers.{implicits, implicitsDetailed} import collection.mutable /** Implicit resolution */ @@ -801,14 +801,15 @@ class SearchHistory(val searchDepth: Int, val seen: Map[ClassSymbol, Int]) { def updateMap(csyms: List[ClassSymbol], seen: Map[ClassSymbol, Int]): SearchHistory = csyms match { case csym :: csyms1 => seen get csym match { + // proto complexity is >= than the last time it was seen → diverge case Some(prevSize) if size >= prevSize => this case _ => updateMap(csyms1, seen.updated(csym, size)) } - case nil => - if (csyms.isEmpty) this - else new SearchHistory(searchDepth + 1, seen) + case _ => + new SearchHistory(searchDepth + 1, seen) } - updateMap(proto.classSymbols, seen) + if (proto.classSymbols.isEmpty) this + else updateMap(proto.classSymbols, seen) } } } diff --git a/src/dotty/tools/dotc/typer/ImportInfo.scala b/src/dotty/tools/dotc/typer/ImportInfo.scala index 2ca90311f..3aa289181 100644 --- a/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -60,10 +60,11 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], val isRootImp def recur(sels: List[untpd.Tree]): Unit = sels match { case sel :: sels1 => sel match { - case Pair(Ident(name: TermName), Ident(nme.WILDCARD)) => + case Thicket(Ident(name: TermName) :: Ident(nme.WILDCARD) :: Nil) => myExcluded += name - case Pair(Ident(from: TermName), Ident(to: TermName)) => + case Thicket(Ident(from: TermName) :: Ident(to: TermName) :: Nil) => myMapped = myMapped.updated(to, from) + myExcluded += from myOriginals += from case Ident(nme.WILDCARD) => myWildcardImport = true @@ -98,7 +99,7 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], val isRootImp lazy val hiddenRoot: Symbol = { val sym = site.termSymbol def hasMaskingSelector = selectors exists { - case Pair(_, Ident(nme.WILDCARD)) => true + case Thicket(_ :: Ident(nme.WILDCARD) :: Nil) => true case _ => false } if ((defn.RootImportTypes exists (_.symbol == sym)) && hasMaskingSelector) sym else NoSymbol diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 719e8d7fc..9a1a42e44 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -15,7 +15,7 @@ import util.{Stats, SimpleMap} import util.common._ import Decorators._ import Uniques._ -import config.Printers._ +import config.Printers.{typr, constr} import annotation.tailrec import reporting._ import collection.mutable diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index d90f37860..cfd49fd87 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -15,7 +15,7 @@ import annotation.tailrec import ErrorReporting._ import tpd.ListOfTreeDecorator import config.Config -import config.Printers._ +import config.Printers.{typr, completions, noPrinter} import Annotations._ import Inferencing._ import transform.ValueClasses._ @@ -273,6 +273,7 @@ class Namer { typer: Typer => } val inSuperCall = if (ctx.mode is Mode.InSuperCall) InSuperCall else EmptyFlags + tree match { case tree: TypeDef if tree.isClassDef => val name = checkNoConflict(tree.name.encode).asTypeName @@ -280,7 +281,7 @@ class Namer { typer: Typer => val cls = recordSym(ctx.newClassSymbol( ctx.owner, name, flags | inSuperCall, cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree), - privateWithinClass(tree.mods), tree.pos, ctx.source.file), tree) + privateWithinClass(tree.mods), tree.namePos, ctx.source.file), tree) cls.completer.asInstanceOf[ClassCompleter].init() cls case tree: MemberDef => @@ -315,7 +316,7 @@ class Namer { typer: Typer => recordSym(ctx.newSymbol( ctx.owner, name, flags | deferred | method | higherKinded | inSuperCall1, adjustIfModule(completer, tree), - privateWithinClass(tree.mods), tree.pos), tree) + privateWithinClass(tree.mods), tree.namePos), tree) case tree: Import => recordSym(ctx.newSymbol( ctx.owner, nme.IMPORT, Synthetic, new Completer(tree), NoSymbol, tree.pos), tree) diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index f209c99be..80f0fd186 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -15,7 +15,7 @@ import util.common._ import Decorators._ import Uniques._ import ErrorReporting.errorType -import config.Printers._ +import config.Printers.typr import collection.mutable object ProtoTypes { @@ -182,6 +182,8 @@ object ProtoTypes { if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this else new FunProto(args, resultType, typer) + override def notApplied = WildcardType + /** Forget the types of any arguments that have been typed producing a constraint in a * typer state that is not yet committed into the one of the current context `ctx`. * This is necessary to avoid "orphan" PolyParams that are referred to from @@ -319,6 +321,8 @@ object ProtoTypes { if ((targs eq this.targs) && (resType eq this.resType)) this else PolyProto(targs, resType) + override def notApplied = WildcardType + def map(tm: TypeMap)(implicit ctx: Context): PolyProto = derivedPolyProto(targs mapConserve tm, tm(resultType)) diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala index a4f92271a..9750957bf 100644 --- a/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/src/dotty/tools/dotc/typer/ReTyper.scala @@ -38,12 +38,6 @@ class ReTyper extends Typer { untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt) } - override def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): Tree = { - assert(tree.hasType) - val qual1 = typed(tree.qualifier, AnySelectionProto) - untpd.cpy.SelectFromTypeTree(tree)(qual1, tree.name).withType(tree.typeOpt) - } - override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal = promote(tree) diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala index 2838866fd..1f150c519 100644 --- a/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/src/dotty/tools/dotc/typer/RefChecks.scala @@ -525,7 +525,7 @@ object RefChecks { subclassMsg(concreteSym, abstractSym) else "" - undefined(s"\n(Note that $pa does not match $pc$addendum)") + undefined(s"\n(Note that ${pa.show} does not match ${pc.show}$addendum)") case xs => undefined(s"\n(The class implements a member with a different type: ${concrete.showDcl})") } diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 36404a68f..ba8f35cd8 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -8,7 +8,7 @@ import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._ import TypeApplications.AppliedType import util.Positions._ -import config.Printers._ +import config.Printers.typr import ast.Trees._ import NameOps._ import collection.mutable @@ -81,10 +81,11 @@ trait TypeAssigner { parentType.findMember(decl.name, info.cls.thisType, Private) .suchThat(decl.matches(_)) val inheritedInfo = inherited.info - if (inheritedInfo.exists && decl.info <:< inheritedInfo && !(inheritedInfo <:< decl.info)) - typr.echo( - i"add ref $parent $decl --> ", - RefinedType(parent, decl.name, decl.info)) + if (inheritedInfo.exists && decl.info <:< inheritedInfo && !(inheritedInfo <:< decl.info)) { + val r = RefinedType(parent, decl.name, decl.info) + typr.println(i"add ref $parent $decl --> " + r) + r + } else parent } @@ -168,7 +169,9 @@ trait TypeAssigner { val d2 = pre.nonPrivateMember(name) if (reallyExists(d2) && firstTry) test(tpe.shadowed.withDenot(d2), false) - else { + else if (pre.derivesFrom(defn.DynamicClass)) { + TryDynamicCallType + } else { val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists) val what = alts match { case Nil => @@ -260,9 +263,6 @@ trait TypeAssigner { tree.withType(tp) } - def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) = - tree.withType(accessibleSelectionType(tree, qual)) - def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context) = tree.withType(tpt.tpe) @@ -321,21 +321,30 @@ trait TypeAssigner { case pt: PolyType => val paramNames = pt.paramNames if (hasNamedArg(args)) { - val argMap = new mutable.HashMap[Name, Type] + // Type arguments which are specified by name (immutable after this first loop) + val namedArgMap = new mutable.HashMap[Name, Type] for (NamedArg(name, arg) <- args) - if (argMap.contains(name)) + if (namedArgMap.contains(name)) ctx.error("duplicate name", arg.pos) else if (!paramNames.contains(name)) ctx.error(s"undefined parameter name, required: ${paramNames.mkString(" or ")}", arg.pos) else - argMap(name) = arg.tpe + namedArgMap(name) = arg.tpe + + // Holds indexes of non-named typed arguments in paramNames val gapBuf = new mutable.ListBuffer[Int] - def nextPoly = { - val idx = gapBuf.length + def nextPoly(idx: Int) = { + val newIndex = gapBuf.length gapBuf += idx - PolyParam(pt, idx) + // Re-index unassigned type arguments that remain after transformation + PolyParam(pt, newIndex) } - val normArgs = paramNames.map(pname => argMap.getOrElse(pname, nextPoly)) + + // Type parameters after naming assignment, conserving paramNames order + val normArgs: List[Type] = paramNames.zipWithIndex.map { case (pname, idx) => + namedArgMap.getOrElse(pname, nextPoly(idx)) + } + val transform = new TypeMap { def apply(t: Type) = t match { case PolyParam(`pt`, idx) => normArgs(idx) @@ -347,25 +356,23 @@ trait TypeAssigner { else { val gaps = gapBuf.toList pt.derivedPolyType( - gaps.map(paramNames.filterNot(argMap.contains)), + gaps.map(paramNames), gaps.map(idx => transform(pt.paramBounds(idx)).bounds), resultType1) } } else { val argTypes = args.tpes - if (sameLength(argTypes, paramNames)|| ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes) + if (sameLength(argTypes, paramNames) || ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes) else wrongNumberOfArgs(fn.tpe, "type ", pt.paramNames.length, tree.pos) } case _ => errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos) } + tree.withType(ownType) } - def assignType(tree: untpd.Pair, left: Tree, right: Tree)(implicit ctx: Context) = - tree.withType(defn.PairType.appliedTo(left.tpe :: right.tpe :: Nil)) - def assignType(tree: untpd.Typed, tpt: Tree)(implicit ctx: Context) = tree.withType(tpt.tpe) @@ -383,8 +390,8 @@ trait TypeAssigner { def assignType(tree: untpd.Closure, meth: Tree, target: Tree)(implicit ctx: Context) = tree.withType( - if (target.isEmpty) meth.tpe.widen.toFunctionType(tree.env.length) - else target.tpe) + if (target.isEmpty) meth.tpe.widen.toFunctionType(tree.env.length) + else target.tpe) def assignType(tree: untpd.CaseDef, body: Tree)(implicit ctx: Context) = tree.withType(body.tpe) @@ -487,7 +494,7 @@ trait TypeAssigner { def assignType(tree: untpd.Import, sym: Symbol)(implicit ctx: Context) = tree.withType(sym.nonMemberTermRef) - def assignType(tree: untpd.Annotated, annot: Tree, arg: Tree)(implicit ctx: Context) = + def assignType(tree: untpd.Annotated, arg: Tree, annot: Tree)(implicit ctx: Context) = tree.withType(AnnotatedType(arg.tpe.widen, Annotation(annot))) def assignType(tree: untpd.PackageDef, pid: Tree)(implicit ctx: Context) = diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index fdcfe347b..562af75f6 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -31,7 +31,7 @@ import collection.mutable import annotation.tailrec import Implicits._ import util.Stats.{track, record} -import config.Printers._ +import config.Printers.{typr, gadts} import rewrite.Rewrites.patch import NavigateAST._ import transform.SymUtils._ @@ -72,6 +72,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit */ private var importedFromRoot: Set[Symbol] = Set() + /** Temporary data item for single call to typed ident: + * This symbol would be found under Scala2 mode, but is not + * in dotty (because dotty conforms to spec section 2 + * wrt to package member resolution but scalac doe not). + */ + private var foundUnderScala2: Type = NoType + def newLikeThis: Typer = new Typer /** Attribute an identifier consisting of a simple name or wildcard @@ -133,14 +140,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * imported by <tree> * or defined in <symbol> */ - def bindingString(prec: Int, whereFound: Context, qualifier: String = "") = + def bindingString(prec: Int, whereFound: Context, qualifier: String = "")(implicit ctx: Context) = if (prec == wildImport || prec == namedImport) ex"imported$qualifier by ${whereFound.importInfo}" else ex"defined$qualifier in ${whereFound.owner}" /** Check that any previously found result from an inner context * does properly shadow the new one from an outer context. + * @param found The newly found result + * @param newPrec Its precedence + * @param scala2pkg Special mode where we check members of the same package, but defined + * in different compilation units under Scala2. If set, and the + * previous and new contexts do not have the same scope, we select + * the previous (inner) definition. This models what scalac does. */ - def checkNewOrShadowed(found: Type, newPrec: Int): Type = + def checkNewOrShadowed(found: Type, newPrec: Int, scala2pkg: Boolean = false)(implicit ctx: Context): Type = if (!previous.exists || ctx.typeComparer.isSameRef(previous, found)) found else if ((prevCtx.scope eq ctx.scope) && (newPrec == definition || @@ -150,7 +163,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit found } else { - if (!previous.isError && !found.isError) { + if (!scala2pkg && !previous.isError && !found.isError) { error( ex"""reference to $name is ambiguous; |it is both ${bindingString(newPrec, ctx, "")} @@ -163,7 +176,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit /** The type representing a named import with enclosing name when imported * from given `site` and `selectors`. */ - def namedImportRef(site: Type, selectors: List[untpd.Tree]): Type = { + def namedImportRef(site: Type, selectors: List[untpd.Tree])(implicit ctx: Context): Type = { def checkUnambiguous(found: Type) = { val other = namedImportRef(site, selectors.tail) if (other.exists && found.exists && (found != other)) @@ -173,15 +186,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val Name = name.toTermName.decode selectors match { - case Pair(Ident(from), Ident(Name)) :: rest => - val selName = if (name.isTypeName) from.toTypeName else from - // Pass refctx so that any errors are reported in the context of the - // reference instead of the context of the import. - checkUnambiguous(selectionType(site, selName, tree.pos)(refctx)) - case Ident(Name) :: rest => - checkUnambiguous(selectionType(site, name, tree.pos)(refctx)) - case _ :: rest => - namedImportRef(site, rest) + case selector :: rest => + selector match { + case Thicket(fromId :: Ident(Name) :: _) => + val Ident(from) = fromId + val selName = if (name.isTypeName) from.toTypeName else from + // Pass refctx so that any errors are reported in the context of the + // reference instead of the context of the import. + checkUnambiguous(selectionType(site, selName, tree.pos)(refctx)) + case Ident(Name) => + checkUnambiguous(selectionType(site, name, tree.pos)(refctx)) + case _ => + namedImportRef(site, rest) + } case nil => NoType } @@ -190,7 +207,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit /** The type representing a wildcard import with enclosing name when imported * from given import info */ - def wildImportRef(imp: ImportInfo): Type = { + def wildImportRef(imp: ImportInfo)(implicit ctx: Context): Type = { if (imp.isWildcardImport) { val pre = imp.site if (!isDisabled(imp, pre) && !(imp.excluded contains name.toTermName) && name != nme.CONSTRUCTOR) { @@ -204,54 +221,71 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit /** Is (some alternative of) the given predenotation `denot` * defined in current compilation unit? */ - def isDefinedInCurrentUnit(denot: Denotation): Boolean = denot match { + def isDefinedInCurrentUnit(denot: Denotation)(implicit ctx: Context): Boolean = denot match { case MultiDenotation(d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2) case denot: SingleDenotation => denot.symbol.sourceFile == ctx.source.file } /** Is `denot` the denotation of a self symbol? */ - def isSelfDenot(denot: Denotation) = denot match { + def isSelfDenot(denot: Denotation)(implicit ctx: Context) = denot match { case denot: SymDenotation => denot is SelfName case _ => false } - // begin findRef - if (ctx.scope == null) previous - else { - val outer = ctx.outer - if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) { - val defDenot = ctx.denotNamed(name) - if (qualifies(defDenot)) { - val curOwner = ctx.owner - val found = - if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType - else curOwner.thisType.select(name, defDenot) - if (!(curOwner is Package) || isDefinedInCurrentUnit(defDenot)) - return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry - else if (defDenot.symbol is Package) - return checkNewOrShadowed(previous orElse found, packageClause) - else if (prevPrec < packageClause) - return findRef(found, packageClause, ctx)(outer) + /** Would import of kind `prec` be not shadowed by a nested higher-precedence definition? */ + def isPossibleImport(prec: Int)(implicit ctx: Context) = + prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope) + + @tailrec def loop(implicit ctx: Context): Type = { + if (ctx.scope == null) previous + else { + val outer = ctx.outer + var result: Type = NoType + + // find definition + if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) { + val defDenot = ctx.denotNamed(name) + if (qualifies(defDenot)) { + val curOwner = ctx.owner + val found = + if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType + else curOwner.thisType.select(name, defDenot) + if (!(curOwner is Package) || isDefinedInCurrentUnit(defDenot)) + result = checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry + else { + if (ctx.scala2Mode && !foundUnderScala2.exists) + foundUnderScala2 = checkNewOrShadowed(found, definition, scala2pkg = true) + if (defDenot.symbol is Package) + result = checkNewOrShadowed(previous orElse found, packageClause) + else if (prevPrec < packageClause) + result = findRef(found, packageClause, ctx)(outer) + } + } } - } - val curImport = ctx.importInfo - if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) - return previous // no more conflicts possible in this case - // would import of kind `prec` be not shadowed by a nested higher-precedence definition? - def isPossibleImport(prec: Int) = - prevPrec < prec || prevPrec == prec && (prevCtx.scope eq ctx.scope) - if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && !curImport.sym.isCompleting) { - val namedImp = namedImportRef(curImport.site, curImport.selectors) - if (namedImp.exists) - return findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer) - if (isPossibleImport(wildImport)) { - val wildImp = wildImportRef(curImport) - if (wildImp.exists) - return findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer) + + if (result.exists) result + else { // find import + val curImport = ctx.importInfo + if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) + previous // no more conflicts possible in this case + else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && !curImport.sym.isCompleting) { + val namedImp = namedImportRef(curImport.site, curImport.selectors) + if (namedImp.exists) + findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer) + else if (isPossibleImport(wildImport)) { + val wildImp = wildImportRef(curImport) + if (wildImp.exists) + findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer) + else loop(outer) + } + else loop(outer) + } + else loop(outer) } } - findRef(previous, prevPrec, prevCtx)(outer) } + + loop } // begin typedIdent @@ -264,12 +298,28 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit return typed(desugar.patternVar(tree), pt) } - val saved = importedFromRoot - importedFromRoot = Set.empty - val rawType = - try findRef(NoType, BindingPrec.nothingBound, NoContext) - finally importedFromRoot = saved + val rawType = { + val saved1 = importedFromRoot + val saved2 = foundUnderScala2 + importedFromRoot = Set.empty + foundUnderScala2 = NoType + try { + var found = findRef(NoType, BindingPrec.nothingBound, NoContext) + if (foundUnderScala2.exists && !(foundUnderScala2 =:= found)) { + ctx.migrationWarning( + ex"""Name resolution will change. + | currently selected : $foundUnderScala2 + | in the future, without -language:Scala2: $found""", tree.pos) + found = foundUnderScala2 + } + found + } + finally { + importedFromRoot = saved1 + foundUnderScala2 = saved2 + } + } val ownType = if (rawType.exists) @@ -313,55 +363,42 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit else tree def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") { - def asSelect(implicit ctx: Context): Tree = { + def typeSelectOnTerm(implicit ctx: Context): Tree = { val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt, this)) if (tree.name.isTypeName) checkStable(qual1.tpe, qual1.pos) val select = typedSelect(tree, pt, qual1) - pt match { - case _: FunProto | AssignProto => select - case _ => - if (select.tpe eq TryDynamicCallType) typedDynamicSelect(tree, pt) - else select - } - } - - def asJavaSelectFromTypeTree(implicit ctx: Context): Tree = { - // Translate names in Select/Ident nodes to type names. - def convertToTypeName(tree: untpd.Tree): Option[untpd.Tree] = tree match { - case Select(qual, name) => Some(untpd.Select(qual, name.toTypeName)) - case Ident(name) => Some(untpd.Ident(name.toTypeName)) - case _ => None - } + if (select.tpe ne TryDynamicCallType) select + else if (pt.isInstanceOf[PolyProto] || pt.isInstanceOf[FunProto] || pt == AssignProto) select + else typedDynamicSelect(tree, Nil, pt) + } - // Try to convert Select(qual, name) to a SelectFromTypeTree. - def convertToSelectFromType(qual: untpd.Tree, origName: Name): Option[untpd.SelectFromTypeTree] = - convertToTypeName(qual) match { - case Some(qual1) => Some(untpd.SelectFromTypeTree(qual1 withPos qual.pos, origName.toTypeName)) - case _ => None - } + def typeSelectOnType(qual: untpd.Tree)(implicit ctx: Context) = + typedSelect(untpd.cpy.Select(tree)(qual, tree.name.toTypeName), pt) - convertToSelectFromType(tree.qualifier, tree.name) match { - case Some(sftt) => typedSelectFromTypeTree(sftt, pt) - case _ => ctx.error(em"Could not convert $tree to a SelectFromTypeTree"); EmptyTree - } + def tryJavaSelectOnType(implicit ctx: Context): Tree = tree.qualifier match { + case Select(qual, name) => typeSelectOnType(untpd.Select(qual, name.toTypeName)) + case Ident(name) => typeSelectOnType(untpd.Ident(name.toTypeName)) + case _ => errorTree(tree, "cannot convert to type selection") // will never be printed due to fallback } - def selectWithFallback(fallBack: => Tree) = - tryEither(tryCtx => asSelect(tryCtx))((_, _) => fallBack) + def selectWithFallback(fallBack: Context => Tree) = + tryAlternatively(typeSelectOnTerm(_))(fallBack) - if (ctx.compilationUnit.isJava && tree.name.isTypeName) + if (tree.qualifier.isType) { + val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this)) + assignType(cpy.Select(tree)(qual1, tree.name), qual1) + } + else if (ctx.compilationUnit.isJava && tree.name.isTypeName) // SI-3120 Java uses the same syntax, A.B, to express selection from the // value A and from the type A. We have to try both. - selectWithFallback(asJavaSelectFromTypeTree(ctx)) + selectWithFallback(tryJavaSelectOnType(_)) // !!! possibly exponential bcs of qualifier retyping else if (tree.name == nme.withFilter && tree.getAttachment(desugar.MaybeFilter).isDefined) - selectWithFallback(typedSelect(untpd.cpy.Select(tree)(tree.qualifier, nme.filter), pt)) + selectWithFallback { + implicit ctx => + typedSelect(untpd.cpy.Select(tree)(tree.qualifier, nme.filter), pt) // !!! possibly exponential bcs of qualifier retyping + } else - asSelect(ctx) - } - - def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): Tree = track("typedSelectFromTypeTree") { - val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this)) - assignType(cpy.SelectFromTypeTree(tree)(qual1, tree.name), qual1) + typeSelectOnTerm(ctx) } def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = track("typedThis") { @@ -405,16 +442,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } - def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = track("typedPair") { - val (leftProto, rightProto) = pt.argTypesLo match { - case l :: r :: Nil if pt isRef defn.PairClass => (l, r) - case _ => (WildcardType, WildcardType) - } - val left1 = typed(tree.left, leftProto) - val right1 = typed(tree.right, rightProto) - assignType(cpy.Pair(tree)(left1, right1), left1, right1) - } - def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = track("typedTyped") { /* Handles three cases: * @param ifPat how to handle a pattern (_: T) @@ -518,11 +545,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit reassignmentToVal } case TryDynamicCallType => - tree match { - case Assign(Select(qual, name), rhs) if !isDynamicMethod(name) => - typedDynamicAssign(qual, name, rhs, pt) - case _ => reassignmentToVal - } + typedDynamicAssign(tree, pt) case tpe => reassignmentToVal } @@ -533,7 +556,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") { val exprCtx = index(tree.stats) val stats1 = typedStats(tree.stats, ctx.owner) - val expr1 = typedExpr(tree.expr, pt)(exprCtx) + val ept = + if (tree.isInstanceOf[untpd.InfixOpBlock]) + // Right-binding infix operations are expanded to InfixBlocks, which may be followed by arguments. + // Example: `(a /: bs)(op)` expands to `{ val x = a; bs./:(x) } (op)` where `{...}` is an InfixBlock. + pt + else pt.notApplied + val expr1 = typedExpr(tree.expr, ept)(exprCtx) ensureNoLocalRefs( assignType(cpy.Block(tree)(stats1, expr1), stats1, expr1), pt, localSyms(stats1)) } @@ -580,8 +609,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = track("typedIf") { val cond1 = typed(tree.cond, defn.BooleanType) - val thenp1 = typed(tree.thenp, pt) - val elsep1 = typed(tree.elsep orElse (untpd.unitLiteral withPos tree.pos), pt) + val thenp1 = typed(tree.thenp, pt.notApplied) + val elsep1 = typed(tree.elsep orElse (untpd.unitLiteral withPos tree.pos), pt.notApplied) val thenp2 :: elsep2 :: Nil = harmonize(thenp1 :: elsep1 :: Nil) assignType(cpy.If(tree)(cond1, thenp2, elsep2), thenp2, elsep2) } @@ -754,7 +783,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val selType = widenForMatchSelector( fullyDefinedType(sel1.tpe, "pattern selector", tree.pos)) - val cases1 = typedCases(tree.cases, selType, pt) + val cases1 = typedCases(tree.cases, selType, pt.notApplied) val cases2 = harmonize(cases1).asInstanceOf[List[CaseDef]] assignType(cpy.Match(tree)(sel1, cases2), cases2) } @@ -881,8 +910,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") { - val expr1 = typed(tree.expr, pt) - val cases1 = typedCases(tree.cases, defn.ThrowableType, pt) + val expr1 = typed(tree.expr, pt.notApplied) + val cases1 = typedCases(tree.cases, defn.ThrowableType, pt.notApplied) val finalizer1 = typed(tree.finalizer, defn.UnitType) val expr2 :: cases2x = harmonize(expr1 :: cases1) val cases2 = cases2x.asInstanceOf[List[CaseDef]] @@ -1104,7 +1133,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (sym.is(Lazy, butNot = Deferred | Module | Synthetic) && !sym.isVolatile && ctx.scala2Mode && ctx.settings.rewrite.value.isDefined && !ctx.isAfterTyper) - patch(Position(toUntyped(vdef).envelope.start), "@volatile ") + patch(Position(toUntyped(vdef).pos.start), "@volatile ") } def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") { @@ -1297,7 +1326,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val annot1 = typedExpr(tree.annot, defn.AnnotationType) val arg1 = typed(tree.arg, pt) if (ctx.mode is Mode.Type) - assignType(cpy.Annotated(tree)(annot1, arg1), annot1, arg1) + assignType(cpy.Annotated(tree)(arg1, annot1), arg1, annot1) else { val tpt = TypeTree(AnnotatedType(arg1.tpe.widen, Annotation(annot1))) assignType(cpy.Typed(tree)(arg1, tpt), tpt) @@ -1354,7 +1383,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tree match { case tree: untpd.Ident => typedIdent(tree, pt) case tree: untpd.Select => typedSelect(tree, pt) - case tree: untpd.SelectFromTypeTree => typedSelectFromTypeTree(tree, pt) case tree: untpd.Bind => typedBind(tree, pt) case tree: untpd.ValDef => if (tree.isEmpty) tpd.EmptyValDef @@ -1377,7 +1405,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case tree: untpd.This => typedThis(tree) case tree: untpd.Literal => typedLiteral(tree) case tree: untpd.New => typedNew(tree, pt) - case tree: untpd.Pair => typedPair(tree, pt) case tree: untpd.Typed => typedTyped(tree, pt) case tree: untpd.NamedArg => typedNamedArg(tree, pt) case tree: untpd.Assign => typedAssign(tree, pt) @@ -1478,6 +1505,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } + /** Try `op1`, if there are errors, try `op2`, if `op2` also causes errors, fall back + * to errors and result of `op1`. + */ + def tryAlternatively[T](op1: Context => T)(op2: Context => T)(implicit ctx: Context): T = + tryEither(op1) { (failedVal, failedState) => + tryEither(op2) { (_, _) => + failedState.commit + failedVal + } + } + /** Add apply node or implicit conversions. Two strategies are tried, and the first * that is successful is picked. If neither of the strategies are successful, continues with * `fallBack`. @@ -1496,8 +1534,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } /** If this tree is a select node `qual.name`, try to insert an implicit conversion - * `c` around `qual` so that `c(qual).name` conforms to `pt`. If that fails - * return `tree` itself. + * `c` around `qual` so that `c(qual).name` conforms to `pt`. */ def tryInsertImplicitOnQualifier(tree: Tree, pt: Type)(implicit ctx: Context): Option[Tree] = ctx.traceIndented(i"try insert impl on qualifier $tree $pt") { tree match { diff --git a/src/dotty/tools/dotc/typer/VarianceChecker.scala b/src/dotty/tools/dotc/typer/VarianceChecker.scala index 274218ee3..d5dd5a024 100644 --- a/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -132,11 +132,11 @@ class VarianceChecker()(implicit ctx: Context) { case defn: MemberDef if skip => ctx.debuglog(s"Skipping variance check of ${sym.showDcl}") case tree: TypeDef => - checkVariance(sym, tree.envelope) + checkVariance(sym, tree.pos) case tree: ValDef => - checkVariance(sym, tree.envelope) + checkVariance(sym, tree.pos) case DefDef(_, tparams, vparamss, _, _) => - checkVariance(sym, tree.envelope) + checkVariance(sym, tree.pos) tparams foreach traverse vparamss foreach (_ foreach traverse) case Template(_, _, _, body) => diff --git a/test/test/parsePackage.scala b/test/test/parsePackage.scala index bef7bbe06..6fa5c0f86 100644 --- a/test/test/parsePackage.scala +++ b/test/test/parsePackage.scala @@ -23,8 +23,8 @@ object parsePackage extends ParserTest { TypedSplice(t) case SymbolLit(str) => tree - case InterpolatedString(id, parts, elems) => - InterpolatedString(id, parts map (transformSub(_)), elems map transform) + case InterpolatedString(id, segments) => + InterpolatedString(id, segments map transform) case mdef @ ModuleDef(name, impl) => ModuleDef(name, transformSub(impl)).withMods(mdef.mods) case Function(params, body) => diff --git a/tests/pending/hkt/compiler.error b/tests/disabled/not-representable/hkt/compiler.error index b31760891..b31760891 100644 --- a/tests/pending/hkt/compiler.error +++ b/tests/disabled/not-representable/hkt/compiler.error diff --git a/tests/pending/hkt/hkt.scala b/tests/disabled/not-representable/hkt/hkt.scala index 34858cd95..1a9932d73 100644 --- a/tests/pending/hkt/hkt.scala +++ b/tests/disabled/not-representable/hkt/hkt.scala @@ -1,3 +1,6 @@ +// This one is unavoidable. Dotty does not allow several overloaded +// parameterless methods, so it picks the one in the subclass. + import scala.language.higherKinds // Minimal reproduction for: // scala.collection.mutable.ArrayStack.empty[Int] diff --git a/tests/pending/run/t2337.scala b/tests/disabled/not-representable/t2337.scala index edb574cba..9e3b8c555 100644 --- a/tests/pending/run/t2337.scala +++ b/tests/disabled/not-representable/t2337.scala @@ -1,4 +1,4 @@ - +// Failure of autotupling in the presence of overloaded functions. object Test { def compare(first: Any, second: Any): Any = { diff --git a/tests/neg/applydynamic_sip.check b/tests/neg/applydynamic_sip.check new file mode 100644 index 000000000..1bd8304bf --- /dev/null +++ b/tests/neg/applydynamic_sip.check @@ -0,0 +1,52 @@ +tests/neg/applydynamic_sip.scala:8: error: value applyDynamic is not a member of Dynamic(Test.qual) +possible cause: maybe a wrong Dynamic method signature? + qual.sel(a, a2: _*) // error + ^ +tests/neg/applydynamic_sip.scala:9: error: applyDynamicNamed does not support passing a vararg parameter + qual.sel(arg = a, a2: _*) // error + ^ +tests/neg/applydynamic_sip.scala:10: error: applyDynamicNamed does not support passing a vararg parameter + qual.sel(arg, arg2 = "a2", a2: _*) // error + ^ +tests/neg/applydynamic_sip.scala:20: error: type mismatch: + found : String("sel") + required: Int + bad1.sel // error + ^ +tests/neg/applydynamic_sip.scala:21: error: type mismatch: + found : String("sel") + required: Int + bad1.sel(1) // error // error + ^ +tests/neg/applydynamic_sip.scala:21: error: method applyDynamic in class Bad1 does not take more parameters + bad1.sel(1) // error // error + ^ +tests/neg/applydynamic_sip.scala:22: error: type mismatch: + found : String("sel") + required: Int + bad1.sel(a = 1) // error // error + ^ +tests/neg/applydynamic_sip.scala:22: error: method applyDynamicNamed in class Bad1 does not take more parameters + bad1.sel(a = 1) // error // error + ^ +tests/neg/applydynamic_sip.scala:23: error: type mismatch: + found : String("sel") + required: Int + bad1.sel = 1 // error // error + ^ +tests/neg/applydynamic_sip.scala:23: error: method updateDynamic in class Bad1 does not take more parameters + bad1.sel = 1 // error // error + ^ +tests/neg/applydynamic_sip.scala:32: error: method selectDynamic in class Bad2 does not take parameters + bad2.sel // error + ^ +tests/neg/applydynamic_sip.scala:33: error: method applyDynamic in class Bad2 does not take parameters + bad2.sel(1) // error + ^ +tests/neg/applydynamic_sip.scala:34: error: method applyDynamicNamed in class Bad2 does not take parameters + bad2.sel(a = 1) // error + ^ +tests/neg/applydynamic_sip.scala:35: error: method updateDynamic in class Bad2 does not take parameters + bad2.sel = 1 // error + ^ +14 errors found diff --git a/tests/untried/neg/applydynamic_sip.flags b/tests/neg/applydynamic_sip.flags index 1141f9750..1141f9750 100644 --- a/tests/untried/neg/applydynamic_sip.flags +++ b/tests/neg/applydynamic_sip.flags diff --git a/tests/neg/applydynamic_sip.scala b/tests/neg/applydynamic_sip.scala new file mode 100644 index 000000000..7b131e7ff --- /dev/null +++ b/tests/neg/applydynamic_sip.scala @@ -0,0 +1,36 @@ +import scala.language.dynamics +object Test extends App { + val qual: Dynamic = ??? + val expr = "expr" + val a = "a" + val a2 = "a2" + + qual.sel(a, a2: _*) // error + qual.sel(arg = a, a2: _*) // error + qual.sel(arg, arg2 = "a2", a2: _*) // error + + class Bad1 extends Dynamic { + def selectDynamic(n: Int) = n + def applyDynamic(n: Int) = n + def applyDynamicNamed(n: Int) = n + def updateDynamic(n: Int) = n + + } + val bad1 = new Bad1 + bad1.sel // error + bad1.sel(1) // error // error + bad1.sel(a = 1) // error // error + bad1.sel = 1 // error // error + + class Bad2 extends Dynamic { + def selectDynamic = 1 + def applyDynamic = 1 + def applyDynamicNamed = 1 + def updateDynamic = 1 + } + val bad2 = new Bad2 + bad2.sel // error + bad2.sel(1) // error + bad2.sel(a = 1) // error + bad2.sel = 1 // error +} diff --git a/tests/neg/emptyCatch.scala b/tests/neg/emptyCatch.scala new file mode 100644 index 000000000..60951d27a --- /dev/null +++ b/tests/neg/emptyCatch.scala @@ -0,0 +1,3 @@ +object Test { + try {} catch {} // error: `catch` block does not contain a valid expression, try adding a case like - `case e: Exception =>` to the block +} diff --git a/tests/neg/i1503.scala b/tests/neg/i1503.scala new file mode 100644 index 000000000..8e5dc53c6 --- /dev/null +++ b/tests/neg/i1503.scala @@ -0,0 +1,14 @@ +object Test { + + val cond = true + def foo1() = println("hi") + def bar1() = println("there") + + def foo2(x: Int) = println("hi") + def bar2(x: Int) = println("there") + + def main(args: Array[String]) = { + (if (cond) foo1 else bar1)() // error: Unit does not take parameters + (if (cond) foo2 else bar2)(22) // error: missing arguments // error: missing arguments + } +} diff --git a/tests/untried/neg/t6355b.check b/tests/neg/t6355b.check index f827f07e5..fb73b9c42 100644 --- a/tests/untried/neg/t6355b.check +++ b/tests/neg/t6355b.check @@ -1,11 +1,11 @@ t6355b.scala:14: error: value applyDynamic is not a member of A error after rewriting to x.<applyDynamic: error>("bippy") possible cause: maybe a wrong Dynamic method signature? - println(x.bippy(42)) + println(x.bippy(42)) // error ^ t6355b.scala:15: error: value applyDynamic is not a member of A error after rewriting to x.<applyDynamic: error>("bippy") possible cause: maybe a wrong Dynamic method signature? - println(x.bippy("42")) + println(x.bippy("42")) // error ^ two errors found diff --git a/tests/untried/neg/t6355b.scala b/tests/neg/t6355b.scala index 5f3c97cb0..bba3c4fdc 100644 --- a/tests/untried/neg/t6355b.scala +++ b/tests/neg/t6355b.scala @@ -11,7 +11,7 @@ class B(method: String) { object Test { def main(args: Array[String]): Unit = { val x = new A - println(x.bippy(42)) - println(x.bippy("42")) + println(x.bippy(42)) // error + println(x.bippy("42")) // error } } diff --git a/tests/untried/neg/t6663.check b/tests/neg/t6663.check index aa4faa4a4..aa4faa4a4 100644 --- a/tests/untried/neg/t6663.check +++ b/tests/neg/t6663.check diff --git a/tests/untried/neg/t6663.scala b/tests/neg/t6663.scala index 4a358dfbc..aa4ab08ed 100644 --- a/tests/untried/neg/t6663.scala +++ b/tests/neg/t6663.scala @@ -13,7 +13,7 @@ object Test extends App { // but, before fixing SI-6663, became // C(42).selectDynamic("foo").get, ignoring // the [String] type parameter - var v = new C(42).foo[String].get :Int + var v = new C(42).foo[String].get :Int // error println(v) } diff --git a/tests/untried/neg/t6920.check b/tests/neg/t6920.check index ee4eafb83..8bfd16a5f 100644 --- a/tests/untried/neg/t6920.check +++ b/tests/neg/t6920.check @@ -1,6 +1,6 @@ t6920.scala:9: error: too many arguments for method applyDynamicNamed: (values: Seq[(String, Any)])String error after rewriting to CompilerError.this.test.applyDynamicNamed("crushTheCompiler")(scala.Tuple2("a", 1), scala.Tuple2("b", 2)) possible cause: maybe a wrong Dynamic method signature? - test.crushTheCompiler(a = 1, b = 2) + test.crushTheCompiler(a = 1, b = 2) // error ^ one error found diff --git a/tests/untried/neg/t6920.scala b/tests/neg/t6920.scala index 25dc7b3b6..9601ed8d2 100644 --- a/tests/untried/neg/t6920.scala +++ b/tests/neg/t6920.scala @@ -6,5 +6,5 @@ class DynTest extends Dynamic { class CompilerError { val test = new DynTest - test.crushTheCompiler(a = 1, b = 2) + test.crushTheCompiler(a = 1, b = 2) // error } diff --git a/tests/untried/neg/t8006.check b/tests/neg/t8006.check index fbac26e3a..98207ba30 100644 --- a/tests/untried/neg/t8006.check +++ b/tests/neg/t8006.check @@ -1,6 +1,6 @@ t8006.scala:3: error: too many arguments for method applyDynamicNamed: (value: (String, Any))String error after rewriting to X.this.d.applyDynamicNamed("meth")(scala.Tuple2("value1", 10), scala.Tuple2("value2", 100)) possible cause: maybe a wrong Dynamic method signature? - d.meth(value1 = 10, value2 = 100) // two arguments here, but only one is allowed + d.meth(value1 = 10, value2 = 100) // error: two arguments here, but only one is allowed ^ one error found diff --git a/tests/untried/neg/t8006.scala b/tests/neg/t8006.scala index 8dc60697d..34946a659 100644 --- a/tests/untried/neg/t8006.scala +++ b/tests/neg/t8006.scala @@ -1,6 +1,6 @@ object X { val d = new D - d.meth(value1 = 10, value2 = 100) // two arguments here, but only one is allowed + d.meth(value1 = 10, value2 = 100) // error: two arguments here, but only one is allowed } import language.dynamics class D extends Dynamic { diff --git a/tests/pending/import-rewrite/compiler.error b/tests/pending/import-rewrite/compiler.error deleted file mode 100644 index 0832d33bb..000000000 --- a/tests/pending/import-rewrite/compiler.error +++ /dev/null @@ -1,6 +0,0 @@ -$ scalac tests/pending/import-rewrite/*.scala -$ ./bin/dotc tests/pending/import-rewrite/*.scala -tests/pending/import-rewrite/rewrite.scala:5: error: value apply is not a member of java.io.File.type - Seq("").map(File.apply) - ^ -one error found diff --git a/tests/pending/run/t2337.check b/tests/pending/run/t2337.check deleted file mode 100644 index 18f1f66fc..000000000 --- a/tests/pending/run/t2337.check +++ /dev/null @@ -1,4 +0,0 @@ -(Both Int,-1,-1) -(Both Float,1,1) -(Float then Int,0,0) -(Int then Float,0,0) diff --git a/tests/pending/run/t3150.scala b/tests/pending/run/t3150.scala index 034703b5f..dc95af373 100644 --- a/tests/pending/run/t3150.scala +++ b/tests/pending/run/t3150.scala @@ -1,10 +1,26 @@ -object Test { - case object Bob { override def equals(other: Any) = true } - def f(x: Any) = x match { case Bob => Bob } - - def main(args: Array[String]): Unit = { - assert(f(Bob) eq Bob) - assert(f(0) eq Bob) - assert(f(Nil) eq Bob) - } -} + object Test { + case object Bob { override def equals(other: Any) = true } + + class Bob2 { + override def equals(other: Any) = true + } + val Bob2 = new Bob2 + + def f0(x: Any) = x match { case Bob2 => Bob2 } // class cast exception at runtime, dotc only + def f1(x: Any) = x match { case Bob => Bob } // class cast exception at runtime, dotc only + def f2(x: Any): Bob.type = x match { case x @ Bob => x } // class cast exception at runtime, dotc and javac. + + def main(args: Array[String]): Unit = { + assert(f0(Bob2) eq Bob2) + assert(f0(0) eq Bob2) // only dotty fails here + assert(f0(Nil) eq Bob2) + + assert(f1(Bob) eq Bob) + assert(f1(0) eq Bob) // only dotty fails here + assert(f1(Nil) eq Bob) + + assert(f2(Bob) eq Bob) + assert(f2(0) eq Bob) // both dotty and scalac fail here + assert(f2(Nil) eq Bob) + } + } diff --git a/tests/pending/run/unapply.check b/tests/pending/run/unapply.check deleted file mode 100644 index 847e3b381..000000000 --- a/tests/pending/run/unapply.check +++ /dev/null @@ -1,3 +0,0 @@ -unapply.scala:57: warning: comparing values of types Null and Null using `==' will always yield true - assert(doMatch2(b) == null) - ^ diff --git a/tests/pos-scala2/naming-resolution/callsite.scala b/tests/pos-scala2/naming-resolution/callsite.scala new file mode 100644 index 000000000..036803a26 --- /dev/null +++ b/tests/pos-scala2/naming-resolution/callsite.scala @@ -0,0 +1,10 @@ +// This one should be rejected according to spec. The import takes precedence +// over the type in the same package because the typeis declared in a +// different compilation unit. scalac does not conform to spec here. +package naming.resolution + +import java.nio.file._ // Imports `Files` + +object Resolution { + def gimmeFiles: Files = Files.list(Paths.get(".")) +} diff --git a/tests/pos-scala2/naming-resolution/package.scala b/tests/pos-scala2/naming-resolution/package.scala new file mode 100644 index 000000000..f0e26ee95 --- /dev/null +++ b/tests/pos-scala2/naming-resolution/package.scala @@ -0,0 +1,5 @@ +package naming + +package object resolution { + type Files = java.util.stream.Stream[java.nio.file.Path] +} diff --git a/tests/pending/run/t3050.scala b/tests/pos-scala2/t3050.scala index 160f8b664..160f8b664 100644 --- a/tests/pending/run/t3050.scala +++ b/tests/pos-scala2/t3050.scala diff --git a/tests/pending/import-rewrite/file.scala b/tests/pos/import-rewrite/file.scala index e52581e81..e52581e81 100644 --- a/tests/pending/import-rewrite/file.scala +++ b/tests/pos/import-rewrite/file.scala diff --git a/tests/pending/import-rewrite/rewrite.scala b/tests/pos/import-rewrite/rewrite.scala index 0bda02c5e..0bda02c5e 100644 --- a/tests/pending/import-rewrite/rewrite.scala +++ b/tests/pos/import-rewrite/rewrite.scala diff --git a/tests/pos/t1500a.scala b/tests/pos/t1500a.scala new file mode 100644 index 000000000..adf46329a --- /dev/null +++ b/tests/pos/t1500a.scala @@ -0,0 +1,28 @@ +trait Step0 +trait Step1 +trait Step2 +trait Step3 +trait Step4 +trait Step5 +trait Step6 + +object Steps { + implicit val Step0: Step0 = new Step0 {} + implicit def Step1(implicit p: Step0): Step1 = new Step1 {} + implicit def Step2(implicit p: Step1): Step2 = new Step2 {} + implicit def Step3(implicit p: Step2): Step3 = new Step3 {} + implicit def Step4(implicit p: Step3): Step4 = new Step4 {} + implicit def Step5(implicit p: Step4): Step5 = new Step5 {} + implicit def Step6(implicit p: Step5): Step6 = new Step6 {} +} + +object StepsTest { + import Steps._ + + implicitly[Step0] + implicitly[Step1] + implicitly[Step2] + implicitly[Step3] + implicitly[Step4] + implicitly[Step6] +} diff --git a/tests/pos/t1513a.scala b/tests/pos/t1513a.scala new file mode 100644 index 000000000..3c4c02376 --- /dev/null +++ b/tests/pos/t1513a.scala @@ -0,0 +1,36 @@ +object Test { + // Heterogeneous lists and natural numbers as defined in shapeless. + + sealed trait HList + sealed trait ::[H, T <: HList] extends HList + sealed trait HNil extends HList + + sealed trait Nat + sealed trait Succ[P <: Nat] extends Nat + sealed trait Zero extends Nat + + // Accessor type class to compute the N'th element of an HList L. + + trait Accessor[L <: HList, N <: Nat] { type Out } + object Accessor { + type Aux[L <: HList, N <: Nat, O] = Accessor[L, N] { type Out = O } + + // (H :: T).At[Zero] = H + implicit def caseZero[H, T <: HList]: Aux[H :: T, Zero, H] = ??? + + // T.At[N] = O => (H :: T).At[Succ[N]] = O + implicit def caseN[H, T <: HList, N <: Nat, O] + (implicit a: Aux[T, N, O]): Aux[H :: T, Succ[N], O] = ??? + } + + case class Proxy[T]() + + def at1[NN <: Nat, OO] (implicit e: Accessor.Aux[String :: HNil, NN, OO]): OO = ??? + def at2[NN <: Nat, OO](p: Proxy[NN])(implicit e: Accessor.Aux[String :: HNil, NN, OO]): OO = ??? + + // N is fixed by a value + at2(Proxy[Zero]): String + + // N is fixed as a type parameter (by name) + at1[NN = Zero]: String +} diff --git a/tests/pos/t1513b.scala b/tests/pos/t1513b.scala new file mode 100644 index 000000000..546649383 --- /dev/null +++ b/tests/pos/t1513b.scala @@ -0,0 +1,25 @@ +object Test { + def f[ + T1 <: String, + T2 <: Int, + T3 <: Boolean + ](a1: T1, a2: T2, a3: T3) = () + + f ("", 1, true) + f[T1 = String] ("", 1, true) + f[T2 = Int] ("", 1, true) + f[T3 = Boolean] ("", 1, true) + f[T1 = String, T2 = Int] ("", 1, true) + f[T1 = String, T3 = Boolean] ("", 1, true) + f[T2 = Int, T1 = String] ("", 1, true) + f[T2 = Int, T3 = Boolean] ("", 1, true) + f[T3 = Boolean, T2 = Int] ("", 1, true) + f[T3 = Boolean, T1 = String] ("", 1, true) + f[T1 = String, T2 = Int, T3 = Boolean]("", 1, true) + f[T1 = String, T3 = Boolean, T2 = Int] ("", 1, true) + f[T2 = Int, T1 = String, T3 = Boolean]("", 1, true) + f[T2 = Int, T3 = Boolean, T1 = String] ("", 1, true) + f[T3 = Boolean, T1 = String, T2 = Int] ("", 1, true) + f[T3 = Boolean, T2 = Int, T1 = String] ("", 1, true) + f[String, Int, Boolean] ("", 1, true) +} diff --git a/tests/pos/tryWithoutHandler.scala b/tests/pos/tryWithoutHandler.scala new file mode 100644 index 000000000..ffe334984 --- /dev/null +++ b/tests/pos/tryWithoutHandler.scala @@ -0,0 +1,7 @@ +object Test { + def main(args: Array[String]): Unit = { + try { + println("hello") + } + } +} diff --git a/tests/pending/run/applydynamic_sip.check b/tests/run/applydynamic_sip.check index 6d04dc452..6d04dc452 100644 --- a/tests/pending/run/applydynamic_sip.check +++ b/tests/run/applydynamic_sip.check diff --git a/tests/pending/run/applydynamic_sip.flags b/tests/run/applydynamic_sip.flags index ba6d37305..ba6d37305 100644 --- a/tests/pending/run/applydynamic_sip.flags +++ b/tests/run/applydynamic_sip.flags diff --git a/tests/pending/run/applydynamic_sip.scala b/tests/run/applydynamic_sip.scala index a163ab960..7f81a644a 100644 --- a/tests/pending/run/applydynamic_sip.scala +++ b/tests/run/applydynamic_sip.scala @@ -1,3 +1,4 @@ +import scala.language.dynamics object Test extends dotty.runtime.LegacyApp { object stubUpdate { def update(as: Any*) = println(".update"+as.toList.mkString("(",", ", ")")) diff --git a/tests/pending/run/dynamic-anyval.check b/tests/run/dynamic-anyval.check index dee7bef8e..dee7bef8e 100644 --- a/tests/pending/run/dynamic-anyval.check +++ b/tests/run/dynamic-anyval.check diff --git a/tests/pending/run/dynamic-anyval.scala b/tests/run/dynamic-anyval.scala index 605503d37..605503d37 100644 --- a/tests/pending/run/dynamic-anyval.scala +++ b/tests/run/dynamic-anyval.scala diff --git a/tests/run/dynamicDynamicTests.scala b/tests/run/dynamicDynamicTests.scala index 3f8da8298..05b878f1c 100644 --- a/tests/run/dynamicDynamicTests.scala +++ b/tests/run/dynamicDynamicTests.scala @@ -23,7 +23,16 @@ class Baz extends scala.Dynamic { def updateDynamic(name: String)(value: String): String = "updateDynamic(" + name + ")(" + value + ")" } +class Qux extends scala.Dynamic { + def selectDynamic[T](name: String): String = "selectDynamic(" + name + ")" + def applyDynamic[T](name: String)(args: String*): String = "applyDynamic(" + name + ")" + args.mkString("(", ", ", ")") + def applyDynamicNamed[T](name: String)(args: (String, Any)*): String = "applyDynamicNamed(" + name + ")" + args.mkString("(", ", ", ")") + def updateDynamic[T](name: String)(value: T): String = "updateDynamic(" + name + ")(" + value + ")" +} + object Test { + val qux = new Qux + implicit class StringUpdater(str: String) { def update(name: String, v: String) = s"$str.update(" + name + ", " + v + ")" } @@ -42,6 +51,7 @@ object Test { runFooTests2() runBarTests() runBazTests() + runQuxTests() assert(!failed) } @@ -161,4 +171,35 @@ object Test { assertEquals("selectDynamic(bazSelectUpdate).update(7, value)", baz.bazSelectUpdate(7) = "value") assertEquals("selectDynamic(bazSelectUpdate).update(7, 10)", baz.bazSelectUpdate(7) = 10) } + + /** Test correct lifting of type parameters */ + def runQuxTests() = { + implicit def intToString(n: Int): String = n.toString + + val qux = new Qux + + assertEquals("selectDynamic(quxSelect)", qux.quxSelect) + assertEquals("selectDynamic(quxSelect)", qux.quxSelect[Int]) + + assertEquals("applyDynamic(quxApply)()", qux.quxApply()) + assertEquals("applyDynamic(quxApply)()", qux.quxApply[Int]()) + assertEquals("applyDynamic(quxApply)(1)", qux.quxApply(1)) + assertEquals("applyDynamic(quxApply)(1)", qux.quxApply[Int](1)) + assertEquals("applyDynamic(quxApply)(1, 2, 3)", qux.quxApply(1, 2, 3)) + assertEquals("applyDynamic(quxApply)(1, 2, 3)", qux.quxApply[Int](1, 2, 3)) + assertEquals("applyDynamic(quxApply)(1, 2, a)", qux.quxApply(1, 2, "a")) + assertEquals("applyDynamic(quxApply)(1, 2, a)", qux.quxApply[Int](1, 2, "a")) + + assertEquals("applyDynamicNamed(quxApplyNamed)((a,1))", qux.quxApplyNamed(a = 1)) + assertEquals("applyDynamicNamed(quxApplyNamed)((a,1))", qux.quxApplyNamed[Int](a = 1)) + assertEquals("applyDynamicNamed(quxApplyNamed)((a,1), (b,2))", qux.quxApplyNamed(a = 1, b = "2")) + assertEquals("applyDynamicNamed(quxApplyNamed)((a,1), (b,2))", qux.quxApplyNamed[Int](a = 1, b = "2")) + assertEquals("applyDynamicNamed(quxApplyNamed)((a,1), (,abc))", qux.quxApplyNamed(a = 1, "abc")) + assertEquals("applyDynamicNamed(quxApplyNamed)((a,1), (,abc))", qux.quxApplyNamed[Int](a = 1, "abc")) + + assertEquals("updateDynamic(quxUpdate)(abc)", qux.quxUpdate = "abc") + + assertEquals("selectDynamic(quxSelectUpdate).update(key, value)", qux.quxSelectUpdate("key") = "value") + assertEquals("selectDynamic(quxSelectUpdate).update(key, value)", qux.quxSelectUpdate[Int]("key") = "value") + } } diff --git a/tests/run/i1503.check b/tests/run/i1503.check new file mode 100644 index 000000000..8cc0be027 --- /dev/null +++ b/tests/run/i1503.check @@ -0,0 +1,5 @@ +hello +hi +33 +hi +hi diff --git a/tests/run/i1503.scala b/tests/run/i1503.scala new file mode 100644 index 000000000..56bb9af0c --- /dev/null +++ b/tests/run/i1503.scala @@ -0,0 +1,38 @@ +object Test { + + def test1() = + (new Function0[Unit] { + def apply() = println("hello") + })() + + val cond = true + val foo = () => println("hi") + val bar = () => println("there") + + val baz = (x: Int) => println(x) + + def test2() = + (if (cond) foo else bar)() + + def test2a() = + (if (cond) baz else baz)(33) + + def test3() = + (try foo + catch { case ex: Exception => bar } + finally ())() + + def test4() = + (cond match { + case true => foo + case false => bar + })() + + def main(args: Array[String]) = { + test1() + test2() + test2a() + test3() + test4() + } +} diff --git a/tests/run/t1335.scala b/tests/run/t1335.scala new file mode 100644 index 000000000..047f7b566 --- /dev/null +++ b/tests/run/t1335.scala @@ -0,0 +1,11 @@ +case class MyTuple(a: Int, b: Int) + +object Test { + def main(args: Array[String]): Unit = + try { + val mt: MyTuple = null + val MyTuple(a, b) = mt + } catch { + case e: MatchError => () + } +} diff --git a/tests/run/t1500b.scala b/tests/run/t1500b.scala new file mode 100644 index 000000000..8b52731a5 --- /dev/null +++ b/tests/run/t1500b.scala @@ -0,0 +1,21 @@ +sealed trait Nat +sealed trait Succ[Prev <: Nat] extends Nat +sealed trait Zero extends Nat + +case class ToInt[N <: Nat](value: Int) + +object ToInt { + implicit val caseZero: ToInt[Zero] = ToInt(0) + implicit def caseSucc[Prev <: Nat](implicit e: ToInt[Prev]): ToInt[Succ[Prev]] = ToInt(e.value + 1) +} + +object Test { + def main(args: Array[String]): Unit = { + assert(implicitly[ToInt[Zero]].value == 0) + assert(implicitly[ToInt[Succ[Zero]]].value == 1) + assert(implicitly[ToInt[Succ[Succ[Zero]]]].value == 2) + assert(implicitly[ToInt[Succ[Succ[Succ[Zero]]]]].value == 3) + assert(implicitly[ToInt[Succ[Succ[Succ[Succ[Zero]]]]]].value == 4) + assert(implicitly[ToInt[Succ[Succ[Succ[Succ[Succ[Zero]]]]]]].value == 5) + } +} diff --git a/tests/run/t1500c.scala b/tests/run/t1500c.scala new file mode 100644 index 000000000..5c33b7a2f --- /dev/null +++ b/tests/run/t1500c.scala @@ -0,0 +1,19 @@ +sealed trait HList +sealed trait HNil extends HList +sealed trait ::[H, T <: HList] extends HList + +case class Size[L <: HList](value: Int) + +object Size { + implicit val caseHNil: Size[HNil] = Size(0) + implicit def caseHCons[H, T <: HList](implicit e: Size[T]): Size[H :: T] = Size(e.value + 1) +} + +object Test { + def main(args: Array[String]): Unit = { + assert(implicitly[Size[HNil]].value == 0) + assert(implicitly[Size[Int :: HNil]].value == 1) + assert(implicitly[Size[Int :: Int :: HNil]].value == 2) + assert(implicitly[Size[Int :: Int :: Int :: HNil]].value == 3) + } +} diff --git a/tests/pending/run/t298.check b/tests/run/t298.check index 1cd1d2266..1cd1d2266 100644 --- a/tests/pending/run/t298.check +++ b/tests/run/t298.check diff --git a/tests/pending/run/t298.scala b/tests/run/t298.scala index 5728bb6c9..5728bb6c9 100644 --- a/tests/pending/run/t298.scala +++ b/tests/run/t298.scala diff --git a/tests/pending/run/t3026.check b/tests/run/t3026.check index 8c29b615f..8c29b615f 100644 --- a/tests/pending/run/t3026.check +++ b/tests/run/t3026.check diff --git a/tests/pending/run/t3026.scala b/tests/run/t3026.scala index 22dde9cc0..22dde9cc0 100755 --- a/tests/pending/run/t3026.scala +++ b/tests/run/t3026.scala diff --git a/tests/pending/run/t3353.check b/tests/run/t3353.check index 8b4ae1fe6..8b4ae1fe6 100644 --- a/tests/pending/run/t3353.check +++ b/tests/run/t3353.check diff --git a/tests/pending/run/t3353.scala b/tests/run/t3353.scala index 472723b3c..472723b3c 100644 --- a/tests/pending/run/t3353.scala +++ b/tests/run/t3353.scala diff --git a/tests/pending/run/t4536.check b/tests/run/t4536.check index 0c5a72ada..0c5a72ada 100644 --- a/tests/pending/run/t4536.check +++ b/tests/run/t4536.check diff --git a/tests/pending/run/t4536.flags b/tests/run/t4536.flags index 1141f9750..1141f9750 100644 --- a/tests/pending/run/t4536.flags +++ b/tests/run/t4536.flags diff --git a/tests/pending/run/t4536.scala b/tests/run/t4536.scala index 6661eae6a..89a93a5e0 100644 --- a/tests/pending/run/t4536.scala +++ b/tests/run/t4536.scala @@ -1,8 +1,4 @@ - - - - - +import scala.language.dynamics object dynamicObject extends Dynamic { def applyDynamic(m: String)() = println("obj: " + m); @@ -38,7 +34,7 @@ object dynamicMixin extends dynamicAbstractClass with dynamicTrait { object Test { - def main(args: Array[String]) { + def main(args: Array[String]) = { val cls = new dynamicClass dynamicMixin } diff --git a/tests/pending/run/t5040.check b/tests/run/t5040.check index 3f7b5908a..3f7b5908a 100644 --- a/tests/pending/run/t5040.check +++ b/tests/run/t5040.check diff --git a/tests/pending/run/t5040.flags b/tests/run/t5040.flags index 1141f9750..1141f9750 100644 --- a/tests/pending/run/t5040.flags +++ b/tests/run/t5040.flags diff --git a/tests/pending/run/t5040.scala b/tests/run/t5040.scala index 6813c1b27..58d054412 100644 --- a/tests/pending/run/t5040.scala +++ b/tests/run/t5040.scala @@ -1,3 +1,4 @@ +import scala.language.dynamics // originaly used the flag -language:dynamics in t5040.flags, .flags are currently ignored abstract class Prova2 extends Dynamic { def applyDynamic(m: String)(): Unit private def privateMethod() = println("private method") diff --git a/tests/pending/run/t5733.check b/tests/run/t5733.check index e697046a9..e697046a9 100644 --- a/tests/pending/run/t5733.check +++ b/tests/run/t5733.check diff --git a/tests/pending/run/t5733.scala b/tests/run/t5733.scala index a9e58d77e..a9e58d77e 100644 --- a/tests/pending/run/t5733.scala +++ b/tests/run/t5733.scala diff --git a/tests/pending/run/t6353.check b/tests/run/t6353.check index 5676bed24..5676bed24 100644 --- a/tests/pending/run/t6353.check +++ b/tests/run/t6353.check diff --git a/tests/pending/run/t6353.scala b/tests/run/t6353.scala index 7077eaeda..7077eaeda 100644 --- a/tests/pending/run/t6353.scala +++ b/tests/run/t6353.scala diff --git a/tests/pending/run/t6355.check b/tests/run/t6355.check index ce74ab38a..ce74ab38a 100644 --- a/tests/pending/run/t6355.check +++ b/tests/run/t6355.check diff --git a/tests/pending/run/t6355.scala b/tests/run/t6355.scala index f1921391a..f1921391a 100644 --- a/tests/pending/run/t6355.scala +++ b/tests/run/t6355.scala diff --git a/tests/pending/run/t6663.check b/tests/run/t6663.check index d81cc0710..d81cc0710 100644 --- a/tests/pending/run/t6663.check +++ b/tests/run/t6663.check diff --git a/tests/pending/run/t6663.flags b/tests/run/t6663.flags index ea7fc37e1..ea7fc37e1 100644 --- a/tests/pending/run/t6663.flags +++ b/tests/run/t6663.flags diff --git a/tests/pending/run/t6663.scala b/tests/run/t6663.scala index bfe464ad6..bfe464ad6 100644 --- a/tests/pending/run/t6663.scala +++ b/tests/run/t6663.scala diff --git a/tests/pending/run/unapply.scala b/tests/run/unapply.scala index 43f02b9f3..7b10030ba 100644 --- a/tests/pending/run/unapply.scala +++ b/tests/run/unapply.scala @@ -87,8 +87,8 @@ object Mas { object LisSeqArr { def run(): Unit = { - assert((1,2) == ((List(1,2,3): Any) match { case List(x,y,_*) => (x,y)})) - assert((1,2) == ((List(1,2,3): Any) match { case Seq(x,y,_*) => (x,y)})) + assert((1,2) == ((List(1,2,3): Any) match { case List(x,y,_: _*) => (x,y)})) + assert((1,2) == ((List(1,2,3): Any) match { case Seq(x,y,_: _*) => (x,y)})) } } diff --git a/tests/untried/neg/applydynamic_sip.check b/tests/untried/neg/applydynamic_sip.check deleted file mode 100644 index 2cb2e7f09..000000000 --- a/tests/untried/neg/applydynamic_sip.check +++ /dev/null @@ -1,73 +0,0 @@ -applydynamic_sip.scala:7: error: applyDynamic does not support passing a vararg parameter - qual.sel(a, a2: _*) - ^ -applydynamic_sip.scala:8: error: applyDynamicNamed does not support passing a vararg parameter - qual.sel(arg = a, a2: _*) - ^ -applydynamic_sip.scala:8: error: not found: value arg - qual.sel(arg = a, a2: _*) - ^ -applydynamic_sip.scala:9: error: applyDynamicNamed does not support passing a vararg parameter - qual.sel(arg, arg2 = "a2", a2: _*) - ^ -applydynamic_sip.scala:9: error: not found: value arg - qual.sel(arg, arg2 = "a2", a2: _*) - ^ -applydynamic_sip.scala:9: error: not found: value arg2 - qual.sel(arg, arg2 = "a2", a2: _*) - ^ -applydynamic_sip.scala:18: error: type mismatch; - found : String("sel") - required: Int -error after rewriting to Test.this.bad1.selectDynamic("sel") -possible cause: maybe a wrong Dynamic method signature? - bad1.sel - ^ -applydynamic_sip.scala:19: error: type mismatch; - found : String("sel") - required: Int -error after rewriting to Test.this.bad1.applyDynamic("sel") -possible cause: maybe a wrong Dynamic method signature? - bad1.sel(1) - ^ -applydynamic_sip.scala:20: error: type mismatch; - found : String("sel") - required: Int -error after rewriting to Test.this.bad1.applyDynamicNamed("sel") -possible cause: maybe a wrong Dynamic method signature? - bad1.sel(a = 1) - ^ -applydynamic_sip.scala:20: error: reassignment to val - bad1.sel(a = 1) - ^ -applydynamic_sip.scala:21: error: type mismatch; - found : String("sel") - required: Int -error after rewriting to Test.this.bad1.updateDynamic("sel") -possible cause: maybe a wrong Dynamic method signature? - bad1.sel = 1 - ^ -applydynamic_sip.scala:29: error: Int does not take parameters -error after rewriting to Test.this.bad2.selectDynamic("sel") -possible cause: maybe a wrong Dynamic method signature? - bad2.sel - ^ -applydynamic_sip.scala:30: error: Int does not take parameters -error after rewriting to Test.this.bad2.applyDynamic("sel") -possible cause: maybe a wrong Dynamic method signature? - bad2.sel(1) - ^ -applydynamic_sip.scala:31: error: Int does not take parameters -error after rewriting to Test.this.bad2.applyDynamicNamed("sel") -possible cause: maybe a wrong Dynamic method signature? - bad2.sel(a = 1) - ^ -applydynamic_sip.scala:31: error: reassignment to val - bad2.sel(a = 1) - ^ -applydynamic_sip.scala:32: error: Int does not take parameters -error after rewriting to Test.this.bad2.updateDynamic("sel") -possible cause: maybe a wrong Dynamic method signature? - bad2.sel = 1 - ^ -16 errors found diff --git a/tests/untried/neg/applydynamic_sip.scala b/tests/untried/neg/applydynamic_sip.scala deleted file mode 100644 index ee4432ebe..000000000 --- a/tests/untried/neg/applydynamic_sip.scala +++ /dev/null @@ -1,33 +0,0 @@ -object Test extends App { - val qual: Dynamic = ??? - val expr = "expr" - val a = "a" - val a2 = "a2" - - qual.sel(a, a2: _*) - qual.sel(arg = a, a2: _*) - qual.sel(arg, arg2 = "a2", a2: _*) - - val bad1 = new Dynamic { - def selectDynamic(n: Int) = n - def applyDynamic(n: Int) = n - def applyDynamicNamed(n: Int) = n - def updateDynamic(n: Int) = n - - } - bad1.sel - bad1.sel(1) - bad1.sel(a = 1) - bad1.sel = 1 - - val bad2 = new Dynamic { - def selectDynamic = 1 - def applyDynamic = 1 - def applyDynamicNamed = 1 - def updateDynamic = 1 - } - bad2.sel - bad2.sel(1) - bad2.sel(a = 1) - bad2.sel = 1 -} |