Skip to content

Commit 8d07271

Browse files
Merge pull request #3342 from dotty-staging/implement-unused
Implement unused
2 parents 2a85106 + 68afbcd commit 8d07271

File tree

130 files changed

+1746
-128
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+1746
-128
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class Compiler {
8181
new CrossCastAnd, // Normalize selections involving intersection types.
8282
new Splitter) :: // Expand selections involving union types into conditionals
8383
List(new PhantomArgLift, // Extracts the evaluation of phantom arguments placing them before the call.
84+
new UnusedDecls, // Removes all unused defs and vals decls (except for parameters)
8485
new VCInlineMethods, // Inlines calls to value class methods
8586
new SeqLiterals, // Express vararg arguments as arrays
8687
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ object desugar {
258258
private def toDefParam(tparam: TypeDef): TypeDef =
259259
tparam.withMods(tparam.rawMods & EmptyFlags | Param)
260260
private def toDefParam(vparam: ValDef): ValDef =
261-
vparam.withMods(vparam.rawMods & Implicit | Param)
261+
vparam.withMods(vparam.rawMods & (Implicit | Unused) | Param)
262262

263263
/** The expansion of a class definition. See inline comments for what is involved */
264264
def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = {
@@ -825,7 +825,7 @@ object desugar {
825825

826826
def makeImplicitFunction(formals: List[Type], body: Tree)(implicit ctx: Context): Tree = {
827827
val params = makeImplicitParameters(formals.map(TypeTree))
828-
new ImplicitFunction(params, body)
828+
new NonEmptyFunction(params, body, Modifiers(Implicit))
829829
}
830830

831831
/** Add annotation to tree:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
396396
* flags set.
397397
*/
398398
private def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
399-
if (!tree.tpe.widen.isParameterless) SimplyPure
399+
if (!tree.tpe.widen.isParameterless || tree.symbol.is(Unused)) SimplyPure
400400
else if (!tree.symbol.isStable) Impure
401401
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
402402
else SimplyPure

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
202202
case tp: MethodType =>
203203
def valueParam(name: TermName, info: Type): TermSymbol = {
204204
val maybeImplicit = if (tp.isImplicitMethod) Implicit else EmptyFlags
205-
ctx.newSymbol(sym, name, TermParam | maybeImplicit, info, coord = sym.coord)
205+
val maybeUnused = if (tp.isUnusedMethod) Unused else EmptyFlags
206+
ctx.newSymbol(sym, name, TermParam | maybeImplicit | maybeUnused, info, coord = sym.coord)
206207
}
207208
val params = (tp.paramNames, tp.paramInfos).zipped.map(valueParam)
208209
val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.termRef)))

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,14 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
5050
*/
5151
case class InterpolatedString(id: TermName, segments: List[Tree]) extends TermTree
5252

53+
/** A function type */
5354
case class Function(args: List[Tree], body: Tree) extends Tree {
5455
override def isTerm = body.isTerm
5556
override def isType = body.isType
5657
}
5758

58-
/** An implicit function type */
59-
class ImplicitFunction(args: List[Tree], body: Tree) extends Function(args, body) {
60-
override def toString = s"ImplicitFunction($args, $body)"
61-
}
59+
/** A function type that should have non empty args */
60+
class NonEmptyFunction(args: List[Tree], body: Tree, val mods: Modifiers) extends Function(args, body)
6261

6362
/** A function created from a wildcard expression
6463
* @param placeHolderParams a list of definitions of synthetic parameters
@@ -119,6 +118,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
119118

120119
case class Implicit() extends Mod(Flags.ImplicitCommon)
121120

121+
case class Unused() extends Mod(Flags.Unused)
122+
122123
case class Final() extends Mod(Flags.Final)
123124

124125
case class Sealed() extends Mod(Flags.Sealed)

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

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Definitions {
8888
newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered
8989
}
9090

91-
/** The trait FunctionN or ImplicitFunctionN, for some N
91+
/** The trait FunctionN, ImplicitFunctionN, UnusedFunctionN or UnusedImplicitFunction, for some N
9292
* @param name The name of the trait to be created
9393
*
9494
* FunctionN traits follow this template:
@@ -106,6 +106,20 @@ class Definitions {
106106
* trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object with FunctionN[T0,...,T{N-1}, R] {
107107
* def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
108108
* }
109+
*
110+
* UnusedFunctionN traits follow this template:
111+
*
112+
* trait UnusedFunctionN[T0,...,T{N-1}, R] extends Object {
113+
* def apply(unused $x0: T0, ..., $x{N_1}: T{N-1}): R
114+
* }
115+
*
116+
* UnusedImplicitFunctionN traits follow this template:
117+
*
118+
* trait UnusedImplicitFunctionN[T0,...,T{N-1}, R] extends Object with UnusedFunctionN[T0,...,T{N-1}, R] {
119+
* def apply(unused implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
120+
* }
121+
*
122+
* UnusedFunctionN and UnusedImplicitFunctionN erase to Function0.
109123
*/
110124
def newFunctionNTrait(name: TypeName): ClassSymbol = {
111125
val completer = new LazyType {
@@ -117,18 +131,12 @@ class Definitions {
117131
val argParamRefs = List.tabulate(arity) { i =>
118132
enterTypeParam(cls, paramNamePrefix ++ "T" ++ (i + 1).toString, Contravariant, decls).typeRef
119133
}
120-
val resParam = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls)
121-
val (methodType, parentTraits) =
122-
if (name.firstPart.startsWith(str.ImplicitFunction)) {
123-
val superTrait =
124-
FunctionType(arity).appliedTo(argParamRefs ::: resParam.typeRef :: Nil)
125-
(ImplicitMethodType, superTrait :: Nil)
126-
}
127-
else (MethodType, Nil)
128-
val applyMeth =
129-
decls.enter(
130-
newMethod(cls, nme.apply,
131-
methodType(argParamRefs, resParam.typeRef), Deferred))
134+
val resParamRef = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls).typeRef
135+
val methodType = MethodType.maker(isJava = false, name.isImplicitFunction, name.isUnusedFunction)
136+
val parentTraits =
137+
if (!name.isImplicitFunction) Nil
138+
else FunctionType(arity, isUnused = name.isUnusedFunction).appliedTo(argParamRefs ::: resParamRef :: Nil) :: Nil
139+
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
132140
denot.info =
133141
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: parentTraits, decls)
134142
}
@@ -748,14 +756,14 @@ class Definitions {
748756
sym.owner.linkedClass.typeRef
749757

750758
object FunctionOf {
751-
def apply(args: List[Type], resultType: Type, isImplicit: Boolean = false)(implicit ctx: Context) =
752-
FunctionType(args.length, isImplicit).appliedTo(args ::: resultType :: Nil)
759+
def apply(args: List[Type], resultType: Type, isImplicit: Boolean = false, isUnused: Boolean = false)(implicit ctx: Context) =
760+
FunctionType(args.length, isImplicit, isUnused).appliedTo(args ::: resultType :: Nil)
753761
def unapply(ft: Type)(implicit ctx: Context) = {
754762
val tsym = ft.typeSymbol
755763
if (isFunctionClass(tsym)) {
756764
val targs = ft.dealias.argInfos
757765
if (targs.isEmpty) None
758-
else Some(targs.init, targs.last, tsym.name.isImplicitFunction)
766+
else Some(targs.init, targs.last, tsym.name.isImplicitFunction, tsym.name.isUnusedFunction)
759767
}
760768
else None
761769
}
@@ -819,20 +827,29 @@ class Definitions {
819827

820828
lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2)
821829

822-
def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) =
823-
if (isImplicit) {
830+
def FunctionClass(n: Int, isImplicit: Boolean = false, isUnused: Boolean = false)(implicit ctx: Context) = {
831+
if (isImplicit && isUnused) {
832+
require(n > 0)
833+
ctx.requiredClass("scala.UnusedImplicitFunction" + n.toString)
834+
}
835+
else if (isImplicit) {
824836
require(n > 0)
825837
ctx.requiredClass("scala.ImplicitFunction" + n.toString)
826838
}
839+
else if (isUnused) {
840+
require(n > 0)
841+
ctx.requiredClass("scala.UnusedFunction" + n.toString)
842+
}
827843
else if (n <= MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
828844
else ctx.requiredClass("scala.Function" + n.toString)
845+
}
829846

830847
lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply)
831848
def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
832849

833-
def FunctionType(n: Int, isImplicit: Boolean = false)(implicit ctx: Context): TypeRef =
834-
if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes)) ImplementedFunctionType(n)
835-
else FunctionClass(n, isImplicit).typeRef
850+
def FunctionType(n: Int, isImplicit: Boolean = false, isUnused: Boolean = false)(implicit ctx: Context): TypeRef =
851+
if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes) && !isUnused) ImplementedFunctionType(n)
852+
else FunctionClass(n, isImplicit, isUnused).typeRef
836853

