From de23b34852d2a1cbb69052f798396a248a19c4d7 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 12 Nov 2020 18:20:42 +0000 Subject: [PATCH] Dealias val aliases to modules so they're =:= This changes the definitely of =:= in the smallest possible way: if you have a singleton type that widens to a module, then widen to that module. --- .../scala/reflect/internal/Types.scala | 6 ++-- test/files/pos/t12186.scala | 29 +++++++++++++++++++ .../scala/reflect/internal/TypesTest.scala | 27 +++++++++++++++-- 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 test/files/pos/t12186.scala diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index a7399e805b09..123d569463d1 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4558,9 +4558,9 @@ trait Types if (isRawType(tp)) rawToExistential(tp) else tp.normalize match { // 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 + case st @ SingleType(_, sym) if st.dealiasWiden.typeSymbol.isModuleOrModuleClass => st.dealiasWiden.normalize + case st @ ThisType(sym) if sym.isModuleClass => normalizePlus(st.underlying) + case tpNorm => tpNorm } } diff --git a/test/files/pos/t12186.scala b/test/files/pos/t12186.scala new file mode 100644 index 000000000000..b8a72238510f --- /dev/null +++ b/test/files/pos/t12186.scala @@ -0,0 +1,29 @@ +// scalac: -Werror + +// this is remodeling of the scala package object and scala.collection.immutable.{ List, ::, Nil } +// in order to: +// * avoid the scala package, which is auto-imported +// * avoid List, which is rewritten/fudged in the pattern matcher +package skala.collect { + sealed trait Xs[+A] + final case class Cons[+A](head: A, tail: Xs[A]) extends Xs[A] + final case object Done extends Xs[Nothing] + object Xs +} +package object skala { + type Cons[+A] = skala.collect.Cons[A] + type Xs[+A] = skala.collect.Xs[A] + val Cons = skala.collect.Cons + val Done: skala.collect.Done.type = skala.collect.Done + val Xs = skala.collect.Xs +} + +import skala._ + +class Test { + def test(xs: Xs[Int]): Boolean = xs match { + case Cons(_, _) => true + case _: Done.type => false + //case _: skala.collect.Done.type => false // done this way it already works + } +} diff --git a/test/junit/scala/reflect/internal/TypesTest.scala b/test/junit/scala/reflect/internal/TypesTest.scala index ab0cdd954e58..a31a3dc8deb6 100644 --- a/test/junit/scala/reflect/internal/TypesTest.scala +++ b/test/junit/scala/reflect/internal/TypesTest.scala @@ -46,9 +46,14 @@ class TypesTest { val tp1 = TypeRef(ThisType(EmptyPackageClass), moduleClass, Nil) val tp2 = SingleType(ThisType(EmptyPackageClass), module) val tp3 = ThisType(moduleClass) - val tps = List(tp1, tp2, tp3) + + val (otherModule, otherModuleClass) = EmptyPackageClass.newModuleAndClassSymbol(TermName("Other"), NoPosition, 0L) + val aliasSym = otherModuleClass.newTermSymbol(TermName("alias")).setInfo(tp2) + val tp4 = singleType(TypeRef(ThisType(EmptyPackageClass), otherModuleClass, Nil), aliasSym) + + val tps = List(tp1, tp2, tp3, tp4) val results = mutable.Buffer[String]() - tps.permutations.foreach { + tps.combinations(3).flatMap(_.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" @@ -61,6 +66,24 @@ class TypesTest { } } + @Test + def testNilModuleUnification(): Unit = { + import rootMirror.RootClass + val nil1 = singleType(ThisType(RootClass), typeOf[scala.`package`.type].member(TermName("Nil"))) + val nil2 = typeOf[scala.collection.immutable.Nil.type].underlying + + assert(nil1.isInstanceOf[UniqueSingleType], nil1.getClass) + assert(nil2.isInstanceOf[ModuleTypeRef], nil2.getClass) + + val tps = List(nil1, nil2) + val results = mutable.Buffer[String]() + tps.permutations.foreach { case List(a, b) => + if (!(a =:= b)) + results += s"expected a =:= b; where a=${showRaw(a)} b=${showRaw(b)}" + } + assertTrue(s"Mismatches:\n${results.mkString("\n")}", results.isEmpty) + } + @Test def testRefinementContains(): Unit = { val refinement = typeOf[{def foo: Int}]