Skip to content

Commit bd86363

Browse files
authored
Warn on inline given aliases with functions as RHS (#16499)
```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 #16497 Alternative to #16498
2 parents f1dcbbe + 8274b10 commit bd86363

File tree

4 files changed

+40
-0
lines changed

4 files changed

+40
-0
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
187187
case MissingArgumentID // errorNumer 171
188188
case MissingImplicitArgumentID // errorNumber 172
189189
case CannotBeAccessedID // errorNumber 173
190+
case InlineGivenShouldNotBeFunctionID // errorNumber 174
190191

191192
def errorNumber = ordinal - 1
192193

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2769,4 +2769,24 @@ extends ReferenceMsg(CannotBeAccessedID):
27692769
i"$whatCanNot be accessed as a member of $pre$where.$whyNot"
27702770
def explain(using Context) = ""
27712771

2772+
class InlineGivenShouldNotBeFunction()(using Context)
2773+
extends SyntaxMsg(InlineGivenShouldNotBeFunctionID):
2774+
def msg(using Context) =
2775+
i"""An inline given alias with a function value as right-hand side can significantly increase
2776+
|generated code size. You should either drop the `inline` or rewrite the given with an
2777+
|explicit `apply` method."""
2778+
def explain(using Context) =
2779+
i"""A function value on the right-hand side of an inline given alias expands to
2780+
|an anonymous class. Each application of the inline given will then create a
2781+
|fresh copy of that class, which can increase code size in surprising ways.
2782+
|For that reason, functions are discouraged as right hand sides of inline given aliases.
2783+
|You should either drop `inline` or rewrite to an explicit `apply` method. E.g.
2784+
|
2785+
| inline given Conversion[A, B] = x => x.toB
2786+
|
2787+
|should be re-formulated as
2788+
|
2789+
| given Conversion[A, B] with
2790+
| inline def apply(x: A) = x.toB
2791+
"""
27722792

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
23742374
if sym.isInlineMethod then
23752375
if StagingContext.level > 0 then
23762376
report.error("inline def cannot be within quotes", sym.sourcePos)
2377+
if sym.is(Given)
2378+
&& untpd.stripBlock(untpd.unsplice(ddef.rhs)).isInstanceOf[untpd.Function]
2379+
then
2380+
report.warning(InlineGivenShouldNotBeFunction(), ddef.rhs.srcPos)
23772381
val rhsToInline = PrepareInlineable.wrapRHS(ddef, tpt1, rhs1)
23782382
PrepareInlineable.registerInlineInfo(sym, rhsToInline)
23792383

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
class Item(x: String)
3+
4+
inline given a: Conversion[String, Item] =
5+
Item(_) // error
6+
7+
inline given b: Conversion[String, Item] =
8+
(x => Item(x)) // error
9+
10+
inline given c: Conversion[String, Item] =
11+
{ x => Item(x) } // error
12+
13+
inline given d: Conversion[String, Item] with
14+
def apply(x: String) = Item(x) // ok
15+

0 commit comments

Comments
 (0)