diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 7121f7e7370d..920871210eee 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -783,7 +783,7 @@ object desugar { DefDef( className.toTermName, joinParams(constrTparams, defParamss), classTypeRef, creatorExpr) - .withMods(companionMods | mods.flags.toTermFlags & GivenOrImplicit | Final) + .withMods(companionMods | mods.flags.toTermFlags & (GivenOrImplicit | Inline) | Final) .withSpan(cdef.span) :: Nil } @@ -809,7 +809,9 @@ object desugar { Nil } } - val classMods = if mods.is(Given) then mods | Synthetic else mods + if mods.isAllOf(Given | Inline | Transparent) then + report.error("inline given instances cannot be trasparent", cdef) + val classMods = if mods.is(Given) then mods &~ (Inline | Transparent) | Synthetic else mods cpy.TypeDef(cdef: TypeDef)( name = className, rhs = cpy.Template(impl)(constr, parents1, clsDerived, self1, diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index bbe2ea914a43..3ffef90057ef 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3637,7 +3637,7 @@ object Parsers { val templ = if isStatSep || isStatSeqEnd then Template(constr, parents, Nil, EmptyValDef, Nil) else withTemplate(constr, parents) - if noParams then ModuleDef(name, templ) + if noParams && !mods.is(Inline) then ModuleDef(name, templ) else TypeDef(name.toTypeName, templ) end gdef finalizeDef(gdef, mods1, start) diff --git a/docs/docs/reference/contextual/givens.md b/docs/docs/reference/contextual/givens.md index 9b90040c01c3..2af94c0a8aea 100644 --- a/docs/docs/reference/contextual/givens.md +++ b/docs/docs/reference/contextual/givens.md @@ -100,6 +100,28 @@ transparent inline given mkAnnotations[A, T]: Annotations[A, T] = ${ Since `mkAnnotations` is `transparent`, the type of an application is the type of its right-hand side, which can be a proper subtype of the declared result type `Annotations[A, T]`. +Given instances can have the `inline` but not `transparent` modifiers as their type is already known from the signature. +Example: + +```scala +trait Show[T] { + inline def show(x: T): String +} + +inline given Show[Foo] with { + /*transparent*/ inline def show(x: Foo): String = ${ ... } +} + +def app = + // inlines `show` method call and removes the call to `given Show[Foo]` + summon[Show[Foo]].show(foo) +``` +Note that the inline methods within the given instances may be `transparent`. + +The inlining of given instances will not inline/duplicate the implementation of the given, it will just inline the instantiation of that instance. +This is used to help dead code elimination of the given instances that are not used after inlining. + + ## Pattern-Bound Given Instances Given instances can also appear in patterns. Example: diff --git a/tests/neg/i14177a.scala b/tests/neg/i14177a.scala new file mode 100644 index 000000000000..3031271c369b --- /dev/null +++ b/tests/neg/i14177a.scala @@ -0,0 +1,6 @@ +import scala.compiletime.* + +trait C[A] + +inline given [Tup <: Tuple]: C[Tup] with + val cs = summonAll[Tuple.Map[Tup, C]] // error cannot reduce inline match with diff --git a/tests/neg/i14177c.scala b/tests/neg/i14177c.scala new file mode 100644 index 000000000000..d281938ca0ea --- /dev/null +++ b/tests/neg/i14177c.scala @@ -0,0 +1,15 @@ +class T + +transparent inline given fail1: T with // error + val cs = scala.compiletime.summonAll[EmptyTuple] +transparent inline given fail2[X]: T with // error + val cs = scala.compiletime.summonAll[EmptyTuple] +transparent inline given fail3(using DummyImplicit): T with // error + val cs = scala.compiletime.summonAll[EmptyTuple] + +transparent inline given ok1: T = new T: + val cs = scala.compiletime.summonAll[EmptyTuple] +transparent inline given ok2[X]: T = new T: + val cs = scala.compiletime.summonAll[EmptyTuple] +transparent inline given ok3(using DummyImplicit): T = new T: + val cs = scala.compiletime.summonAll[EmptyTuple] diff --git a/tests/pos/i14177b.scala b/tests/pos/i14177b.scala new file mode 100644 index 000000000000..6da9a72ae551 --- /dev/null +++ b/tests/pos/i14177b.scala @@ -0,0 +1,15 @@ +class T + +inline given fail1: T with + val cs = scala.compiletime.summonAll[EmptyTuple] +inline given fail2[X]: T with + val cs = scala.compiletime.summonAll[EmptyTuple] +inline given fail3(using DummyImplicit): T with + val cs = scala.compiletime.summonAll[EmptyTuple] + +inline given ok1: T = new T: + val cs = scala.compiletime.summonAll[EmptyTuple] +inline given ok2[X]: T = new T: + val cs = scala.compiletime.summonAll[EmptyTuple] +inline given ok3(using DummyImplicit): T = new T: + val cs = scala.compiletime.summonAll[EmptyTuple] diff --git a/tests/pos/i14282.scala b/tests/pos/i14282.scala new file mode 100644 index 000000000000..2cc3ff1226e2 --- /dev/null +++ b/tests/pos/i14282.scala @@ -0,0 +1,13 @@ +trait Foo[A] { + inline def foo(): Unit +} + +inline given FooA[A]: Foo[A] with { + inline def foo(): Unit = println() +} +def test1 = FooA.foo() + +inline given FooInt: Foo[Int] with { + inline def foo(): Unit = println() +} +def test2 = FooInt.foo()