diff options
21 files changed, 228 insertions, 62 deletions
diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index b164f395fe..c9782de7c8 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -33,7 +33,7 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w if (option) reporter.warning(pos, msg) else if (!(warnings contains pos)) warnings += ((pos, msg)) def summarize() = - if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)) { + if (warnings.nonEmpty && (option.isDefault || option)) { val numWarnings = warnings.size val warningVerb = if (numWarnings == 1) "was" else "were" val warningCount = countElementsAsString(numWarnings, s"$what warning") @@ -105,4 +105,4 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w reporter.error(NoPosition, "No warnings can be incurred under -Xfatal-warnings.") } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 47465875e9..af4e9e8927 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1287,6 +1287,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans private def checkUndesiredProperties(sym: Symbol, pos: Position) { // If symbol is deprecated, and the point of reference is not enclosed // in either a deprecated member or a scala bridge method, issue a warning. + // TODO: x.hasBridgeAnnotation doesn't seem to be needed here... if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) currentRun.reporting.deprecationWarning(pos, sym) @@ -1305,7 +1306,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans reporter.warning(pos, s"${sym.fullLocationString} has changed semantics in version ${sym.migrationVersion.get}:\n${sym.migrationMessage.get}") } // See an explanation of compileTimeOnly in its scaladoc at scala.annotation.compileTimeOnly. - if (sym.isCompileTimeOnly) { + if (sym.isCompileTimeOnly && !currentOwner.ownerChain.exists(x => x.isCompileTimeOnly)) { def defaultMsg = sm"""Reference to ${sym.fullLocationString} should not have survived past type checking, |it should have been processed and eliminated during expansion of an enclosing macro.""" @@ -1633,7 +1634,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if (settings.warnNullaryUnit) checkNullaryMethodReturnType(sym) if (settings.warnInaccessible) { - if (!sym.isConstructor && !sym.isEffectivelyFinal && !sym.isSynthetic) + if (!sym.isConstructor && !sym.isEffectivelyFinalOrNotOverridden && !sym.isSynthetic) checkAccessibilityOfReferencedTypes(tree) } tree match { diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 38b00a015b..db81eecdf5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -82,11 +82,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val buf = accDefs.getOrElse(clazz, sys.error("no acc def buf for "+clazz)) buf += typers(clazz) typed tree } - private def ensureAccessor(sel: Select) = { + private def ensureAccessor(sel: Select, mixName: TermName = nme.EMPTY) = { val Select(qual, name) = sel val sym = sel.symbol val clazz = qual.symbol - val supername = nme.superName(name) + val supername = nme.superName(name, mixName) val superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) orElse { debuglog(s"add super acc ${sym.fullLocationString} to $clazz") val acc = clazz.newMethod(supername, sel.pos, SUPERACCESSOR | PRIVATE | ARTIFACT) setAlias sym @@ -150,8 +150,20 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } } - if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner)) - ensureAccessor(sel) + def mixIsTrait = sup.tpe match { + case SuperType(thisTpe, superTpe) => superTpe.typeSymbol.isTrait + } + + val needAccessor = name.isTermName && { + mix.isEmpty && (clazz.isTrait || clazz != currentClass || !validCurrentOwner) || + // SI-8803. If we access super[A] from an inner class (!= currentClass) or closure (validCurrentOwner), + // where A is the superclass we need an accessor. If A is a parent trait we don't: in this case mixin + // will re-route the super call directly to the impl class (it's statically known). + !mix.isEmpty && (clazz != currentClass || !validCurrentOwner) && !mixIsTrait + } + + if (needAccessor) + ensureAccessor(sel, mix.toTermName) else sel } diff --git a/src/library/scala/runtime/SeqCharSequence.scala b/src/library/scala/runtime/SeqCharSequence.scala index ce7d7afc9e..74e67bb9e7 100644 --- a/src/library/scala/runtime/SeqCharSequence.scala +++ b/src/library/scala/runtime/SeqCharSequence.scala @@ -44,5 +44,10 @@ final class ArrayCharSequence(val xs: Array[Char], start: Int, end: Int) extends new ArrayCharSequence(xs, start1, start1 + newlen) } } - override def toString = xs drop start take length mkString "" + override def toString = { + val start = math.max(this.start, 0) + val end = math.min(xs.length, start + length) + + if (start >= end) "" else new String(xs, start, end - start) + } } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 6848c357c5..d203218c09 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -473,7 +473,7 @@ trait StdNames { ) def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">") - def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name) + def superName(name: Name, mix: Name = EMPTY): TermName = newTermName(SUPER_PREFIX_STRING + name + (if (mix.isEmpty) "" else "$" + mix)) /** The name of an accessor for protected symbols. */ def protName(name: Name): TermName = newTermName(PROTECTED_PREFIX + name) diff --git a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala index d5e2f9a2c4..7cd8fa8e51 100755 --- a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala @@ -681,10 +681,10 @@ trait CommentFactoryBase { this: MemberLookupBase => jump("[[") val parens = 2 + repeatJump('[') val stop = "]" * parens - val target = readUntil { check(stop) || check(" ") } + val target = readUntil { check(stop) || isWhitespaceOrNewLine(char) } val title = if (!check(stop)) Some({ - jump(" ") + jumpWhitespaceOrNewLine() inline(check(stop)) }) else None @@ -723,49 +723,15 @@ trait CommentFactoryBase { this: MemberLookupBase => */ def normalizeIndentation(_code: String): String = { - val code = _code.trim - var maxSkip = Integer.MAX_VALUE - var crtSkip = 0 - var wsArea = true - var index = 0 - var firstLine = true - var emptyLine = true - - while (index < code.length) { - code(index) match { - case ' ' => - if (wsArea) - crtSkip += 1 - case c => - wsArea = (c == '\n') - maxSkip = if (firstLine || emptyLine) maxSkip else if (maxSkip <= crtSkip) maxSkip else crtSkip - crtSkip = if (c == '\n') 0 else crtSkip - firstLine = if (c == '\n') false else firstLine - emptyLine = if (c == '\n') true else false - } - index += 1 - } + val code = _code.replaceAll("\\s+$", "").dropWhile(_ == '\n') // right-trim + remove all leading '\n' + val lines = code.split("\n") - if (maxSkip == 0) - code - else { - index = 0 - val builder = new StringBuilder - while (index < code.length) { - builder.append(code(index)) - if (code(index) == '\n') { - // we want to skip as many spaces are available, if there are less spaces (like on empty lines, do not - // over-consume them) - index += 1 - val limit = index + maxSkip - while ((index < code.length) && (code(index) == ' ') && index < limit) - index += 1 - } - else - index += 1 - } - builder.toString - } + // maxSkip - size of the longest common whitespace prefix of non-empty lines + val nonEmptyLines = lines.filter(_.trim.nonEmpty) + val maxSkip = if (nonEmptyLines.isEmpty) 0 else nonEmptyLines.map(line => line.prefixLength(_ == ' ')).min + + // remove common whitespace prefix + lines.map(line => if (line.trim.nonEmpty) line.substring(maxSkip) else line).mkString("\n") } def checkParaEnded(): Boolean = { @@ -899,6 +865,8 @@ trait CommentFactoryBase { this: MemberLookupBase => def jumpWhitespace() = jumpUntil(!isWhitespace(char)) + def jumpWhitespaceOrNewLine() = jumpUntil(!isWhitespaceOrNewLine(char)) + /* READERS */ final def readUntil(c: Char): String = { @@ -938,5 +906,7 @@ trait CommentFactoryBase { this: MemberLookupBase => /* CHARS CLASSES */ def isWhitespace(c: Char) = c == ' ' || c == '\t' + + def isWhitespaceOrNewLine(c: Char) = isWhitespace(c) || c == '\n' } } diff --git a/test/files/jvm/varargs/VaClass.scala b/test/files/jvm/varargs/VaClass.scala index e94e8a625a..d83e63ace1 100644 --- a/test/files/jvm/varargs/VaClass.scala +++ b/test/files/jvm/varargs/VaClass.scala @@ -9,5 +9,7 @@ class VaClass { @varargs def vs(a: Int, b: String*) = println(a + b.length) @varargs def vi(a: Int, b: Int*) = println(a + b.sum) @varargs def vt[T](a: Int, b: T*) = println(a + b.length) - @varargs def vt1[T](a: Int, b: T*): T = b.head + + // TODO remove type bound after fixing SI-8786, see also https://github.com/scala/scala/pull/3961 + @varargs def vt1[T <: String](a: Int, b: T*): T = b.head } diff --git a/test/files/neg/compile-time-only-a.check b/test/files/neg/compile-time-only-a.check index 9bc96f6b9b..b1ed1d24c2 100644 --- a/test/files/neg/compile-time-only-a.check +++ b/test/files/neg/compile-time-only-a.check @@ -4,9 +4,6 @@ compile-time-only-a.scala:10: error: C3 compile-time-only-a.scala:12: error: C4 @compileTimeOnly("C4") case class C4(x: Int) ^ -compile-time-only-a.scala:17: error: C5 - implicit class C5(val x: Int) { - ^ compile-time-only-a.scala:32: error: C1 new C1() ^ @@ -76,4 +73,4 @@ compile-time-only-a.scala:75: error: placebo compile-time-only-a.scala:75: error: placebo @placebo def x = (2: @placebo) ^ -26 errors found +25 errors found diff --git a/test/files/pos/t8410.flags b/test/files/pos/t8410.flags new file mode 100644 index 0000000000..dcd5943c2f --- /dev/null +++ b/test/files/pos/t8410.flags @@ -0,0 +1 @@ +-optimise -Xfatal-warnings -deprecation:false -Yinline-warnings:false diff --git a/test/files/pos/t8410.scala b/test/files/pos/t8410.scala new file mode 100644 index 0000000000..4d862311fa --- /dev/null +++ b/test/files/pos/t8410.scala @@ -0,0 +1,15 @@ + +object Test extends App { + @deprecated("","") def f = 42 + @deprecated("","") def z = f + def g = { @deprecated("","") def _f = f ; _f } // warns in 2.11.0-M8 + def x = { @deprecated("","") class X { def x = f } ; new X().x } // warns in 2.11.0-M8 + Console println g + Console println f // warns + + @deprecated("","") trait T + object T extends T { def t = f } + Console println T.t + + def k = List(0).dropWhile(_ < 1) // inlining warns doubly +} diff --git a/test/files/pos/t8498.scala b/test/files/pos/t8498.scala new file mode 100644 index 0000000000..6808c89051 --- /dev/null +++ b/test/files/pos/t8498.scala @@ -0,0 +1,6 @@ +import scala.annotation.compileTimeOnly + +class C(val s: String) extends AnyVal { + @compileTimeOnly("error") + def error = ??? +} diff --git a/test/files/pos/t8828.flags b/test/files/pos/t8828.flags new file mode 100644 index 0000000000..e68991f643 --- /dev/null +++ b/test/files/pos/t8828.flags @@ -0,0 +1 @@ +-Xlint:inaccessible -Xfatal-warnings diff --git a/test/files/pos/t8828.scala b/test/files/pos/t8828.scala new file mode 100644 index 0000000000..92092b4dd4 --- /dev/null +++ b/test/files/pos/t8828.scala @@ -0,0 +1,20 @@ + +package outer + +package inner { + + private[inner] class A + + // the class is final: no warning + private[outer] final class B { + def doWork(a: A): A = a + } + + // the trait is sealed and doWork is not + // and cannot be overriden: no warning + private[outer] sealed trait C { + def doWork(a: A): A = a + } + + private[outer] final class D extends C +} diff --git a/test/files/run/t8803.check b/test/files/run/t8803.check new file mode 100644 index 0000000000..bd26a0fb14 --- /dev/null +++ b/test/files/run/t8803.check @@ -0,0 +1,16 @@ +a +b +b +c +a +b +b +c +a +b +b +c +a +b +b +c diff --git a/test/files/run/t8803.scala b/test/files/run/t8803.scala new file mode 100644 index 0000000000..2e56180502 --- /dev/null +++ b/test/files/run/t8803.scala @@ -0,0 +1,57 @@ +class A { + def m = "a" + protected def n = "a" +} + +trait B { + def m = "b" + protected def n = "b" +} + +class C extends A with B { + override def m = "c" + override protected def n = "c" + + val f1 = () => super[A].m + val f2 = () => super[B].m + val f3 = () => super.m + val f4 = () => this.m + + val g1 = new runtime.AbstractFunction0[String] { def apply() = C.super[A].m } + val g2 = new runtime.AbstractFunction0[String] { def apply() = C.super[B].m } + val g3 = new runtime.AbstractFunction0[String] { def apply() = C.super.m } + val g4 = new runtime.AbstractFunction0[String] { def apply() = C.this.m } + + val h1 = () => super[A].n + val h2 = () => super[B].n + val h3 = () => super.n + val h4 = () => this.n + + val i1 = new runtime.AbstractFunction0[String] { def apply() = C.super[A].n } + val i2 = new runtime.AbstractFunction0[String] { def apply() = C.super[B].n } + val i3 = new runtime.AbstractFunction0[String] { def apply() = C.super.n } + val i4 = new runtime.AbstractFunction0[String] { def apply() = C.this.n } +} + +object Test extends App { + val c = new C + println(c.f1()) + println(c.f2()) + println(c.f3()) + println(c.f4()) + + println(c.g1()) + println(c.g2()) + println(c.g3()) + println(c.g4()) + + println(c.h1()) + println(c.h2()) + println(c.h3()) + println(c.h4()) + + println(c.i1()) + println(c.i2()) + println(c.i3()) + println(c.i4()) +} diff --git a/test/scaladoc/resources/code-indent.scala b/test/scaladoc/resources/code-indent.scala index 88946ffc7f..2eee3352b4 100644 --- a/test/scaladoc/resources/code-indent.scala +++ b/test/scaladoc/resources/code-indent.scala @@ -20,6 +20,12 @@ * an alternative * the e l s e branch * }}} + * {{{ + * Trait example { + * Val x = a + * Val y = b + * } + * }}} * NB: Trailing spaces are necessary for this test! * {{{ * l1 diff --git a/test/scaladoc/run/t8113.check b/test/scaladoc/run/t8113.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/t8113.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/t8113.scala b/test/scaladoc/run/t8113.scala new file mode 100644 index 0000000000..f006213ef2 --- /dev/null +++ b/test/scaladoc/run/t8113.scala @@ -0,0 +1,36 @@ +import scala.tools.nsc.doc.base._ +import scala.tools.nsc.doc.base.comment._ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def code = """ + /** + * Check out [[http://www.scala-lang.org + * this great website]]! + */ + class Test + """ + + def scaladocSettings = "" + + def testModel(rootPackage: Package) = { + import access._ + + val test = rootPackage._class("Test") + + // find Link + def find(body: Any): Option[Link] = body match { + case l: Link => Some(l) + case s: Seq[_] => s.toList.map(find(_)).flatten.headOption + case p: Product => p.productIterator.toList.map(find(_)).flatten.headOption + case _ => None + } + + val link = find(test.comment.get.body).collect { case Link(ta, Text(ti)) => (ta, ti) } + assert(link.isDefined) + val expected = ("http://www.scala-lang.org", "this great website") + link.foreach {l => assert(l == expected, s"$l != $expected")} + } +} diff --git a/test/scaladoc/run/t8314.check b/test/scaladoc/run/t8314.check new file mode 100644 index 0000000000..aa04c12c8f --- /dev/null +++ b/test/scaladoc/run/t8314.check @@ -0,0 +1,3 @@ +Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This should be ), Monospace(Text(monospaced)))))))))) + +Done. diff --git a/test/scaladoc/run/t8314.scala b/test/scaladoc/run/t8314.scala new file mode 100644 index 0000000000..7f6d6fdb00 --- /dev/null +++ b/test/scaladoc/run/t8314.scala @@ -0,0 +1,16 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + override def code = """ + /** This should be `monospaced` */ + class A + """ + + def scaladocSettings = "" + + def testModel(root: Package) = { + import access._ + root._class("A").comment foreach println + } +} diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index ef70e0bf21..da0f253a37 100644 --- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -659,6 +659,7 @@ object Test extends Properties("HtmlFactory") { s.contains("<pre>two lines, one useful</pre>") && s.contains("<pre>line1\nline2\nline3\nline4</pre>") && s.contains("<pre>a ragged example\na (condition)\n the t h e n branch\nan alternative\n the e l s e branch</pre>") && + s.contains("<pre>Trait example {\n Val x = a\n Val y = b\n}</pre>") && s.contains("<pre>l1\n\nl2\n\nl3\n\nl4\n\nl5</pre>") } case _ => false @@ -683,7 +684,7 @@ object Test extends Properties("HtmlFactory") { oneAuthor match { case node: scala.xml.Node => { val s = node.toString - s.contains("<h6>Author:</h6>") + s.contains("<h6>Author:</h6>") && s.contains("<p>The Only Author\n</p>") } case _ => false @@ -696,8 +697,8 @@ object Test extends Properties("HtmlFactory") { twoAuthors match { case node: scala.xml.Node => { val s = node.toString - s.contains("<h6>Authors:</h6>") - s.contains("<p>The First Author\n</p>") + s.contains("<h6>Authors:</h6>") && + s.contains("<p>The First Author</p>") && s.contains("<p>The Second Author\n</p>") } case _ => false |