diff options
Diffstat (limited to 'src/compiler')
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 |