Skip to content

Drop implementation restriction for polymorphic functions #12863

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

Merged
merged 2 commits into from
Jun 18, 2021
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
50 changes: 27 additions & 23 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1632,12 +1632,12 @@ object desugar {
}
}

def makePolyFunction(targs: List[Tree], body: Tree): Tree = body match {
def makePolyFunction(targs: List[Tree], body: Tree): Tree = body match
case Parens(body1) =>
makePolyFunction(targs, body1)
case Block(Nil, body1) =>
makePolyFunction(targs, body1)
case Function(vargs, res) =>
case _ =>
assert(targs.nonEmpty)
// TODO: Figure out if we need a `PolyFunctionWithMods` instead.
val mods = body match {
Expand All @@ -1646,33 +1646,37 @@ object desugar {
}
val polyFunctionTpt = ref(defn.PolyFunctionType)
val applyTParams = targs.asInstanceOf[List[TypeDef]]
if (ctx.mode.is(Mode.Type)) {
if ctx.mode.is(Mode.Type) then
// Desugar [T_1, ..., T_M] -> (P_1, ..., P_N) => R
// Into scala.PolyFunction { def apply[T_1, ..., T_M](x$1: P_1, ..., x$N: P_N): R }

val applyVParams = vargs.zipWithIndex.map {
case (p: ValDef, _) => p.withAddedFlags(mods.flags)
case (p, n) => makeSyntheticParameter(n + 1, p).withAddedFlags(mods.flags)
}
val (res, applyVParamss) = body match
case Function(vargs, res) =>
( res,
vargs.zipWithIndex.map {
case (p: ValDef, _) => p.withAddedFlags(mods.flags)
case (p, n) => makeSyntheticParameter(n + 1, p).withAddedFlags(mods.flags)
} :: Nil
)
case _ =>
(body, Nil)
RefinedTypeTree(polyFunctionTpt, List(
DefDef(nme.apply, applyTParams :: applyVParams :: Nil, res, EmptyTree)
DefDef(nme.apply, applyTParams :: applyVParamss, res, EmptyTree)
))
}
else {
else
// Desugar [T_1, ..., T_M] -> (x_1: P_1, ..., x_N: P_N) => body
// Into new scala.PolyFunction { def apply[T_1, ..., T_M](x_1: P_1, ..., x_N: P_N) = body }

val applyVParams = vargs.asInstanceOf[List[ValDef]]
.map(varg => varg.withAddedFlags(mods.flags | Param))
New(Template(emptyConstructor, List(polyFunctionTpt), Nil, EmptyValDef,
List(DefDef(nme.apply, applyTParams :: applyVParams :: Nil, TypeTree(), res))
))
}
case _ =>
// may happen for erroneous input. An error will already have been reported.
assert(ctx.reporter.errorsReported)
EmptyTree
}
val (res, applyVParamss) = body match
case Function(vargs, res) =>
( res,
vargs.asInstanceOf[List[ValDef]]
.map(varg => varg.withAddedFlags(mods.flags | Param))
:: Nil
)
case _ =>
(body, Nil)
New(Template(emptyConstructor, List(polyFunctionTpt), Nil, EmptyValDef,
List(DefDef(nme.apply, applyTParams :: applyVParamss, TypeTree(), res))
))

// begin desugar

Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
* - otherwise, if T is a type parameter coming from Java, []Object
* - otherwise, Object
* - For a term ref p.x, the type <noprefix> # x.
* - For a refined type scala.PolyFunction { def apply[...]: R }, scala.Function0
* - For a refined type scala.PolyFunction { def apply[...](x_1, ..., x_N): R }, scala.FunctionN
* - For a typeref scala.Any, scala.AnyVal, scala.Singleton, scala.Tuple, or scala.*: : |java.lang.Object|
* - For a typeref scala.Unit, |scala.runtime.BoxedUnit|.
Expand Down Expand Up @@ -600,8 +601,9 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
assert(refinedInfo.isInstanceOf[PolyType])
val res = refinedInfo.resultType
val paramss = res.paramNamess
assert(paramss.length == 1)
this(defn.FunctionType(paramss.head.length, isContextual = res.isImplicitMethod, isErased = res.isErasedMethod))
assert(paramss.length <= 1)
val arity = if paramss.isEmpty then 0 else paramss.head.length
this(defn.FunctionType(arity, isContextual = res.isImplicitMethod, isErased = res.isErasedMethod))
case tp: TypeProxy =>
this(tp.underlying)
case tp @ AndType(tp1, tp2) =>
Expand Down
18 changes: 2 additions & 16 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1434,14 +1434,7 @@ object Parsers {
else if (in.token == ARROW) {
val arrowOffset = in.skipToken()
val body = toplevelTyp()
atSpan(start, arrowOffset) {
if (isFunction(body))
PolyFunction(tparams, body)
else {
syntaxError("Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
Ident(nme.ERROR.toTypeName)
}
}
atSpan(start, arrowOffset) { PolyFunction(tparams, body) }
}
else { accept(TLARROW); typ() }
}
Expand Down Expand Up @@ -1917,14 +1910,7 @@ object Parsers {
val tparams = typeParamClause(ParamOwner.TypeParam)
val arrowOffset = accept(ARROW)
val body = expr(location)
atSpan(start, arrowOffset) {
if (isFunction(body))
PolyFunction(tparams, body)
else {
syntaxError("Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
errorTermTree
}
}
atSpan(start, arrowOffset) { PolyFunction(tparams, body) }
case _ =>
val saved = placeholderParams
placeholderParams = Nil
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/i2887b.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
trait A { type S[X[_] <: [_] => Any, Y[_]] <: [_] => Any; type I[_] } // error // error
trait B { type S[X[_],Y[_]]; type I[_] <: [_] => Any } // error
trait A { type S[X[_] <: [_] => Any, Y[_]] <: [_] => Any; type I[_] }
trait B { type S[X[_],Y[_]]; type I[_] <: [_] => Any }
trait C { type M <: B }
trait D { type M >: A }

Expand Down