Skip to content

Commit 3bdc4a5

Browse files
committed
Implement revised desugaring scheme
1 parent 4470c9e commit 3bdc4a5

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,8 @@ object desugar {
355355
val originalVparamss = constr1.vparamss
356356
lazy val derivedEnumParams = enumClass.typeParams.map(derivedTypeParam)
357357
val impliedTparams =
358-
if (isEnumCase && originalTparams.isEmpty)
358+
if (isEnumCase && originalTparams.isEmpty &&
359+
typeParamIsReferenced(enumClass.typeParams, originalVparamss, parents))
359360
derivedEnumParams.map(tdef => tdef.withFlags(tdef.mods.flags | PrivateLocal))
360361
else
361362
originalTparams

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,44 @@ object DesugarEnums {
168168
}
169169
}
170170

171+
/** Is a type parameter in `tparams` referenced from an enum class case that has
172+
* given value parameters `vparamss` and given parents `parents`?
173+
*/
174+
def typeParamIsReferenced(tparams: List[TypeSymbol], vparamss: List[List[ValDef]], parents: List[Tree])(implicit ctx: Context): Boolean = {
175+
176+
val searchRef = new untpd.TreeAccumulator[Boolean] {
177+
var tparamNames = tparams.map(_.name).toSet[Name]
178+
def underBinders(binders: List[MemberDef], op: => Boolean): Boolean = {
179+
val saved = tparamNames
180+
tparamNames = tparamNames -- binders.map(_.name)
181+
try op
182+
finally tparamNames = saved
183+
}
184+
def apply(x: Boolean, tree: Tree)(implicit ctx: Context) = x || {
185+
tree match {
186+
case Ident(name) => tparamNames.contains(name)
187+
case LambdaTypeTree(lambdaParams, body) => underBinders(lambdaParams, foldOver(x, tree))
188+
case RefinedTypeTree(parent, refinements) => underBinders(refinements.asInstanceOf[List[MemberDef]], foldOver(x, tree))
189+
case _ => foldOver(x, tree)
190+
}
191+
}
192+
}
193+
194+
def typeHasRef(tpt: Tree) = searchRef(false, tpt)
195+
def valDefHasRef(vd: ValDef) = typeHasRef(vd.tpt)
196+
def parentHasRef(parent: Tree): Boolean = parent match {
197+
case Apply(fn, _) => parentHasRef(fn)
198+
case TypeApply(_, targs) => targs.exists(typeHasRef)
199+
case Select(nu, nme.CONSTRUCTOR) => parentHasRef(nu)
200+
case New(tpt) => typeHasRef(tpt)
201+
case parent if parent.isType => typeHasRef(parent)
202+
}
203+
204+
parents.isEmpty || // a parent class that refers to type parameters will be generated in this case
205+
vparamss.exists(_.exists(valDefHasRef)) ||
206+
parents.exists(parentHasRef)
207+
}
208+
171209
/** A pair consisting of
172210
* - the next enum tag
173211
* - scaffolding containing the necessary definitions for singleton enum cases

tests/neg/enum-tparams.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
object Test {
2+
3+
enum Opt[+T] {
4+
case S(x: T) extends Opt[T]
5+
case I(x: Int) extends Opt[Int]
6+
case V() extends Opt[`T`]
7+
case P(x: List[T]) extends Opt[String]
8+
case N extends Opt[Nothing]
9+
}
10+
11+
type Id[_]
12+
13+
enum E[F[_], G[_]] {
14+
case C1() extends E[[X] => X, Id]
15+
case C2() extends E[[F] => F, Id]
16+
case C3() extends E[[X] => { type Y = F[Int] }, Id]
17+
case C4() extends E[[X] => { type F = Int }, Id]
18+
case C5() extends E[[F] => G[Int], Id]
19+
}
20+
21+
Opt.S[Int](1) // OK
22+
Opt.S(1) // OK
23+
Opt.I[Int](1) // error: does not take type parameters
24+
Opt.I(1) // OK
25+
Opt.V[Int]() // OK
26+
Opt.V() // OK
27+
Opt.P[Int](List(1, 2, 3)) // OK
28+
Opt.P(List(1, 2, 3)) // OK
29+
30+
E.C1[List, Id]() // error: does not take type parameters
31+
E.C1() // OK
32+
E.C2[List, Id]() // error: does not take type parameters
33+
E.C2() // OK
34+
E.C3[List, Id]() // OK
35+
E.C3() // OK
36+
E.C4[List, Id]() // error: does not take type parameters
37+
E.C4() // OK
38+
E.C5[List, Id]() // OK
39+
E.C5() // OK
40+
}

0 commit comments

Comments
 (0)