837854
private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
838855

@@ -857,14 +874,23 @@ class Definitions {
857874
/** Is a function class.
858875
* - FunctionN for N >= 0
859876
* - ImplicitFunctionN for N > 0
877+
* - UnusedFunctionN for N > 0
878+
* - UnusedImplicitFunctionN for N > 0
860879
*/
861880
def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction
862881

863882
/** Is an implicit function class.
864883
* - ImplicitFunctionN for N > 0
884+
* - UnusedImplicitFunctionN for N > 0
865885
*/
866886
def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction
867887

888+
/** Is an unused function class.
889+
* - UnusedFunctionN for N > 0
890+
* - UnusedImplicitFunctionN for N > 0
891+
*/
892+
def isUnusedFunctionClass(cls: Symbol) = scalaClassName(cls).isUnusedFunction
893+
868894
/** Is a class that will be erased to FunctionXXL
869895
* - FunctionN for N >= 22
870896
* - ImplicitFunctionN for N >= 22
@@ -889,11 +915,14 @@ class Definitions {
889915
* - FunctionN for 22 > N >= 0 remains as FunctionN
890916
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
891917
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
918+
* - UnusedFunctionN becomes Function0
919+
* - ImplicitUnusedFunctionN becomes Function0
892920
* - anything else becomes a NoSymbol
893921
*/
894922
def erasedFunctionClass(cls: Symbol): Symbol = {
895923
val arity = scalaClassName(cls).functionArity
896-
if (arity > 22) FunctionXXLClass
924+
if (cls.name.isUnusedFunction) FunctionClass(0)
925+
else if (arity > 22) FunctionXXLClass
897926
else if (arity >= 0) FunctionClass(arity)
898927
else NoSymbol
899928
}
@@ -903,12 +932,15 @@ class Definitions {
903932
* - FunctionN for 22 > N >= 0 remains as FunctionN
904933
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
905934
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
935+
* - UnusedFunctionN becomes Function0
936+
* - ImplicitUnusedFunctionN becomes Function0
906937
* - anything else becomes a NoType
907938
*/
908939
def erasedFunctionType(cls: Symbol): Type = {
909940
val arity = scalaClassName(cls).functionArity
910-
if (arity > 22) defn.FunctionXXLType
911-
else if (arity >= 0) defn.FunctionType(arity)
941+
if (cls.name.isUnusedFunction) FunctionType(0)
942+
else if (arity > 22) FunctionXXLType
943+
else if (arity >= 0) FunctionType(arity)
912944
else NoType
913945
}
914946

@@ -976,7 +1008,7 @@ class Definitions {
9761008
def isNonDepFunctionType(tp: Type)(implicit ctx: Context) = {
9771009
val arity = functionArity(tp)
9781010
val sym = tp.dealias.typeSymbol
979-
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction).typeSymbol)
1011+
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction, sym.name.isUnusedFunction).typeSymbol)
9801012
}
9811013

