diff options
18 files changed, 152 insertions, 25 deletions
diff --git a/.drone.yml b/.drone.yml index 935297a5b..83309ef4e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,7 +7,6 @@ pipeline: - ln -s /var/cache/drone/ivy2 "$HOME/.ivy2" - ./scripts/update-scala-library - sbt -J-Xmx4096m -J-XX:ReservedCodeCacheSize=512m -J-XX:MaxMetaspaceSize=1024m -Ddotty.drone.mem=4096m "${TEST}" - - ./compiler/test/debug/test when: branch: exclude: gh-pages diff --git a/.drone.yml.sig b/.drone.yml.sig index 63609e5c8..1093928f0 100644 --- a/.drone.yml.sig +++ b/.drone.yml.sig @@ -1 +1 @@ -eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIGxuIC1zIC92YXIvY2FjaGUvZHJvbmUvc2NhbGEtc2NhbGEgc2NhbGEtc2NhbGEKICAgICAgLSBsbiAtcyAvdmFyL2NhY2hlL2Ryb25lL2l2eTIgIiRIT01FLy5pdnkyIgogICAgICAtIC4vc2NyaXB0cy91cGRhdGUtc2NhbGEtbGlicmFyeQogICAgICAtIHNidCAtSi1YbXg0MDk2bSAtSi1YWDpSZXNlcnZlZENvZGVDYWNoZVNpemU9NTEybSAtSi1YWDpNYXhNZXRhc3BhY2VTaXplPTEwMjRtIC1EZG90dHkuZHJvbmUubWVtPTQwOTZtICIke1RFU1R9IgogICAgICAtIC4vY29tcGlsZXIvdGVzdC9kZWJ1Zy90ZXN0CiAgICB3aGVuOgogICAgICBicmFuY2g6CiAgICAgICAgZXhjbHVkZTogZ2gtcGFnZXMKCiAgZG9jdW1lbnRhdGlvbjoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIC4vcHJvamVjdC9zY3JpcHRzL2dlbkRvY3MgIiR7VEVTVH0iICRCT1RfUEFTUwogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIKCiAgZ2l0dGVyOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0dGVyCiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgogICAgICBzdGF0dXM6IGNoYW5nZWQKCiAgc2xhY2s6CiAgICBpbWFnZTogcGx1Z2lucy9zbGFjawogICAgY2hhbm5lbDogZG90dHkKICAgIHdoZW46CiAgICAgIGJyYW5jaDogbWFzdGVyCiAgICAgIHN0YXR1czogY2hhbmdlZAoKbWF0cml4OgogIFRFU1Q6CiAgICAtIDt0ZXN0O2RvdHR5LWJpbi10ZXN0cy90ZXN0CiAgICAtIDtwdWJsaXNoTG9jYWw7ZG90dHktYm9vdHN0cmFwcGVkL3Rlc3QKICAgIC0gcGFydGVzdC1vbmx5LW5vLWJvb3RzdHJhcCAtLXNob3ctZGlmZiAtLXZlcmJvc2UKICAgIC0gcGFydGVzdC1vbmx5IC0tc2hvdy1kaWZmIC0tdmVyYm9zZQo.NgZCPjkR9Z1A96-ryvHIVJOsL9GI6aIvU6tGC_hv5Lo
\ No newline at end of file +eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIGxuIC1zIC92YXIvY2FjaGUvZHJvbmUvc2NhbGEtc2NhbGEgc2NhbGEtc2NhbGEKICAgICAgLSBsbiAtcyAvdmFyL2NhY2hlL2Ryb25lL2l2eTIgIiRIT01FLy5pdnkyIgogICAgICAtIC4vc2NyaXB0cy91cGRhdGUtc2NhbGEtbGlicmFyeQogICAgICAtIHNidCAtSi1YbXg0MDk2bSAtSi1YWDpSZXNlcnZlZENvZGVDYWNoZVNpemU9NTEybSAtSi1YWDpNYXhNZXRhc3BhY2VTaXplPTEwMjRtIC1EZG90dHkuZHJvbmUubWVtPTQwOTZtICIke1RFU1R9IgogICAgd2hlbjoKICAgICAgYnJhbmNoOgogICAgICAgIGV4Y2x1ZGU6IGdoLXBhZ2VzCgogIGRvY3VtZW50YXRpb246CiAgICBpbWFnZTogbGFtcGVwZmwvZG90dHk6bGF0ZXN0CiAgICBwdWxsOiB0cnVlCiAgICBjb21tYW5kczoKICAgICAgLSAuL3Byb2plY3Qvc2NyaXB0cy9nZW5Eb2NzICIke1RFU1R9IiAkQk9UX1BBU1MKICAgIHdoZW46CiAgICAgIGJyYW5jaDogbWFzdGVyCgogIGdpdHRlcjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdHRlcgogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIKICAgICAgc3RhdHVzOiBjaGFuZ2VkCgogIHNsYWNrOgogICAgaW1hZ2U6IHBsdWdpbnMvc2xhY2sKICAgIGNoYW5uZWw6IGRvdHR5CiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgogICAgICBzdGF0dXM6IGNoYW5nZWQKCm1hdHJpeDoKICBURVNUOgogICAgLSA7dGVzdDtkb3R0eS1iaW4tdGVzdHMvdGVzdAogICAgLSA7cHVibGlzaExvY2FsO2RvdHR5LWJvb3RzdHJhcHBlZC90ZXN0CiAgICAtIHBhcnRlc3Qtb25seS1uby1ib290c3RyYXAgLS1zaG93LWRpZmYgLS12ZXJib3NlCiAgICAtIHBhcnRlc3Qtb25seSAtLXNob3ctZGlmZiAtLXZlcmJvc2UK.VRqZiSgeE6OumPlEvs4TWfxIHNOEVjR_ZmyBmapxZ-U
\ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index e3102fda2..deb239143 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -559,7 +559,7 @@ object desugar { * ValDef or DefDef. */ def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match { - case VarPattern(named, tpt) => + case IdPattern(named, tpt) => derivedValDef(original, named, tpt, rhs, mods) case _ => val rhsUnchecked = makeAnnotated("scala.unchecked", rhs) @@ -816,7 +816,7 @@ object desugar { * Otherwise this gives { case pat => body } */ def makeLambda(pat: Tree, body: Tree): Tree = pat match { - case VarPattern(named, tpt) => + case IdPattern(named, tpt) => Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body) case _ => makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false) @@ -898,7 +898,9 @@ object desugar { } def isIrrefutableGenFrom(gen: GenFrom): Boolean = - gen.isInstanceOf[IrrefutableGenFrom] || isIrrefutable(gen.pat, gen.expr) + gen.isInstanceOf[IrrefutableGenFrom] || + IdPattern.unapply(gen.pat).isDefined || + isIrrefutable(gen.pat, gen.expr) /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when * matched against `rhs`. @@ -1062,9 +1064,9 @@ object desugar { TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait) } - /** If tree is a variable pattern, return its name and type, otherwise return None. + /** If tree is of the form `id` or `id: T`, return its name and type, otherwise return None. */ - private object VarPattern { + private object IdPattern { def unapply(tree: Tree)(implicit ctx: Context): Option[VarInfo] = tree match { case id: Ident => Some(id, TypeTree()) case Typed(id: Ident, tpt) => Some((id, tpt)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 69ab6c21a..9e9e39a84 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -527,6 +527,8 @@ class Definitions { lazy val EqType = ctx.requiredClassRef("scala.Eq") def EqClass(implicit ctx: Context) = EqType.symbol.asClass + lazy val XMLTopScopeModuleRef = ctx.requiredModuleRef("scala.xml.TopScope") + // Annotation base classes lazy val AnnotationType = ctx.requiredClassRef("scala.annotation.Annotation") def AnnotationClass(implicit ctx: Context) = AnnotationType.symbol.asClass diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 4a9c50dad..c424c6182 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -533,6 +533,7 @@ object StdNames { val nullRuntimeClass: N = "scala.runtime.Null$" val synthSwitch: N = "$synthSwitch" + val _scope: N = "$scope" // unencoded operators object raw { diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 9f4cdbd35..45ae842b6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -110,7 +110,8 @@ object Parsers { */ def syntaxError(msg: => Message, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { - syntaxError(msg, Position(offset)) + val length = if (in.name != null) in.name.show.length else 0 + syntaxError(msg, Position(offset, offset + length)) lastErrorOffset = in.offset } @@ -249,11 +250,6 @@ object Parsers { lastErrorOffset = in.offset } // DEBUG - private def expectedMsg(token: Int): String = - expectedMessage(showToken(token)) - private def expectedMessage(what: String): String = - s"$what expected but ${showToken(in.token)} found" - /** Consume one token of the specified type, or * signal an error if it is not there. * @@ -262,7 +258,7 @@ object Parsers { def accept(token: Int): Int = { val offset = in.offset if (in.token != token) { - syntaxErrorOrIncomplete(expectedMsg(token)) + syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token, in.name)) } if (in.token == token) in.nextToken() offset @@ -474,7 +470,7 @@ object Parsers { in.nextToken() name } else { - syntaxErrorOrIncomplete(expectedMsg(IDENTIFIER)) + syntaxErrorOrIncomplete(ExpectedTokenButFound(IDENTIFIER, in.token, in.name)) nme.ERROR } @@ -1055,7 +1051,7 @@ object Parsers { case Block(Nil, EmptyTree) => assert(handlerStart != -1) syntaxError( - new EmptyCatchBlock(body), + EmptyCatchBlock(body), Position(handlerStart, endOffset(handler)) ) case _ => diff --git a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala index 20b655a19..09d1b20b1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala +++ b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala @@ -55,7 +55,6 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont val _buf: TermName = "$buf" val _md: TermName = "$md" val _plus: TermName = "$amp$plus" - val _scope: TermName = "$scope" val _tmpscope: TermName = "$tmpscope" val _xml: TermName = "xml" } diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 280832ef3..8d42e525a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -17,7 +17,7 @@ abstract class TokensCommon { def showToken(token: Int) = { val str = tokenString(token) - if (keywords contains token) s"'$str'" else str + if (isKeyword(token)) s"'$str'" else str } val tokenString, debugString = new Array[String](maxToken + 1) @@ -114,6 +114,8 @@ abstract class TokensCommon { val keywords: TokenSet + def isKeyword(token: Token): Boolean = keywords contains token + /** parentheses */ final val LPAREN = 90; enter(LPAREN, "'('") final val RPAREN = 91; enter(RPAREN, "')'") diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index 2497fb216..ab1222dab 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -119,6 +119,8 @@ class ExtendMessage(_msg: () => Message)(f: String => String) { self => class NoExplanation(val msg: String) extends Message(NoExplanation.ID) { val explanation = "" val kind = "" + + override def toString(): String = s"NoExplanation($msg)" } /** The extractor for `NoExplanation` can be used to check whether any error diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index c25c49597..94611e10d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -4,10 +4,17 @@ package reporting package diagnostic import dotc.core._ -import Contexts.Context, Decorators._, Symbols._, Names._, NameOps._, Types._ +import Contexts.Context +import Decorators._ +import Symbols._ +import Names._ +import NameOps._ +import Types._ import util.SourcePosition import config.Settings.Setting -import interfaces.Diagnostic.{ERROR, WARNING, INFO} +import interfaces.Diagnostic.{ERROR, INFO, WARNING} +import dotc.parsing.Scanners.Token +import dotc.parsing.Tokens import printing.Highlighting._ import printing.Formatting @@ -1034,4 +1041,49 @@ object messages { |""" } + case class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) + extends Message(39) { + val kind = "Reference" + val msg = hl"`${definition.name}` is a forward reference extending over the definition of `${value.name}`" + + val explanation = + hl"""|`${definition.name}` is used before you define it, and the definition of `${value.name}` + |appears between that use and the definition of `${definition.name}`. + | + |Forward references are allowed only, if there are no value definitions between + |the reference and the referred method definition. + | + |Define `${definition.name}` before it is used, + |or move the definition of `${value.name}` so it does not appear between + |the declartion of `${definition.name}` and its use, + |or define `${value.name}` as lazy. + |""".stripMargin + } + + case class ExpectedTokenButFound(expected: Token, found: Token, foundName: TermName)(implicit ctx: Context) + extends Message(40) { + val kind = "Syntax" + + private val expectedText = + if (Tokens.isIdentifier(expected)) "an identifier" + else Tokens.showToken(expected) + + private val foundText = + if (foundName != null) hl"`${foundName.show}`" + else Tokens.showToken(found) + + val msg = hl"""${expectedText} expected, but ${foundText} found""" + + private val ifKeyword = + if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found)) + s""" + |If you necessarily want to use $foundText as identifier, you may put it in backticks.""".stripMargin + else + "" + + val explanation = + s"""|The text ${foundText} may not occur at that position, the compiler expected ${expectedText}.$ifKeyword + |""".stripMargin + } + } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index ada53047a..eab91701b 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -767,6 +767,7 @@ import RefChecks._ class RefChecks extends MiniPhase { thisTransformer => import tpd._ + import reporting.diagnostic.messages.ForwardReferenceExtendsOverDefinition override def phaseName: String = "refchecks" @@ -789,8 +790,7 @@ class RefChecks extends MiniPhase { thisTransformer => if (sym.exists && sym.owner.isTerm && !sym.is(Lazy)) currentLevel.levelAndIndex.get(sym) match { case Some((level, symIdx)) if symIdx < level.maxIndex => - ctx.debuglog("refsym = " + level.refSym) - ctx.error(s"forward reference extends over definition of $sym", level.refPos) + ctx.error(ForwardReferenceExtendsOverDefinition(sym, level.refSym), level.refPos) case _ => } tree diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index e04667223..2b57cf778 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -351,6 +351,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val ownType = if (rawType.exists) ensureAccessible(rawType, superAccess = false, tree.pos) + else if (name == nme._scope) { + // gross hack to support current xml literals. + // awaiting a better implicits based solution for library-supported xml + return ref(defn.XMLTopScopeModuleRef) + } else errorType(new MissingIdent(tree, kind, name.show), tree.pos) diff --git a/compiler/test/debug/Gen.scala b/compiler/test/debug/Gen.scala index f7a5cc432..dee6b33e3 100755 --- a/compiler/test/debug/Gen.scala +++ b/compiler/test/debug/Gen.scala @@ -19,7 +19,7 @@ import scala.collection.mutable.ListBuffer object Gen { val MainObject = "Test" - val CommandWait = 0.5 + val CommandWait = 1 sealed trait Tree diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala index 57d66c60b..9be98ee65 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala @@ -65,7 +65,7 @@ trait ErrorMessagesTest extends DottyTest { } def assertMessageCount(expected: Int, messages: List[Message]): Unit = - assertEquals( + assertEquals(messages.mkString, expected, messages.length ) diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index be641fe15..697a00510 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -4,7 +4,7 @@ package reporting import core.Contexts.Context import diagnostic.messages._ - +import dotty.tools.dotc.parsing.Tokens import org.junit.Assert._ import org.junit.Test @@ -85,4 +85,55 @@ class ErrorMessagesTests extends ErrorMessagesTest { assert(sameName.forall(_.symbol.name.show == "bar"), "at least one method had an unexpected name") } + + @Test def forwardReference = + checkMessagesAfter("refchecks") { + """ + |object Forward { + | def block = { + | a.toInt + | val b = 2 + | val a = BigDecimal("4") + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + assertMessageCount(1, messages) + val ForwardReferenceExtendsOverDefinition(value, definition) :: Nil = messages + assertEquals("value b", value.show) + assertEquals("value a", definition.show) + } + + @Test def unexpectedToken = + checkMessagesAfter("frontend") { + """ + |object Forward { + | def val = "ds" + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + assertMessageCount(1, messages) + val ExpectedTokenButFound(expected, found, foundName) :: Nil = messages + assertEquals(Tokens.IDENTIFIER, expected) + assertEquals(Tokens.VAL, found) + assertEquals("val", foundName.show) + } + + @Test def expectedToken = + checkMessagesAfter("frontend") { + """ + |object Forward { + | def `val` = "ds" + |} + """.stripMargin + } + .expectNoErrors } diff --git a/tests/pos/i1975.scala b/tests/pos/i1975.scala new file mode 100644 index 000000000..4657a6735 --- /dev/null +++ b/tests/pos/i1975.scala @@ -0,0 +1,5 @@ +object Test { + val X = Seq(1, 2) + + for (X <- Seq(3, 4)) yield println(X) +} diff --git a/tests/pos/i1976.scala b/tests/pos/i1976.scala new file mode 100644 index 000000000..32967977d --- /dev/null +++ b/tests/pos/i1976.scala @@ -0,0 +1,4 @@ +object Test { + import scala.xml._ + val node = <node>{ "whatever " }</node> +} diff --git a/tests/repl/errmsgs.check b/tests/repl/errmsgs.check index 0dc8e8ae5..d7a230e61 100644 --- a/tests/repl/errmsgs.check +++ b/tests/repl/errmsgs.check @@ -85,4 +85,11 @@ scala> val x: List[Int] = "foo" :: List(1) | found: String($1$) | required: Int | +scala> { def f: Int = g; val x: Int = 1; def g: Int = 5; } +-- [E039] Reference Error: <console> ------------------------------------------- +5 |{ def f: Int = g; val x: Int = 1; def g: Int = 5; } + | ^ + | `g` is a forward reference extending over the definition of `x` + +longer explanation available when compiling with `-explain` scala> :quit |