Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow opaque type aliases of context functions #16041

Merged
merged 2 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ object Erasure {
case _: FunProto | AnyFunctionProto => tree
case _ => tree.tpe.widen match
case mt: MethodType if tree.isTerm =>
assert(mt.paramInfos.isEmpty)//, i"bad adapt for $tree: $mt")
assert(mt.paramInfos.isEmpty, i"bad adapt for $tree: $mt")
adaptToType(tree.appliedToNone, pt)
case tpw =>
if (pt.isInstanceOf[ProtoType] || tree.tpe <:< pt)
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,15 @@ trait Checking {
|CanThrow capabilities can only be generated $req.""",
pat.srcPos)

/** Check that tree does not define a context function type */
def checkNoContextFunctionType(tree: Tree)(using Context): Unit =
def recur(tp: Type): Unit = tp.dealias match
case tp: HKTypeLambda => recur(tp.resType)
case tp if defn.isContextFunctionType(tp) =>
report.error(em"context function type cannot have opaque aliases", tree.srcPos)
case _ =>
recur(tree.tpe)

/** (1) Check that every named import selector refers to a type or value member of the
* qualifier type.
* (2) Check that no import selector is renamed more than once.
Expand Down Expand Up @@ -1495,6 +1504,7 @@ trait ReChecking extends Checking {
override def checkNoModuleClash(sym: Symbol)(using Context) = ()
override def checkCanThrow(tp: Type, span: Span)(using Context): Tree = EmptyTree
override def checkCatch(pat: Tree, guard: Tree)(using Context): Unit = ()
override def checkNoContextFunctionType(tree: Tree)(using Context): Unit = ()
override def checkFeature(name: TermName, description: => String, featureUseSite: Symbol, pos: SrcPos)(using Context): Unit = ()
}

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2417,6 +2417,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case rhs =>
typedType(rhs)
checkFullyAppliedType(rhs1)
if sym.isOpaqueAlias then checkNoContextFunctionType(rhs1)
assignType(cpy.TypeDef(tdef)(name, rhs1), sym)
}

Expand Down
1 change: 1 addition & 0 deletions docs/_docs/reference/other-new-features/opaques-details.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def id(x: o.T): o.T = x
```

Opaque type aliases cannot be `private` and cannot be overridden in subclasses.
Opaque type aliases cannot have a context function type as right-hand side.

## Type Parameters of Opaque Types

Expand Down
12 changes: 12 additions & 0 deletions tests/neg/i16035.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
object Scope:
opaque type Uses[A, B] = A ?=> B // error
opaque type UsesAlt = [A, B] =>> A ?=> B // error

object Uses:
def apply[A, B](fn: A ?=> B): Uses[A, B] = fn

import Scope.*
val uses =
given Int = 1
Uses[Int, String](i ?=> s"*$i*")

14 changes: 14 additions & 0 deletions tests/neg/i16035a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
trait S:
type Uses[A, B] <: A ?=> B
object Uses:
def apply[A, B](fn: A ?=> B): Uses[A, B] = fn // error
val uses1 =
given Int = 1
Uses[Int, String](i ?=> s"*$i*")

object I extends S:
type Uses[A, B] = A ?=> B
val uses2 =
given Int = 1
Uses[Int, String](i ?=> s"*$i*")

11 changes: 11 additions & 0 deletions tests/pos/i16035.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
object Scope:
type Uses[A, B] = A ?=> B

object Uses:
def apply[A, B](fn: A ?=> B): Uses[A, B] = fn

import Scope.*
val uses =
given Int = 1
Uses[Int, String](i ?=> s"*$i*")