9821014
/** Is `tp` a representation of a (possibly depenent) function type or an alias of such? */
@@ -1042,6 +1074,9 @@ class Definitions {
10421074
def isImplicitFunctionType(tp: Type)(implicit ctx: Context): Boolean =
10431075
asImplicitFunctionType(tp).exists
10441076

1077+
def isUnusedFunctionType(tp: Type)(implicit ctx: Context) =
1078+
isFunctionType(tp) && tp.dealias.typeSymbol.name.isUnusedFunction
1079+
10451080
// ----- primitive value class machinery ------------------------------------------
10461081

10471082
/** This class would also be obviated by the implicit function type design */

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ object Flags {
367367
/** Symbol is a Java enum */
368368
final val Enum = commonFlag(40, "<enum>")
369369

370+
/** Labeled with `unused` modifier (unused value) */
371+
final val Unused = termFlag(42, "unused")
372+
370373
// Flags following this one are not pickled
371374

372375
/** Symbol is not a member of its owner */
@@ -438,7 +441,7 @@ object Flags {
438441
/** Flags representing source modifiers */
439442
final val SourceModifierFlags =
440443
commonFlags(Private, Protected, Abstract, Final, Inline,
441-
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic)
444+
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Unused)
442445

443446
/** Flags representing modifiers that can appear in trees */
444447
final val ModifierFlags =
@@ -512,7 +515,7 @@ object Flags {
512515
/** Flags that can apply to a module val */
513516
final val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
514517
Override | Final | Method | Implicit | Lazy |
515-
Accessor | AbsOverride | Stable | Captured | Synchronized | Inline
518+
Accessor | AbsOverride | Stable | Captured | Synchronized | Inline | Unused
516519

517520
/** Flags that can apply to a module class */
518521
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass | Enum

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,5 @@ object Mode {
9393

9494
/** We are in the IDE */
9595
val Interactive = newMode(20, "Interactive")
96+
9697
}

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,31 +174,53 @@ object NameOps {
174174
*/
175175
def functionArity: Int =
176176
functionArityFor(str.Function) max {
177-
val n = functionArityFor(str.ImplicitFunction)
177+
val n =
178+
functionArityFor(str.ImplicitFunction) max
179+
functionArityFor(str.UnusedFunction) max
180+
functionArityFor(str.UnusedImplicitFunction)
178181
if (n == 0) -1 else n
179182
}
180183

181184
/** Is a function name
182185
* - FunctionN for N >= 0
183186
* - ImplicitFunctionN for N >= 1
187+
* - UnusedFunctionN for N >= 1
188+
* - UnusedImplicitFunctionN for N >= 1
184189
* - false otherwise
185190
*/
186191
def isFunction: Boolean = functionArity >= 0
187192

188193
/** Is a implicit function name
189194
* - ImplicitFunctionN for N >= 1
195+
* - UnusedImplicitFunctionN for N >= 1
190196
* - false otherwise
191197
*/
192-
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 1
198+
def isImplicitFunction: Boolean = {
199+
functionArityFor(str.ImplicitFunction) >= 1 ||
200+
functionArityFor(str.UnusedImplicitFunction) >= 1
201+
}
202+
203+
/** Is a implicit function name
204+
* - UnusedFunctionN for N >= 1
205+
* - UnusedImplicitFunctionN for N >= 1
206+
* - false otherwise
207+
*/
208+
def isUnusedFunction: Boolean = {
209+
functionArityFor(str.UnusedFunction) >= 1 ||
210+
functionArityFor(str.UnusedImplicitFunction) >= 1
211+
}
193212

194213
/** Is a synthetic function name
195214
* - FunctionN for N > 22
196215
* - ImplicitFunctionN for N >= 1
216+
* - UnusedFunctionN for N >= 1
217+
* - UnusedImplicitFunctionN for N >= 1
197218
* - false otherwise
198219
*/
199220
def isSyntheticFunction: Boolean = {
200221
functionArityFor(str.Function) > MaxImplementedFunctionArity ||
201-
functionArityFor(str.ImplicitFunction) >= 1
222+
functionArityFor(str.ImplicitFunction) >= 1 ||
223+
isUnusedFunction
202224
}
203225

204226
/** Parsed function arity for function with some specific prefix */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ object StdNames {
3636
final val MODULE_INSTANCE_FIELD = "MODULE$"
3737

3838
final val Function = "Function"
39+
final val UnusedFunction = "UnusedFunction"
3940
final val ImplicitFunction = "ImplicitFunction"
41+
final val UnusedImplicitFunction = "UnusedImplicitFunction"
4042
final val AbstractFunction = "AbstractFunction"
4143
final val Tuple = "Tuple"
4244
final val Product = "Product"

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

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

0 commit comments

Comments
 (0)