diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index d6b69420596b..124a23e7069c 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -202,18 +202,6 @@ object desugar { * def f[T](x: Int)(y: String)(implicit evidence$0: B[T]) = ... * def f$default$1[T] = 1 * def f$default$2[T](x: Int) = x + "m" - * - * 3. Convert <: T to : T in specializing inline methods. E.g. - * - * inline def f(x: Boolean) <: Any = if (x) 1 else "" - * ==> - * inline def f(x: Boolean): Any = if (x) 1 else "" - * - * 4. Upcast non-specializing inline methods. E.g. - * - * inline def f(x: Boolean): Any = if (x) 1 else "" - * ==> - * inline def f(x: Boolean): Any = (if (x) 1 else ""): Any */ private def defDef(meth0: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = { val meth @ DefDef(_, tparams, vparamss, tpt, rhs) = transformQuotedPatternName(meth0) @@ -247,18 +235,9 @@ object desugar { cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs)) } - var meth1 = addEvidenceParams( + val meth1 = addEvidenceParams( cpy.DefDef(meth)(name = methName, tparams = tparams1), epbuf.toList) - if (meth1.mods.is(Inline)) - meth1.tpt match { - case TypeBoundsTree(_, tpt1, _) => - meth1 = cpy.DefDef(meth1)(tpt = tpt1) - case tpt if !tpt.isEmpty && !meth1.rhs.isEmpty => - meth1 = cpy.DefDef(meth1)(rhs = Typed(meth1.rhs, tpt)) - case _ => - } - /** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */ def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match { case vparams :: vparamss1 => diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 24dc1611d229..7251fa986885 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -195,6 +195,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Lazy()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Lazy) case class Inline()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Inline) + + case class Transparent()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.EmptyFlags) } /** Modifiers and annotations for definitions @@ -326,7 +328,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def derivedTree(originalSym: Symbol)(implicit ctx: Context): tpd.Tree } - /** Property key containing TypeTrees whose type is computed + /** Property key containing TypeTrees whose type is computed * from the symbol in this type. These type trees have marker trees * TypeRefOfSym or InfoOfSym as their originals. */ diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 6ae10e0765bb..3f79794fe21a 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -593,6 +593,7 @@ object StdNames { val toString_ : N = "toString" val toTypeConstructor: N = "toTypeConstructor" val tpe : N = "tpe" + val transparent : N = "transparent" val tree : N = "tree" val true_ : N = "true" val typedProductIterator: N = "typedProductIterator" diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index cacfbc9d0ff9..093224b2e5c5 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -33,6 +33,8 @@ object Parsers { import reporting.Message import reporting.messages._ + val AllowOldWhiteboxSyntax = true + case class OpInfo(operand: Tree, operator: Ident, offset: Offset) class ParensCounters { @@ -2692,6 +2694,7 @@ object Parsers { case nme.inline => Mod.Inline() case nme.opaque => Mod.Opaque() case nme.open => Mod.Open() + case nme.transparent => Mod.Transparent() } } @@ -2748,7 +2751,7 @@ object Parsers { * | AccessModifier * | override * | opaque - * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased | inline + * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased | inline | transparent */ def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = { @tailrec @@ -2766,7 +2769,11 @@ object Parsers { } else mods - normalize(loop(start)) + val result = normalize(loop(start)) + for case mod @ Mod.Transparent() <- result.mods do + if !result.is(Inline) then + syntaxError(em"`transparent` can only be used in conjunction with `inline`", mod.span) + result } val funTypeArgMods: BitSet = BitSet(ERASED) @@ -3248,9 +3255,10 @@ object Parsers { case rparamss => leadingVparamss ::: rparamss var tpt = fromWithinReturnType { - if in.token == SUBTYPE && mods.is(Inline) then + if in.token == SUBTYPE && mods.is(Inline) && AllowOldWhiteboxSyntax then in.nextToken() - TypeBoundsTree(EmptyTree, toplevelTyp()) + mods1 = addMod(mods1, Mod.Transparent()) + toplevelTyp() else typedOpt() } if (in.isScala2CompatMode) newLineOptWhenFollowedBy(LBRACE) @@ -3516,12 +3524,13 @@ object Parsers { accept(EQUALS) mods1 |= Final DefDef(name, tparams, vparamss, tpt, subExpr()) - if in.token == USCORE then + if in.token == USCORE && AllowOldWhiteboxSyntax then if !mods.is(Inline) then syntaxError("`_ <:` is only allowed for given with `inline` modifier") in.nextToken() accept(SUBTYPE) - givenAlias(TypeBoundsTree(EmptyTree, toplevelTyp())) + mods1 = addMod(mods1, Mod.Transparent()) + givenAlias(toplevelTyp()) else val parents = constrApps(commaOK = true, templateCanFollow = true) if in.token == EQUALS && parents.length == 1 && parents.head.isType then diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 31a77e51933e..c194108a0484 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -282,5 +282,5 @@ object Tokens extends TokensCommon { final val scala3keywords = BitSet(ENUM, ERASED, GIVEN) - final val softModifierNames = Set(nme.inline, nme.opaque, nme.open) + final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent) } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index dd5d6742c2c5..a30506ba4e69 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -864,7 +864,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { val rawFlags = if (sym.exists) sym.flags else mods.flags if (rawFlags.is(Param)) flagMask = flagMask &~ Given val flags = rawFlags & flagMask - val flagsText = toTextFlags(sym, flags) + var flagsText = toTextFlags(sym, flags) + if mods.hasMod(classOf[untpd.Mod.Transparent]) then + flagsText = "transparent " ~ flagsText val annotations = if (sym.exists) sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(_.tree) else mods.annotations.filterNot(tree => dropAnnotForModText(tree.symbol)) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 41a721e91c0e..71f0d1e03559 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -863,10 +863,10 @@ class Namer { typer: Typer => private def addInlineInfo(sym: Symbol) = original match { case original: untpd.DefDef if sym.isInlineMethod => - PrepareInlineable.registerInlineInfo( - sym, - implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs - )(localContext(sym)) + def rhsToInline(using Context): tpd.Tree = + val mdef = typedAheadExpr(original).asInstanceOf[tpd.DefDef] + PrepareInlineable.wrapRHS(original, mdef.tpt, mdef.rhs) + PrepareInlineable.registerInlineInfo(sym, rhsToInline)(localContext(sym)) case _ => } diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index 1cf6983fedec..d19e4f5b6f0d 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -204,6 +204,11 @@ object PrepareInlineable { def isLocal(sym: Symbol, inlineMethod: Symbol)(implicit ctx: Context): Boolean = isLocalOrParam(sym, inlineMethod) && !(sym.is(Param) && sym.owner == inlineMethod) + /** The type ascription `rhs: tpt`, unless `original` is `transparent`. */ + def wrapRHS(original: untpd.DefDef, tpt: Tree, rhs: Tree)(using Context): Tree = + if original.mods.hasMod(classOf[untpd.Mod.Transparent]) then rhs + else Typed(rhs, tpt) + /** Register inline info for given inlineable method `sym`. * * @param sym The symbol denotation of the inlineable method for which info is registered @@ -213,7 +218,7 @@ object PrepareInlineable { * to have the inline method as owner. */ def registerInlineInfo( - inlined: Symbol, treeExpr: Context => Tree)(implicit ctx: Context): Unit = + inlined: Symbol, treeExpr: Context ?=> Tree)(implicit ctx: Context): Unit = inlined.unforcedAnnotation(defn.BodyAnnot) match { case Some(ann: ConcreteBodyAnnotation) => case Some(ann: LazyBodyAnnotation) if ann.isEvaluated || ann.isEvaluating => @@ -223,7 +228,7 @@ object PrepareInlineable { inlined.updateAnnotation(LazyBodyAnnotation { given ctx as Context = inlineCtx val initialErrorCount = ctx.reporter.errorCount - var inlinedBody = treeExpr(ctx) + var inlinedBody = treeExpr if (ctx.reporter.errorCount == initialErrorCount) { inlinedBody = ctx.compilationUnit.inlineAccessors.makeInlineable(inlinedBody) checkInlineMethod(inlined, inlinedBody) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 426f1487dcf8..6307817963fa 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1735,9 +1735,10 @@ class Typer extends Namer if (sym.isInlineMethod) rhsCtx.addMode(Mode.InlineableBody) val rhs1 = typedExpr(ddef.rhs, tpt1.tpe.widenExpr)(rhsCtx) + val rhsToInline = PrepareInlineable.wrapRHS(ddef, tpt1, rhs1) if (sym.isInlineMethod) - PrepareInlineable.registerInlineInfo(sym, _ => rhs1) + PrepareInlineable.registerInlineInfo(sym, rhsToInline) if (sym.isConstructor && !sym.isPrimaryConstructor) { val ename = sym.erasedName diff --git a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala index c70826a71934..1d6ad20c5a1a 100644 --- a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala @@ -75,7 +75,7 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947 = { val source = """class Foo { - | inline def track[T](inline f: T) <: T = { + | transparent inline def track[T](inline f: T): T = { | foo("tracking") // line 3 | f // line 4 | } @@ -134,11 +134,11 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947b = { val source = """class Foo { - | inline def track2[T](inline f: T) <: T = { + | transparent inline def track2[T](inline f: T): T = { | foo("tracking2") // line 3 | f // line 4 | } - | inline def track[T](inline f: T) <: T = { + | transparent inline def track[T](inline f: T): T = { | foo("tracking") // line 7 | track2 { // line 8 | f // line 9 @@ -194,11 +194,11 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947c = { val source = """class Foo { - | inline def track2[T](inline f: T) <: T = { + | transparent inline def track2[T](inline f: T): T = { | foo("tracking2") // line 3 | f // line 4 | } - | inline def track[T](inline f: T) <: T = { + | transparent inline def track[T](inline f: T): T = { | track2 { // line 7 | foo("fgh") // line 8 | f // line 9 @@ -254,11 +254,11 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947d = { val source = """class Foo { - | inline def track2[T](inline f: T) <: T = { + | transparent inline def track2[T](inline f: T): T = { | foo("tracking2") // line 3 | f // line 4 | } - | inline def track[T](inline f: T) <: T = { + | transparent inline def track[T](inline f: T): T = { | track2 { // line 7 | track2 { // line 8 | f // line 9 @@ -319,7 +319,7 @@ class InlineBytecodeTests extends DottyBytecodeTest { | def test: Int = { | var a = 10 | - | inline def f() = { + | transparent inline def f() = { | a += 1 | } | @@ -356,7 +356,7 @@ class InlineBytecodeTests extends DottyBytecodeTest { val source = """class Test: | given Int = 0 | def f(): Int ?=> Boolean = true : (Int ?=> Boolean) - | inline def g(): Int ?=> Boolean = true + | transparent inline def g(): Int ?=> Boolean = true | def test = g() """.stripMargin diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index c8434db96410..96d0506c06d6 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -104,7 +104,8 @@ yield ### Soft keywords ``` -as derives extension inline on opaque open using +as derives extension inline on opaque open transparent +using * + - ``` diff --git a/docs/docs/reference/contextual/givens.md b/docs/docs/reference/contextual/givens.md index 284997dd5673..000681379ab4 100644 --- a/docs/docs/reference/contextual/givens.md +++ b/docs/docs/reference/contextual/givens.md @@ -79,17 +79,16 @@ given (using config: Config) as Factory = MemoizingFactory(config) An alias given can have type parameters and context parameters just like any other given, but it can only implement a single type. -## Given Whitebox Macro Instances +## Given Macros -An `inline` alias given can be marked as a whitebox macro by writing -`_ <:` in front of the implemented type. Example: +Given aliases can have the `inline` and `transparent` modifiers. +Example: ```scala -inline given mkAnnotations[A, T] as _ <: Annotations[A, T] = ${ +transparent inline given mkAnnotations[A, T] as Annotations[A, T] = ${ // code producing a value of a subtype of Annotations } ``` -The type of an application of `mkAnnotations` is the type of its right hand side, -which can be a proper subtype of the declared result type `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 Instance Initialization @@ -104,7 +103,7 @@ Here is the new syntax for given instances, seen as a delta from the [standard c ``` TmplDef ::= ... | ‘given’ GivenDef -GivenDef ::= [GivenSig] [‘_’ ‘<:’] Type ‘=’ Expr +GivenDef ::= [GivenSig] Type ‘=’ Expr | [GivenSig] ConstrApp {‘,’ ConstrApp } [TemplateBody] GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘as’ ``` diff --git a/docs/docs/reference/metaprogramming/erased-terms.md b/docs/docs/reference/metaprogramming/erased-terms.md index 80347677eedd..2313538c570a 100644 --- a/docs/docs/reference/metaprogramming/erased-terms.md +++ b/docs/docs/reference/metaprogramming/erased-terms.md @@ -171,11 +171,11 @@ final class On extends State final class Off extends State class Machine[S <: State] { - inline def turnOn() <: Machine[On] = inline erasedValue[S] match { + transparent inline def turnOn(): Machine[On] = inline erasedValue[S] match { case _: Off => new Machine[On] case _: On => error("Turning on an already turned on machine") } - inline def turnOff() <: Machine[Off] = inline erasedValue[S] match { + transparent inline def turnOff(): Machine[Off] = inline erasedValue[S] match { case _: On => new Machine[Off] case _: Off => error("Turning off an already turned off machine") } diff --git a/docs/docs/reference/metaprogramming/inline.md b/docs/docs/reference/metaprogramming/inline.md index b47d21bbe0cb..9e1ba3bb002f 100644 --- a/docs/docs/reference/metaprogramming/inline.md +++ b/docs/docs/reference/metaprogramming/inline.md @@ -228,38 +228,33 @@ constant expressions in the sense defined by the [SLS § including _platform-specific_ extensions such as constant folding of pure numeric computations. -## Specializing Inline (Whitebox) +## Transparent Inline Methods -Inline methods support the ` <: T` return type syntax. This means that the return type -of the inline method is going to be specialized to a more precise type upon -expansion. Example: +Inline methods can additionally be declared `transparent`. +This means that the return type of the inline method can be +specialized to a more precise type upon expansion. Example: ```scala class A class B extends A { - def meth() = true + def m() = true } -inline def choose(b: Boolean) <: A = { - if (b) new A() - else new B() -} +transparent inline def choose(b: Boolean): A = + if b then A() else B val obj1 = choose(true) // static type is A val obj2 = choose(false) // static type is B -// obj1.meth() // compile-time error: `meth` is not defined on `A` -obj2.meth() // OK +// obj1.m() // compile-time error: `m` is not defined on `A` +obj2.m() // OK ``` -Here, the inline method `choose` returns an object of either of the two dynamic types -`A` and `B`. If `choose` had been declared with a normal return type `: A`, the result -of its expansion would always be of type `A`, even though the computed value might be -of type `B`. The inline method is a "blackbox" in the sense that details of its -implementation do not leak out. But with the specializing return type `<: A`, -the type of the expansion is the type of the expanded body. If the argument `b` +Here, the inline method `choose` returns an object of either of the two types `A` and `B`. If `choose` had been declared with a normal return type `: A`, the result +of its expansion would always be of type `A`, even though the computed value might be of the subtype `B`. The inline method is a "blackbox" in the sense that details of its implementation do not leak out. But if a `transparent` modifier is given, +the expansion is the type of the expanded body. If the argument `b` is `true`, that type is `A`, otherwise it is `B`. Consequently, calling `meth` on `obj2` type-checks since `obj2` has the same type as the expansion of `choose(false)`, which is `B`. -Inline methods with specializing return types are a "whitebox" in the sense that the type +Transparent inline methods are "whitebox" in the sense that the type of an application of such a method can be more specialized than its declared return type, depending on how the method expands. @@ -268,7 +263,7 @@ the singleton type `0` permitting the addition to be ascribed with the correct type `1`. ```scala -inline def zero() <: Int = 0 +transparent inline def zero(): Int = 0 val one: 1 = zero() + 1 ``` @@ -313,7 +308,7 @@ The example below defines an inline method with a single inline match expression that picks a case based on its static type: ```scala -inline def g(x: Any) <: Any = inline x match { +transparent inline def g(x: Any): Any = inline x match { case x: String => (x, x) // Tuple2[String, String](x, x) case x: Double => x } @@ -323,8 +318,7 @@ g("test") // Has type (String, String) ``` The scrutinee `x` is examined statically and the inline match is reduced -accordingly returning the corresponding value (with the type specialized due to -the `<:` in the return type). This example performs a simple type test over the +accordingly returning the corresponding value (with the type specialized because `g` is declared `transparent`). This example performs a simple type test over the scrutinee. The type can have a richer structure like the simple ADT below. `toInt` matches the structure of a number in [Church-encoding](https://en.wikipedia.org/wiki/Church_encoding) and _computes_ the corresponding integer. @@ -334,7 +328,7 @@ trait Nat case object Zero extends Nat case class Succ[N <: Nat](n: N) extends Nat -inline def toInt(n: Nat) <: Int = inline n match { +transparent inline def toInt(n: Nat): Int = inline n match { case Zero => 0 case Succ(n1) => toInt(n1) + 1 } @@ -357,7 +351,7 @@ type. ```scala import scala.compiletime.{constValue, S} -inline def toIntC[N] <: Int = +transparent inline def toIntC[N]: Int = inline constValue[N] match { case 0 => 0 case _: S[n1] => 1 + toIntC[n1] @@ -423,10 +417,11 @@ Consider the definitions of numbers as in the _Inline Match_ section above. Here is how `toIntT` can be defined: ```scala -inline def toIntT[N <: Nat] <: Int = inline scala.compiletime.erasedValue[N] match { - case _: Zero.type => 0 - case _: Succ[n] => toIntT[n] + 1 -} +transparent inline def toIntT[N <: Nat]: Int = + inline scala.compiletime.erasedValue[N] match { + case _: Zero.type => 0 + case _: Succ[n] => toIntT[n] + 1 + } final val two = toIntT[Succ[Succ[Zero.type]]] ``` @@ -595,7 +590,7 @@ inline def f: Any = summonFrom { The shorthand `summonInline` provides a simple way to write a `summon` that is delayed until the call is inlined. ```scala -inline def summonInline[T] <: T = summonFrom { +transparent inline def summonInline[T]: T = summonFrom { case t: T => t } ``` diff --git a/docs/docs/reference/metaprogramming/macros.md b/docs/docs/reference/metaprogramming/macros.md index 8d93d24927ee..3907cab24b51 100644 --- a/docs/docs/reference/metaprogramming/macros.md +++ b/docs/docs/reference/metaprogramming/macros.md @@ -601,7 +601,7 @@ inline method that can calculate either a value of type `Int` or a value of type `String`. ```scala -inline def defaultOf(inline str: String) <: Any = ${ defaultOfImpl('str) } +transparent inline def defaultOf(inline str: String) = ${ defaultOfImpl('str) } def defaultOfImpl(strExpr: Expr[String])(using QuoteContext): Expr[Any] = strExpr.unliftOrError match diff --git a/tests/disabled/pos/quote-whitebox/Macro_1.scala b/tests/disabled/pos/quote-whitebox/Macro_1.scala index 7f15fc13ae93..f0af21382772 100644 --- a/tests/disabled/pos/quote-whitebox/Macro_1.scala +++ b/tests/disabled/pos/quote-whitebox/Macro_1.scala @@ -3,7 +3,7 @@ import scala.quoted._ object Macro { - inline def charOrString(inline str: String) <: Char | String = ${ impl(str) } + transparent inline def charOrString(inline str: String): Char | String = ${ impl(str) } def impl(str: String) = if (str.length == 1) Expr(str.charAt(0)) else Expr(str) diff --git a/tests/explicit-nulls/pos/flow4.scala b/tests/explicit-nulls/pos/flow4.scala index 8327606bcd13..994b76065d8c 100644 --- a/tests/explicit-nulls/pos/flow4.scala +++ b/tests/explicit-nulls/pos/flow4.scala @@ -6,7 +6,8 @@ class TreeOps { abstract class Tree[A, B](val key: A, val value: B) class RedTree[A, B](override val key: A, override val value: B) extends Tree[A, B](key, value) - private[this] inline def isRedTree(tree: Tree[_, _] | Null) = (tree != null) && tree.isInstanceOf[RedTree[_, _]] + private transparent inline def isRedTree(tree: Tree[_, _] | Null) = + (tree != null) && tree.isInstanceOf[RedTree[_, _]] def foo[A, B](tree: Tree[A, B] | Null): Unit = { if (isRedTree(tree)) { diff --git a/tests/invalid/run/typelevel-patmat.scala b/tests/invalid/run/typelevel-patmat.scala index 62c5225479e1..9f463638c125 100644 --- a/tests/invalid/run/typelevel-patmat.scala +++ b/tests/invalid/run/typelevel-patmat.scala @@ -21,7 +21,7 @@ object Test extends App { type HNil = HNil.type type Z = Z.type - inline def ToNat(inline n: Int) <: Typed[Nat] = + transparent inline def ToNat(inline n: Int): Typed[Nat] = if n == 0 then Typed(Z) else Typed(S(ToNat(n - 1).value)) @@ -35,7 +35,7 @@ object Test extends App { println(x1) println(x2) - inline def toInt(n: Nat) <: Int = inline n match { + transparent inline def toInt(n: Nat): Int = inline n match { case Z => 0 case S(n1) => toInt(n1) + 1 } diff --git a/tests/neg/i7078.scala b/tests/neg/i7078.scala index d49f8a8fee51..9ca3a007c191 100644 --- a/tests/neg/i7078.scala +++ b/tests/neg/i7078.scala @@ -1,7 +1,7 @@ trait A class B extends A -given g1 as _ <: A = B() // error: `_ <:' is only allowed for given with `inline' modifier // error +given g1 as _ <: A = B() // error: `_ <:' is only allowed for given with `inline' modifier inline given g2 as _ <: A: // error: `=' expected def foo = 2 diff --git a/tests/neg/specializing-inline.scala b/tests/neg/specializing-inline.scala index 450c24708b4d..424ff500b6c2 100644 --- a/tests/neg/specializing-inline.scala +++ b/tests/neg/specializing-inline.scala @@ -2,7 +2,7 @@ object Test { inline def h(x: Boolean) = if (x) 1 else "" val z = h(true) - val zc: Int = z + val zc: Int = z // error inline def g <: Any = 1 val y = g diff --git a/tests/neg/transparent-inline.scala b/tests/neg/transparent-inline.scala new file mode 100644 index 000000000000..a5158d9b8a27 --- /dev/null +++ b/tests/neg/transparent-inline.scala @@ -0,0 +1,37 @@ +transparent def bar: Any = 2 // error: transparent can be used only with inline + +object test1: + + def x: Int = baz(true) // error: type mismatch + inline def baz(x: Boolean): Any = + if x then 1 else "" + inline def bam(x: Boolean): Any = + if x then 1 else "" + def y: Int = bam(true) // error: type mismatch + +object test2: + + def x: 1 = baz(true) // OK + transparent inline def baz(x: Boolean) = + if x then 1 else "" + transparent inline def bam(x: Boolean) = + if x then 1 else "" + def y: 1 = bam(true) // OK + +object test3: + + def x: Int = baz(true) // error: type mismatch + inline def baz(x: Boolean) = + if x then 1 else "" + inline def bam(x: Boolean) = + if x then 1 else "" + def y: Int = bam(true) // error: type mismatch + +object test4: + + def x: 1 = baz(true) // OK + transparent inline def baz(x: Boolean): Any = + if x then 1 else "" + transparent inline def bam(x: Boolean): Any = + if x then 1 else "" + def y: 1 = bam(true) // OK diff --git a/tests/pos/inline-rewrite.scala b/tests/pos/inline-rewrite.scala index 3214fa6ad1cc..ce7f0de4de9f 100644 --- a/tests/pos/inline-rewrite.scala +++ b/tests/pos/inline-rewrite.scala @@ -1,6 +1,6 @@ object Test { - inline def f(x: Int) = inline x match { + transparent inline def f(x: Int) = inline x match { case 1 => "a" case 2 => 22 } @@ -9,7 +9,7 @@ object Test { val y = f(2) val yc: Int = y - inline def g(x: Any) = inline x match { + transparent inline def g(x: Any) = inline x match { case x: String => (x, x) case x: Double => x } diff --git a/tests/pos/transparent-inline.scala b/tests/pos/transparent-inline.scala new file mode 100644 index 000000000000..bffebddd6bb2 --- /dev/null +++ b/tests/pos/transparent-inline.scala @@ -0,0 +1,4 @@ +inline def foo: Any = 1 +inline transparent def bar: Any = 2 +val x: 2 = bar + diff --git a/tests/pos/whitebox-given.scala b/tests/pos/whitebox-given.scala new file mode 100644 index 000000000000..2c434d36319d --- /dev/null +++ b/tests/pos/whitebox-given.scala @@ -0,0 +1,2 @@ +transparent inline given Int = 1 +val x: 1 = summon[Int] diff --git a/tests/run-macros/i7887/Macro_1.scala b/tests/run-macros/i7887/Macro_1.scala index be293fdd76ca..74349c8364cb 100644 --- a/tests/run-macros/i7887/Macro_1.scala +++ b/tests/run-macros/i7887/Macro_1.scala @@ -12,6 +12,6 @@ def myMacroImpl(a: quoted.Expr[_])(using qctx: quoted.QuoteContext) = { } -inline def myMacro(a: => Any) = ${ +inline transparent def myMacro(a: => Any) = ${ myMacroImpl('a) }