From 9292a2dddd1de86f2ded767c0054d8684751cefd Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Fri, 5 Jul 2024 18:27:33 +0200 Subject: [PATCH 1/2] Restore forgotten fatal-warnings tests In daeee3544a7933736240d1b79ebe81d699d74b0d, support for tests in the directory `tests/pos-special/fatal-warnings` was dropped in favor of magic `//>` comments in the regular `tests/pos` directory, but a few tests were forgotten in the original directory and were thus not run. This commit moves them to the appropriate directory with the correct magic comment. [Cherry-picked 0ee804f5e5ad4e8712bb11c6a9f1bb172ef7586b][modified] --- compiler/test/dotc/pos-test-pickling.blacklist | 1 + tests/{pos-special/fatal-warnings => pos}/i17735.scala | 4 ++-- tests/{pos-special/fatal-warnings => pos}/i17735a.scala | 2 +- tests/{pos-special/fatal-warnings => pos}/i17741.scala | 4 ++-- tests/{pos-special/fatal-warnings => pos}/nowarnannot.scala | 2 ++ 5 files changed, 8 insertions(+), 5 deletions(-) rename tests/{pos-special/fatal-warnings => pos}/i17735.scala (90%) rename tests/{pos-special/fatal-warnings => pos}/i17735a.scala (90%) rename tests/{pos-special/fatal-warnings => pos}/i17741.scala (90%) rename tests/{pos-special/fatal-warnings => pos}/nowarnannot.scala (66%) diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index cdb65fd40ddc..705570f10d9c 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -28,6 +28,7 @@ i13433.scala i16649-irrefutable.scala strict-pattern-bindings-3.0-migration.scala i17255 +i17735.scala # Tree is huge and blows stack for printing Text i7034.scala diff --git a/tests/pos-special/fatal-warnings/i17735.scala b/tests/pos/i17735.scala similarity index 90% rename from tests/pos-special/fatal-warnings/i17735.scala rename to tests/pos/i17735.scala index 56050d8fd5fd..17fb31010a8a 100644 --- a/tests/pos-special/fatal-warnings/i17735.scala +++ b/tests/pos/i17735.scala @@ -1,4 +1,4 @@ -// scalac: -Wvalue-discard +//> using options -Xfatal-warnings -Wvalue-discard import scala.collection.mutable import scala.annotation.nowarn @@ -21,4 +21,4 @@ object Foo: // here @nowarn is effective without -Wfatal-warnings (i.e. no warning) // But with -Wfatal-warnings we get an error messageBuilder.append("\n").append(s): @nowarn("msg=discarded non-Unit value*") - messageBuilder.result() \ No newline at end of file + messageBuilder.result() diff --git a/tests/pos-special/fatal-warnings/i17735a.scala b/tests/pos/i17735a.scala similarity index 90% rename from tests/pos-special/fatal-warnings/i17735a.scala rename to tests/pos/i17735a.scala index d089763295e6..b4d91f8d25fc 100644 --- a/tests/pos-special/fatal-warnings/i17735a.scala +++ b/tests/pos/i17735a.scala @@ -1,4 +1,4 @@ -// scalac: -Wvalue-discard -Wconf:msg=non-Unit:s +//> using options -Xfatal-warnings -Wvalue-discard -Wconf:msg=non-Unit:s import scala.collection.mutable import scala.annotation.nowarn diff --git a/tests/pos-special/fatal-warnings/i17741.scala b/tests/pos/i17741.scala similarity index 90% rename from tests/pos-special/fatal-warnings/i17741.scala rename to tests/pos/i17741.scala index 07af8b1abd3d..aa32e5a573d4 100644 --- a/tests/pos-special/fatal-warnings/i17741.scala +++ b/tests/pos/i17741.scala @@ -1,4 +1,4 @@ -// scalac: -Wnonunit-statement +//> using options -Xfatal-warnings -Wnonunit-statement class Node() class Elem( @@ -29,4 +29,4 @@ object Main { ) } }: @annotation.nowarn() -} \ No newline at end of file +} diff --git a/tests/pos-special/fatal-warnings/nowarnannot.scala b/tests/pos/nowarnannot.scala similarity index 66% rename from tests/pos-special/fatal-warnings/nowarnannot.scala rename to tests/pos/nowarnannot.scala index 26e9713d0543..1710ae34b56f 100644 --- a/tests/pos-special/fatal-warnings/nowarnannot.scala +++ b/tests/pos/nowarnannot.scala @@ -1,3 +1,5 @@ +//> using options -Xfatal-warnings -Wvalue-discard + case class F(i: Int) object Main { From cb761cb8a17ea2874bbc7951c1b948a3fd9b390e Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 11 Apr 2024 17:41:28 +0200 Subject: [PATCH 2/2] Suppress "extension method will never be selected" for overrides When we're overriding an existing extension method, we don't have the liberty of renaming the method, so we shouldn't get warnings we can't do anything about. [Cherry-picked c7570c81c1eb524ce316360316be0e03fcffde9e] --- .../dotty/tools/dotc/typer/RefChecks.scala | 53 ++++++++++--------- tests/pos/ext-override.scala | 12 +++++ 2 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 tests/pos/ext-override.scala diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index baa9b82b83e8..7db3c90e6f17 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1026,6 +1026,8 @@ object RefChecks { * An extension method is hidden if it does not offer a parameter that is not subsumed * by the corresponding parameter of the member with the same name (or of all alternatives of an overload). * + * This check is suppressed if this method is an override. + * * For example, it is not possible to define a type-safe extension `contains` for `Set`, * since for any parameter type, the existing `contains` method will compile and would be used. * @@ -1043,31 +1045,32 @@ object RefChecks { * If the extension method is nullary, it is always hidden by a member of the same name. * (Either the member is nullary, or the reference is taken as the eta-expansion of the member.) */ - def checkExtensionMethods(sym: Symbol)(using Context): Unit = if sym.is(Extension) then - extension (tp: Type) - def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType - def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes - def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false } - val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver - val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter - def hidden = - target.nonPrivateMember(sym.name) - .filterWithPredicate: - member => - val memberIsImplicit = member.info.hasImplicitParams - val paramTps = - if memberIsImplicit then methTp.stripPoly.firstParamTypes - else methTp.firstExplicitParamTypes - - paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || { - val memberParamTps = member.info.stripPoly.firstParamTypes - !memberParamTps.isEmpty - && memberParamTps.lengthCompare(paramTps) == 0 - && memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m) - } - .exists - if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden - then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos) + def checkExtensionMethods(sym: Symbol)(using Context): Unit = + if sym.is(Extension) && !sym.nextOverriddenSymbol.exists then + extension (tp: Type) + def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType + def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes + def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false } + val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver + val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter + def hidden = + target.nonPrivateMember(sym.name) + .filterWithPredicate: + member => + val memberIsImplicit = member.info.hasImplicitParams + val paramTps = + if memberIsImplicit then methTp.stripPoly.firstParamTypes + else methTp.firstExplicitParamTypes + + paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || { + val memberParamTps = member.info.stripPoly.firstParamTypes + !memberParamTps.isEmpty + && memberParamTps.lengthCompare(paramTps) == 0 + && memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m) + } + .exists + if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden + then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos) end checkExtensionMethods /** Verify that references in the user-defined `@implicitNotFound` message are valid. diff --git a/tests/pos/ext-override.scala b/tests/pos/ext-override.scala new file mode 100644 index 000000000000..d08439e13c9a --- /dev/null +++ b/tests/pos/ext-override.scala @@ -0,0 +1,12 @@ +//> using options -Xfatal-warnings + +trait Foo[T]: + extension (x: T) + def hi: String + +class Bla: + def hi: String = "hi" +object Bla: + given Foo[Bla] with + extension (x: Bla) + def hi: String = x.hi