Skip to content

Commit

Permalink
Merge pull request #3342 from dotty-staging/implement-unused
Browse files Browse the repository at this point in the history
Implement unused
  • Loading branch information
nicolasstucki committed Feb 21, 2018
2 parents 2a85106 + 68afbcd commit 8d07271
Show file tree
Hide file tree
Showing 130 changed files with 1,746 additions and 128 deletions.
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class Compiler {
new CrossCastAnd, // Normalize selections involving intersection types.
new Splitter) :: // Expand selections involving union types into conditionals
List(new PhantomArgLift, // Extracts the evaluation of phantom arguments placing them before the call.
new UnusedDecls, // Removes all unused defs and vals decls (except for parameters)
new VCInlineMethods, // Inlines calls to value class methods
new SeqLiterals, // Express vararg arguments as arrays
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ object desugar {
private def toDefParam(tparam: TypeDef): TypeDef =
tparam.withMods(tparam.rawMods & EmptyFlags | Param)
private def toDefParam(vparam: ValDef): ValDef =
vparam.withMods(vparam.rawMods & Implicit | Param)
vparam.withMods(vparam.rawMods & (Implicit | Unused) | Param)

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

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

/** Add annotation to tree:
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* flags set.
*/
private def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
if (!tree.tpe.widen.isParameterless) SimplyPure
if (!tree.tpe.widen.isParameterless || tree.symbol.is(Unused)) SimplyPure
else if (!tree.symbol.isStable) Impure
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
else SimplyPure
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case tp: MethodType =>
def valueParam(name: TermName, info: Type): TermSymbol = {
val maybeImplicit = if (tp.isImplicitMethod) Implicit else EmptyFlags
ctx.newSymbol(sym, name, TermParam | maybeImplicit, info, coord = sym.coord)
val maybeUnused = if (tp.isUnusedMethod) Unused else EmptyFlags
ctx.newSymbol(sym, name, TermParam | maybeImplicit | maybeUnused, info, coord = sym.coord)
}
val params = (tp.paramNames, tp.paramInfos).zipped.map(valueParam)
val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.termRef)))
Expand Down
9 changes: 5 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,14 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
*/
case class InterpolatedString(id: TermName, segments: List[Tree]) extends TermTree

/** A function type */
case class Function(args: List[Tree], body: Tree) extends Tree {
override def isTerm = body.isTerm
override def isType = body.isType
}

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

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

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

case class Unused() extends Mod(Flags.Unused)

case class Final() extends Mod(Flags.Final)

case class Sealed() extends Mod(Flags.Sealed)
Expand Down
85 changes: 60 additions & 25 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class Definitions {
newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered
}

