diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 9a6ee7296239..302ad7987889 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2857,6 +2857,13 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling tp case tp: HKTypeLambda => tp + case tp: ParamRef => + val st = tp.superTypeNormalized + if st.exists then + disjointnessBoundary(st) + else + // workaround for when ParamRef#underlying returns NoType + defn.AnyType case tp: TypeProxy => disjointnessBoundary(tp.superTypeNormalized) case tp: WildcardType => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9ef075f95e3a..b1bb5805bdc4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2375,7 +2375,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer report.error(MatchTypeScrutineeCannotBeHigherKinded(sel1Tpe), sel1.srcPos) val pt1 = if (bound1.isEmpty) pt else bound1.tpe val cases1 = tree.cases.mapconserve(typedTypeCase(_, sel1Tpe, pt1)) - assignType(cpy.MatchTypeTree(tree)(bound1, sel1, cases1), bound1, sel1, cases1) + val bound2 = if tree.bound.isEmpty then + val lub = cases1.foldLeft(defn.NothingType: Type): (acc, case1) => + if !acc.exists then NoType + else if case1.body.tpe.isProvisional then NoType + else acc | case1.body.tpe + if lub.exists then TypeTree(lub, inferred = true) + else bound1 + else bound1 + assignType(cpy.MatchTypeTree(tree)(bound2, sel1, cases1), bound2, sel1, cases1) } def typedByNameTypeTree(tree: untpd.ByNameTypeTree)(using Context): ByNameTypeTree = tree.result match diff --git a/tests/pos/13633.scala b/tests/pos/13633.scala index ca0f7e68e81e..8883ef98d0be 100644 --- a/tests/pos/13633.scala +++ b/tests/pos/13633.scala @@ -21,7 +21,7 @@ object Sums extends App: type Reverse[A] = ReverseLoop[A, EmptyTuple] - type PlusTri[A, B, C] = (A, B, C) match + type PlusTri[A, B, C] <: Tuple = (A, B, C) match case (false, false, false) => (false, false) case (true, false, false) | (false, true, false) | (false, false, true) => (false, true) case (true, true, false) | (true, false, true) | (false, true, true) => (true, false) diff --git a/tests/pos/Tuple.Drop.scala b/tests/pos/Tuple.Drop.scala new file mode 100644 index 000000000000..9b88cc227966 --- /dev/null +++ b/tests/pos/Tuple.Drop.scala @@ -0,0 +1,7 @@ +import compiletime.ops.int.* + +type Drop[T <: Tuple, N <: Int] <: Tuple = N match + case 0 => T + case S[n1] => T match + case EmptyTuple => EmptyTuple + case x *: xs => Drop[xs, n1] diff --git a/tests/pos/Tuple.Elem.scala b/tests/pos/Tuple.Elem.scala new file mode 100644 index 000000000000..81494485c321 --- /dev/null +++ b/tests/pos/Tuple.Elem.scala @@ -0,0 +1,7 @@ +import compiletime.ops.int.* + +type Elem[T <: Tuple, I <: Int] = T match + case h *: tail => + I match + case 0 => h + case S[j] => Elem[tail, j] diff --git a/tests/pos/i19710.scala b/tests/pos/i19710.scala new file mode 100644 index 000000000000..03fd1e2d80b3 --- /dev/null +++ b/tests/pos/i19710.scala @@ -0,0 +1,11 @@ +import scala.util.NotGiven + +type HasName1 = [n] =>> [x] =>> x match { + case n => true + case _ => false + } +@main def Test = { + summon[HasName1["foo"]["foo"] =:= true] + summon[NotGiven[HasName1["foo"]["bar"] =:= true]] + summon[Tuple.Filter[(1, "foo", 2, "bar"), HasName1["foo"]] =:= Tuple1["foo"]] // error +} diff --git a/tests/run-macros/type-show/Test_2.scala b/tests/run-macros/type-show/Test_2.scala index ace303a6596e..de845f3e84dd 100644 --- a/tests/run-macros/type-show/Test_2.scala +++ b/tests/run-macros/type-show/Test_2.scala @@ -1,18 +1,34 @@ object Test { import TypeToolbox.* + + def assertEql[A](obt: A, exp: A): Unit = + assert(obt == exp, s"\nexpected: $exp\nobtained: $obt") + def main(args: Array[String]): Unit = { val x = 5 - assert(show[x.type] == "x.type") - assert(show[Nil.type] == "scala.Nil.type") - assert(show[Int] == "scala.Int") - assert(show[Int => Int] == "scala.Function1[scala.Int, scala.Int]") - assert(show[(Int, String)] == "scala.Tuple2[scala.Int, scala.Predef.String]") - assert(show[[X] =>> X match { case Int => Int }] == + assertEql(show[x.type], "x.type") + assertEql(show[Nil.type], "scala.Nil.type") + assertEql(show[Int], "scala.Int") + assertEql(show[Int => Int], "scala.Function1[scala.Int, scala.Int]") + assertEql(show[(Int, String)], "scala.Tuple2[scala.Int, scala.Predef.String]") + assertEql(show[[X] =>> X match { case Int => Int }], """[X >: scala.Nothing <: scala.Any] =>> X match { | case scala.Int => scala.Int |}""".stripMargin) - assert(showStructure[[X] =>> X match { case Int => Int }] == """TypeLambda(List(X), List(TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Nothing"), TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Any"))), MatchType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Any"), ParamRef(binder, 0), List(MatchCase(TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "")), "scala"), "Int"), TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "")), "scala"), "Int")))))""") + assertEql(showStructure[[X] =>> X match { case Int => Int }], + """TypeLambda("""+ + """List(X), """+ + """List(TypeBounds("""+ + """TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Nothing"), """+ + """TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Any"))), """+ + """MatchType("""+ + """TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "")), "scala"), "Int"), """+ // match type bound + """ParamRef(binder, 0), """+ + """List("""+ + """MatchCase("""+ + """TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "")), "scala"), "Int"), """+ + """TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "")), "scala"), "Int")))))""") // TODO: more complex types: // - implicit function types