Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Names.TermName
import NameKinds.{InlineAccessorName, InlineBinderName, InlineScrutineeName}
import config.Printers.inlining
import util.SimpleIdentityMap
import CheckRealizable.{Realizable, realizability}

import collection.mutable

Expand Down Expand Up @@ -417,18 +418,34 @@ class InlineReducer(inliner: Inliner)(using Context):
for (bindings, expr) <- recur(cases) yield
// drop unusable vals and check that no referenes to unusable symbols remain
val cleanupUnusable = new TreeMap:

/** Whether we are currently in a type position */
var inType: Boolean = false

override def transform(tree: Tree)(using Context): Tree =
tree match
case tree: ValDef if unusable.contains(tree.symbol) => EmptyTree
case id: Ident if unusable.contains(id.symbol) =>
report.error(
em"""${id.symbol} is unusable in ${ctx.owner} because it refers to an erased expression
|in the selector of an inline match that reduces to
|
|${Block(bindings, expr)}""",
tree.srcPos)
// This conditions allows references to erased values in type
// positions provided the types of these references are
// realizable. See erased-inline-product.scala and
// tests/neg/erased-inline-unrealizable-path.scala.
if !inType || (realizability(id.tpe.widen) ne Realizable) then
report.error(
em"""${id.symbol} is unusable in ${ctx.owner} because it refers to an erased expression
|in the selector of an inline match that reduces to
|
|${Block(bindings, expr)}""",
tree.srcPos)
tree
case _ => super.transform(tree)
case _ if tree.isType =>
val saved = inType
inType = true
val tree1 = super.transform(tree)
inType = saved
tree1
case _ =>
super.transform(tree)

val bindings1 = bindings.mapConserve(cleanupUnusable.transform).collect:
case mdef: MemberDef => mdef
Expand Down
22 changes: 22 additions & 0 deletions tests/neg/erased-inline-unrealizable-path.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import scala.compiletime.erasedValue

class Box[T]

trait T:
type L

class A extends T:
type L <: Int

class B extends T:
type L >: String

inline def f() =
inline erasedValue[A & B] match
case x: (A & B) =>
val y: String = "String"
val z: x.L = y
z: Int

@main def Test =
println(f().abs) // error
21 changes: 21 additions & 0 deletions tests/run/erased-inline-product-1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import scala.compiletime.{erasedValue, summonInline, error}

inline def sizeTuple[T<: Tuple](): Long =
inline erasedValue[T] match
case _: EmptyTuple => 0
case _: (h *: t) => size[h] + sizeTuple[t]()

inline def sizeProduct[T <: Product](m: scala.deriving.Mirror.ProductOf[T]): Long =
sizeTuple[m.MirroredElemTypes]()

inline def size[T]: Long =
inline erasedValue[T] match
case _: Char => 2
case _: Int => 4
case _: Long => 8
case _: Double => 8
case p: Product => sizeProduct(summonInline[scala.deriving.Mirror.ProductOf[p.type]])
case _ => error(s"unsupported type")

@main def Test =
assert(size[(Int, Long)] == 12)
21 changes: 21 additions & 0 deletions tests/run/erased-inline-product-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import scala.compiletime.{erasedValue, summonInline, error}

inline def sizeTuple[T<: Tuple](): Long =
inline erasedValue[T] match
case _: EmptyTuple => 0
case _: (h *: t) => size[h] + sizeTuple[t]()

inline def sizeProduct[T <: Product](m: scala.deriving.Mirror.ProductOf[T]): Long =
sizeTuple[m.MirroredElemTypes]()

inline def size[T]: Long =
inline erasedValue[T] match
case _: Char => 2
case _: Int => 4
case _: Long => 8
case _: Double => 8
case _: (p & Product) => sizeProduct[(p & Product)](summonInline[scala.deriving.Mirror.ProductOf[p & Product]])
case _ => error(s"unsupported type")

@main def Test =
assert(size[(Int, Long)] == 12)
21 changes: 21 additions & 0 deletions tests/run/erased-inline-product-3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import scala.compiletime.{erasedValue, summonInline, error}

inline def sizeTuple[T <: Tuple](): Long =
inline erasedValue[T] match
case _: EmptyTuple => 0
case _: (h *: t) => size[h] + sizeTuple[t]()

inline def sizeProduct[T](m: scala.deriving.Mirror.ProductOf[T]): Long =
sizeTuple[m.MirroredElemTypes]()

inline def size[T]: Long =
inline erasedValue[T] match
case _: Char => 2
case _: Int => 4
case _: Long => 8
case _: Double => 8
case _: Product => sizeProduct[T](summonInline[scala.deriving.Mirror.ProductOf[T]])
case _ => error(s"unsupported type")

@main def Test =
assert(size[(Int, Long)] == 12)
Loading