/** The trait FunctionN or ImplicitFunctionN, for some N
/** The trait FunctionN, ImplicitFunctionN, UnusedFunctionN or UnusedImplicitFunction, for some N
* @param name The name of the trait to be created
*
* FunctionN traits follow this template:
Expand All @@ -106,6 +106,20 @@ class Definitions {
* trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object with FunctionN[T0,...,T{N-1}, R] {
* def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
* }
*
* UnusedFunctionN traits follow this template:
*
* trait UnusedFunctionN[T0,...,T{N-1}, R] extends Object {
* def apply(unused $x0: T0, ..., $x{N_1}: T{N-1}): R
* }
*
* UnusedImplicitFunctionN traits follow this template:
*
* trait UnusedImplicitFunctionN[T0,...,T{N-1}, R] extends Object with UnusedFunctionN[T0,...,T{N-1}, R] {
* def apply(unused implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
* }
*
* UnusedFunctionN and UnusedImplicitFunctionN erase to Function0.
*/
def newFunctionNTrait(name: TypeName): ClassSymbol = {
val completer = new LazyType {
Expand All @@ -117,18 +131,12 @@ class Definitions {
val argParamRefs = List.tabulate(arity) { i =>
enterTypeParam(cls, paramNamePrefix ++ "T" ++ (i + 1).toString, Contravariant, decls).typeRef
}
val resParam = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls)
val (methodType, parentTraits) =
if (name.firstPart.startsWith(str.ImplicitFunction)) {
val superTrait =
FunctionType(arity).appliedTo(argParamRefs ::: resParam.typeRef :: Nil)
(ImplicitMethodType, superTrait :: Nil)
}
else (MethodType, Nil)
val applyMeth =
decls.enter(
newMethod(cls, nme.apply,
methodType(argParamRefs, resParam.typeRef), Deferred))
val resParamRef = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls).typeRef
val methodType = MethodType.maker(isJava = false, name.isImplicitFunction, name.isUnusedFunction)
val parentTraits =
if (!name.isImplicitFunction) Nil
else FunctionType(arity, isUnused = name.isUnusedFunction).appliedTo(argParamRefs ::: resParamRef :: Nil) :: Nil
decls.enter(newMethod(cls, nme.apply, methodType(argParamRefs, resParamRef), Deferred))
denot.info =
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: parentTraits, decls)
}
Expand Down Expand Up @@ -748,14 +756,14 @@ class Definitions {
sym.owner.linkedClass.typeRef

object FunctionOf {
def apply(args: List[Type], resultType: Type, isImplicit: Boolean = false)(implicit ctx: Context) =
FunctionType(args.length, isImplicit).appliedTo(args ::: resultType :: Nil)
def apply(args: List[Type], resultType: Type, isImplicit: Boolean = false, isUnused: Boolean = false)(implicit ctx: Context) =
FunctionType(args.length, isImplicit, isUnused).appliedTo(args ::: resultType :: Nil)
def unapply(ft: Type)(implicit ctx: Context) = {
val tsym = ft.typeSymbol
if (isFunctionClass(tsym)) {
val targs = ft.dealias.argInfos
if (targs.isEmpty) None
else Some(targs.init, targs.last, tsym.name.isImplicitFunction)
else Some(targs.init, targs.last, tsym.name.isImplicitFunction, tsym.name.isUnusedFunction)
}
else None
}
Expand Down Expand Up @@ -819,20 +827,29 @@ class Definitions {

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

def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) =
if (isImplicit) {
def FunctionClass(n: Int, isImplicit: Boolean = false, isUnused: Boolean = false)(implicit ctx: Context) = {
if (isImplicit && isUnused) {
require(n > 0)
ctx.requiredClass("scala.UnusedImplicitFunction" + n.toString)
}
else if (isImplicit) {
require(n > 0)
ctx.requiredClass("scala.ImplicitFunction" + n.toString)
}
else if (isUnused) {
require(n > 0)
ctx.requiredClass("scala.UnusedFunction" + n.toString)
}
else if (n <= MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
else ctx.requiredClass("scala.Function" + n.toString)
}

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

def FunctionType(n: Int, isImplicit: Boolean = false)(implicit ctx: Context): TypeRef =
if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes)) ImplementedFunctionType(n)
else FunctionClass(n, isImplicit).typeRef
def FunctionType(n: Int, isImplicit: Boolean = false, isUnused: Boolean = false)(implicit ctx: Context): TypeRef =
if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes) && !isUnused) ImplementedFunctionType(n)
else FunctionClass(n, isImplicit, isUnused).typeRef

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

Expand All @@ -857,14 +874,23 @@ class Definitions {
/** Is a function class.
* - FunctionN for N >= 0
* - ImplicitFunctionN for N > 0
* - UnusedFunctionN for N > 0
* - UnusedImplicitFunctionN for N > 0
*/
def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction

/** Is an implicit function class.
* - ImplicitFunctionN for N > 0
* - UnusedImplicitFunctionN for N > 0
*/
def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction

/** Is an unused function class.
* - UnusedFunctionN for N > 0
* - UnusedImplicitFunctionN for N > 0
*/
def isUnusedFunctionClass(cls: Symbol) = scalaClassName(cls).isUnusedFunction

/** Is a class that will be erased to FunctionXXL
* - FunctionN for N >= 22
* - ImplicitFunctionN for N >= 22
Expand All @@ -889,11 +915,14 @@ class Definitions {
* - FunctionN for 22 > N >= 0 remains as FunctionN
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
* - UnusedFunctionN becomes Function0
* - ImplicitUnusedFunctionN becomes Function0
* - anything else becomes a NoSymbol
*/
def erasedFunctionClass(cls: Symbol): Symbol = {
val arity = scalaClassName(cls).functionArity
if (arity > 22) FunctionXXLClass
if (cls.name.isUnusedFunction) FunctionClass(0)
else if (arity > 22) FunctionXXLClass
else if (arity >= 0) FunctionClass(arity)
else NoSymbol
}
Expand All @@ -903,12 +932,15 @@ class Definitions {
* - FunctionN for 22 > N >= 0 remains as FunctionN
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
* - UnusedFunctionN becomes Function0
* - ImplicitUnusedFunctionN becomes Function0
* - anything else becomes a NoType
*/
def erasedFunctionType(cls: Symbol): Type = {
val arity = scalaClassName(cls).functionArity
if (arity > 22) defn.FunctionXXLType
else if (arity >= 0) defn.FunctionType(arity)
if (cls.name.isUnusedFunction) FunctionType(0)
else if (arity > 22) FunctionXXLType
else if (arity >= 0) FunctionType(arity)
else NoType
}

Expand Down Expand Up @@ -976,7 +1008,7 @@ class Definitions {
def isNonDepFunctionType(tp: Type)(implicit ctx: Context) = {
val arity = functionArity(tp)
val sym = tp.dealias.typeSymbol
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction).typeSymbol)
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction, sym.name.isUnusedFunction).typeSymbol)
}

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

