Skip to content

Commit 06392a5

Browse files
authored
Merge pull request scala#8049 from adriaanm/pr7966-followup
ObjectTpeJava is truly unique; bounds; isAnyTpe
2 parents 1ae9f82 + 7bf179f commit 06392a5

File tree

13 files changed

+119
-35
lines changed

13 files changed

+119
-35
lines changed

src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -672,11 +672,11 @@ abstract class ClassfileParser(reader: ReusableInstance[ReusableDataReader]) {
672672
case '+' => TypeBounds.upper(sig2type(tparams, skiptvs))
673673
case '-' =>
674674
val tp = sig2type(tparams, skiptvs)
675-
// sig2type seems to return AnyClass regardless of the situation:
676-
// we don't want Any as a LOWER bound.
677-
if (tp.typeSymbol == AnyClass) TypeBounds.empty
678-
else TypeBounds.lower(tp)
679-
case '*' => TypeBounds.empty
675+
// Interpret `sig2type` returning `Any` as "no bounds";
676+
// morally equivalent to TypeBounds.empty, but we're representing Java code, so use ObjectTpeJava for AnyTpe.
677+
if (tp.typeSymbol == AnyClass) TypeBounds.upper(definitions.ObjectTpeJava)
678+
else TypeBounds(tp, definitions.ObjectTpeJava)
679+
case '*' => TypeBounds.upper(definitions.ObjectTpeJava)
680680
}
681681
val newtparam = sym.newExistential(newTypeName("?"+i), sym.pos) setInfo bounds
682682
existentials += newtparam

src/reflect/scala/reflect/internal/Definitions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ trait Definitions extends api.StandardDefinitions {
303303
*
304304
* We use `ObjectTpeJava`'s identity to equate it, but not `ObjectTpe`, to `AnyTpe` in subtyping and type equality.
305305
*/
306-
lazy val ObjectTpeJava = mkObjectTpeJava
306+
lazy val ObjectTpeJava = new ObjectTpeJavaRef
307307

308308
lazy val SerializableTpe = SerializableClass.tpe
309309
lazy val StringTpe = StringClass.tpe

src/reflect/scala/reflect/internal/TypeDebugging.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ trait TypeDebugging {
133133
def refine(defs: Scope): String = defs.toList.mkString("{", " ;\n ", "}")
134134
def bounds(lo: Type, hi: Type): String = {
135135
val lo_s = if (typeIsNothing(lo)) "" else s" >: $lo"
136-
val hi_s = if (typeIsAny(hi)) "" else s" <: $hi"
136+
val hi_s = if (typeIsAnyOrJavaObject(hi)) "" else s" <: $hi"
137137
lo_s + hi_s
138138
}
139139
}

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,7 +1542,7 @@ trait Types
15421542
case _ => lo <:< that && that <:< hi
15431543
}
15441544
private def emptyLowerBound = typeIsNothing(lo) || lo.isWildcard
1545-
private def emptyUpperBound = typeIsAny(hi) || hi.isWildcard
1545+
private def emptyUpperBound = typeIsAnyOrJavaObject(hi) || hi.isWildcard
15461546
def isEmptyBounds = emptyLowerBound && emptyUpperBound
15471547

15481548
override def safeToString = scalaNotation(_.toString)
@@ -2409,7 +2409,11 @@ trait Types
24092409
if (this eq other.asInstanceOf[AnyRef]) true
24102410
else other match {
24112411
case otherTypeRef: TypeRef =>
2412-
Objects.equals(pre, otherTypeRef.pre) && sym.eq(otherTypeRef.sym) && sameElementsEquals(args, otherTypeRef.args)
2412+
Objects.equals(pre, otherTypeRef.pre) &&
2413+
sym.eq(otherTypeRef.sym) &&
2414+
sameElementsEquals(args, otherTypeRef.args) &&
2415+
// `ObjectTpeJavaRef` is not structurally equal to `ObjectTpe` -- they should not be collapsed by `unique`
2416+
!(this.isInstanceOf[ObjectTpeJavaRef] || otherTypeRef.isInstanceOf[ObjectTpeJavaRef])
24132417
case _ => false
24142418
}
24152419
}
@@ -2706,18 +2710,21 @@ trait Types
27062710
private final class ClassArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args)
27072711
private final class AliasNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AliasTypeRef
27082712
private final class AbstractNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AbstractTypeRef
2709-
private final class ClassNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym){
2713+
private final class ClassNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) {
27102714
override def contains(sym0: Symbol): Boolean = (sym eq sym0) || pre.contains(sym0)
27112715
}
27122716

