Skip to content

Commit

Permalink
Fix up DEFAULTPARAM semantics.
Browse files Browse the repository at this point in the history
I foolishly believed the deprecation message on "hasDefaultFlag"
which suggested I use "hasDefault" instead. After lots of head
scratching, I hardened the semantics so it's like this:

  - A method parameter with a default value is PARAM | DEFAULTPARAM
  - A default getter for such a parameter is METHOD | DEFAULTPARAM
  - And "hasDefault" is has(DEFAULTPARAM) && has(PARAM | METHOD)

Why all the bonus logic, why not just hasFlag(DEFAULTPARAM)? For
some reason we have a handful of overloaded flags spanning uses
which someone apparently thinks can never intersect but I have
not been so lucky overall. So since DEFAULTPARAM is overloaded with
TRAIT, unless we think it's fine that default getters and method
parameters with defaults will pose as traits all the time, there
has to be an anchor bit alongside it.
  • Loading branch information
paulp committed Sep 27, 2013
1 parent 0aaf591 commit 693ecff
Show file tree
Hide file tree
Showing 6 changed files with 15 additions and 14 deletions.
4 changes: 1 addition & 3 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1272,9 +1272,7 @@ trait Namers extends MethodSynthesis {
val defRhs = copyUntyped(vparam.rhs)

val defaultTree = atPos(vparam.pos.focus) {
DefDef(
Modifiers(meth.flags & DefaultGetterFlags) | (SYNTHETIC | DEFAULTPARAM | oflag).toLong,
name, deftParams, defvParamss, defTpt, defRhs)
DefDef(Modifiers(paramFlagsToDefaultGetter(meth.flags)) | oflag, name, deftParams, defvParamss, defTpt, defRhs)
}
if (!isConstr)
methOwner.resetFlag(INTERFACE) // there's a concrete member now
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,14 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// those with the DEFAULTPARAM flag, and infer the methods. Looking for the methods
// directly requires inspecting the parameter list of every one. That modification
// shaved 95% off the time spent in this method.
val defaultGetters = defaultClass.info.findMembers(0L, DEFAULTPARAM)
val defaultGetters = defaultClass.info.findMembers(excludedFlags = PARAM, requiredFlags = DEFAULTPARAM)
val defaultMethodNames = defaultGetters map (sym => nme.defaultGetterToMethod(sym.name))

defaultMethodNames.toList.distinct foreach { name =>
val methods = clazz.info.findMember(name, 0L, METHOD, stableOnly = false).alternatives
val methods = clazz.info.findMember(name, 0L, requiredFlags = METHOD, stableOnly = false).alternatives
def hasDefaultParam(tpe: Type): Boolean = tpe match {
case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe)
case _ => false
case _ => false
}
val haveDefaults = methods filter (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name))

Expand Down
13 changes: 9 additions & 4 deletions src/reflect/scala/reflect/internal/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,13 @@ class Flags extends ModifierFlags {
final val GetterFlags = ~(PRESUPER | MUTABLE)
final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR | IMPLICIT)

/** When a symbol for a default getter is created, it inherits these
* flags from the method with the default. Other flags applied at creation
* time are SYNTHETIC, DEFAULTPARAM, and possibly OVERRIDE, and maybe PRESUPER.
/** Since DEFAULTPARAM is overloaded with TRAIT, we need some additional
* means of determining what that bit means. Usually DEFAULTPARAM is coupled
* with PARAM, which suffices. Default getters get METHOD instead.
* This constant is the mask of flags which can survive from the parameter modifiers.
* See paramFlagsToDefaultGetter for the full logic.
*/
final val DefaultGetterFlags = PRIVATE | PROTECTED | FINAL
final val DefaultGetterFlags = PRIVATE | PROTECTED | FINAL | PARAMACCESSOR

/** When a symbol for a method parameter is created, only these flags survive
* from Modifiers. Others which may be applied at creation time are:
Expand Down Expand Up @@ -321,6 +323,9 @@ class Flags extends ModifierFlags {
*/
final val TopLevelPickledFlags = PickledFlags & ~(MODULE | METHOD | PACKAGE | PARAM | EXISTENTIAL)

def paramFlagsToDefaultGetter(paramFlags: Long): Long =
(paramFlags & DefaultGetterFlags) | SYNTHETIC | METHOD | DEFAULTPARAM

def getterFlags(fieldFlags: Long): Long = ACCESSOR + (
if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER
else fieldFlags & ~PRESUPER | STABLE
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/HasFlags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ trait HasFlags {
// identically, testing for a single flag.
def hasAbstractFlag = hasFlag(ABSTRACT)
def hasAccessorFlag = hasFlag(ACCESSOR)
def hasDefault = hasAllFlags(DEFAULTPARAM | PARAM)
def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT
def hasLocalFlag = hasFlag(LOCAL)
def hasModuleFlag = hasFlag(MODULE)
def hasPackageFlag = hasFlag(PACKAGE)
Expand Down
2 changes: 0 additions & 2 deletions src/reflect/scala/reflect/internal/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def isValue = false
def isValueParameter = false
def isVariable = false
override def hasDefault = false
def isTermMacro = false

/** Qualities of MethodSymbols, always false for TypeSymbols
Expand Down Expand Up @@ -2601,7 +2600,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def companionSymbol: Symbol = companionClass
override def moduleClass = if (isModule) referenced else NoSymbol

override def hasDefault = this hasFlag DEFAULTPARAM // overloaded with TRAIT
override def isBridge = this hasFlag BRIDGE
override def isEarlyInitialized = this hasFlag PRESUPER
override def isMethod = this hasFlag METHOD
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/TreeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ abstract class TreeGen extends macros.TreeBuilder {
DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant())))))
}
}
constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus=false))
constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus = false))
// Field definitions for the class - remove defaults.
val fieldDefs = vparamss.flatten map (vd => copyValDef(vd)(mods = vd.mods &~ DEFAULTPARAM, rhs = EmptyTree))

Expand Down

0 comments on commit 693ecff

Please sign in to comment.