From f38d86cb94f379af4dc764cc113ea2d24a64e06a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 2 Oct 2020 18:56:19 +0200 Subject: [PATCH 1/3] Fix #9735: Tighten opaque types check We already has a check that opaque type aliases must be fully applied, but that check did not kick in when the opaque type has type parameters. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- tests/neg/i9735.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i9735.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 02607393580d..7cc54c862e44 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -888,7 +888,7 @@ class Namer { typer: Typer => val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType) def opaqueToBounds(info: Type): Type = - if sym.isOpaqueAlias && tparamSyms.isEmpty && info.typeParams.nonEmpty then + if sym.isOpaqueAlias && info.typeParams.nonEmpty then report.error(em"opaque type alias must be fully applied", rhs.srcPos) sym.opaqueToBounds(info, rhs1, tparamSyms) diff --git a/tests/neg/i9735.scala b/tests/neg/i9735.scala new file mode 100644 index 000000000000..8beb1bf09eb5 --- /dev/null +++ b/tests/neg/i9735.scala @@ -0,0 +1,6 @@ +trait Two[A, B] + +opaque type U[A] = [B] =>> Two[A, B] // error: opaque type alias must be fully applied // error: cannot instantiate +opaque type T[A] = [B] =>> String // error: opaque type alias must be fully applied +opaque type S = [B] =>> String // error: opaque type alias must be fully applied + From 9173abaec7dd8b9a74b70d01fa945a433cd56154 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 3 Oct 2020 13:12:02 +0200 Subject: [PATCH 2/3] Fix opaque types check --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 4 ++-- tests/neg/i9735.scala | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 7cc54c862e44..41917a3ea82f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -888,8 +888,8 @@ class Namer { typer: Typer => val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType) def opaqueToBounds(info: Type): Type = - if sym.isOpaqueAlias && info.typeParams.nonEmpty then - report.error(em"opaque type alias must be fully applied", rhs.srcPos) + if sym.isOpaqueAlias && info.typeParams.nonEmpty && info.hkResult.typeParams.nonEmpty then + report.error(em"opaque type alias cannot have multiple type parameter lists", rhs.srcPos) sym.opaqueToBounds(info, rhs1, tparamSyms) if (isDerived) sym.info = unsafeInfo diff --git a/tests/neg/i9735.scala b/tests/neg/i9735.scala index 8beb1bf09eb5..0daa14403bdd 100644 --- a/tests/neg/i9735.scala +++ b/tests/neg/i9735.scala @@ -1,6 +1,7 @@ trait Two[A, B] -opaque type U[A] = [B] =>> Two[A, B] // error: opaque type alias must be fully applied // error: cannot instantiate -opaque type T[A] = [B] =>> String // error: opaque type alias must be fully applied -opaque type S = [B] =>> String // error: opaque type alias must be fully applied - +opaque type U[A] = [B] =>> Two[A, B] // error: opaque type alias cannot have multiple type parameter lists // error: cannot instantiate +opaque type T = [A] =>> [B] =>> String // error: opaque type alias cannot have multiple type parameter lists +opaque type S = [B] =>> String // ok +opaque type IArray[+T] = Array[? <: T] // ok +opaque type S2[B] = String // ok From 079b4f9c1209cdbfe92f2f7247226751c3239ea9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 3 Oct 2020 13:16:54 +0200 Subject: [PATCH 3/3] Document restriction --- .../other-new-features/opaques-details.md | 14 ++++++++++++++ tests/neg/i9735.scala | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/docs/docs/reference/other-new-features/opaques-details.md b/docs/docs/reference/other-new-features/opaques-details.md index e6021a4a3b9a..ccbbc1770429 100644 --- a/docs/docs/reference/other-new-features/opaques-details.md +++ b/docs/docs/reference/other-new-features/opaques-details.md @@ -46,6 +46,20 @@ object o { def id(x: o.T): o.T = x ``` +### Type Parameters of Opaque Types + +Opaque type aliases can have a single type parameter list. The following aliases +are well-formed +```scala +opaque type F[T] = (T, T) +opaque type G = [T] =>> List[T] +``` +but the following are not: +```scala +opaque type BadF[T] = [U] =>> (T, U) +opaque type BadG = [T] =>> [U] => (T, U) +``` + ### Translation of Equality Comparing two values of opaque type with `==` or `!=` normally uses universal equality, diff --git a/tests/neg/i9735.scala b/tests/neg/i9735.scala index 0daa14403bdd..a76aad435a00 100644 --- a/tests/neg/i9735.scala +++ b/tests/neg/i9735.scala @@ -5,3 +5,8 @@ opaque type T = [A] =>> [B] =>> String // error: opaque type alias cannot have m opaque type S = [B] =>> String // ok opaque type IArray[+T] = Array[? <: T] // ok opaque type S2[B] = String // ok + +opaque type BadF[T] = [U] =>> (T, U) // error +opaque type BadG = [T] =>> [U] =>> (T, U) // error + +