diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-11-26 14:26:33 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2016-02-01 13:23:20 +1000 |
commit | 6f8c05722ba4452279e353df2d81b58f260277d2 (patch) | |
tree | 2388344a8a22a4a059977e0d021bbb589017c254 | |
parent | 907fe03e57b3cac4d0a67663edcd2b3b040e6ff8 (diff) | |
download | scala-6f8c05722ba4452279e353df2d81b58f260277d2.tar.gz scala-6f8c05722ba4452279e353df2d81b58f260277d2.tar.bz2 scala-6f8c05722ba4452279e353df2d81b58f260277d2.zip |
SI-9542 Unify different reprs. of module type refs
The new unit test shows failures in transitivity of subtyping
and type equivalence, which boil down the the inconsistent
handling of the semantically equivalent:
ThisType(pre, ModuleClass)
ModuleTypeRef(pre, ModuleClass)
SingleType(pre, Module)
This commit:
- adds a case to `normalizePlus` to unwrap a `ThisType` to
a `ModuleTypeRef`
- Use `normalizePlus` more widely during subtype comparison
- refactor `fourthTry` (part of `isSubType`) to remove code
that becomes obviated by the use of `normalizePlus`.
This fixes the regression in the extension methods phase which
was triggered by https://github.com/scala/scala/pull/4749.
We can also fix that regression by tweaking the extension methods
phase itself to emit the `ThisType` representation of the owner
of the value class, as before.
I plan to demonstrate the two approaches to fixing the regression
on separate branches, and the propose that the merged result of these
two is useds.
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 11 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/tpe/TypeComparers.scala | 28 | ||||
-rw-r--r-- | test/files/pos/t9542.scala | 8 | ||||
-rw-r--r-- | test/junit/scala/reflect/internal/TypesTest.scala | 28 |
4 files changed, 52 insertions, 23 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 2e6cd819b4..e53b47e808 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3970,14 +3970,15 @@ trait Types } } - def normalizePlus(tp: Type) = ( + def normalizePlus(tp: Type): Type = { if (isRawType(tp)) rawToExistential(tp) else tp.normalize match { - // Unify the two representations of module classes - case st @ SingleType(_, sym) if sym.isModule => st.underlying.normalize - case _ => tp.normalize + // Unify the representations of module classes + case st@SingleType(_, sym) if sym.isModule => st.underlying.normalize + case st@ThisType(sym) if sym.isModuleClass => normalizePlus(st.underlying) + case _ => tp.normalize } - ) + } /* todo: change to: diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index f9b10c90be..e6d7b11cad 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -463,7 +463,7 @@ trait TypeComparers { case SingletonClass => tp1.isStable || fourthTry case _: ClassSymbol => classOnRight case _: TypeSymbol if sym2.isDeferred => abstractTypeOnRight(tp2.bounds.lo) || fourthTry - case _: TypeSymbol => retry(tp1.normalize, tp2.normalize) + case _: TypeSymbol => retry(normalizePlus(tp1), normalizePlus(tp2)) case _ => fourthTry } } @@ -517,7 +517,7 @@ trait TypeComparers { * - handle typerefs, refined types, and singleton types. */ def fourthTry = { - def retry(lhs: Type, rhs: Type) = isSubType(lhs, rhs, depth) + def retry(lhs: Type, rhs: Type) = ((tp1 ne lhs) || (tp2 ne rhs)) && isSubType(lhs, rhs, depth) def abstractTypeOnLeft(hi: Type) = isDifferentTypeConstructor(tp1, hi) && retry(hi, tp2) tp1 match { @@ -526,22 +526,16 @@ trait TypeComparers { case TypeRef(_, sym2, _) => sym1 isBottomSubClass sym2 case _ => isSingleType(tp2) && retry(tp1, tp2.widen) } - def moduleOnLeft = tp2 match { - case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2) - case _ => false - } - def classOnLeft = ( - if (isRawType(tp1)) retry(rawToExistential(tp1), tp2) - else if (sym1.isModuleClass) moduleOnLeft - else sym1.isRefinementClass && retry(sym1.info, tp2) - ) + sym1 match { - case NothingClass => true - case NullClass => nullOnLeft - case _: ClassSymbol => classOnLeft - case _: TypeSymbol if sym1.isDeferred => abstractTypeOnLeft(tp1.bounds.hi) - case _: TypeSymbol => retry(tp1.normalize, tp2.normalize) - case _ => false + case NothingClass => true + case NullClass => nullOnLeft + case _: ClassSymbol if isRawType(tp1) => retry(normalizePlus(tp1), normalizePlus(tp2)) + case _: ClassSymbol if sym1.isModuleClass => retry(normalizePlus(tp1), normalizePlus(tp2)) + case _: ClassSymbol if sym1.isRefinementClass => retry(sym1.info, tp2) + case _: TypeSymbol if sym1.isDeferred => abstractTypeOnLeft(tp1.bounds.hi) + case _: TypeSymbol => retry(normalizePlus(tp1), normalizePlus(tp2)) + case _ => false } case RefinedType(parents, _) => parents exists (retry(_, tp2)) case _: SingletonType => retry(tp1.underlying, tp2) diff --git a/test/files/pos/t9542.scala b/test/files/pos/t9542.scala new file mode 100644 index 0000000000..d65f7ac4c6 --- /dev/null +++ b/test/files/pos/t9542.scala @@ -0,0 +1,8 @@ +object O { + trait T + + class VC(val self: Any) extends AnyVal { + def extMethod(f: F1[T, Any]) = () + } +} +trait F1[A, B] diff --git a/test/junit/scala/reflect/internal/TypesTest.scala b/test/junit/scala/reflect/internal/TypesTest.scala index 95194ef0a4..05a77cfb47 100644 --- a/test/junit/scala/reflect/internal/TypesTest.scala +++ b/test/junit/scala/reflect/internal/TypesTest.scala @@ -1,9 +1,10 @@ package scala.reflect.internal import org.junit.Assert._ -import org.junit.Test +import org.junit.{Assert, Test} import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import scala.collection.mutable import scala.tools.nsc.symtab.SymbolTableForUnitTesting @RunWith(classOf[JUnit4]) @@ -32,4 +33,29 @@ class TypesTest { val uniquelyNarrowed2 = refinedType(boolWithString1narrow2 :: Nil, NoSymbol) assert(uniquelyNarrowed1 =:= uniquelyNarrowed2) } + + @Test + def testTransitivityWithModuleTypeRef(): Unit = { + import rootMirror.EmptyPackageClass + val (module, moduleClass) = EmptyPackageClass.newModuleAndClassSymbol(TermName("O"), NoPosition, 0L) + val minfo = ClassInfoType(List(ObjectTpe), newScope, moduleClass) + module.moduleClass setInfo minfo + module setInfo module.moduleClass.tpe + val tp1 = TypeRef(ThisType(EmptyPackageClass), moduleClass, Nil) + val tp2 = SingleType(ThisType(EmptyPackageClass), module) + val tp3 = ThisType(moduleClass) + val tps = List(tp1, tp2, tp3) + val results = mutable.Buffer[String]() + tps.permutations.foreach { + case ts @ List(a, b, c) => + def tsShownRaw = ts.map(t => showRaw(t)).mkString(", ") + if (a <:< b && b <:< c && !(a <:< c)) results += s"<:< intransitive: $tsShownRaw" + if (a =:= b && b =:= c && !(a =:= c)) results += s"=:= intransitive: $tsShownRaw" + } + results.toList match { + case Nil => // okay + case xs => + Assert.fail(xs.mkString("\n")) + } + } } |