Skip to content

Commit c484461

Browse files
committed
Fix #8564: Make concrete inline methods final
1 parent 68e2023 commit c484461

File tree

6 files changed

+66
-16
lines changed

6 files changed

+66
-16
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

+2
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ object desugar {
251251
cpy.DefDef(meth)(name = methName, tparams = tparams1), epbuf.toList)
252252

253253
if (meth1.mods.is(Inline))
254+
if !meth1.rhs.isEmpty then
255+
meth1 = meth1.withMods(meth1.mods | Final)
254256
meth1.tpt match {
255257
case TypeBoundsTree(_, tpt1, _) =>
256258
meth1 = cpy.DefDef(meth1)(tpt = tpt1)

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ object RefChecks {
157157
* 1.8.3 M is of type ()S, O is of type []T and S <: T, or
158158
* 1.9.1 If M is erased, O is erased. If O is erased, M is erased or inline.
159159
* 1.9.2 If M or O are extension methods, they must both be extension methods.
160-
* 1.10 If O is inline, M must be inline
160+
* 1.10.1. If O is inline, M must be inline
161+
* 1.10.2. If M is inline, M must not be deferred
161162
* 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro.
162163
* 2. Check that only abstract classes have deferred members
163164
* 3. Check that concrete classes do not have deferred definitions
@@ -397,8 +398,10 @@ object RefChecks {
397398
overrideError("is an extension method, cannot override a normal method")
398399
else if (other.isAllOf(ExtensionMethod) && !member.isAllOf(ExtensionMethod)) // (1.9.2)
399400
overrideError("is a normal method, cannot override an extension method")
400-
else if other.isInlineMethod && !member.isInlineMethod then // (1.10)
401+
else if other.isInlineMethod && !member.isInlineMethod then // (1.10.1)
401402
overrideError("is not inline, cannot override an inline method")
403+
else if member.isInlineMethod && member.is(Deferred) then // (1.10.2)
404+
overrideError("is inline method, cannot be an abstract override")
402405
else if (other.isScala2Macro && !member.isScala2Macro) // (1.11)
403406
overrideError("cannot be used here - only Scala-2 macros can override Scala-2 macros")
404407
else if (!compatibleTypes(memberTp(self), otherTp(self)) &&

docs/docs/reference/metaprogramming/inline.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ funkyAssertEquals(computeActual(), computeExpected(), computeDelta())
144144
```
145145
### Rules for Overriding
146146

147-
Inline methods can override other methods and can themselves be overridden by other inline methods. The rules are as follows:
147+
Inline methods can override other non-inline methods. The rules are as follows:
148148

149149
1. If an inline method `f` implements or overrides another, non-inline method, the inline method can also be invoked at runtime. For instance, consider the scenario:
150150
```scala
@@ -167,7 +167,7 @@ assert(a.g() == 33)
167167
```
168168
The inlined invocations and the dynamically dispatched invocations give the same results.
169169

170-
2. Inline methods can override or implement normal methods, as the previous example shows. Inline methods can be overridden only by other inline methods.
170+
2. Inline methods are final.
171171

172172
3. Inline methods can also be abstract. An abstract inline method can be implemented only by other inline methods. It cannot be invoked directly:
173173
```scala

tests/neg/inline-override.scala

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
object Test {
2+
3+
abstract class A {
4+
def f1(): Int = 1
5+
def f2(): Int
6+
inline def f3(): Int
7+
inline def f4(): Int = 1
8+
}
9+
10+
class B extends A {
11+
override def f1(): Int = 1 // OK
12+
override def f2(): Int = 1 // OK
13+
override def f3(): Int = 1 // error
14+
override def f4(): Int = 1 // error
15+
}
16+
17+
class C extends A {
18+
inline override def f1(): Int = 1 // OK
19+
inline override def f2(): Int = 1 // OK retained
20+
inline override def f3(): Int = 1 // OK not retianed
21+
inline override def f4(): Int = 1 // error
22+
}
23+
24+
abstract class D extends A {
25+
override def f1(): Int // OK
26+
override def f2(): Int // OK
27+
override def f3(): Int // error
28+
override def f4(): Int // FIXME (1.10.2): error
29+
}
30+
31+
abstract class E extends A { // error f1
32+
inline override def f1(): Int
33+
inline override def f2(): Int // error
34+
inline override def f3(): Int // error
35+
inline override def f4(): Int // FIXME (1.10.1): error
36+
}
37+
38+
}

tests/neg/quote-MacroOverride.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
3+
abstract class A {
4+
inline def f1(): String = "A.f1"
5+
inline def f2(): String = "A.f2"
6+
def f3(): String = "A.f3"
7+
}
8+
9+
object B extends A {
10+
override inline def f1(): String = "B.f1" // error
11+
override inline def f2(): String = "B.f2" // error
12+
override inline def f3(): String = "B.f3"
13+
}
14+
15+
}

tests/run/quote-MacroOverride.scala

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
object Test {
22

33
abstract class A {
4-
inline def f1(): String = "A.f1"
5-
inline def f2(): String = "A.f2"
6-
def f3(): String = "A.f3"
4+
def f(): String = "A.f"
75
}
86

97
object B extends A {
10-
override inline def f1(): String = "B.f1"
11-
override inline def f2(): String = "B.f2"
12-
override inline def f3(): String = "B.f3"
8+
override inline def f(): String = "B.f"
139
}
1410

1511
def main(args: Array[String]): Unit = {
1612
val a: A = B
17-
assert(a.f1() == "A.f1")
18-
assert(a.f2() == "A.f2")
19-
assert(a.f3() == "B.f3")
13+
assert(a.f() == "B.f")
2014

2115
val b: B.type = B
22-
assert(b.f1() == "B.f1")
23-
assert(b.f2() == "B.f2")
24-
assert(b.f3() == "B.f3")
16+
assert(b.f() == "B.f")
2517
}
2618

2719
}

0 commit comments

Comments
 (0)