Skip to content
Open
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
16 changes: 15 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,16 @@ abstract class Lifter {
// Mark the type of lifted definitions as inferred
ValDef(sym, rhs, inferred = true)

/** Type assigned to a lifted temporary symbol. */
protected def liftedExprType(expr: Tree)(using Context): Type =
expr.tpe.widen.deskolemized

private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: TermName = EmptyTermName)(using Context): Tree =
if (noLift(expr)) expr
else {
val name = UniqueName.fresh(prefix)
// don't instantiate here, as the type params could be further constrained, see tests/pos/pickleinf.scala
var liftedType = expr.tpe.widen.deskolemized
var liftedType = liftedExprType(expr)
if (liftedFlags.is(Method)) liftedType = ExprType(liftedType)
val lifted = newSymbol(ctx.owner, name, liftedFlags | Synthetic, liftedType, coord = spanCoord(expr.span),
// Lifted definitions will be added to a local block, so they need to be
Expand Down Expand Up @@ -213,6 +217,16 @@ object LiftCoverage extends LiftImpure {
override def noLift(expr: tpd.Tree)(using Context) =
if liftingArgs then noLiftArg(expr) else super.noLift(expr)

/** Preserve singleton precision for lifted coverage temps when the underlying value is a
* compile-time constant (same notion ConstFold uses), so constant re-folding after lifting
* still matches the original inferred singleton type. Everything else uses the base widen.
*/
override protected def liftedExprType(expr: tpd.Tree)(using Context): Type =
val dealiased = expr.tpe.dealias.deskolemized
dealiased.widenTermRefExpr.normalized.simplified match
case _: ConstantType => dealiased
case _ => super.liftedExprType(expr)

def liftForCoverage(defs: mutable.ListBuffer[tpd.Tree], tree: tpd.Apply)(using Context) = {
val liftedFun = liftApp(defs, tree.fun)
val liftedArgs = liftArgs(defs, tree.fun.tpe, tree.args)(using liftingArgsContext)
Expand Down
1 change: 0 additions & 1 deletion compiler/test/dotc/scoverage-ignore.excludelist
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ i9228.scala
i9880.scala
infersingle.scala
interop-unsound-src
java-collectors.scala
large2.scala
match-single-sub-case.scala
match-sub-cases.scala
Expand Down
19 changes: 19 additions & 0 deletions tests/coverage/pos/SingletonLiftCoverage.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** Coverage test: singleton precision preserved when lifting for coverage.
*
* Regression test for the GenBCodeOps crash (Found: Int, Required: (9 : Int)).
* Both examples trigger LiftCoverage to lift Apply args; the fix preserves
* singleton types so Ycheck passes.
*/
package covtest

object Ops:
final val PUBLIC = 1
final val STATIC = 8

object SingletonLiftMinimal:
// + 0 forces the arg to be an Apply (lifted by coverage), producing Ops.PUBLIC | x$1
final val PublicStatic = Ops.PUBLIC | (Ops.STATIC + 0)

object SingletonLiftJavaReflect:
final val PublicStatic =
java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.STATIC
105 changes: 105 additions & 0 deletions tests/coverage/pos/SingletonLiftCoverage.scoverage.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Coverage data, format version: 3.0
# Statement data:
# - id
# - source path
# - package name
# - class name
# - class type (Class, Object or Trait)
# - full class name
# - method name
# - start offset
# - end offset
# - line number
# - symbol name
# - tree name
# - is branch
# - invocations count
# - is ignored
# - description (can be multi-line)
# ' ' sign
# ------------------------------------------
0
SingletonLiftCoverage.scala
covtest
Ops
Object
covtest.Ops
<init>
331
332
10
<none>
Literal
false
0
false
1

1
SingletonLiftCoverage.scala
covtest
Ops
Object
covtest.Ops
<init>
354
355
11
<none>
Literal
false
0
false
8

2
SingletonLiftCoverage.scala
covtest
SingletonLiftMinimal
Object
covtest.SingletonLiftMinimal
<init>
501
529
15
|
Apply
false
0
false
Ops.PUBLIC | (Ops.STATIC + 0

3
SingletonLiftCoverage.scala
covtest
SingletonLiftMinimal
Object
covtest.SingletonLiftMinimal
<init>
515
529
15
+
Apply
false
0
false
Ops.STATIC + 0

4
SingletonLiftCoverage.scala
covtest
SingletonLiftJavaReflect
Object
covtest.SingletonLiftJavaReflect
<init>
596
665
19
|
Apply
false
0
false
java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.STATIC

Loading