Skip to content

Commit da17a60

Browse files
authored
Merge pull request scala#10113 from som-snytt/issue/11644-eta-sam-msg
Tweak messaging for -Xlint:eta-sam
2 parents 46bf385 + cbb9e93 commit da17a60

File tree

25 files changed

+200
-58
lines changed

25 files changed

+200
-58
lines changed

src/compiler/scala/reflect/reify/Errors.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
* additional information regarding copyright ownership.
1111
*/
1212

13-
package scala.reflect.reify
13+
package scala.reflect
14+
package reify
1415

15-
import scala.reflect.macros.ReificationException
16-
import scala.reflect.macros.UnexpectedReificationException
16+
import internal.util.StringContextStripMarginOps
17+
import macros.ReificationException
18+
import macros.UnexpectedReificationException
1719

1820
trait Errors {
1921
self: Reifier =>

src/compiler/scala/tools/nsc/package.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
package scala.tools
1414

15+
import scala.reflect.internal.util.StringContextStripMarginOps
16+
1517
package object nsc {
1618
type Mode = scala.reflect.internal.Mode
1719
val Mode = scala.reflect.internal.Mode
@@ -32,4 +34,8 @@ package object nsc {
3234

3335
@deprecated("Use scala.reflect.internal.util.ListOfNil", "2.11.0")
3436
lazy val ListOfNil = scala.reflect.internal.util.ListOfNil
37+
38+
/** Adds the `sm` interpolator to a [[scala.StringContext]].
39+
*/
40+
implicit val `strip margin`: StringContext => StringContextStripMarginOps = StringContextStripMarginOps
3541
}

src/compiler/scala/tools/nsc/settings/Warnings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ trait Warnings {
205205
val Serial = LintWarning("serial", "@SerialVersionUID on traits and non-serializable classes.")
206206
val ValPattern = LintWarning("valpattern", "Enable pattern checks in val definitions.")
207207
val EtaZero = LintWarning("eta-zero", "Usage `f` of parameterless `def f()` resulted in eta-expansion, not empty application `f()`.")
208-
val EtaSam = LintWarning("eta-sam", "The Java-defined target interface for eta-expansion was not annotated @FunctionalInterface.")
208+
val EtaSam = LintWarning("eta-sam", "A method reference was eta-expanded but the expected SAM type was not annotated @FunctionalInterface.")
209209
val Deprecation = LintWarning("deprecation", "Enable -deprecation and also check @deprecated annotations.")
210210
val ByNameImplicit = LintWarning("byname-implicit", "Block adapted by implicit with by-name parameter.")
211211
val RecurseWithDefault = LintWarning("recurse-with-default", "Recursive call used default argument.")

src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
* additional information regarding copyright ownership.
1111
*/
1212

13-
package scala.tools.nsc.transform.patmat
13+
package scala.tools.nsc
14+
package transform.patmat
1415

1516
/** Translate typed Trees that represent pattern matches into the patternmatching IR, defined by TreeMakers.
1617
*/

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ package typechecker
1717
import scala.annotation.{tailrec, unused}
1818
import scala.collection.mutable
1919
import scala.reflect.internal.{Chars, TypesStats}
20-
import scala.reflect.internal.util.{FreshNameCreator, ListOfNil, Statistics}
20+
import scala.reflect.internal.util.{FreshNameCreator, ListOfNil, Statistics, StringContextStripMarginOps}
2121
import scala.tools.nsc.Reporting.{MessageFilter, Suppression, WConf, WarningCategory}
2222
import scala.util.chaining._
2323
import mutable.ListBuffer
@@ -884,26 +884,35 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
884884

885885
def warnTree = original orElse tree
886886

887-
def warnEtaZero(): Boolean = {
888-
if (!settings.warnEtaZero) return true
889-
context.warning(tree.pos,
890-
s"""An unapplied 0-arity method was eta-expanded (due to the expected type $pt), rather than applied to `()`.
891-
|Write ${Apply(warnTree, Nil)} to invoke method ${meth.decodedName}, or change the expected type.""".stripMargin,
892-
WarningCategory.LintEtaZero)
887+
def warnEtaZero(): true = {
888+
if (settings.warnEtaZero) {
889+
context.warning(tree.pos,
890+
s"""An unapplied 0-arity method was eta-expanded (due to the expected type $pt), rather than applied to `()`.
891+
|Write ${Apply(warnTree, Nil)} to invoke method ${meth.decodedName}, or change the expected type.""".stripMargin,
892+
WarningCategory.LintEtaZero)
893+
}
893894
true
894895
}
895896

896-
def warnEtaSam(): Boolean = {
897-
if (!settings.warnEtaSam) return true
898-
val sam = samOf(pt)
899-
val samClazz = sam.owner
900-
// TODO: we allow a Java class as a SAM type, whereas Java only allows the @FunctionalInterface on interfaces -- align?
901-
if (sam.exists && (!samClazz.hasFlag(JAVA) || samClazz.hasFlag(INTERFACE)) && !samClazz.hasAnnotation(definitions.FunctionalInterfaceClass))
902-
context.warning(tree.pos,
903-
s"""Eta-expansion performed to meet expected type $pt, which is SAM-equivalent to ${samToFunctionType(pt)},
904-
|even though $samClazz is not annotated with `@FunctionalInterface`;
905-
|to suppress warning, add the annotation or write out the equivalent function literal.""".stripMargin,
906-
WarningCategory.LintEtaSam)
897+
def warnEtaSam(): true = {
898+
if (settings.warnEtaSam || currentRun.isScala3) {
899+
val sam = samOf(pt)
900+
if (sam.exists) {
901+
val samClazz = sam.owner
902+
val isJavaClass = samClazz.isJava && !samClazz.isInterface
903+
if (!samClazz.hasAnnotation(definitions.FunctionalInterfaceClass)) {
904+
val ft = samToFunctionType(pt)
905+
val sample = Function(meth.paramss.head.map(ValDef(_)), Apply(meth, meth.paramss.head.map(p => Ident(p.name)): _*))
906+
val places = Apply(meth, meth.paramss.head.map(_ => Ident(nme.USCOREkw)): _*)
907+
val advice = if (isJavaClass) "" else s"\n$samClazz should be annotated with `@FunctionalInterface` if eta-expansion is desired."
908+
context.warning(tree.pos,
909+
sm"""Eta-expansion to expected type $pt, which is not a function type but is SAM-convertible to $ft.$advice
910+
|Avoid eta-expansion by writing the function literal `$sample` or `$places`.
911+
|This warning can be filtered with `-Wconf:cat=lint-eta-sam`.""",
912+
WarningCategory.LintEtaSam)
913+
}
914+
}
915+
}
907916
true
908917
}
909918

src/reflect/scala/reflect/internal/Definitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import scala.collection.mutable
1919
import Flags._
2020
import scala.reflect.api.{Universe => ApiUniverse}
2121
import PartialFunction.cond
22+
import util.StringContextStripMarginOps
2223

2324
trait Definitions extends api.StandardDefinitions {
2425
self: SymbolTable =>

src/reflect/scala/reflect/internal/SymbolPairs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package scala
1414
package reflect
1515
package internal
1616

17-
import util.HashSet
17+
import util.{HashSet, StringContextStripMarginOps}
1818
import scala.annotation.tailrec
1919

2020
/** An abstraction for considering symbol pairs.

src/reflect/scala/reflect/internal/SymbolTable.scala

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,12 +509,6 @@ abstract class SymbolTable extends macros.Universe
509509
@deprecated("use enteringPhase", "2.10.0") // Used in sbt 0.12.4
510510
@inline final def atPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph)(op)
511511

512-
513-
/**
514-
* Adds the `sm` String interpolator to a [[scala.StringContext]].
515-
*/
516-
implicit val StringContextStripMarginOps: StringContext => StringContextStripMarginOps = util.StringContextStripMarginOps
517-
518512
protected[scala] def currentRunProfilerBeforeCompletion(root: Symbol, associatedFile: AbstractFile): Unit = ()
519513
protected[scala] def currentRunProfilerAfterCompletion(root: Symbol, associatedFile: AbstractFile): Unit = ()
520514
}

src/reflect/scala/reflect/internal/Trees.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import scala.annotation.{nowarn, tailrec}
1919
import scala.collection.mutable
2020
import scala.collection.mutable.ListBuffer
2121
import scala.reflect.macros.Attachments
22-
import util.{ReusableInstance, Statistics}
22+
import util.{ReusableInstance, Statistics, StringContextStripMarginOps}
2323

2424
trait Trees extends api.Trees {
2525
self: SymbolTable =>

src/reflect/scala/reflect/internal/tpe/TypeComparers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ package reflect
1515
package internal
1616
package tpe
1717

18-
import scala.collection.mutable
19-
import util.TriState
2018
import scala.annotation.tailrec
19+
import scala.collection.mutable
20+
import util.{StringContextStripMarginOps, TriState}
2121

2222
trait TypeComparers {
2323
self: SymbolTable =>

0 commit comments

Comments
 (0)