2713-
/** Expose ClassNoArgsTypeRef so we can create a non-uniqued ObjectTpeJava here and in reflect
2714-
*
2715-
* NOTE:
2716-
* - definitions.ObjectTpe is forced first, so that it ends up in the unique cache.
2717-
* - the created TypeRef is structurally equal to ObjectTpe, but with its own identity
2718-
* - we don't want the TypeRef we create here to be unique'd
2719-
*/
2720-
private[scala] def mkObjectTpeJava: Type = new ClassNoArgsTypeRef(definitions.ObjectTpe.prefix, definitions.ObjectClass)
2717+
/** Expose ObjectTpeJavaRef so we can create a non-uniqued ObjectTpeJava
2718+
* (using a type test rather than `eq`, which causes cycles).
2719+
*
2720+
* NOTE:
2721+
* - definitions.ObjectTpe is forced first, so that it ends up in the unique cache.
2722+
* - the created TypeRef is structurally equal to ObjectTpe, but with its own identity
2723+
* - we don't want the TypeRef we create here to be unique'd
2724+
*/
2725+
private[internal] final class ObjectTpeJavaRef extends NoArgsTypeRef(definitions.ObjectTpe.prefix, definitions.ObjectClass) {
2726+
override def contains(sym0: Symbol): Boolean = (sym eq sym0) || pre.contains(sym0)
2727+
}
27212728

