diff options
-rw-r--r-- | src/compiler/scala/reflect/reify/codegen/GenSymbols.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/reflect/reify/codegen/GenTypes.scala | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 54 | ||||
-rw-r--r-- | test/files/neg/t0764.check | 7 | ||||
-rw-r--r-- | test/files/neg/t0764.scala | 45 | ||||
-rw-r--r-- | test/files/neg/t0764b.check | 47 | ||||
-rw-r--r-- | test/files/neg/t0764b.scala (renamed from test/files/pos/t0764b.scala) | 2 | ||||
-rw-r--r-- | test/files/neg/t8177a.check | 6 | ||||
-rw-r--r-- | test/files/neg/t8177a.scala | 6 | ||||
-rw-r--r-- | test/files/pos/t0764.scala | 27 | ||||
-rw-r--r-- | test/files/pos/t8177h.scala | 5 | ||||
-rw-r--r-- | test/files/run/t6992/Test_2.scala | 2 |
12 files changed, 160 insertions, 47 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 3a97089d51..2965db17c6 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -93,7 +93,7 @@ trait GenSymbols { // todo. make sure that free methods and free local defs work correctly if (sym.isExistential) reifySymDef(sym) else if (sym.isTerm) reifyFreeTerm(Ident(sym)) - else reifyFreeType(Ident(sym)) + else reifyFreeType(Ident(sym)) // TODO: reify refinement classes } } diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index a90a3a338b..3e2acc28e5 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -55,7 +55,9 @@ trait GenTypes { case tpe @ ConstantType(value) => mirrorFactoryCall(nme.ConstantType, reifyProduct(value)) case tpe @ TypeRef(pre, sym, args) => - reifyProduct(tpe) + // TODO: remove special case!!! for now, as we can't reify these symbols, let's hope dealias gets us out of this bind... + if (pre.typeSymbol.isAnonOrRefinementClass && (tpe ne tpe.dealias)) reifyType(tpe.dealias) + else reifyProduct(tpe) case tpe @ TypeBounds(lo, hi) => reifyProduct(tpe) case tpe @ NullaryMethodType(restpe) => diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 6010d4eb12..27ec882549 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4100,24 +4100,44 @@ trait Types ) } - /** Does member `sym1` of `tp1` have a stronger type - * than member `sym2` of `tp2`? + /** Does member `symLo` of `tpLo` have a stronger type + * than member `symHi` of `tpHi`? */ - protected[internal] def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol, depth: Depth): Boolean = { - require((sym1 ne NoSymbol) && (sym2 ne NoSymbol), ((tp1, sym1, tp2, sym2, depth))) - val info1 = tp1.memberInfo(sym1) - val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1) - //System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG - ( sym2.isTerm && isSubType(info1, info2, depth) && (!sym2.isStable || sym1.isStable) && (!sym1.hasVolatileType || sym2.hasVolatileType) - || sym2.isAbstractType && { - val memberTp1 = tp1.memberType(sym1) - // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner))) - info2.bounds.containsType(memberTp1) && - kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner) - } - || sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok - ) - } + protected[internal] def specializesSym(preLo: Type, symLo: Symbol, preHi: Type, symHi: Symbol, depth: Depth): Boolean = + (symHi.isAliasType || symHi.isTerm || symHi.isAbstractType) && { + // only now that we know symHi is a viable candidate ^^^^^^^, do the expensive checks: ----V + require((symLo ne NoSymbol) && (symHi ne NoSymbol), ((preLo, symLo, preHi, symHi, depth))) + + val tpHi = preHi.memberInfo(symHi).substThis(preHi.typeSymbol, preLo) + + // Should we use memberType or memberInfo? + // memberType transforms (using `asSeenFrom`) `sym.tpe`, + // whereas memberInfo performs the same transform on `sym.info`. + // For term symbols, this ends up being the same thing (`sym.tpe == sym.info`). + // For type symbols, however, the `.info` of an abstract type member + // is defined by its bounds, whereas its `.tpe` is a `TypeRef` to that type symbol, + // so that `sym.tpe <:< sym.info`, but not the other way around. + // + // Thus, for the strongest (correct) result, + // we should use `memberType` on the low side. + // + // On the high side, we should use the result appropriate + // for the right side of the `<:<` above (`memberInfo`). + val tpLo = preLo.memberType(symLo) + + debuglog(s"specializesSymHi: $preHi . $symHi : $tpHi") + debuglog(s"specializesSymLo: $preLo . $symLo : $tpLo") + + if (symHi.isTerm) + (isSubType(tpLo, tpHi, depth) && + (!symHi.isStable || symLo.isStable) && // sub-member must remain stable + (!symLo.hasVolatileType || symHi.hasVolatileType)) // sub-member must not introduce volatility + else if (symHi.isAbstractType) + ((tpHi.bounds containsType tpLo) && + kindsConform(symHi :: Nil, tpLo :: Nil, preLo, symLo.owner)) + else // we know `symHi.isAliasType` (see above) + tpLo =:= tpHi + } /** A function implementing `tp1` matches `tp2`. */ final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { diff --git a/test/files/neg/t0764.check b/test/files/neg/t0764.check new file mode 100644 index 0000000000..0c7cff1e1e --- /dev/null +++ b/test/files/neg/t0764.check @@ -0,0 +1,7 @@ +t0764.scala:13: error: type mismatch; + found : Node{type T = _1.type} where val _1: Node{type T = NextType} + required: Node{type T = Main.this.AType} + (which expands to) Node{type T = Node{type T = NextType}} + new Main[AType]( (value: AType).prepend ) + ^ +one error found diff --git a/test/files/neg/t0764.scala b/test/files/neg/t0764.scala new file mode 100644 index 0000000000..9f77a59414 --- /dev/null +++ b/test/files/neg/t0764.scala @@ -0,0 +1,45 @@ +class Top[A] { + type AType = A +} + +trait Node { outer => + type T <: Node + def prepend = new Node { type T = outer.type } +} + +class Main[NextType <: Node](value: Node { type T = NextType }) + extends Top[Node { type T = NextType }] { + + new Main[AType]( (value: AType).prepend ) +} + +/* we've been back-and-forth on this one -- see PRs on SI-8177 for the reasoning +I think it should compile and that the following error is due to broken =:= on existentials + found : Node{type T = _1.type} where val _1: Node{type T = NextType} + required: Node{type T = Main.this.AType} + (which expands to) Node{type T = Node{type T = NextType}} + +I claim (omitting the forSome for brevity, even though the premature skolemization is probably the issue) +_1.type =:= Main.this.AType +because +(1) _1.type <:< Main.this.AType and (2) Main.this.AType <:< _1.type +(1), because: +_1.type <:< Node{type T = NextType} (because skolemization and _1's upper bound) +(2), because: +Node{type T = NextType} <:< _1.type forSome val _1: Node{type T = NextType} +because: +Node{type T = NextType} <:< T forSome {type T <: Node{type T = NextType} with Singleton} +because +Node{type T = NextType} <:< Node{type T = NextType} with Singleton + +hmmm.. might the with Singleton be throwing a wrench in our existential house? + +Behold the equivalent program which type checks without the fix for SI-8177. +(Expand type alias, convert type member to type param; +note the covariance to encode subtyping on type members.) + +class Node[+T <: Node[_]] { def prepend = new Node[this.type] } +class Main[NextType <: Node[_]](value: Node[NextType]) { + new Main(value.prepend) +} +*/
\ No newline at end of file diff --git a/test/files/neg/t0764b.check b/test/files/neg/t0764b.check new file mode 100644 index 0000000000..4040954e7c --- /dev/null +++ b/test/files/neg/t0764b.check @@ -0,0 +1,47 @@ +t0764b.scala:27: error: type mismatch; + found : p1.t0764.Node{type T = p1.t0764.<refinement>.type} + required: p1.t0764.NodeAlias[p1.t0764.NodeAlias[A]] + (which expands to) p1.t0764.Node{type T = p1.t0764.Node{type T = A}} + private[this] def f2 = new Main1[NodeAlias[A]](v.prepend) // fail + ^ +t0764b.scala:28: error: type mismatch; + found : p1.t0764.Node{type T = p1.t0764.<refinement>.type} + required: p1.t0764.NodeAlias[p1.t0764.Node{type T = A}] + (which expands to) p1.t0764.Node{type T = p1.t0764.Node{type T = A}} + private[this] def f3 = new Main1[Node { type T = A }](v.prepend) // fail + ^ +t0764b.scala:34: error: type mismatch; + found : p1.t0764.Node{type T = p1.t0764.<refinement>.type} + required: p1.t0764.Node{type T = p1.t0764.NodeAlias[A]} + (which expands to) p1.t0764.Node{type T = p1.t0764.Node{type T = A}} + private[this] def f2 = new Main2[NodeAlias[A]](v.prepend) // fail + ^ +t0764b.scala:35: error: type mismatch; + found : p1.t0764.Node{type T = p1.t0764.<refinement>.type} + required: p1.t0764.Node{type T = p1.t0764.Node{type T = A}} + private[this] def f3 = new Main2[Node { type T = A }](v.prepend) // fail + ^ +t0764b.scala:51: error: type mismatch; + found : p2.t0764.Node{type T = p2.t0764.<refinement>.type} + required: p2.t0764.NodeAlias[p2.t0764.NodeAlias[A]] + (which expands to) p2.t0764.Node{type T = p2.t0764.Node{type T = A}} + private[this] def f2 = new Main1[NodeAlias[A]](v.prepend) // fail + ^ +t0764b.scala:52: error: type mismatch; + found : p2.t0764.Node{type T = p2.t0764.<refinement>.type} + required: p2.t0764.NodeAlias[p2.t0764.Node{type T = A}] + (which expands to) p2.t0764.Node{type T = p2.t0764.Node{type T = A}} + private[this] def f3 = new Main1[Node { type T = A }](v.prepend) // fail + ^ +t0764b.scala:58: error: type mismatch; + found : p2.t0764.Node{type T = p2.t0764.<refinement>.type} + required: p2.t0764.Node{type T = p2.t0764.NodeAlias[A]} + (which expands to) p2.t0764.Node{type T = p2.t0764.Node{type T = A}} + private[this] def f2 = new Main2[NodeAlias[A]](v.prepend) // fail + ^ +t0764b.scala:59: error: type mismatch; + found : p2.t0764.Node{type T = p2.t0764.<refinement>.type} + required: p2.t0764.Node{type T = p2.t0764.Node{type T = A}} + private[this] def f3 = new Main2[Node { type T = A }](v.prepend) // fail + ^ +8 errors found diff --git a/test/files/pos/t0764b.scala b/test/files/neg/t0764b.scala index 6ae3c105c9..14c623c67a 100644 --- a/test/files/pos/t0764b.scala +++ b/test/files/neg/t0764b.scala @@ -1,3 +1,5 @@ +// see neg/t0764 why this should probably be a pos/ test -- alas something's wrong with existential subtyping (?) + // In all cases when calling "prepend" the receiver 'v' // has static type NodeAlias[A] or (equivalently) Node { type T = A }. // Since prepend explicitly returns the singleton type of the receiver, diff --git a/test/files/neg/t8177a.check b/test/files/neg/t8177a.check new file mode 100644 index 0000000000..0d01206e0c --- /dev/null +++ b/test/files/neg/t8177a.check @@ -0,0 +1,6 @@ +t8177a.scala:5: error: type mismatch; + found : A{type Result = Int} + required: A{type Result = String} + : A { type Result = String} = x + ^ +one error found diff --git a/test/files/neg/t8177a.scala b/test/files/neg/t8177a.scala new file mode 100644 index 0000000000..d1e47f8c1e --- /dev/null +++ b/test/files/neg/t8177a.scala @@ -0,0 +1,6 @@ +trait A { type Result } + +class PolyTests { + def wrong(x: A { type Result = Int }) + : A { type Result = String} = x +}
\ No newline at end of file diff --git a/test/files/pos/t0764.scala b/test/files/pos/t0764.scala deleted file mode 100644 index f1084f5ff8..0000000000 --- a/test/files/pos/t0764.scala +++ /dev/null @@ -1,27 +0,0 @@ -class Top[A] { - type AType = A -} - -trait Node { outer => - type T <: Node - def prepend = new Node { type T = outer.type } -} - -class Main[NextType <: Node](value: Node { type T = NextType }) - extends Top[Node { type T = NextType }] { - - new Main[AType]( (value: AType).prepend ) -} - -/* this used to be a neg test, even though it should've compiled -SI-8177 fixed this. - -Behold the equivalent program which type checks without the fix for SI-8177. -(Expand type alias, convert type member to type param; -note the covariance to encode subtyping on type members.) - -class Node[+T <: Node[_]] { def prepend = new Node[this.type] } -class Main[NextType <: Node[_]](value: Node[NextType]) { - new Main(value.prepend) -} -*/
\ No newline at end of file diff --git a/test/files/pos/t8177h.scala b/test/files/pos/t8177h.scala new file mode 100644 index 0000000000..90b8a26ce7 --- /dev/null +++ b/test/files/pos/t8177h.scala @@ -0,0 +1,5 @@ +class Module { self => + type settingsType <: Any + final type commonModuleType = Module {type settingsType = self.settingsType} + def foo(s: self.type): commonModuleType = s +} diff --git a/test/files/run/t6992/Test_2.scala b/test/files/run/t6992/Test_2.scala index 05282d6f5b..0f226b01ce 100644 --- a/test/files/run/t6992/Test_2.scala +++ b/test/files/run/t6992/Test_2.scala @@ -2,7 +2,7 @@ import scala.language.reflectiveCalls object Test extends App { val foo = Macros.foo("T") - println(scala.reflect.runtime.universe.weakTypeOf[foo.T].typeSymbol.typeSignature) + println(scala.reflect.runtime.universe.weakTypeOf[foo.T]) val bar = Macros.bar("test") println(bar.test) |