def isUnusedFunctionType(tp: Type)(implicit ctx: Context) =
isFunctionType(tp) && tp.dealias.typeSymbol.name.isUnusedFunction

// ----- primitive value class machinery ------------------------------------------

/** This class would also be obviated by the implicit function type design */
Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ object Flags {
/** Symbol is a Java enum */
final val Enum = commonFlag(40, "<enum>")

/** Labeled with `unused` modifier (unused value) */
final val Unused = termFlag(42, "unused")

// Flags following this one are not pickled

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

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

/** Flags that can apply to a module class */
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass | Enum
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Mode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,5 @@ object Mode {

/** We are in the IDE */
val Interactive = newMode(20, "Interactive")

}
28 changes: 25 additions & 3 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -174,31 +174,53 @@ object NameOps {
*/
def functionArity: Int =
functionArityFor(str.Function) max {
val n = functionArityFor(str.ImplicitFunction)
val n =
functionArityFor(str.ImplicitFunction) max
functionArityFor(str.UnusedFunction) max
functionArityFor(str.UnusedImplicitFunction)
if (n == 0) -1 else n
}

/** Is a function name
* - FunctionN for N >= 0
* - ImplicitFunctionN for N >= 1
* - UnusedFunctionN for N >= 1
* - UnusedImplicitFunctionN for N >= 1
* - false otherwise
*/
def isFunction: Boolean = functionArity >= 0

/** Is a implicit function name
* - ImplicitFunctionN for N >= 1
* - UnusedImplicitFunctionN for N >= 1
* - false otherwise
*/
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 1
def isImplicitFunction: Boolean = {
functionArityFor(str.ImplicitFunction) >= 1 ||
functionArityFor(str.UnusedImplicitFunction) >= 1
}

/** Is a implicit function name
* - UnusedFunctionN for N >= 1
* - UnusedImplicitFunctionN for N >= 1
* - false otherwise
*/
def isUnusedFunction: Boolean = {
functionArityFor(str.UnusedFunction) >= 1 ||
functionArityFor(str.UnusedImplicitFunction) >= 1
}

/** Is a synthetic function name
* - FunctionN for N > 22
* - ImplicitFunctionN for N >= 1
* - UnusedFunctionN for N >= 1
* - UnusedImplicitFunctionN for N >= 1
* - false otherwise
*/
def isSyntheticFunction: Boolean = {
functionArityFor(str.Function) > MaxImplementedFunctionArity ||
functionArityFor(str.ImplicitFunction) >= 1
functionArityFor(str.ImplicitFunction) >= 1 ||
isUnusedFunction
}

/** Parsed function arity for function with some specific prefix */
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ object StdNames {
final val MODULE_INSTANCE_FIELD = "MODULE$"

final val Function = "Function"
final val UnusedFunction = "UnusedFunction"
final val ImplicitFunction = "ImplicitFunction"
final val UnusedImplicitFunction = "UnusedImplicitFunction"
final val AbstractFunction = "AbstractFunction"
final val Tuple = "Tuple"
final val Product = "Product"
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
def paramErasure(tpToErase: Type) =
erasureFn(tp.isJavaMethod, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
val (names, formals0) =
if (tp.paramInfos.exists(_.isPhantom)) tp.paramNames.zip(tp.paramInfos).filterNot(_._2.isPhantom).unzip
if (tp.isUnusedMethod) (Nil, Nil)
else if (tp.paramInfos.exists(_.isPhantom)) tp.paramNames.zip(tp.paramInfos).filterNot(_._2.isPhantom).unzip
else (tp.paramNames, tp.paramInfos)
val formals = formals0.mapConserve(paramErasure)
eraseResult(tp.resultType) match {
Expand Down

0 comments on commit 8d07271

Please sign in to comment.