Skip to content

Commit c467d3e

Browse files
authored
Merge pull request #5939 from milessabin/topic/i5938
Prevent synthetic casts from blocking erasure
2 parents ff3b6d1 + 305d6df commit c467d3e

13 files changed

+83
-8
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
562562

563563
/** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */
564564
def stripCast(tree: Tree)(implicit ctx: Context): Tree = {
565-
def isCast(sel: Tree) = sel.symbol == defn.Any_asInstanceOf
565+
def isCast(sel: Tree) = sel.symbol.isTypeCast
566566
unsplice(tree) match {
567567
case TypeApply(sel @ Select(inner, _), _) if isCast(sel) =>
568568
stripCast(inner)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,11 @@ class Definitions {
272272
lazy val Any_isInstanceOf: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
273273
lazy val Any_asInstanceOf: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, _.paramRefs(0), Final)
274274
lazy val Any_typeTest: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final | Synthetic | Artifact)
275+
lazy val Any_typeCast: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOfPM, _.paramRefs(0), Final | Synthetic | Artifact | Erased)
275276
// generated by pattern matcher, eliminated by erasure
276277

277278
def AnyMethods: List[TermSymbol] = List(Any_==, Any_!=, Any_equals, Any_hashCode,
278-
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf, Any_typeTest)
279+
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf, Any_typeTest, Any_typeCast)
279280

280281
lazy val ObjectClass: ClassSymbol = {
281282
val cls = ctx.requiredClass("java.lang.Object")

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ object StdNames {
383383
val asType: N = "asType"
384384
val asClass: N = "asClass"
385385
val asInstanceOf_ : N = "asInstanceOf"
386+
val asInstanceOfPM: N = "$asInstanceOf$"
386387
val assert_ : N = "assert"
387388
val assume_ : N = "assume"
388389
val box: N = "box"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ class ReifyQuotes extends MacroTransform {
346346
override def transform(tree: Tree)(implicit ctx: Context): Tree =
347347
reporting.trace(i"Reifier.transform $tree at $level", show = true) {
348348
tree match {
349-
case TypeApply(Select(spliceTree @ Spliced(_), _), tp) if tree.symbol == defn.Any_asInstanceOf =>
349+
case TypeApply(Select(spliceTree @ Spliced(_), _), tp) if tree.symbol.isTypeCast =>
350350
// Splice term which should be in the form `x.unary_~.asInstanceOf[T]` where T is an artefact of
351351
// typer to allow pickling/unpickling phase consistent types
352352
transformSplice(spliceTree)

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ class SymUtils(val self: Symbol) extends AnyVal {
4646
def isTypeTest(implicit ctx: Context): Boolean =
4747
self == defn.Any_isInstanceOf || self == defn.Any_typeTest
4848

49+
def isTypeCast(implicit ctx: Context): Boolean =
50+
self == defn.Any_asInstanceOf || self == defn.Any_typeCast
51+
4952
def isTypeTestOrCast(implicit ctx: Context): Boolean =
50-
self == defn.Any_asInstanceOf || isTypeTest
53+
isTypeCast || isTypeTest
5154

5255
def isVolatile(implicit ctx: Context): Boolean = self.hasAnnotation(defn.VolatileAnnot)
5356

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ object TypeTestsCasts {
294294
ctx.warning(i"the type test for $argType cannot be checked at runtime", tree.sourcePos)
295295
transformTypeTest(expr, tree.args.head.tpe, flagUnrelated = true)
296296
}
297-
else if (sym eq defn.Any_asInstanceOf)
297+
else if (sym.isTypeCast)
298298
transformAsInstanceOf(erasure(tree.args.head.tpe))
299299
else tree
300300

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
989989
t match {
990990
case Typed(expr, _) =>
991991
Block(stats, expr)
992-
case TypeApply(Select(expr, n), _) if n == defn.Any_asInstanceOf.name =>
992+
case TypeApply(sel@Select(expr, _), _) if sel.symbol.isTypeCast =>
993993
Block(stats, expr)
994994
case _ =>
995995
rhs0

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2622,7 +2622,7 @@ class Typer extends Namer
26222622
// I suspect, but am not 100% sure that this might affect inferred types,
26232623
// if the expected type is a supertype of the GADT bound. It would be good to come
26242624
// up with a test case for this.
2625-
tree.asInstance(pt)
2625+
tree.select(defn.Any_typeCast).appliedToType(pt)
26262626
else
26272627
tree
26282628
}

compiler/test/dotc/pos-from-tasty.blacklist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ i4006c.scala
2424
# Not sure what's wring here
2525
i4203.scala
2626
t6278-synth-def.scala
27+
28+
# Need to print empty tree for implicit match
29+
i5938.scala

compiler/test/dotc/run-from-tasty.blacklist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ typeclass-derivation2a.scala
1212
typeclass-derivation3.scala
1313
derive-generic.scala
1414
deriving-interesting-prefixes.scala
15-
15+
companion-loading.scala

tests/pos/i5938.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
trait Link[T, A]
2+
3+
inline def link[T] = implicit match {
4+
case _: Link[T, s] =>
5+
implicit match {
6+
case stuff: s => stuff
7+
}
8+
}
9+
10+
class Foo
11+
object Foo {
12+
erased implicit val barLink: Link[Foo, Bar.type] = null
13+
}
14+
15+
implicit object Bar {
16+
def baz: Unit = ()
17+
}
18+
19+
object Test extends App {
20+
val bar = link[Foo]
21+
bar.baz
22+
}

tests/run/companion-loading.check

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Test
2+
Foo companion
3+
foo: Foo(23)
4+
FooAssoc
5+
assoc: 23

tests/run/companion-loading.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
trait Assoc[T] {
2+
type U
3+
def foo(t: T): U
4+
}
5+
6+
trait Link[T, A]
7+
8+
case class Foo(i: Int)
9+
object Foo {
10+
println(s"Foo companion")
11+
12+
erased implicit val barLink: Link[Foo, FooAssoc.type] = null
13+
}
14+
15+
implicit object FooAssoc extends Assoc[Foo] {
16+
println(s"FooAssoc")
17+
18+
type U = Int
19+
def foo(t: Foo): Int = t.i
20+
}
21+
22+
inline def link[T] = implicit match {
23+
case _: Link[T, s] =>
24+
implicit match {
25+
case stuff: s => stuff
26+
}
27+
}
28+
29+
object Test {
30+
println(s"Test")
31+
32+
def main(args: Array[String]): Unit = {
33+
val foo = Foo(23)
34+
println(s"foo: $foo")
35+
36+
val assoc = link[Foo]
37+
val res: Int = assoc.foo(foo)
38+
println(s"assoc: ${res}")
39+
}
40+
}

0 commit comments

Comments
 (0)