Skip to content

Commit

Permalink
Warn on inline given aliases with functions as RHS
Browse files Browse the repository at this point in the history
```scala
    inline given a: Conversion[String, Item] = Item(_)
```
will now produce this warning:
```
 5 |  inline given a: Conversion[String, Item] = Item(_)
   |                                             ^^^^^^^
   |An inline given alias with a function value as right-hand side can significantly increase
   |generated code size. You should either drop the `inline` or rewrite the given with an
   |explicit `apply` method.
   |----------------------------------------------------------------------------
   | Explanation (enabled by `-explain`)
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   | A function value on the right-hand side of an inline given alias expands to
   | an anonymous class. Each application of the inline given will then create a
   | fresh copy of that class, which can increase code size in surprising ways.
   | For that reason, functions are discouraged as right hand sides of inline given aliases.
   | You should either drop `inline` or rewrite to an explicit `apply` method. E.g.
   |
   |     inline given Conversion[A, B] = x => x.toB
   |
   | should be re-formulated as
   |
   |     inline given Conversion[A, B] with
   |       def apply(x: A) = x.toB
   |
```
Fixes scala#16497
  • Loading branch information
odersky authored and little-inferno committed Jan 25, 2023
1 parent 758f3eb commit 5bb693e
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case MissingArgumentID // errorNumer 171
case MissingImplicitArgumentID // errorNumber 172
case CannotBeAccessedID // errorNumber 173
case InlineGivenShouldNotBeFunctionID // errorNumber 174

def errorNumber = ordinal - 1

Expand Down
20 changes: 20 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2769,4 +2769,24 @@ extends ReferenceMsg(CannotBeAccessedID):
i"$whatCanNot be accessed as a member of $pre$where.$whyNot"
def explain(using Context) = ""

class InlineGivenShouldNotBeFunction()(using Context)
extends SyntaxMsg(InlineGivenShouldNotBeFunctionID):
def msg(using Context) =
i"""An inline given alias with a function value as right-hand side can significantly increase
|generated code size. You should either drop the `inline` or rewrite the given with an
|explicit `apply` method."""
def explain(using Context) =
i"""A function value on the right-hand side of an inline given alias expands to
|an anonymous class. Each application of the inline given will then create a
|fresh copy of that class, which can increase code size in surprising ways.
|For that reason, functions are discouraged as right hand sides of inline given aliases.
|You should either drop `inline` or rewrite to an explicit `apply` method. E.g.
|
| inline given Conversion[A, B] = x => x.toB
|
|should be re-formulated as
|
| inline given Conversion[A, B] with
| def apply(x: A) = x.toB
"""

4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2374,6 +2374,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
if sym.isInlineMethod then
if StagingContext.level > 0 then
report.error("inline def cannot be within quotes", sym.sourcePos)
if sym.is(Given)
&& untpd.stripBlock(untpd.unsplice(ddef.rhs)).isInstanceOf[untpd.Function]
then
report.warning(InlineGivenShouldNotBeFunction(), ddef.rhs.srcPos)
val rhsToInline = PrepareInlineable.wrapRHS(ddef, tpt1, rhs1)
PrepareInlineable.registerInlineInfo(sym, rhsToInline)

Expand Down
15 changes: 15 additions & 0 deletions tests/neg-custom-args/fatal-warnings/inline-givens.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

class Item(x: String)

inline given a: Conversion[String, Item] =
Item(_) // error

inline given b: Conversion[String, Item] =
(x => Item(x)) // error

inline given c: Conversion[String, Item] =
{ x => Item(x) } // error

inline given d: Conversion[String, Item] with
def apply(x: String) = Item(x) // ok

0 comments on commit 5bb693e

Please sign in to comment.