summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala13
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala37
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala0
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Adaptations.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala52
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala450
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala57
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala2
22 files changed, 390 insertions, 275 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 819887f959..56ad4738d9 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -86,6 +86,19 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def erasurePhase: Phase = if (currentRun.isDefined) currentRun.erasurePhase else NoPhase
+ /* Override `newStubSymbol` defined in `SymbolTable` to provide us access
+ * to the last tree to typer, whose position is the trigger of stub errors. */
+ override def newStubSymbol(owner: Symbol,
+ name: Name,
+ missingMessage: String): Symbol = {
+ val stubSymbol = super.newStubSymbol(owner, name, missingMessage)
+ val stubErrorPosition = {
+ val lastTreeToTyper = analyzer.lastTreeToTyper
+ if (lastTreeToTyper != EmptyTree) lastTreeToTyper.pos else stubSymbol.pos
+ }
+ stubSymbol.setPos(stubErrorPosition)
+ }
+
// platform specific elements
protected class GlobalPlatform extends {
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index a2c37b59fb..b073cb828c 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -300,7 +300,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
resTp: Type = functionResultType(fun.tpe),
additionalFlags: FlagSet = NoFlags): DefDef = {
val methSym = owner.newMethod(name, fun.pos, FINAL | additionalFlags)
- // for sams, methParamProtos is the parameter symbols for the sam's method, so that we generate the correct override (based on parmeter types)
+ // for sams, methParamProtos is the parameter symbols for the sam's method, so that we generate the correct override (based on parameter types)
val methParamSyms = methParamProtos.map { param => methSym.newSyntheticValueParam(param.tpe, param.name.toTermName) }
methSym setInfo MethodType(methParamSyms, resTp)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 01a083018c..707fe15f91 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -234,7 +234,7 @@ self =>
else currentRun.parsing.incompleteInputError(o2p(offset), msg)
}
- /** parse unit. If there are inbalanced braces,
+ /** parse unit. If there are unbalanced braces,
* try to correct them and reparse.
*/
def smartParse(): Tree = withSmartParsing {
@@ -812,7 +812,7 @@ self =>
false
} else true
- /** Strip the artifitial `Parens` node to create a tuple term Tree. */
+ /** Strip the artificial `Parens` node to create a tuple term Tree. */
def stripParens(t: Tree) = t match {
case Parens(ts) => atPos(t.pos) { makeSafeTupleTerm(ts, t.pos.point) }
case _ => t
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 3ed1570c1c..0618f5d06e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -1254,7 +1254,7 @@ trait Scanners extends ScannersCommon {
class MalformedInput(val offset: Offset, val msg: String) extends Exception
/** A scanner for a given source file not necessarily attached to a compilation unit.
- * Useful for looking inside source files that aren not currently compiled to see what's there
+ * Useful for looking inside source files that are not currently compiled to see what's there
*/
class SourceFileScanner(val source: SourceFile) extends Scanner {
val buf = source.content
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index 92a5cbdd73..40aabb0df1 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -261,8 +261,8 @@ class MutableSettings(val errorFn: String => Unit)
*/
private var singleOutDir: Option[AbstractFile] = None
- /** Add a destination directory for sources found under srcdir.
- * Both directories should exits.
+ /** Add a destination directory for sources found under `srcDir`.
+ * Both directories should exist.
*/
def add(srcDir: String, outDir: String): Unit = // used in ide?
add(checkDir(AbstractFile.getDirectory(srcDir), srcDir),
diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
index d3c7ba4d76..3ac283b9a4 100644
--- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
@@ -52,7 +52,7 @@ abstract class BrowsingLoaders extends GlobalSymbolLoaders {
}
/** Browse the top-level of given abstract file `src` and enter
- * eny encountered top-level classes and modules in `root`
+ * any encountered top-level classes and modules in `root`
*/
def browseTopLevel(root: Symbol, src: AbstractFile) {
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 9129478b41..f146419a73 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -553,6 +553,7 @@ abstract class ClassfileParser {
val name = readName()
val sym = ownerForFlags(jflags).newMethod(name.toTermName, NoPosition, sflags)
var info = pool.getType(sym, u2)
+ var removedOuterParameter = false
if (name == nme.CONSTRUCTOR)
info match {
case MethodType(params, restpe) =>
@@ -567,6 +568,7 @@ abstract class ClassfileParser {
* ClassfileParser for 1 executes, and clazz.owner is the package.
*/
assert(params.head.tpe.typeSymbol == clazz.owner || clazz.owner.hasPackageFlag, params.head.tpe.typeSymbol + ": " + clazz.owner)
+ removedOuterParameter = true
params.tail
case _ =>
params
@@ -586,7 +588,7 @@ abstract class ClassfileParser {
// parsed from SignatureATTR
sym setInfo info
propagatePackageBoundary(jflags, sym)
- parseAttributes(sym, info)
+ parseAttributes(sym, info, removedOuterParameter)
if (jflags.isVarargs)
sym modifyInfo arrayToRepeated
@@ -769,7 +771,7 @@ abstract class ClassfileParser {
GenPolyType(ownTypeParams, tpe)
} // sigToType
- def parseAttributes(sym: Symbol, symtype: Type) {
+ def parseAttributes(sym: Symbol, symtype: Type, removedOuterParameter: Boolean = false) {
def convertTo(c: Constant, pt: Type): Constant = {
if (pt.typeSymbol == BooleanClass && c.tag == IntTag)
Constant(c.value != 0)
@@ -804,16 +806,24 @@ abstract class ClassfileParser {
else devWarning(s"failure to convert $c to $symtype")
case tpnme.MethodParametersATTR =>
def readParamNames(): Unit = {
- import tools.asm.Opcodes.ACC_SYNTHETIC
+ import scala.tools.asm.Opcodes.ACC_SYNTHETIC
val paramCount = u1
var i = 0
+ if (removedOuterParameter && i < paramCount) {
+ in.skip(4)
+ i += 1
+ }
+ var remainingParams = sym.paramss.head // Java only has exactly one parameter list
while (i < paramCount) {
val name = pool.getName(u2)
val access = u2
- if ((access & ACC_SYNTHETIC) != ACC_SYNTHETIC) { // name not synthetic
- val params = sym.paramss.head // Java only has exactly one parameter list
- params(i).name = name.encode
- params(i).resetFlag(SYNTHETIC)
+ if (remainingParams.nonEmpty) {
+ val param = remainingParams.head
+ remainingParams = remainingParams.tail
+ if ((access & ACC_SYNTHETIC) != ACC_SYNTHETIC) { // name not synthetic
+ param.name = name.encode
+ param.resetFlag(SYNTHETIC)
+ }
}
i += 1
}
@@ -1051,8 +1061,11 @@ abstract class ClassfileParser {
val sflags = jflags.toScalaFlags
val owner = ownerForFlags(jflags)
val scope = getScope(jflags)
- def newStub(name: Name) =
- owner.newStubSymbol(name, s"Class file for ${entry.externalName} not found").setFlag(JAVA)
+ def newStub(name: Name) = {
+ val stub = owner.newStubSymbol(name, s"Class file for ${entry.externalName} not found")
+ stub.setPos(owner.pos)
+ stub.setFlag(JAVA)
+ }
val (innerClass, innerModule) = if (file == NoAbstractFile) {
(newStub(name.toTypeName), newStub(name.toTermName))
@@ -1174,7 +1187,11 @@ abstract class ClassfileParser {
if (enclosing == clazz) entry.scope lookup name
else lookupMemberAtTyperPhaseIfPossible(enclosing, name)
}
- def newStub = enclosing.newStubSymbol(name, s"Unable to locate class corresponding to inner class entry for $name in owner ${entry.outerName}")
+ def newStub = {
+ enclosing
+ .newStubSymbol(name, s"Unable to locate class corresponding to inner class entry for $name in owner ${entry.outerName}")
+ .setPos(enclosing.pos)
+ }
member.orElse(newStub)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ /dev/null
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 744b9c8a8e..9e3e8ff455 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -84,7 +84,7 @@ abstract class TailCalls extends Transform {
* </p>
* <p>
* Assumes: `Uncurry` has been run already, and no multiple
- * parameter lists exit.
+ * parameter lists exist.
* </p>
*/
class TailCallElimination(unit: CompilationUnit) extends Transformer {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
index 57de44a038..b1901c04bb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
@@ -80,7 +80,9 @@ trait Adaptations {
context.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(msg), "2.11.0")
}
} else if (settings.warnAdaptedArgs)
- context.warning(t.pos, adaptWarningMessage(s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want."))
+ context.warning(t.pos, adaptWarningMessage(
+ s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want.")
+ )
// return `true` if the adaptation should be kept
!(settings.noAdaptedArgs || (args.isEmpty && settings.future))
diff --git a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
index 9898cfd785..e9cce95096 100644
--- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
@@ -38,7 +38,7 @@ trait AnalyzerPlugins { self: Analyzer =>
* Let analyzer plugins modify the type that has been computed for a tree.
*
* @param tpe The type inferred by the type checker, initially (for first plugin) `tree.tpe`
- * @param typer The yper that type checked `tree`
+ * @param typer The typer that type checked `tree`
* @param tree The type-checked tree
* @param mode Mode that was used for typing `tree`
* @param pt Expected type that was used for typing `tree`
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 0910dca445..3bbc9f3a62 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -376,7 +376,7 @@ trait ContextErrors {
}
issueNormalTypeError(sel, errMsg)
// the error has to be set for the copied tree, otherwise
- // the error remains persistent acros multiple compilations
+ // the error remains persistent across multiple compilations
// and causes problems
//setError(sel)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 67168917e1..c80bdb180b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -437,7 +437,7 @@ trait Contexts { self: Analyzer =>
* Construct a child context. The parent and child will share the report buffer.
* Compare with `makeSilent`, in which the child has a fresh report buffer.
*
- * If `tree` is an `Import`, that import will be avaiable at the head of
+ * If `tree` is an `Import`, that import will be available at the head of
* `Context#imports`.
*/
def make(tree: Tree = tree, owner: Symbol = owner,
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index bee2ae8e99..66ed0902d8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -154,11 +154,6 @@ trait Implicits {
private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]()
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }
- private def isInvalidConversionSource(tpe: Type): Boolean = tpe match {
- case Function1(in, _) => in <:< NullClass.tpe
- case _ => false
- }
-
def resetImplicits() {
implicitsCache.clear()
infoMapCache.clear()
@@ -166,7 +161,7 @@ trait Implicits {
}
/* Map a polytype to one in which all type parameters and argument-dependent types are replaced by wildcards.
- * Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate debruijn index types
+ * Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate de Bruijn index types
* when checking whether `b` is a valid implicit, as we haven't even searched a value for the implicit arg `x`,
* so we have to approximate (otherwise it is excluded a priori).
*/
@@ -255,7 +250,10 @@ trait Implicits {
this.sym == that.sym
case _ => false
}
- override def hashCode = name.## + pre.## + sym.##
+ override def hashCode = {
+ import scala.util.hashing.MurmurHash3._
+ finalizeHash(mix(mix(productSeed, name.##), sym.##), 2)
+ }
override def toString = (
if (tpeCache eq null) name + ": ?"
else name + ": " + tpe
@@ -360,8 +358,8 @@ trait Implicits {
val undetParams = if (isView) Nil else context.outer.undetparams
val wildPt = approximate(pt)
- private val runDefintions = currentRun.runDefinitions
- import runDefintions._
+ private val stableRunDefsForImport = currentRun.runDefinitions
+ import stableRunDefsForImport._
def undet_s = if (undetParams.isEmpty) "" else undetParams.mkString(" inferring ", ", ", "")
def tree_s = typeDebug ptTree tree
@@ -1409,27 +1407,32 @@ trait Implicits {
}
}
if (result.isSuccess && isView) {
- def maybeInvalidConversionError(msg: String) {
+ def maybeInvalidConversionError(msg: String): Boolean = {
// We have to check context.ambiguousErrors even though we are calling "issueAmbiguousError"
// which ostensibly does exactly that before issuing the error. Why? I have no idea. Test is pos/t7690.
// AM: I would guess it's because ambiguous errors will be buffered in silent mode if they are not reported
if (context.ambiguousErrors)
context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg))
+ true
}
pt match {
- case Function1(_, out) =>
- // must inline to avoid capturing result
- def prohibit(sym: Symbol) = (sym.tpe <:< out) && {
- maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
- true
- }
- if (prohibit(AnyRefClass) || (settings.isScala211 && prohibit(AnyValClass)))
- result = SearchFailure
- case _ => false
- }
- if (settings.isScala211 && isInvalidConversionSource(pt)) {
- maybeInvalidConversionError("an expression of type Null is ineligible for implicit conversion")
- result = SearchFailure
+ // SI-10206 don't use subtyping to rule out AnyRef/AnyVal:
+ // - there are several valid structural types that are supertypes of AnyRef (e.g., created by HasMember);
+ // typeSymbol will do the trick (AnyRef is a type alias for Object), while ruling out these structural types
+ // - also don't want to accidentally constrain type vars through using <:<
+ case Function1(in, out) =>
+ val outSym = out.typeSymbol
+
+ val fail =
+ if (out.annotations.isEmpty && (outSym == ObjectClass || (isScala211 && outSym == AnyValClass)))
+ maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than $out")
+ else if (isScala211 && in.annotations.isEmpty && in.typeSymbol == NullClass)
+ maybeInvalidConversionError("an expression of type Null is ineligible for implicit conversion")
+ else false
+
+ if (fail) result = SearchFailure
+
+ case _ =>
}
}
@@ -1439,6 +1442,9 @@ trait Implicits {
result
}
+ // this setting is expensive to check, actually....
+ private[this] val isScala211 = settings.isScala211
+
def allImplicits: List[SearchResult] = {
def search(iss: Infoss, isLocalToCallsite: Boolean) = applicableInfos(iss, isLocalToCallsite).values
(
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index d7c53ed3c4..6de95ab658 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -697,7 +697,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
// foo(Foo(23, "foo", true))
//
// In the snippet above, even though we know that there's a fundep going from T to U
- // (in a sense that a datatype's uniform representation is unambiguously determined by the datatype,
+ // (in a sense that a datatype's uniform representation is unambiguously determined by the data type,
// e.g. for Foo it will be Int :: String :: Boolean :: HNil), there's no way to convey this information
// to the typechecker. Therefore the typechecker will infer Nothing for L, which is hardly what we want.
//
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 0f257d3717..72d186b301 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -146,8 +146,8 @@ trait MethodSynthesis {
// if there's no field symbol, the ValDef tree receives the getter symbol and thus is not a synthetic
if (fieldSym != NoSymbol) {
context.unit.synthetics(getterSym) = getter.derivedTree(getterSym)
- getterSym setInfo namer.accessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = false)
- } else getterSym setInfo namer.valTypeCompleter(tree)
+ getterSym setInfo new namer.AccessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = false)
+ } else getterSym setInfo new namer.ValTypeCompleter(tree)
enterInScope(getterSym)
@@ -155,17 +155,17 @@ trait MethodSynthesis {
val setter = Setter(tree)
val setterSym = setter.createSym
context.unit.synthetics(setterSym) = setter.derivedTree(setterSym)
- setterSym setInfo namer.accessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = true)
+ setterSym setInfo new namer.AccessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = true)
enterInScope(setterSym)
}
// TODO: delay emitting the field to the fields phase (except for private[this] vals, which only get a field and no accessors)
if (fieldSym != NoSymbol) {
- fieldSym setInfo namer.valTypeCompleter(tree)
+ fieldSym setInfo new namer.ValTypeCompleter(tree)
enterInScope(fieldSym)
}
} else {
- getterSym setInfo namer.valTypeCompleter(tree)
+ getterSym setInfo new namer.ValTypeCompleter(tree)
enterInScope(getterSym)
}
@@ -208,11 +208,11 @@ trait MethodSynthesis {
sym
}
- val getterCompleter = namer.accessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = false)
+ val getterCompleter = new namer.AccessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = false)
enterInScope(deriveBeanAccessor(if (hasBeanProperty) "get" else "is") setInfo getterCompleter)
if (tree.mods.isMutable) {
- val setterCompleter = namer.accessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = true)
+ val setterCompleter = new namer.AccessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = true)
enterInScope(deriveBeanAccessor("set") setInfo setterCompleter)
}
}
@@ -221,9 +221,9 @@ trait MethodSynthesis {
def enterImplicitWrapper(classDef: ClassDef): Unit = {
val methDef = factoryMeth(classDef.mods & AccessFlags | METHOD | IMPLICIT | SYNTHETIC, classDef.name.toTermName, classDef)
- val methSym = assignAndEnterSymbol(methDef)
+ val methSym = enterInScope(assignMemberSymbol(methDef))
context.unit.synthetics(methSym) = methDef
- methSym setInfo implicitFactoryMethodCompleter(methDef, classDef.symbol, completerOf(methDef).asInstanceOf[LockingTypeCompleter])
+ methSym setInfo implicitFactoryMethodCompleter(methDef, classDef.symbol)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 28169c9da1..fee56cfc13 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -103,14 +103,10 @@ trait Namers extends MethodSynthesis {
else newNamer(cx)
}
- def enterValueParams(vparamss: List[List[ValDef]]): List[List[Symbol]] = {
+ def enterValueParams(vparamss: List[List[ValDef]]): List[List[Symbol]] =
mmap(vparamss) { param =>
- val sym = assignSymbol(param, param.name, mask = ValueParameterFlags)
- setPrivateWithin(param, sym)
- enterInScope(sym)
- sym setInfo monoTypeCompleter(param)
+ enterInScope(assignMemberSymbol(param, mask = ValueParameterFlags)) setInfo new MonoTypeCompleter(param)
}
- }
protected def owner = context.owner
def contextFile = context.unit.source.file
@@ -286,9 +282,7 @@ trait Namers extends MethodSynthesis {
case tree @ DefDef(_, _, _, _, _, _) => enterDefDef(tree)
case tree @ TypeDef(_, _, _, _) => enterTypeDef(tree)
case DocDef(_, defn) => enterSym(defn)
- case tree @ Import(_, _) =>
- assignSymbol(tree)
- returnContext = context.make(tree)
+ case tree @ Import(_, _) => enterImport(tree); returnContext = context.make(tree)
case _ =>
}
returnContext
@@ -299,25 +293,15 @@ trait Namers extends MethodSynthesis {
}
}
- /** Creates a new symbol and assigns it to the tree, returning the symbol
- */
- def assignSymbol(tree: Tree): Symbol =
- logAssignSymbol(tree, tree match {
- case PackageDef(pid, _) => createPackageSymbol(tree.pos, pid)
- case imp: Import => createImportSymbol(imp)
- case mdef: MemberDef => createMemberSymbol(mdef, mdef.name, -1L)
- case _ => abort("Unexpected tree: " + tree)
- })
- def assignSymbol(tree: MemberDef, name: Name, mask: Long): Symbol =
- logAssignSymbol(tree, createMemberSymbol(tree, name, mask))
-
- def assignAndEnterSymbol(tree: MemberDef): Symbol = {
- val sym = assignSymbol(tree, tree.name, -1L)
+ def assignMemberSymbol(tree: MemberDef, mask: Long = -1L): Symbol = {
+ val sym = createMemberSymbol(tree, tree.name, mask)
setPrivateWithin(tree, sym)
- enterInScope(sym)
+ tree.symbol = sym
+ sym
}
+
def assignAndEnterFinishedSymbol(tree: MemberDef): Symbol = {
- val sym = assignAndEnterSymbol(tree)
+ val sym = enterInScope(assignMemberSymbol(tree))
sym setInfo completerOf(tree)
// log("[+info] " + sym.fullLocationString)
sym
@@ -329,19 +313,6 @@ trait Namers extends MethodSynthesis {
sym
}
- private def logAssignSymbol(tree: Tree, sym: Symbol): Symbol = {
- if (isPastTyper) sym.name.toTermName match {
- case nme.IMPORT | nme.OUTER | nme.ANON_CLASS_NAME | nme.ANON_FUN_NAME | nme.CONSTRUCTOR => ()
- case _ =>
- tree match {
- case md: DefDef => log("[+symbol] " + sym.debugLocationString)
- case _ =>
- }
- }
- tree.symbol = sym
- sym
- }
-
/** Create a new symbol at the context owner based on the given tree.
* A different name can be given. If the modifier flags should not be
* be transferred to the symbol as they are, supply a mask containing
@@ -366,8 +337,10 @@ trait Namers extends MethodSynthesis {
}
}
- def createImportSymbol(tree: Import) =
- NoSymbol.newImport(tree.pos) setInfo (namerOf(tree.symbol) importTypeCompleter tree)
+ def createImportSymbol(tree: Import) = {
+ val importNamer = namerOf(tree.symbol)
+ NoSymbol.newImport(tree.pos) setInfo new importNamer.ImportTypeCompleter(tree)
+ }
/** All PackageClassInfoTypes come from here. */
def createPackageSymbol(pos: Position, pid: RefTree): Symbol = {
@@ -419,7 +392,7 @@ trait Namers extends MethodSynthesis {
clearRenamedCaseAccessors(existing)
existing
}
- else assignAndEnterSymbol(tree) setFlag inConstructorFlag
+ else enterInScope(assignMemberSymbol(tree)) setFlag inConstructorFlag
}
clazz match {
case csym: ClassSymbol if csym.isTopLevel => enterClassSymbol(tree, csym)
@@ -457,7 +430,8 @@ trait Namers extends MethodSynthesis {
def enterModuleDef(tree: ModuleDef) = {
val sym = enterModuleSymbol(tree)
- sym.moduleClass setInfo namerOf(sym).moduleClassTypeCompleter(tree)
+ val mcsNamer = namerOf(sym)
+ sym.moduleClass setInfo new mcsNamer.ModuleClassTypeCompleter(tree)
sym setInfo completerOf(tree)
validateCompanionDefs(tree)
sym
@@ -466,9 +440,10 @@ trait Namers extends MethodSynthesis {
/** Enter a module symbol.
*/
def enterModuleSymbol(tree : ModuleDef): Symbol = {
- var m: Symbol = context.scope lookupModule tree.name
val moduleFlags = tree.mods.flags | MODULE
- if (m.isModule && !m.hasPackageFlag && inCurrentScope(m) && (currentRun.canRedefine(m) || m.isSynthetic)) {
+
+ val existingModule = context.scope lookupModule tree.name
+ if (existingModule.isModule && !existingModule.hasPackageFlag && inCurrentScope(existingModule) && (currentRun.canRedefine(existingModule) || existingModule.isSynthetic)) {
// This code accounts for the way the package objects found in the classpath are opened up
// early by the completer of the package itself. If the `packageobjects` phase then finds
// the same package object in sources, we have to clean the slate and remove package object
@@ -476,21 +451,24 @@ trait Namers extends MethodSynthesis {
//
// TODO SI-4695 Pursue the approach in https://github.com/scala/scala/pull/2789 that avoids
// opening up the package object on the classpath at all if one exists in source.
- if (m.isPackageObject) {
- val packageScope = m.enclosingPackageClass.rawInfo.decls
- packageScope.foreach(mem => if (mem.owner != m.enclosingPackageClass) packageScope unlink mem)
+ if (existingModule.isPackageObject) {
+ val packageScope = existingModule.enclosingPackageClass.rawInfo.decls
+ packageScope.foreach(mem => if (mem.owner != existingModule.enclosingPackageClass) packageScope unlink mem)
}
- updatePosFlags(m, tree.pos, moduleFlags)
- setPrivateWithin(tree, m)
- m.moduleClass andAlso (setPrivateWithin(tree, _))
- context.unit.synthetics -= m
- tree.symbol = m
+ updatePosFlags(existingModule, tree.pos, moduleFlags)
+ setPrivateWithin(tree, existingModule)
+ existingModule.moduleClass andAlso (setPrivateWithin(tree, _))
+ context.unit.synthetics -= existingModule
+ tree.symbol = existingModule
}
else {
- m = assignAndEnterSymbol(tree)
+ enterInScope(assignMemberSymbol(tree))
+ val m = tree.symbol
m.moduleClass setFlag moduleClassFlags(moduleFlags)
setPrivateWithin(tree, m.moduleClass)
}
+
+ val m = tree.symbol
if (m.isTopLevel && !m.hasPackageFlag) {
m.moduleClass.associatedFile = contextFile
currentRun.symSource(m) = m.moduleClass.sourceFile
@@ -613,13 +591,11 @@ trait Namers extends MethodSynthesis {
noDuplicates(selectors map (_.rename), AppearsTwice)
}
- def enterCopyMethod(copyDef: DefDef): Symbol = {
- val sym = copyDef.symbol
- val lazyType = completerOf(copyDef)
-
+ def copyMethodCompleter(copyDef: DefDef): TypeCompleter = {
/* Assign the types of the class parameters to the parameters of the
- * copy method. See comment in `Unapplies.caseClassCopyMeth` */
- def assignParamTypes() {
+ * copy method. See comment in `Unapplies.caseClassCopyMeth`
+ */
+ def assignParamTypes(copyDef: DefDef, sym: Symbol) {
val clazz = sym.owner
val constructorType = clazz.primaryConstructor.tpe
val subst = new SubstSymMap(clazz.typeParams, copyDef.tparams map (_.symbol))
@@ -632,16 +608,84 @@ trait Namers extends MethodSynthesis {
)
}
- sym setInfo {
- mkTypeCompleter(copyDef) { sym =>
- assignParamTypes()
- lazyType complete sym
+ new CompleterWrapper(completerOf(copyDef)) {
+ override def complete(sym: Symbol): Unit = {
+ assignParamTypes(tree.asInstanceOf[DefDef], sym)
+ super.complete(sym)
}
}
}
+ // for apply/unapply, which may need to disappear when they clash with a user-defined method of matching signature
+ def applyUnapplyMethodCompleter(un_applyDef: DefDef, companionContext: Context): TypeCompleter =
+ new CompleterWrapper(completerOf(un_applyDef)) {
+ override def complete(sym: Symbol): Unit = {
+ assert(sym hasAllFlags CASE | SYNTHETIC, sym.defString)
+
+ super.complete(sym)
+
+ // don't propagate e.g. @volatile annot to apply's argument
+ def retainOnlyParamAnnots(param: Symbol) =
+ param setAnnotations (param.annotations filter AnnotationInfo.mkFilter(ParamTargetClass, defaultRetention = false))
+
+ sym.info.paramss.foreach(_.foreach(retainOnlyParamAnnots))
+
+ // owner won't be locked
+ val ownerInfo = companionContext.owner.info
+
+ // If there's a same-named locked symbol, we're currently completing its signature.
+ // If `scopePartiallyCompleted`, the program is known to have a type error, since
+ // this means a user-defined method is missing a result type while its rhs refers to `sym` or an overload.
+ // This is an error because overloaded/recursive methods must have a result type.
+ // The method would be overloaded if its signature, once completed, would not match the synthetic method's,
+ // or recursive if it turned out we should unlink our synthetic method (matching sig).
+ // In any case, error out. We don't unlink the symbol so that `symWasOverloaded` says yes,
+ // which would be wrong if the method is in fact recursive, but it seems less confusing.
+ val scopePartiallyCompleted = new HasMember(ownerInfo, sym.name, BridgeFlags | SYNTHETIC, LOCKED).apply()
+
+ // Check `scopePartiallyCompleted` first to rule out locked symbols from the owner.info.member call,
+ // as FindMember will call info on a locked symbol (while checking type matching to assemble an overloaded type),
+ // and throw a TypeError, so that we are aborted.
+ // Do not consider deferred symbols, as suppressing our concrete implementation would be an error regardless
+ // of whether the signature matches (if it matches, we omitted a valid implementation, if it doesn't,
+ // we would get an error for the missing implementation it isn't implemented by some overload other than our synthetic one)
+ val suppress = scopePartiallyCompleted || {
+ // can't exclude deferred members using DEFERRED flag here (TODO: why?)
+ val userDefined = ownerInfo.memberBasedOnName(sym.name, BridgeFlags | SYNTHETIC)
+
+ (userDefined != NoSymbol) && {
+ assert(userDefined != sym)
+ val alts = userDefined.alternatives // could be just the one, if this member isn't overloaded
+ // don't compute any further `memberInfo`s if there's an error somewhere
+ alts.exists(_.isErroneous) || {
+ val self = companionContext.owner.thisType
+ val memberInfo = self.memberInfo(sym)
+ alts.exists(alt => !alt.isDeferred && (self.memberInfo(alt) matches memberInfo))
+ }
+ }
+ }
+
+ if (suppress) {
+ sym setInfo ErrorType
+ sym setFlag IS_ERROR
+
+ // Don't unlink in an error situation to generate less confusing error messages.
+ // Ideally, our error reporting would distinguish overloaded from recursive user-defined apply methods without signature,
+ // but this would require some form of partial-completion of method signatures, so that we can
+ // know what the argument types were, even though we can't complete the result type, because
+ // we hit a cycle while trying to compute it (when we get here with locked user-defined symbols, we
+ // are in the complete for that symbol, and thus the locked symbol has not yet received enough info;
+ // I hesitate to provide more info, because it would involve a WildCard or something for its result type,
+ // which could upset other code paths)
+ if (!scopePartiallyCompleted)
+ companionContext.scope.unlink(sym)
+ }
+ }
+ }
+
def completerOf(tree: MemberDef): TypeCompleter = {
- val mono = namerOf(tree.symbol) monoTypeCompleter tree
+ val treeNamer = namerOf(tree.symbol)
+ val mono = new treeNamer.MonoTypeCompleter(tree)
val tparams = treeInfo.typeParameters(tree)
if (tparams.isEmpty) mono
else {
@@ -675,25 +719,34 @@ trait Namers extends MethodSynthesis {
}
def enterPackage(tree: PackageDef) {
- val sym = assignSymbol(tree)
+ val sym = createPackageSymbol(tree.pos, tree.pid)
+ tree.symbol = sym
newNamer(context.make(tree, sym.moduleClass, sym.info.decls)) enterSyms tree.stats
}
+
+ private def enterImport(tree: Import) = {
+ val sym = createImportSymbol(tree)
+ tree.symbol = sym
+ }
+
def enterTypeDef(tree: TypeDef) = assignAndEnterFinishedSymbol(tree)
def enterDefDef(tree: DefDef): Unit = tree match {
case DefDef(_, nme.CONSTRUCTOR, _, _, _, _) =>
assignAndEnterFinishedSymbol(tree)
- case DefDef(mods, name, tparams, _, _, _) =>
+ case DefDef(mods, name, _, _, _, _) =>
val bridgeFlag = if (mods hasAnnotationNamed tpnme.bridgeAnnot) BRIDGE | ARTIFACT else 0
- val sym = assignAndEnterSymbol(tree) setFlag bridgeFlag
+ val sym = enterInScope(assignMemberSymbol(tree)) setFlag bridgeFlag
- if (name == nme.copy && sym.isSynthetic)
- enterCopyMethod(tree)
- else if (name == nme.apply && sym.hasAllFlags(SYNTHETIC | CASE))
- sym setInfo caseApplyMethodCompleter(tree, completerOf(tree).asInstanceOf[LockingTypeCompleter])
- else
- sym setInfo completerOf(tree)
- }
+ val completer =
+ if (sym hasFlag SYNTHETIC) {
+ if (name == nme.copy) copyMethodCompleter(tree)
+ else if (sym hasFlag CASE) applyUnapplyMethodCompleter(tree, context)
+ else completerOf(tree)
+ } else completerOf(tree)
+
+ sym setInfo completer
+ }
def enterClassDef(tree: ClassDef) {
val ClassDef(mods, _, _, impl) = tree
@@ -762,125 +815,129 @@ trait Namers extends MethodSynthesis {
NoSymbol
}
- def monoTypeCompleter(tree: MemberDef) = mkTypeCompleter(tree) { sym =>
- // this early test is there to avoid infinite baseTypes when
- // adding setters and getters --> bug798
- // It is a def in an attempt to provide some insulation against
- // uninitialized symbols misleading us. It is not a certainty
- // this accomplishes anything, but performance is a non-consideration
- // on these flag checks so it can't hurt.
- def needsCycleCheck = sym.isNonClassType && !sym.isParameter && !sym.isExistential
-
- val annotations = annotSig(tree.mods.annotations)
+ def monoTypeCompleter(tree: MemberDef) = new MonoTypeCompleter(tree)
+ class MonoTypeCompleter(tree: MemberDef) extends TypeCompleterBase(tree) {
+ override def completeImpl(sym: Symbol): Unit = {
+ // this early test is there to avoid infinite baseTypes when
+ // adding setters and getters --> bug798
+ // It is a def in an attempt to provide some insulation against
+ // uninitialized symbols misleading us. It is not a certainty
+ // this accomplishes anything, but performance is a non-consideration
+ // on these flag checks so it can't hurt.
+ def needsCycleCheck = sym.isNonClassType && !sym.isParameter && !sym.isExistential
+
+ val annotations = annotSig(tree.mods.annotations)
+
+ val tp = typeSig(tree, annotations)
+
+ findCyclicalLowerBound(tp) andAlso { sym =>
+ if (needsCycleCheck) {
+ // neg/t1224: trait C[T] ; trait A { type T >: C[T] <: C[C[T]] }
+ // To avoid an infinite loop on the above, we cannot break all cycles
+ log(s"Reinitializing info of $sym to catch any genuine cycles")
+ sym reset sym.info
+ sym.initialize
+ }
+ }
- val tp = typeSig(tree, annotations)
+ sym.setInfo(if (!sym.isJavaDefined) tp else RestrictJavaArraysMap(tp))
- findCyclicalLowerBound(tp) andAlso { sym =>
if (needsCycleCheck) {
- // neg/t1224: trait C[T] ; trait A { type T >: C[T] <: C[C[T]] }
- // To avoid an infinite loop on the above, we cannot break all cycles
- log(s"Reinitializing info of $sym to catch any genuine cycles")
- sym reset sym.info
- sym.initialize
+ log(s"Needs cycle check: ${sym.debugLocationString}")
+ if (!typer.checkNonCyclic(tree.pos, tp))
+ sym setInfo ErrorType
}
- }
- sym.setInfo(if (!sym.isJavaDefined) tp else RestrictJavaArraysMap(tp))
-
- if (needsCycleCheck) {
- log(s"Needs cycle check: ${sym.debugLocationString}")
- if (!typer.checkNonCyclic(tree.pos, tp))
- sym setInfo ErrorType
+ validate(sym)
}
-
- validate(sym)
}
- def moduleClassTypeCompleter(tree: ModuleDef) = mkTypeCompleter(tree) { sym =>
- val moduleSymbol = tree.symbol
- assert(moduleSymbol.moduleClass == sym, moduleSymbol.moduleClass)
- moduleSymbol.info // sets moduleClass info as a side effect.
+ def moduleClassTypeCompleter(tree: ModuleDef) = new ModuleClassTypeCompleter(tree)
+ class ModuleClassTypeCompleter(tree: ModuleDef) extends TypeCompleterBase(tree) {
+ override def completeImpl(sym: Symbol): Unit = {
+ val moduleSymbol = tree.symbol
+ assert(moduleSymbol.moduleClass == sym, moduleSymbol.moduleClass)
+ moduleSymbol.info // sets moduleClass info as a side effect.
+ }
}
-
- def importTypeCompleter(imp: Import) = mkTypeCompleter(imp) { sym =>
- sym setInfo importSig(imp)
+ def importTypeCompleter(tree: Import) = new ImportTypeCompleter(tree)
+ class ImportTypeCompleter(imp: Import) extends TypeCompleterBase(imp) {
+ override def completeImpl(sym: Symbol): Unit = {
+ sym setInfo importSig(imp)
+ }
}
import AnnotationInfo.{mkFilter => annotationFilter}
- def implicitFactoryMethodCompleter(tree: DefDef, classSym: Symbol, sigCompleter: LockingTypeCompleter) = mkTypeCompleter(tree) { methSym =>
- sigCompleter.completeImpl(methSym)
-
- val annotations = classSym.initialize.annotations
-
- methSym setAnnotations (annotations filter annotationFilter(MethodTargetClass, defaultRetention = false))
- classSym setAnnotations (annotations filter annotationFilter(ClassTargetClass, defaultRetention = true))
- }
-
- def caseApplyMethodCompleter(tree: DefDef, sigCompleter: LockingTypeCompleter) = mkTypeCompleter(tree) { methSym =>
- sigCompleter.completeImpl(methSym)
+ def implicitFactoryMethodCompleter(tree: DefDef, classSym: Symbol) = new CompleterWrapper(completerOf(tree)) {
+ override def complete(methSym: Symbol): Unit = {
+ super.complete(methSym)
+ val annotations = classSym.initialize.annotations
- // don't propagate e.g. @volatile annot to apply's argument
- def retainOnlyParamAnnots(param: Symbol) =
- param setAnnotations (param.annotations filter AnnotationInfo.mkFilter(ParamTargetClass, defaultRetention = false))
-
- methSym.info.paramss.foreach(_.foreach(retainOnlyParamAnnots))
+ methSym setAnnotations (annotations filter annotationFilter(MethodTargetClass, defaultRetention = false))
+ classSym setAnnotations (annotations filter annotationFilter(ClassTargetClass, defaultRetention = true))
+ }
}
// complete the type of a value definition (may have a method symbol, for those valdefs that never receive a field,
// as specified by Field.noFieldFor)
- def valTypeCompleter(tree: ValDef) = mkTypeCompleter(tree) { fieldOrGetterSym =>
- val mods = tree.mods
- val isGetter = fieldOrGetterSym.isMethod
- val annots =
- if (mods.annotations.isEmpty) Nil
- else {
- val annotSigs = annotSig(mods.annotations)
+ def valTypeCompleter(tree: ValDef) = new ValTypeCompleter(tree)
+ class ValTypeCompleter(tree: ValDef) extends TypeCompleterBase(tree) {
+ override def completeImpl(fieldOrGetterSym: Symbol): Unit = {
+ val mods = tree.mods
+ val isGetter = fieldOrGetterSym.isMethod
+ val annots =
+ if (mods.annotations.isEmpty) Nil
+ else {
+ val annotSigs = annotSig(mods.annotations)
if (isGetter) filterAccessorAnnots(annotSigs, tree) // if this is really a getter, retain annots targeting either field/getter
else annotSigs filter annotationFilter(FieldTargetClass, !mods.isParamAccessor)
- }
+ }
- // must use typeSig, not memberSig (TODO: when do we need to switch namers?)
- val sig = typeSig(tree, annots)
+ // must use typeSig, not memberSig (TODO: when do we need to switch namers?)
+ val sig = typeSig(tree, annots)
- fieldOrGetterSym setInfo (if (isGetter) NullaryMethodType(sig) else sig)
+ fieldOrGetterSym setInfo (if (isGetter) NullaryMethodType(sig) else sig)
- validate(fieldOrGetterSym)
+ validate(fieldOrGetterSym)
+ }
}
// knowing `isBean`, we could derive `isSetter` from `valDef.name`
- def accessorTypeCompleter(valDef: ValDef, missingTpt: Boolean, isBean: Boolean, isSetter: Boolean) = mkTypeCompleter(valDef) { accessorSym =>
- context.unit.synthetics get accessorSym match {
- case Some(ddef: DefDef) =>
- // `accessorSym` is the accessor for which we're completing the info (tree == ddef),
- // while `valDef` is the field definition that spawned the accessor
- // NOTE: `valTypeCompleter` handles abstract vals, trait vals and lazy vals, where the ValDef carries the getter's symbol
-
- // reuse work done in valTypeCompleter if we already computed the type signature of the val
- // (assuming the field and accessor symbols are distinct -- i.e., we're not in a trait)
- val valSig =
- if ((accessorSym ne valDef.symbol) && valDef.symbol.isInitialized) valDef.symbol.info
- else typeSig(valDef, Nil) // don't set annotations for the valdef -- we just want to compute the type sig (TODO: dig deeper and see if we can use memberSig)
-
- // patch up the accessor's tree if the valdef's tpt was not known back when the tree was synthesized
- // can't look at `valDef.tpt` here because it may have been completed by now (this is why we pass in `missingTpt`)
- // HACK: a param accessor `ddef.tpt.tpe` somehow gets out of whack with `accessorSym.info`, so always patch it back...
- // (the tpt is typed in the wrong namer, using the class as owner instead of the outer context, which is where param accessors should be typed)
- if (missingTpt || accessorSym.isParamAccessor) {
- if (!isSetter) ddef.tpt setType valSig
- else if (ddef.vparamss.nonEmpty && ddef.vparamss.head.nonEmpty) ddef.vparamss.head.head.tpt setType valSig
- else throw new TypeError(valDef.pos, s"Internal error: could not complete parameter/return type for $ddef from $accessorSym")
- }
+ def accessorTypeCompleter(valDef: ValDef, missingTpt: Boolean, isBean: Boolean, isSetter: Boolean) = new AccessorTypeCompleter(valDef, missingTpt, isBean, isSetter)
+ class AccessorTypeCompleter(valDef: ValDef, missingTpt: Boolean, isBean: Boolean, isSetter: Boolean) extends TypeCompleterBase(valDef) {
+ override def completeImpl(accessorSym: Symbol): Unit = {
+ context.unit.synthetics get accessorSym match {
+ case Some(ddef: DefDef) =>
+ // `accessorSym` is the accessor for which we're completing the info (tree == ddef),
+ // while `valDef` is the field definition that spawned the accessor
+ // NOTE: `valTypeCompleter` handles abstract vals, trait vals and lazy vals, where the ValDef carries the getter's symbol
+
+ // reuse work done in valTypeCompleter if we already computed the type signature of the val
+ // (assuming the field and accessor symbols are distinct -- i.e., we're not in a trait)
+ val valSig =
+ if ((accessorSym ne valDef.symbol) && valDef.symbol.isInitialized) valDef.symbol.info
+ else typeSig(valDef, Nil) // don't set annotations for the valdef -- we just want to compute the type sig (TODO: dig deeper and see if we can use memberSig)
+
+ // patch up the accessor's tree if the valdef's tpt was not known back when the tree was synthesized
+ // can't look at `valDef.tpt` here because it may have been completed by now (this is why we pass in `missingTpt`)
+ // HACK: a param accessor `ddef.tpt.tpe` somehow gets out of whack with `accessorSym.info`, so always patch it back...
+ // (the tpt is typed in the wrong namer, using the class as owner instead of the outer context, which is where param accessors should be typed)
+ if (missingTpt || accessorSym.isParamAccessor) {
+ if (!isSetter) ddef.tpt setType valSig
+ else if (ddef.vparamss.nonEmpty && ddef.vparamss.head.nonEmpty) ddef.vparamss.head.head.tpt setType valSig
+ else throw new TypeError(valDef.pos, s"Internal error: could not complete parameter/return type for $ddef from $accessorSym")
+ }
- val mods = valDef.mods
- val annots =
- if (mods.annotations.isEmpty) Nil
- else filterAccessorAnnots(annotSig(mods.annotations), valDef, isSetter, isBean)
+ val mods = valDef.mods
+ val annots =
+ if (mods.annotations.isEmpty) Nil
+ else filterAccessorAnnots(annotSig(mods.annotations), valDef, isSetter, isBean)
- // for a setter, call memberSig to attribute the parameter (for a bean, we always use the regular method sig completer since they receive method types)
- // for a regular getter, make sure it gets a NullaryMethodType (also, no need to recompute it: we already have the valSig)
- val sig =
+ // for a setter, call memberSig to attribute the parameter (for a bean, we always use the regular method sig completer since they receive method types)
+ // for a regular getter, make sure it gets a NullaryMethodType (also, no need to recompute it: we already have the valSig)
+ val sig =
if (isSetter || isBean) typeSig(ddef, annots)
else {
if (annots.nonEmpty) annotate(accessorSym, annots)
@@ -888,16 +945,17 @@ trait Namers extends MethodSynthesis {
NullaryMethodType(valSig)
}
- accessorSym setInfo pluginsTypeSigAccessor(sig, typer, valDef, accessorSym)
+ accessorSym setInfo pluginsTypeSigAccessor(sig, typer, valDef, accessorSym)
- if (!isBean && accessorSym.isOverloaded)
- if (isSetter) ddef.rhs.setType(ErrorType)
- else GetterDefinedTwiceError(accessorSym)
+ if (!isBean && accessorSym.isOverloaded)
+ if (isSetter) ddef.rhs.setType(ErrorType)
+ else GetterDefinedTwiceError(accessorSym)
- validate(accessorSym)
+ validate(accessorSym)
- case _ =>
- throw new TypeError(valDef.pos, s"Internal error: no synthetic tree found for bean accessor $accessorSym")
+ case _ =>
+ throw new TypeError(valDef.pos, s"Internal error: no synthetic tree found for bean accessor $accessorSym")
+ }
}
}
@@ -942,11 +1000,14 @@ trait Namers extends MethodSynthesis {
}
- def selfTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
- val selftpe = typer.typedType(tree).tpe
- sym setInfo {
- if (selftpe.typeSymbol isNonBottomSubClass sym.owner) selftpe
- else intersectionType(List(sym.owner.tpe, selftpe))
+ def selfTypeCompleter(tree: Tree) = new SelfTypeCompleter(tree)
+ class SelfTypeCompleter(tree: Tree) extends TypeCompleterBase(tree) {
+ override def completeImpl(sym: Symbol): Unit = {
+ val selftpe = typer.typedType(tree).tpe
+ sym setInfo {
+ if (selftpe.typeSymbol isNonBottomSubClass sym.owner) selftpe
+ else intersectionType(List(sym.owner.tpe, selftpe))
+ }
}
}
@@ -1020,7 +1081,7 @@ trait Namers extends MethodSynthesis {
val sym = (
if (hasType || hasName) {
- owner.typeOfThis = if (hasType) selfTypeCompleter(tpt) else owner.tpe_*
+ owner.typeOfThis = if (hasType) new SelfTypeCompleter(tpt) else owner.tpe_*
val selfSym = owner.thisSym setPos self.pos
if (hasName) selfSym setName name else selfSym
}
@@ -1114,7 +1175,7 @@ trait Namers extends MethodSynthesis {
val res = GenPolyType(tparams0, resultType)
val pluginsTp = pluginsTypeSig(res, typer, cdef, WildcardType)
- // Already assign the type to the class symbol (monoTypeCompleter will do it again).
+ // Already assign the type to the class symbol (MonoTypeCompleter will do it again).
// Allows isDerivedValueClass to look at the info.
clazz setInfo pluginsTp
if (clazz.isDerivedValueClass) {
@@ -1128,7 +1189,7 @@ trait Namers extends MethodSynthesis {
private def moduleSig(mdef: ModuleDef): Type = {
val moduleSym = mdef.symbol
- // The info of both the module and the moduleClass symbols need to be assigned. monoTypeCompleter assigns
+ // The info of both the module and the moduleClass symbols need to be assigned. MonoTypeCompleter assigns
// the result of typeSig to the module symbol. The module class info is assigned here as a side-effect.
val result = templateSig(mdef.impl)
val pluginsTp = pluginsTypeSig(result, typer, mdef, WildcardType)
@@ -1348,7 +1409,7 @@ trait Namers extends MethodSynthesis {
// Add a () parameter section if this overrides some method with () parameters
val vparamSymssOrEmptyParamsFromOverride =
- if (overridden != NoSymbol && vparamSymss.isEmpty && overridden.alternatives.exists(_.info.isInstanceOf[MethodType])) ListOfNil // NOTEL must check `.info.isInstanceOf[MethodType]`, not `.isMethod`!
+ if (overridden != NoSymbol && vparamSymss.isEmpty && overridden.alternatives.exists(_.info.isInstanceOf[MethodType])) ListOfNil // NOTE: must check `.info.isInstanceOf[MethodType]`, not `.isMethod`!
else vparamSymss
val methSig = deskolemizedPolySig(vparamSymssOrEmptyParamsFromOverride, resTp)
@@ -1464,7 +1525,7 @@ trait Namers extends MethodSynthesis {
val defTpt =
// don't mess with tpt's of case copy default getters, because assigning something other than TypeTree()
- // will break the carefully orchestrated naming/typing logic that involves enterCopyMethod and caseClassCopyMeth
+ // will break the carefully orchestrated naming/typing logic that involves copyMethodCompleter and caseClassCopyMeth
if (meth.isCaseCopy) TypeTree()
else {
// If the parameter type mentions any type parameter of the method, let the compiler infer the
@@ -1528,7 +1589,7 @@ trait Namers extends MethodSynthesis {
// (a val's name ends in a " ", so can't compare to def)
val overridingSym = if (isGetter) vdef.symbol else vdef.symbol.getterIn(valOwner)
- // We're called from an accessorTypeCompleter, which is completing the info for the accessor's symbol,
+ // We're called from an AccessorTypeCompleter, which is completing the info for the accessor's symbol,
// which may or may not be `vdef.symbol` (see isGetter above)
val overridden = safeNextOverriddenSymbol(overridingSym)
@@ -1671,7 +1732,7 @@ trait Namers extends MethodSynthesis {
}
/**
- * TypeSig is invoked by monoTypeCompleters. It returns the type of a definition which
+ * TypeSig is invoked by MonoTypeCompleters. It returns the type of a definition which
* is then assigned to the corresponding symbol (typeSig itself does not need to assign
* the type to the symbol, but it can if necessary).
*/
@@ -1862,10 +1923,9 @@ trait Namers extends MethodSynthesis {
}
}
- def mkTypeCompleter(t: Tree)(c: Symbol => Unit) = new LockingTypeCompleter with FlagAgnosticCompleter {
- val tree = t
- def completeImpl(sym: Symbol) = c(sym)
- }
+ // NOTE: only meant for monomorphic definitions,
+ // do not use to wrap existing completers (see CompleterWrapper for that)
+ abstract class TypeCompleterBase[T <: Tree](val tree: T) extends LockingTypeCompleter with FlagAgnosticCompleter
trait LockingTypeCompleter extends TypeCompleter {
def completeImpl(sym: Symbol): Unit
@@ -1909,6 +1969,22 @@ trait Namers extends MethodSynthesis {
}
}
+ /**
+ * Wrap an existing completer to do some post/pre-processing of the completed type.
+ *
+ * @param completer
+ */
+ class CompleterWrapper(completer: TypeCompleter) extends TypeCompleter {
+ // override important when completer.isInstanceOf[PolyTypeCompleter]!
+ override val typeParams = completer.typeParams
+
+ val tree = completer.tree
+
+ override def complete(sym: Symbol): Unit = {
+ completer.complete(sym)
+ }
+ }
+
// Can we relax these restrictions? For motivation, see
// test/files/pos/depmet_implicit_oopsla_session_2.scala
// neg/depmet_try_implicit.scala
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index b1e7592b47..86a1d3f2e4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1659,7 +1659,7 @@ abstract class RefChecks extends Transform {
case tp @ ExistentialType(tparams, tpe) =>
existentialParams ++= tparams
case ann: AnnotatedType if ann.hasAnnotation(UncheckedBoundsClass) =>
- // SI-7694 Allow code synthetizers to disable checking of bounds for TypeTrees based on inferred LUBs
+ // SI-7694 Allow code synthesizers to disable checking of bounds for TypeTrees based on inferred LUBs
// which might not conform to the constraints.
skipBounds = true
case tp: TypeRef =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 8b1b2f35c5..57906cfe0a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -315,7 +315,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
* A trait which extends a class and accesses a protected member
* of that class cannot implement the necessary accessor method
* because jvm access restrictions require the call site to be
- * in an actual subclass, and an interface cannot extenda class.
+ * in an actual subclass, and an interface cannot extend a class.
* So, non-trait classes inspect their ancestors for any such situations
* and generate the accessors. See SI-2296.
*
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index a0139937f1..cd1dd18768 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -119,13 +119,13 @@ trait TypeDiagnostics {
*/
final def exampleTuplePattern(names: List[Name]): String = {
val arity = names.length
- val varPatterNames: Option[List[String]] = sequence(names map {
+ val varPatternNames: Option[List[String]] = sequence(names map {
case name if nme.isVariableName(name) => Some(name.decode)
case _ => None
})
def parenthesize(a: String) = s"($a)"
def genericParams = (Seq("param1") ++ (if (arity > 2) Seq("...") else Nil) ++ Seq(s"param$arity"))
- parenthesize(varPatterNames.getOrElse(genericParams).mkString(", "))
+ parenthesize(varPatternNames.getOrElse(genericParams).mkString(", "))
}
def alternatives(tree: Tree): List[Type] = tree.tpe match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b0a8b5d4c6..cd4a883a33 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -904,7 +904,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (meth.isConstructor) cantAdapt
// (4.2) eta-expand method value when function or sam type is expected
else if (isFunctionType(pt) || (!mt.params.isEmpty && samOf(pt).exists)) {
- // SI-9536 `!mt.params.isEmpty &&`: for backwards compatiblity with 2.11,
+ // SI-9536 `!mt.params.isEmpty &&`: for backwards compatibility with 2.11,
// we don't adapt a zero-arg method value to a SAM
// In 2.13, we won't do any eta-expansion for zero-arg method values, but we should deprecate first
@@ -2404,7 +2404,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
for (stat <- block.stats) enterLabelDef(stat)
if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
- // This is very tricky stuff, because we are navigating the Skylla and Charybdis of
+ // This is very tricky stuff, because we are navigating the Scylla and Charybdis of
// anonymous classes and what to return from them here. On the one hand, we cannot admit
// every non-private member of an anonymous class as a part of the structural type of the
// enclosing block. This runs afoul of the restriction that a structural type may not
@@ -2978,7 +2978,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val funPt = normalize(methTyped.tpe) baseType FunctionClass(numVparams)
// println(s"typeUnEtaExpanded $meth : ${methTyped.tpe} --> normalized: $funPt")
- // If we are sure this function type provides all the necesarry info, so that we won't have
+ // If we are sure this function type provides all the necessary info, so that we won't have
// any undetermined argument types, go ahead an recurse below (`typedFunction(fun, mode, ptUnrollingEtaExpansion)`)
// and rest assured we won't end up right back here (and keep recursing)
if (isFunctionType(funPt) && funPt.typeArgs.iterator.take(numVparams).forall(isFullyDefined)) funPt
@@ -3091,7 +3091,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
result
}
- // TODO: adapt to new trait field encoding, figure out why this exaemption is made
+ // TODO: adapt to new trait field encoding, figure out why this exemption is made
// 'accessor' and 'accessed' are so similar it becomes very difficult to
//follow the logic, so I renamed one to something distinct.
def accesses(looker: Symbol, accessed: Symbol) = accessed.isLocalToThis && (
@@ -3099,8 +3099,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
|| (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
)
- def checkNoDoubleDefs: Unit = {
- val scope = if (inBlock) context.scope else context.owner.info.decls
+ def checkNoDoubleDefs(scope: Scope): Unit = {
var e = scope.elems
while ((e ne null) && e.owner == scope) {
var e1 = scope.lookupNextEntry(e)
@@ -3143,8 +3142,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
- def addSynthetics(stats: List[Tree]): List[Tree] = {
- val scope = if (inBlock) context.scope else context.owner.info.decls
+ def addSynthetics(stats: List[Tree], scope: Scope): List[Tree] = {
var newStats = new ListBuffer[Tree]
var moreToAdd = true
while (moreToAdd) {
@@ -3219,11 +3217,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val stats1 = stats mapConserve typedStat
if (phase.erasedTypes) stats1
else {
+ val scope = if (inBlock) context.scope else context.owner.info.decls
+
// As packages are open, it doesn't make sense to check double definitions here. Furthermore,
// it is expensive if the package is large. Instead, such double definitions are checked in `Namers.enterInScope`
if (!context.owner.isPackageClass)
- checkNoDoubleDefs
- addSynthetics(stats1)
+ checkNoDoubleDefs(scope)
+
+ addSynthetics(stats1, scope)
}
}
@@ -3426,29 +3427,29 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// repeat vararg as often as needed, remove by-name
val formals = formalTypes(paramTypes, argslen)
- /* Try packing all arguments into a Tuple and apply `fun`
- * to that. This is the last thing which is tried (after
- * default arguments)
+ /* Try packing all arguments into a Tuple and apply `fun` to that.
+ * This is the last thing which is tried (after default arguments).
*/
- def tryTupleApply: Tree = {
- if (eligibleForTupleConversion(paramTypes, argslen) && !phase.erasedTypes) {
+ def tryTupleApply: Tree =
+ if (phase.erasedTypes || !eligibleForTupleConversion(paramTypes, argslen)) EmptyTree
+ else {
val tupleArgs = List(atPos(tree.pos.makeTransparent)(gen.mkTuple(args)))
// expected one argument, but got 0 or >1 ==> try applying to tuple
// the inner "doTypedApply" does "extractUndetparams" => restore when it fails
val savedUndetparams = context.undetparams
- silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) map { t =>
- // Depending on user options, may warn or error here if
- // a Unit or tuple was inserted.
- val keepTree = (
- !mode.typingExprNotFun // why? introduced in 4e488a60, doc welcome
- || t.symbol == null // ditto
- || checkValidAdaptation(t, args)
- )
- if (keepTree) t else EmptyTree
- } orElse { _ => context.undetparams = savedUndetparams ; EmptyTree }
+ // May warn or error if a Unit or tuple was inserted.
+ def validate(t: Tree): Tree = {
+ // regardless of typer's mode
+ val invalidAdaptation = t.symbol != null && !checkValidAdaptation(t, args)
+ // only bail if we're typing an expression (and not inside another application)
+ if (invalidAdaptation && mode.typingExprNotFun) EmptyTree else t
+ }
+ def reset(errors: Seq[AbsTypeError]): Tree = {
+ context.undetparams = savedUndetparams
+ EmptyTree
+ }
+ silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)).map(validate).orElse(reset)
}
- else EmptyTree
- }
/* Treats an application which uses named or default arguments.
* Also works if names + a vararg used: when names are used, the vararg
@@ -4843,7 +4844,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (!(context.unit.isJava && cls.isClass && !cls.isModuleClass)) NoSymbol else {
val companion = companionSymbolOf(cls, context)
if (!companion.exists) NoSymbol
- else member(gen.mkAttributedRef(pre, companion), name) // assert(res.isStatic, s"inCompanionJavaStatic($pre, $cls, $name) = $res ${res.debugFlagString}")
+ else member(gen.mkAttributedRef(pre, companion), name) // assert(res.isStatic, s"inCompanionForJavaStatic($pre, $cls, $name) = $res ${res.debugFlagString}")
}
/* Attribute a selection where `tree` is `qual.name`.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index f2e9b260b0..c13257f6ec 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -24,7 +24,7 @@ trait Unapplies extends ast.TreeDSL {
private def unapplyParamName = nme.x_0
private def caseMods = Modifiers(SYNTHETIC | CASE)
- // In the typeCompleter (templateSig) of a case class (resp it's module),
+ // In the typeCompleter (templateSig) of a case class (resp its module),
// synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute
// their signatures, the corresponding ClassDef is needed. During naming (in
// `enterClassDef`), the case class ClassDef is added as an attachment to the