Skip to content

Commit b757533

Browse files
committed
Allow abstract inline methods
- Introduce a new restriction that inline methods can only be implemented or overridden by other inline methods. - Drop the old restriction that inline methods must override at least one concrete method. - Change the rules for retaining inline methods: An inline method is retained if it overrides or implements at least one non-inline method.
1 parent a8bdfe5 commit b757533

File tree

10 files changed

+32
-20
lines changed

10 files changed

+32
-20
lines changed

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,8 @@ object SymDenotations {
938938
def isInlineMethod(implicit ctx: Context): Boolean =
939939
isAllOf(InlineMethod, butNot = Accessor)
940940

941-
def isInlineRetained: Ctx[Boolean] = is(Override)
941+
def isInlineRetained: Ctx[Boolean] =
942+
allOverriddenSymbols.exists(!_.is(Inline))
942943

943944
/** Is this a Scala 2 macro */
944945
final def isScala2Macro(implicit ctx: Context): Boolean = is(Macro) && symbol.owner.is(Scala2x)

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class TreeChecker extends Phase with SymTransformer {
8080
val badDeferredAndPrivate =
8181
sym.is(Method) && sym.is(Deferred) && sym.is(Private)
8282
&& !sym.hasAnnotation(defn.NativeAnnot)
83-
&& !sym.is(Erased)
83+
&& !sym.isEffectivelyErased
84+
8485
assert(!badDeferredAndPrivate, i"$sym is both Deferred and Private")
8586

8687
checkCompanion(symd)

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,6 @@ object Checking {
472472
fail(OnlyClassesCanHaveDeclaredButUndefinedMembers(sym))
473473
checkWithDeferred(Private)
474474
checkWithDeferred(Final)
475-
checkWithDeferred(Inline)
476475
}
477476
if (sym.isValueClass && sym.is(Trait) && !sym.isRefinementClass)
478477
fail(CannotExtendAnyVal(sym))

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ 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 M is an inline or Scala-2 macro method, O cannot be deferred unless
161-
* there's also a concrete method that M overrides.
160+
* 1.10 If O is inline, M must be inline
162161
* 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro.
163162
* 2. Check that only abstract classes have deferred members
164163
* 3. Check that concrete classes do not have deferred definitions
@@ -398,9 +397,8 @@ object RefChecks {
398397
overrideError("is an extension method, cannot override a normal method")
399398
else if (other.isAllOf(ExtensionMethod) && !member.isAllOf(ExtensionMethod)) // (1.9.2)
400399
overrideError("is a normal method, cannot override an extension method")
401-
else if ((member.isInlineMethod || member.isScala2Macro) && other.is(Deferred) &&
402-
member.extendedOverriddenSymbols.forall(_.is(Deferred))) // (1.10)
403-
overrideError("is an inline method, must override at least one concrete method")
400+
else if other.isInlineMethod && !member.isInlineMethod then // (1.10)
401+
overrideError("is not inline, cannot override an inline method")
404402
else if (other.isScala2Macro && !member.isScala2Macro) // (1.11)
405403
overrideError("cannot be used here - only Scala-2 macros can override Scala-2 macros")
406404
else if (!compatibleTypes(memberTp(self), otherTp(self)) &&

tests/neg-macros/quote-MacroOverride.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ object Test {
66
}
77

88
object B extends A {
9-
override inline def f() = () // error: method f of type (): Unit is an inline method, must override at least one concrete method
10-
override def g() = ()
9+
override inline def f() = ()
10+
override def g() = () // error: is not inline, cannot override an inline method
1111
}
1212

1313
}

tests/neg/inlinevals.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
object Test {
22

3-
def power0(x: Double, inline n: Int): Double = ??? // error
3+
def power0(x: Double, inline n: Int): Double = ??? // error: inline modifier can only be used for parameters of inline methods
44

55
inline def power(x: Double, inline n: Int): Double = // ok
66
inline if n == 0 then ??? else ???
@@ -10,21 +10,21 @@ object Test {
1010

1111
inline inline val twice = 30 // error: repeated modifier
1212

13-
class C(inline x: Int, private inline val y: Int) { // error // error
14-
inline val foo: Int // error: abstract member may not be inline
15-
inline def bar: Int // error: abstract member may not be inline
13+
class C(inline x: Int, private inline val y: Int) { // error // error inline modifier can only be used for parameters of inline methods (both)
14+
inline val foo: Int
15+
inline def bar: Int
1616
}
1717

1818
power(2.0, N) // ok, since it's a by-name parameter
19-
power(2.0, X) // error: argument to inline parameter must be a constant expression
19+
power(2.0, X) // error: cannot reduce inline if
2020

2121
inline val M = X // error: rhs must be constant expression
2222

2323
inline val xs = List(1, 2, 3) // error: must be a constant expression
2424

2525
inline def foo(x: Int) = {
2626

27-
def f(inline xs: List[Int]) = xs // error
27+
def f(inline xs: List[Int]) = xs // error: inline modifier can only be used for parameters of inline methods
2828

2929
inline val y = { println("hi"); 1 } // ok
3030
inline val z = x // ok
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
class B extends A {
2-
inline def f(x: Int): Int = inline x match { // error
2+
inline def f(x: Int): Int = inline x match { // OK
33
case 0 => 1
44
case _ => x
55
}
6-
def g(x: Int): Int = 1 // error
6+
override def g(x: Int): Int = 1 // error: is not inline, cannot override an inline methiod
77
}
88

99

tests/run/inline-override.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
inline 22
22
inline 22
3+
inline 22
4+
inline 22
5+
inline 22

tests/run/inline-override.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
class A:
1+
abstract class A:
22
def f(x: Int) = s"dynamic $x"
3+
def h(x: Int): String
4+
inline def i(x: Int): String
35

46
class B extends A:
57
inline override def f(x: Int) = g(x)
68
inline def g(x: Int) = s"inline $x"
9+
inline def h(x: Int) = g(x)
10+
inline def i(x: Int) = g(x)
711

812
@main def Test =
913
val b = B()
1014
println(b.f(22))
15+
println(b.h(22))
16+
println(b.i(22))
1117
val a: A = b
1218
println(a.f(22))
19+
println(a.h(22))
20+
// println(a.i(22))
21+
22+
1323

tests/run/quote-MacroOverride.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ object Test {
77
}
88

99
object B extends A {
10-
override def f1(): String = "B.f1"
10+
override inline def f1(): String = "B.f1"
1111
override inline def f2(): String = "B.f2"
1212
override inline def f3(): String = "B.f3"
1313
}

0 commit comments

Comments
 (0)