Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/Reporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,8 @@ object Reporting {
WFlagSelfImplicit,
WFlagUnnamedBooleanLiteral,
WFlagTostringInterpolated,
WFlagValueDiscard
WFlagValueDiscard,
WFlagTraitArgs
= wflag()

sealed class Unused extends WarningCategory {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ abstract class TreeBrowsers {
}
}

jTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
jTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener {
def valueChanged(e: javax.swing.event.TreeSelectionEvent): Unit = {
textArea.setText(e.getPath().getLastPathComponent().toString)
infoPanel.update(e.getPath().getLastPathComponent())
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/settings/Warnings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ trait Warnings {
val warnToString = BooleanSetting("-Wtostring-interpolated", "Warn when a standard interpolator uses toString.")
val warnMultiargInfix = BooleanSetting("-Wmultiarg-infix", "Infix operator was defined or used with multiarg operand.")
def multiargInfix = warnMultiargInfix.value
val warnTraitParens = BooleanSetting("-Wtrait-args", "Warn when a trait has empty parens.")

object PerformanceWarnings extends MultiChoiceEnumeration {
val Captured = Choice("captured", "Modification of var in closure causes boxing.")
Expand Down
56 changes: 27 additions & 29 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1182,37 +1182,35 @@ trait Namers extends MethodSynthesis {

private def templateSig(templ: Template): Type = {
val clazz = context.owner
val parentTrees = typer.typedParentTypes(templ)
val pending = mutable.ListBuffer[AbsTypeError]()
parentTrees foreach { tpt =>
val ptpe = tpt.tpe
if (!ptpe.isError && !phase.erasedTypes) {
val psym = ptpe.typeSymbol
if (psym.isSealed) {
val sameSourceFile = context.unit.source.file == psym.sourceFile
val okChild =
if (psym.isJava)
psym.attachments.get[PermittedSubclassSymbols] match {
case Some(permitted) => permitted.permits.exists(_ == clazz)
case _ => sameSourceFile
}
else
sameSourceFile
if (okChild)
psym.addChild(clazz)
else
pending += ParentSealedInheritanceError(tpt, psym)
val parents =
typer.typedParentTypes(templ).map { tpt =>
val ptpe = tpt.tpe
if (ptpe.isError)
AnyRefTpe
else {
if (!phase.erasedTypes) {
val psym = ptpe.typeSymbol
if (psym.isSealed) {
val sameSourceFile = context.unit.source.file == psym.sourceFile
val okChild =
if (psym.isJava)
psym.attachments.get[PermittedSubclassSymbols] match {
case Some(permitted) => permitted.permits.exists(_ == clazz)
case _ => sameSourceFile
}
else
sameSourceFile
if (okChild)
psym.addChild(clazz)
else
ErrorUtils.issueTypeError(ParentSealedInheritanceError(tpt, psym))
}
if (psym.isLocalToBlock && psym.isClass)
psym.addChild(clazz)
}
ptpe
}
if (psym.isLocalToBlock && psym.isClass)
psym.addChild(clazz)
}
}
pending.foreach(ErrorUtils.issueTypeError)

val parents = {
def checkParent(tpt: Tree): Type = if (tpt.tpe.isError) AnyRefTpe else tpt.tpe
parentTrees map checkParent
}

enterSelf(templ.self)

Expand Down
92 changes: 52 additions & 40 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import scala.annotation._
import scala.collection.mutable, mutable.{ArrayBuffer, ListBuffer}
import scala.reflect.internal.{Chars, TypesStats}
import scala.reflect.internal.util.{CodeAction, FreshNameCreator, ListOfNil, Statistics}
import scala.tools.nsc.Reporting.{MessageFilter, Suppression, WConf, WarningCategory}, WarningCategory.Scala3Migration
import scala.tools.nsc.Reporting.{MessageFilter, Suppression, WConf, WarningCategory}, WarningCategory._
import scala.util.chaining._
import symtab.Flags._
import Mode._
Expand Down Expand Up @@ -1582,12 +1582,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* (3 times from the typer)
* <the same three calls>
*/
private def typedParentType(encodedtpt: Tree, templ: Template, inMixinPosition: Boolean): Tree = {
private def typedParentType(encodedtpt: Tree, templ: Template, inMixinPosition: Boolean, isAnonClass: Boolean): Tree = {
val app @ treeInfo.Applied(core, _, argss) = treeInfo.dissectApplied(encodedtpt)
val decodedtpt = app.callee
val argssAreTrivial = argss == Nil || argss == ListOfNil

// we cannot avoid cyclic references with `initialize` here, because when type macros arrive,
// we cannot avoid cyclic references with `initialize` here, because when type macros arrive [sic],
// we'll have to check the probe for isTypeMacro anyways.
// therefore I think it's reasonable to trade a more specific "inherits itself" error
// for a generic, yet understandable "cyclic reference" error
Expand All @@ -1596,39 +1596,44 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (p == null) NoSymbol
else p.initialize
}

def cookIfNeeded(tpt: Tree) = if (context.unit.isJava) tpt modifyType rawToExistential else tpt
cookIfNeeded(if (probe.isTrait || inMixinPosition) {
if (!argssAreTrivial) {
if (probe.isTrait) ConstrArgsInParentWhichIsTraitError(encodedtpt, probe)
else () // a class in a mixin position - this warrants an error in `validateParentClasses`
// therefore here we do nothing, e.g. don't check that the # of ctor arguments
// matches the # of ctor parameters or stuff like that
}
typedType(decodedtpt)
} else {
val supertpt = typedTypeConstructor(decodedtpt)
val supertparams = if (supertpt.hasSymbolField) supertpt.symbol.typeParams else Nil
def inferParentTypeArgs: Tree = {
typedPrimaryConstrBody(templ) {
val supertpe = PolyType(supertparams, appliedType(supertpt.tpe, supertparams map (_.tpeHK)))
val supercall = New(supertpe, mmap(argss)(_.duplicate))
val treeInfo.Applied(Select(ctor, nme.CONSTRUCTOR), _, _) = supercall: @unchecked
ctor setType supertpe // this is an essential hack, otherwise it will occasionally fail to typecheck
atPos(supertpt.pos.focus)(supercall)
} match {
case EmptyTree => MissingTypeArgumentsParentTpeError(supertpt); supertpt
case tpt => TypeTree(tpt.tpe) setPos supertpt.pos // scala/bug#7224: don't .focus positions of the TypeTree of a parent that exists in source
val tpt =
if (probe.isTrait || inMixinPosition) {
if (probe.isTrait) {
if (!argssAreTrivial)
ConstrArgsInParentWhichIsTraitError(encodedtpt, probe)
else if (settings.warnTraitParens.value && (!isAnonClass || inMixinPosition) && !argss.isEmpty)
context.warning(encodedtpt.pos, "omit parens for trait which takes no arguments", WFlagTraitArgs)
}
//if (!probe.isTrait)
// a class in a mixin position - this warrants an error in `validateParentClasses`
// therefore here we do nothing, e.g. don't check that the # of ctor arguments
// matches the # of ctor parameters or stuff like that
typedType(decodedtpt)
}
else {
val supertpt = typedTypeConstructor(decodedtpt)
val supertparams = if (supertpt.hasSymbolField) supertpt.symbol.typeParams else Nil
def inferParentTypeArgs: Tree = {
typedPrimaryConstrBody(templ) {
val supertpe = PolyType(supertparams, appliedType(supertpt.tpe, supertparams map (_.tpeHK)))
val supercall = New(supertpe, mmap(argss)(_.duplicate))
val treeInfo.Applied(Select(ctor, nme.CONSTRUCTOR), _, _) = supercall: @unchecked
ctor setType supertpe // this is an essential hack, otherwise it will occasionally fail to typecheck
atPos(supertpt.pos.focus)(supercall)
} match {
case EmptyTree => MissingTypeArgumentsParentTpeError(supertpt); supertpt
case tpt => TypeTree(tpt.tpe) setPos supertpt.pos
// scala/bug#7224: don't .focus positions of the TypeTree of a parent that exists in source
}
}
val supertptWithTargs = if (supertparams.isEmpty || context.unit.isJava) supertpt else inferParentTypeArgs

val supertptWithTargs = if (supertparams.isEmpty || context.unit.isJava) supertpt else inferParentTypeArgs

// this is the place where we tell the typer what argss should be used for the super call
// if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`)
// the super call dummy is already good enough, so we don't need to do anything
if (argssAreTrivial) supertptWithTargs else supertptWithTargs updateAttachment SuperArgsAttachment(argss)
})
// this is the place where we tell the typer what argss should be used for the super call
// if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`)
// the super call dummy is already good enough, so we don't need to do anything
if (argssAreTrivial) supertptWithTargs else supertptWithTargs updateAttachment SuperArgsAttachment(argss)
}
if (context.unit.isJava) tpt.modifyType(rawToExistential) else tpt
}

/** Typechecks the mishmash of trees that happen to be stuffed into the primary constructor of a given template.
Expand Down Expand Up @@ -1714,7 +1719,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* If the first parent is a trait, prepend its supertype to the list until it's a class.
*/
private def normalizeFirstParent(parents: List[Tree]): List[Tree] = {
@annotation.tailrec
@tailrec
def explode0(parents: List[Tree]): List[Tree] = {
val supertpt :: rest = parents: @unchecked // parents is always non-empty here - it only grows
if (supertpt.tpe.typeSymbol == AnyClass) {
Expand Down Expand Up @@ -1744,22 +1749,29 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* So we strip the duplicates before typer.
*/
private def fixDuplicateSyntheticParents(parents: List[Tree]): List[Tree] = parents match {
case Nil => Nil
case x :: xs =>
case x :: xs =>
val sym = x.symbol
x :: fixDuplicateSyntheticParents(
if (isPossibleSyntheticParent(sym)) xs.filter(_.symbol != sym)
else xs
)
case nil => Nil
}

def typedParentTypes(templ: Template): List[Tree] = templ.parents match {
case Nil => List(atPos(templ.pos)(TypeTree(AnyRefTpe)))
case first :: rest =>
case parents =>
val isAnonClass = context.owner.isAnonymousClass // permit new T() {} syntax
def loop(parents: List[Tree], inMixinPosition: Boolean): List[Tree] =
parents match {
case parent :: parents =>
typedParentType(parent, templ, inMixinPosition = inMixinPosition, isAnonClass = isAnonClass) ::
loop(parents, inMixinPosition = true)
case _ => Nil
}
try {
val supertpts = fixDuplicateSyntheticParents(normalizeFirstParent(
typedParentType(first, templ, inMixinPosition = false) +:
(rest map (typedParentType(_, templ, inMixinPosition = true)))))
val tpts0 = loop(parents, inMixinPosition = false)
val supertpts = fixDuplicateSyntheticParents(normalizeFirstParent(tpts0))

// if that is required to infer the targs of a super call
// typedParentType calls typedPrimaryConstrBody to do the inferring typecheck
Expand Down
12 changes: 12 additions & 0 deletions test/files/neg/t6805.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
t6805.scala:5: warning: omit parens for trait which takes no arguments
class C extends T() // error
^
t6805.scala:8: warning: omit parens for trait which takes no arguments
class Y extends X with T() // error
^
t6805.scala:12: warning: omit parens for trait which takes no arguments
def v: T = new X with T() // error
^
error: No warnings can be incurred under -Werror.
3 warnings
1 error
14 changes: 14 additions & 0 deletions test/files/neg/t6805.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//> using options -Wtrait-args -Werror

trait T

class C extends T() // error

class X
class Y extends X with T() // error

object funcs {
def t: T = new T() {} // no error, permissive for Java anon syntax, just because
def v: T = new X with T() // error
def w: T = new T {} // correct in every way
}
13 changes: 13 additions & 0 deletions test/files/neg/t6805b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
t6805b.scala:6: error: trait T is a trait; does not take constructor arguments
class D extends T(42) // error
^
t6805b.scala:10: error: trait T is a trait; does not take constructor arguments
class Z extends X with T(42) // error
^
t6805b.scala:14: error: trait T is a trait; does not take constructor arguments
def u: T = new T(42) {} // error
^
t6805b.scala:16: error: trait T is a trait; does not take constructor arguments
def w: T = new X with T(42) // error
^
4 errors
17 changes: 17 additions & 0 deletions test/files/neg/t6805b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// status quo

trait T

class C extends T() // ok
class D extends T(42) // error

class X
class Y extends X with T() // ok
class Z extends X with T(42) // error

object funcs {
def t: T = new T() {} // no error, permissive for Java anon syntax, just because
def u: T = new T(42) {} // error
def v: T = new X with T() // ok
def w: T = new X with T(42) // error
}
2 changes: 1 addition & 1 deletion test/files/pos/t6666d.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import scala.math.Ordering

class Test[K](param:TreeMap[K,Int]){
def this() = this({
implicit object TreeOrd extends Ordering[K](){
implicit val TreeOrd: Ordering[K] = new Ordering[K] {
def compare(a: K, b: K) = {
-1
}
Expand Down
2 changes: 1 addition & 1 deletion test/tasty/run/src-2/tastytest/TestGreeting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ object TestGreeting extends Suite("TestGreeting") {
final val greeting = "Hello, World!"
}

test(assert(new Greeter with Hello().accessGreeting === "Hello, World!"))
test(assert((new Greeter with Hello).accessGreeting === "Hello, World!"))

}
2 changes: 1 addition & 1 deletion test/tasty/run/src-2/tastytest/TestInner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package tastytest
object TestInner extends Suite("TestInner") {

test(assert(Inner.Foo.Bar != null))
test(assert(new Inner.Foo(){}.isInstanceOf[Inner.Foo]))
test(assert(new Inner.Foo {}.isInstanceOf[Inner.Foo]))

}
2 changes: 1 addition & 1 deletion test/tasty/run/src-2/tastytest/TestReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package tastytest

object TestReader extends Suite("TestReader") {

implicit def mkReaderMonad[Ctx]: Reader[Ctx] = new Reader[Ctx]() {}
implicit def mkReaderMonad[Ctx]: Reader[Ctx] = new Reader[Ctx] {}

def pureToString[F[_], A](fa: F[A])(implicit F: Monad[F]): F[String] =
F.flatMap(fa)(a => F.pure(a.toString))
Expand Down