27222729
object TypeRef extends TypeRefExtractor {
27232730
def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({
@@ -3534,7 +3541,7 @@ trait Types
35343541
if (typeIsNothing(tp)) { // kind-polymorphic
35353542
addBound(NothingTpe)
35363543
true
3537-
} else if(typeIsAny(tp)) { // kind-polymorphic
3544+
} else if(typeIsAnyExactly(tp)) { // kind-polymorphic
35383545
addBound(AnyTpe)
35393546
true
35403547
} else if (params.isEmpty) {
@@ -5203,9 +5210,17 @@ trait Types
52035210
}
52045211

52055212
@tailrec
5206-
private[scala] final def typeIsAny(tp: Type): Boolean =
5213+
private[scala] final def typeIsAnyOrJavaObject(tp: Type): Boolean =
5214+
tp.dealias match {
5215+
case PolyType(_, tp) => typeIsAnyOrJavaObject(tp)
5216+
case TypeRef(_, AnyClass, _) => true
5217+
case _: ObjectTpeJavaRef => true
5218+
case _ => false
5219+
}
5220+
5221+
private[scala] final def typeIsAnyExactly(tp: Type): Boolean =
52075222
tp.dealias match {
5208-
case PolyType(_, tp) => typeIsAny(tp)
5223+
case PolyType(_, tp) => typeIsAnyExactly(tp)
52095224
case TypeRef(_, AnyClass, _) => true
52105225
case _ => false
52115226
}

src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private[internal] trait TypeConstraints {
9797
* only guards against being created with them.]
9898
*/
9999
private[this] var lobounds = lo0 filterNot typeIsNothing
100-
private[this] var hibounds = hi0 filterNot typeIsAny
100+
private[this] var hibounds = hi0 filterNot typeIsAnyOrJavaObject
101101
private[this] var numlo = numlo0
102102
private[this] var numhi = numhi0
103103
private[this] var avoidWidening = avoidWidening0
@@ -143,7 +143,7 @@ private[internal] trait TypeConstraints {
143143
def addHiBound(tp: Type, isNumericBound: Boolean = false): Unit = {
144144
// My current test case only demonstrates the need to let Nothing through as
145145
// a lower bound, but I suspect the situation is symmetrical.
146-
val mustConsider = typeIsAny(tp) || !(hibounds contains tp)
146+
val mustConsider = typeIsAnyOrJavaObject(tp) || !(hibounds contains tp)
147147
if (mustConsider) {
148148
checkWidening(tp)
149149
if (isNumericBound && isNumericValueType(tp)) {
@@ -182,7 +182,7 @@ private[internal] trait TypeConstraints {
182182
case tp :: Nil => " >: " + tp
183183
case tps => tps.mkString(" >: (", ", ", ")")
184184
}
185-
val hi = hiBounds filterNot typeIsAny match {
185+
val hi = hiBounds filterNot typeIsAnyOrJavaObject match {
186186
case Nil => ""
187187
case tp :: Nil => " <: " + tp
188188
case tps => tps.mkString(" <: (", ", ", ")")

src/reflect/scala/reflect/internal/tpe/TypeMaps.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ private[internal] trait TypeMaps {
384384
def apply(tp: Type): Type =
385385
tp match {
386386
case BoundedWildcardType(TypeBounds(lo, AnyTpe)) if variance.isContravariant => lo
387+
case BoundedWildcardType(TypeBounds(lo, ObjectTpeJava)) if variance.isContravariant => lo
387388
case BoundedWildcardType(TypeBounds(NothingTpe, hi)) if variance.isCovariant => hi
388389
case tp => tp.mapOver(this)
389390
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
S.scala:1: error: class S needs to be abstract. Missing implementation for:
22
def g(y: Int, z: java.util.List): Int // inherited from class J
3-
(Note that java.util.List does not match java.util.List[String]. To implement this raw type, use java.util.List[_ <: Object])
3+
(Note that java.util.List does not match java.util.List[String]. To implement this raw type, use java.util.List[_])
44
class S extends J {
55
^
66
one error found

test/files/neg/abstract-report2.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Missing implementations for 13 members. Stub implementations follow:
1111
def removeAll(x$1: java.util.Collection[_]): Boolean = ???
1212
def retainAll(x$1: java.util.Collection[_]): Boolean = ???
1313
def size(): Int = ???
14-
def toArray[T <: Object](x$1: Array[T with Object]): Array[T with Object] = ???
14+
def toArray[T](x$1: Array[T with Object]): Array[T with Object] = ???
1515
def toArray(): Array[Object] = ???
1616

1717
class Foo extends Collection[Int]
@@ -29,7 +29,7 @@ Missing implementations for 13 members. Stub implementations follow:
2929
def removeAll(x$1: java.util.Collection[_]): Boolean = ???
3030
def retainAll(x$1: java.util.Collection[_]): Boolean = ???
3131
def size(): Int = ???
32-
def toArray[T <: Object](x$1: Array[T with Object]): Array[T with Object] = ???
32+
def toArray[T](x$1: Array[T with Object]): Array[T with Object] = ???
3333
def toArray(): Array[Object] = ???
3434

3535
class Bar extends Collection[List[_ <: String]]
@@ -47,7 +47,7 @@ Missing implementations for 13 members. Stub implementations follow:
4747
def removeAll(x$1: java.util.Collection[_]): Boolean = ???
4848
def retainAll(x$1: java.util.Collection[_]): Boolean = ???
4949
def size(): Int = ???
50-
def toArray[T <: Object](x$1: Array[T with Object]): Array[T with Object] = ???
50+
def toArray[T](x$1: Array[T with Object]): Array[T with Object] = ???
5151
def toArray(): Array[Object] = ???
5252

5353
class Baz[T] extends Collection[T]

test/files/pos/t10418_bounds.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Test {
2+
def foo(c: java.util.Collection[String]): Unit = {
3+
c.removeIf(x => true)
4+
}
5+
}

test/files/pos/t11525.scala

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// scalac: -Ystop-after:refchecks -verbose -Ydebug -uniqid
2+
package java.lang
3+
4+
/* This is a pretty random test that very indirectly tests `unique`ing of `ObjectTpeJavaRef`
5+
It's minimize from scala-js, where CI chanced on a compilation order that would first
6+
unique `TypeBounds(lo, ObjectTpe)`, and then `TypeBounds(lo, ObjectTpeJava)`,
7+
which would result in a Java reference to Object being replaced by one that is used
8+
to represent a Scala occurrence of a reference to Object, which is distinct from Any.
9+
When Java code refers to Object, it's taken as the same thing as Any, at least when
10+
it comes to =:= and `... <:< Object-in-java`.
11+
*/
12+
import java.util.Iterator
13+
14+
class Class[A](o: Object)
15+
16+
class Comparable[A] { def compareTo(o: A): scala.Int = ??? }
17+
18+
object System {
19+
def currentTimeMillis(): scala.Long = ???
20+
21+
def arraycopy(src: Object, srcPos: scala.Int, dest: Object, destPos: scala.Int, length: scala.Int): Unit = {
22+
import scala.{Boolean, Double}
23+
24+
def mismatch(): Nothing =
25+
throw new ArrayStoreException("Incompatible array types")
26+
27+
def copyPrim[@specialized T](src: Array[T], dest: Array[T]): Unit = {
28+
var i = length-1
29+
while (i >= 0) {
30+
dest(i+destPos) = src(i+srcPos)
31+
i -= 1
32+
}
33+
}
34+
35+
def copyRef(src: Array[AnyRef], dest: Array[AnyRef]): Unit = {
36+
val x = (src.length, dest.length)
37+
38+
var i = length-1
39+
while (i >= 0) {
40+
dest(i+destPos) = src(i+srcPos)
41+
i -= 1
42+
}
43+
}
44+
45+
(src match {
46+
case src: Array[Boolean] =>
47+
dest match {
48+
case dest: Array[Boolean] => copyPrim(src, dest)
49+
case _ => mismatch()
50+
}
51+
52+
})
53+
}
54+
55+
def identityHashCode(x: Object): scala.Int = {
56+
x.getClass
57+
1
58+
}
59+
}
60+
61+
trait Iterable[T] {
62+
def iterator(): java.util.Iterator[T]
63+
}

test/files/run/reflection-magicsymbols-invoke.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ method ##: ()Int
77
method ==: (x$1: Any)Boolean
88
method asInstanceOf: [T0]=> T0
99
method equals: (x$1: Any)Boolean
10-
method getClass: ()Class[_ <: Object]
10+
method getClass: ()Class[_]
1111
method hashCode: ()Int
1212
method isInstanceOf: [T0]=> Boolean
1313
method toString: ()String
@@ -45,7 +45,7 @@ method clone: ()Object
4545
method eq: (x$1: AnyRef)Boolean
4646
method equals: (x$1: Object)Boolean
4747
method finalize: ()Unit
48-
method getClass: ()Class[_ <: Object]
48+
method getClass: ()Class[_]
4949
method hashCode: ()Int
5050
method isInstanceOf: [T0]=> Boolean
5151
method ne: (x$1: AnyRef)Boolean
@@ -91,7 +91,7 @@ method clone: ()Array[T]
9191
method eq: (x$1: AnyRef)Boolean
9292
method equals: (x$1: Object)Boolean
9393
method finalize: ()Unit
94-
method getClass: ()Class[_ <: Object]
94+
method getClass: ()Class[_]
9595
method hashCode: ()Int
9696
method isInstanceOf: [T0]=> Boolean
9797
method length: => Int

test/files/run/t5072.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ scala> class C
33
defined class C
44

55
scala> Thread.currentThread.getContextClassLoader.loadClass(classOf[C].getName)
6-
res0: Class[_ <: Object] = class C
6+
res0: Class[_] = class C
77

88
scala> :quit

test/junit/scala/reflect/internal/TypesTest.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ class TypesTest {
319319
val aSym = typeOf[Foo.type].member(TermName("a"))
320320
val nSym = typeOf[Foo.type].member(TermName("n"))
321321

322-
assert(typeIsAny(AnyTpe))
322+
assert(typeIsAnyOrJavaObject(AnyTpe))
323323
assert(typeIsNothing(NothingTpe))
324-
assert(!typeIsAny(LiteralType(Constant(1))))
325-
assert(!typeIsAny(SingleType(NoPrefix, aSym)))
324+
assert(!typeIsAnyOrJavaObject(LiteralType(Constant(1))))
325+
assert(!typeIsAnyOrJavaObject(SingleType(NoPrefix, aSym)))
326326
assert(!typeIsNothing(SingleType(NoPrefix, nSym)))
327327
}
328328

0 commit comments

Comments
 (0)