Skip to content

Commit abafcd3

Browse files
committed
Remove unused params in erasure
With path dependent types on parameters it is not possible to remove them before erasure because there is no type that can be put in their place without messing with typing (Ychecks will fail).
1 parent 7679072 commit abafcd3

File tree

8 files changed

+34
-175
lines changed

8 files changed

+34
-175
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,14 @@ class Compiler {
6464
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
6565
new ClassOf, // Expand `Predef.classOf` calls.
6666
new RefChecks), // Various checks mostly related to abstract members and overriding
67-
List(new UnusedParams), // Removes all unused parameters and arguments
6867
List(new TryCatchPatterns, // Compile cases in try/catch
6968
new PatternMatcher, // Compile pattern matches
7069
new ExplicitOuter, // Add accessors to outer classes from nested ones.
7170
new ExplicitSelf, // Make references to non-trivial self types explicit as casts
7271
new ShortcutImplicits, // Allow implicit functions without creating closures
7372
new CrossCastAnd, // Normalize selections involving intersection types.
7473
new Splitter), // Expand selections involving union types into conditionals
75-
List(new UnusedDecls, // Removes all unused defs and vals decls
74+
List(new UnusedDecls, // Removes all unused defs and vals decls (except for parameters)
7675
new VCInlineMethods, // Inlines calls to value class methods
7776
new SeqLiterals, // Express vararg arguments as arrays
7877
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
400400
def paramErasure(tpToErase: Type) =
401401
erasureFn(tp.isJavaMethod, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
402402
val (names, formals0) =
403-
if (tp.paramInfos.exists(_.isPhantom)) tp.paramNames.zip(tp.paramInfos).filterNot(_._2.isPhantom).unzip
403+
if (tp.isUnusedMethod) (Nil, Nil)
404+
else if (tp.paramInfos.exists(_.isPhantom)) tp.paramNames.zip(tp.paramInfos).filterNot(_._2.isPhantom).unzip
404405
else (tp.paramNames, tp.paramInfos)
405406
val formals = formals0.mapConserve(paramErasure)
406407
eraseResult(tp.resultType) match {

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,15 @@ object Erasure {
456456
case _ => Nil
457457
}
458458

459+
// TODO: merge this whit protoArgs if it is actually needed
460+
private def protoArgs2(pt: Type, tp: Type): List[untpd.Tree] = (pt, tp) match {
461+
case (pt: FunProto, tp: MethodType) if tp.isUnusedMethod => protoArgs2(pt.resType, tp.resType)
462+
case (pt: FunProto, tp: MethodType) => pt.args ++ protoArgs2(pt.resType, tp.resType)
463+
case _ =>
464+
assert(!tp.isInstanceOf[MethodOrPoly], tp)
465+
Nil
466+
}
467+
459468
override def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context) = {
460469
val ntree = interceptTypeApply(tree.asInstanceOf[TypeApply])(ctx.withPhase(ctx.erasurePhase))
461470

@@ -486,7 +495,10 @@ object Erasure {
486495
fun1.tpe.widen match {
487496
case mt: MethodType =>
488497
val outers = outer.args(fun.asInstanceOf[tpd.Tree]) // can't use fun1 here because its type is already erased
489-
var args0 = outers ::: args ++ protoArgs(pt)
498+
var args0 = protoArgs2(pt, tree.typeOpt)
499+
if (!mt.isUnusedMethod) args0 = args ::: args0
500+
args0 = outers ::: args0
501+
490502
if (args0.length > MaxImplementedFunctionArity && mt.paramInfos.length == 1) {
491503
val bunchedArgs = untpd.JavaSeqLiteral(args0, TypeTree(defn.ObjectType))
492504
.withType(defn.ArrayOf(defn.ObjectType))
@@ -554,6 +566,7 @@ object Erasure {
554566
vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil
555567
rhs1 = untpd.Block(paramDefs, rhs1)
556568
}
569+
vparamss1 = vparamss1.mapConserve(_.filterConserve(!_.symbol.is(Flags.Unused)))
557570
vparamss1 = vparamss1.mapConserve(_.filterConserve(vparam => !wasPhantom(vparam.tpe)))
558571
if (sym.is(Flags.ParamAccessor) && wasPhantom(ddef.tpt.tpe)) {
559572
sym.resetFlag(Flags.ParamAccessor)

compiler/src/dotty/tools/dotc/transform/UnusedDecls.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class UnusedDecls extends MiniPhase with InfoTransformer {
2424

2525
/** Check what the phase achieves, to be called at any point after it is finished. */
2626
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
27-
case tree: ValOrDefDef => assert(!tree.symbol.is(Unused))
27+
case tree: ValOrDefDef if !tree.symbol.is(Param) => assert(!tree.symbol.is(Unused, butNot = Param))
2828
case _ =>
2929
}
3030

@@ -35,7 +35,7 @@ class UnusedDecls extends MiniPhase with InfoTransformer {
3535
override def transformValDef(tree: ValDef)(implicit ctx: Context): Tree = transformValOrDefDef(tree)
3636

3737
private def transformValOrDefDef(tree: ValOrDefDef)(implicit ctx: Context): Tree =
38-
if (tree.symbol is Unused) EmptyTree else tree
38+
if (tree.symbol.is(Unused, butNot = Param)) EmptyTree else tree
3939

4040

4141
/* Info transform */

compiler/src/dotty/tools/dotc/transform/UnusedParams.scala

Lines changed: 0 additions & 122 deletions
This file was deleted.

compiler/src/dotty/tools/dotc/transform/UnusedRefs.scala

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package dotty.tools.dotc.transform
33
import dotty.tools.dotc.ast.tpd
44
import dotty.tools.dotc.ast.Trees._
55
import dotty.tools.dotc.core.Contexts._
6-
import dotty.tools.dotc.core.DenotTransformers.InfoTransformer
76
import dotty.tools.dotc.core.Flags._
87
import dotty.tools.dotc.core.Phases
98
import dotty.tools.dotc.core.Symbols._
@@ -17,9 +16,8 @@ import dotty.tools.dotc.transform.MegaPhase.MiniPhase
1716
*
1817
* if `unused val x: T = ...` including parameters
1918
* then `x` --> `(default value for T)`
20-
* `x.Y` --> `T#Y`
2119
*/
22-
class UnusedRefs extends MiniPhase with InfoTransformer {
20+
class UnusedRefs extends MiniPhase {
2321
import tpd._
2422

2523
override def phaseName: String = "unusedRefs"
@@ -29,22 +27,9 @@ class UnusedRefs extends MiniPhase with InfoTransformer {
2927
)
3028

3129
/** Check what the phase achieves, to be called at any point after it is finished. */
32-
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
33-
val checker = new TypeMap {
34-
override def apply(tp: Type): Type = tp match {
35-
case tp: TermParamRef => assert(!tp.binder.isUnusedMethod); tp
36-
case tp: TermRef if !tp.symbol.is(Method) => assert(!tp.symbol.is(Unused)); tp
37-
case _ => mapOver(tp)
38-
}
39-
}
40-
tree match {
41-
case _: ValDef =>
42-
case _: Apply | _: RefTree =>
43-
assert(!tree.symbol.is(Unused))
44-
checker.apply(tree.tpe)
45-
case _ =>
46-
checker.apply(tree.tpe)
47-
}
30+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
31+
case _: Apply | _: RefTree => assert(!tree.symbol.is(Unused))
32+
case _ =>
4833
}
4934

5035
/* Tree transform */
@@ -70,26 +55,4 @@ class UnusedRefs extends MiniPhase with InfoTransformer {
7055
}
7156
}
7257
}
73-
74-
override def transformTypeTree(tree: TypeTree)(implicit ctx: Context): Tree = {
75-
val newType = removeUnusedPaths(tree.tpe)
76-
if (tree.tpe == newType) tree
77-
else TypeTree(newType)
78-
}
79-
80-
81-
/* Tree info */
82-
83-
override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = removeUnusedPaths(tp)
84-
85-
private def removeUnusedPaths(tp: Type)(implicit ctx: Context): Type = {
86-
// TODO: handle variance
87-
new TypeMap {
88-
override def apply(tp: Type): Type = tp match {
89-
case tp: TermParamRef if tp.binder.isUnusedMethod => tp.classSymbol.typeRef
90-
case tp: TermRef if tp.symbol.is(Unused) => tp.widen
91-
case _ => mapOver(tp)
92-
}
93-
}.apply(tp)
94-
}
9558
}

tests/run/unused-3.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
foo
2-
foo
1+
foo1
2+
foo2
33
fun

tests/run/unused-3.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
object Test {
22

33
def main(args: Array[String]): Unit = {
4-
fun(foo)(foo)
4+
fun(foo1)(foo2)
55
}
66

7-
def foo: Int = {
8-
println("foo")
7+
def foo1: Int = {
8+
println("foo1")
99
42
1010
}
1111

12-
def fun(unused a: Int)(unused b: Int): Unit = {
12+
def foo2: String = {
13+
println("foo2")
14+
"abc"
15+
}
16+
17+
def fun(unused a: Int)(unused b: String): Unit = {
1318
println("fun")
1419
}
1520

0 commit comments

Comments
 (0)