From 390ccacfe0caa4c07af6193dec3e172c0fcd7896 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Sat, 30 May 2009 07:36:31 +0000 Subject: Named and default arguments - MethodTypes now have (params: List[Symbol]) - "copy"-methods for case classes - the "copy" object in the compiler is now called "treeCopy" --- src/compiler/scala/tools/ant/Scalac.scala | 12 +- .../scala/tools/nsc/ast/NodePrinters.scala | 1 + .../scala/tools/nsc/ast/TreeBrowsers.scala | 4 +- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 6 +- src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 7 + .../scala/tools/nsc/ast/TreePrinters.scala | 2 +- src/compiler/scala/tools/nsc/ast/Trees.scala | 223 ++++++----- .../scala/tools/nsc/ast/parser/MarkupParsers.scala | 2 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 40 +- .../scala/tools/nsc/ast/parser/Scanners.scala | 2 +- .../tools/nsc/ast/parser/SymbolicXMLBuilder.scala | 2 +- .../tools/nsc/ast/parser/SyntaxAnalyzer.scala | 2 +- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 8 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 2 +- .../scala/tools/nsc/backend/msil/GenMSIL.scala | 23 +- src/compiler/scala/tools/nsc/doc/ModelFrames.scala | 6 +- .../tools/nsc/matching/ParallelMatching.scala | 15 +- .../scala/tools/nsc/matching/PatternNodes.scala | 3 +- .../scala/tools/nsc/matching/TransMatcher.scala | 2 +- .../scala/tools/nsc/symtab/Definitions.scala | 24 +- src/compiler/scala/tools/nsc/symtab/Flags.scala | 1 + .../scala/tools/nsc/symtab/IdeSupport.scala | 4 +- src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 + src/compiler/scala/tools/nsc/symtab/Symbols.scala | 45 ++- src/compiler/scala/tools/nsc/symtab/Types.scala | 132 ++++--- .../nsc/symtab/classfile/ClassfileParser.scala | 50 +-- .../tools/nsc/symtab/classfile/MetaParser.scala | 10 +- .../tools/nsc/symtab/classfile/PickleFormat.scala | 6 +- .../scala/tools/nsc/symtab/classfile/Pickler.scala | 8 +- .../tools/nsc/symtab/classfile/UnPickler.scala | 41 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 72 ++-- .../scala/tools/nsc/transform/AddInterfaces.scala | 16 +- .../scala/tools/nsc/transform/CleanUp.scala | 35 +- .../scala/tools/nsc/transform/Constructors.scala | 12 +- .../scala/tools/nsc/transform/Erasure.scala | 69 ++-- .../scala/tools/nsc/transform/ExplicitOuter.scala | 30 +- .../scala/tools/nsc/transform/Flatten.scala | 3 + .../scala/tools/nsc/transform/LambdaLift.scala | 28 +- .../scala/tools/nsc/transform/LazyVals.scala | 10 +- src/compiler/scala/tools/nsc/transform/Mixin.scala | 25 +- .../scala/tools/nsc/transform/Reifiers.scala | 8 +- .../tools/nsc/transform/SampleTransform.scala | 2 +- .../scala/tools/nsc/transform/TailCalls.scala | 33 +- .../scala/tools/nsc/transform/UnCurry.scala | 45 +-- .../scala/tools/nsc/typechecker/Analyzer.scala | 1 + .../scala/tools/nsc/typechecker/Contexts.scala | 2 + .../scala/tools/nsc/typechecker/DeVirtualize.scala | 28 +- .../scala/tools/nsc/typechecker/EtaExpansion.scala | 12 +- .../scala/tools/nsc/typechecker/Implicits.scala | 2 +- .../scala/tools/nsc/typechecker/Infer.scala | 216 +++++++++-- .../scala/tools/nsc/typechecker/Namers.scala | 295 ++++++++++++--- .../tools/nsc/typechecker/NamesDefaults.scala | 376 +++++++++++++++++++ .../scala/tools/nsc/typechecker/RefChecks.scala | 6 +- .../tools/nsc/typechecker/SuperAccessors.scala | 37 +- .../tools/nsc/typechecker/SyntheticMethods.scala | 69 ++-- .../scala/tools/nsc/typechecker/Typers.scala | 417 +++++++++++++++------ .../scala/tools/nsc/typechecker/Unapplies.scala | 37 +- .../scala/tools/nsc/typechecker/Variances.scala | 4 +- 58 files changed, 1833 insertions(+), 741 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index f5ccf236a1..aaa50cdd08 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -200,7 +200,7 @@ class Scalac extends MatchingTask { /** Sets the origin as a nested src Ant parameter. * @return An origin path to be configured. */ - def createSrc(): Path = createNewPath(origin _, origin = _) + def createSrc(): Path = createNewPath(origin _, p => origin = p) /** Sets the origin as an external reference Ant parameter. * @param input A reference to an origin path. */ @@ -222,7 +222,7 @@ class Scalac extends MatchingTask { compilerPath = setOrAppend(compilerPath, input) } - def createCompilerPath: Path = createNewPath(compilerPath _, compilerPath = _) + def createCompilerPath: Path = createNewPath(compilerPath _, p => compilerPath = p) /** Sets the compilerpathref attribute. Used by Ant. * @param input The value of compilerpathref. */ @@ -232,7 +232,7 @@ class Scalac extends MatchingTask { /** Sets the classpath as a nested classpath Ant parameter. * @return A class path to be configured. */ - def createClasspath(): Path = createNewPath(classpath _, classpath = _) + def createClasspath(): Path = createNewPath(classpath _, p => classpath = p) /** Sets the classpath as an external reference Ant parameter. * @param input A reference to a class path. */ @@ -248,7 +248,7 @@ class Scalac extends MatchingTask { /** Sets the sourcepath as a nested sourcepath Ant parameter. * @return A source path to be configured. */ - def createSourcepath(): Path = createNewPath(sourcepath _, sourcepath = _) + def createSourcepath(): Path = createNewPath(sourcepath _, p => sourcepath = p) /** Sets the sourcepath as an external reference Ant parameter. * @param input A reference to a source path. */ @@ -266,7 +266,7 @@ class Scalac extends MatchingTask { /** Sets the bootclasspath as a nested sourcepath Ant * parameter. * @return A source path to be configured. */ - def createBootclasspath(): Path = createNewPath(bootclasspath _, bootclasspath = _) + def createBootclasspath(): Path = createNewPath(bootclasspath _, p => bootclasspath = p) /** Sets the bootclasspath as an external reference Ant * parameter. @@ -281,7 +281,7 @@ class Scalac extends MatchingTask { /** Sets the extdirs as a nested sourcepath Ant parameter. * @return An extensions path to be configured. */ - def createExtdirs(): Path = createNewPath(extdirs _, extdirs = _) + def createExtdirs(): Path = createNewPath(extdirs _, p => extdirs = p) /** Sets the extdirs as an external reference Ant parameter. * @param input A reference to an extensions path. */ diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 4292cb24a0..c409545527 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -92,6 +92,7 @@ abstract class NodePrinters { if (sym hasFlag CASEACCESSOR ) buf.append(" | CASEACCESSOR") if (sym hasFlag TRAIT ) buf.append(" | TRAIT") + if (sym hasFlag DEFAULTPARAM ) buf.append(" | DEFAULTPARAM") if (sym hasFlag BRIDGE ) buf.append(" | BRIDGE") if (sym hasFlag ACCESSOR ) buf.append(" | ACCESSOR") diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index e278ab3645..e00db368fe 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -650,11 +650,11 @@ abstract class TreeBrowsers { clazz.name.toString() :: ")") ) - case MethodType(paramtypes, result) => + case MethodType(params, result) => Document.group( Document.nest(4, "MethodType(" :/: Document.group("(" :/: - toDocument(paramtypes) :/: + symsToDocument(params) :/: "), ") :/: toDocument(result) :: ")") ) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index a015cd1cd9..0a5df116ac 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -268,12 +268,12 @@ abstract class TreeGen { // def m: T = { if (m$ eq null) m$ = new m$class(...) m$ } // where (...) are eventual outer accessors def mkCachedModuleAccessDef(accessor: Symbol, mvar: Symbol) = - DefDef(accessor, vparamss => mkCached(mvar, newModule(accessor, mvar.tpe))) + DefDef(accessor, mkCached(mvar, newModule(accessor, mvar.tpe))) // def m: T = new tpe(...) // where (...) are eventual outer accessors def mkModuleAccessDef(accessor: Symbol, tpe: Type) = - DefDef(accessor, vparamss => newModule(accessor, tpe)) + DefDef(accessor, newModule(accessor, tpe)) private def newModule(accessor: Symbol, tpe: Type) = New(TypeTree(tpe), @@ -282,7 +282,7 @@ abstract class TreeGen { // def m: T; def mkModuleAccessDcl(accessor: Symbol) = - DefDef(accessor setFlag lateDEFERRED, vparamss => EmptyTree) + DefDef(accessor setFlag lateDEFERRED, EmptyTree) def mkRuntimeCall(meth: Name, args: List[Tree]): Tree = Apply(Select(mkAttributedRef(ScalaRunTimeModule), meth), args) diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 93124d95f3..3d023777f3 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -174,6 +174,13 @@ abstract class TreeInfo { case _ => false } + /** Is tpt a by-name parameter type? */ + def isByNameParamType(tpt: Tree) = tpt match { + case AppliedTypeTree(Select(_, n), _) => n == nme.BYNAME_PARAM_CLASS_NAME.toTypeName + case TypeTree() => tpt.tpe.typeSymbol == definitions.ByNameParamClass + case _ => false + } + /** Is name a left-associative operator? */ def isLeftAssoc(operator: Name): Boolean = operator.length > 0 && operator(operator.length - 1) != ':' diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 6fb1c4e166..2189b449ab 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -72,7 +72,7 @@ abstract class TreePrinters { tree match { case ValDef(mods, name, tp, rhs) => printAnnotations(tree) - print(symName(tree, name)); printOpt(": ", tp) + print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs) case TypeDef(mods, name, tparams, rhs) => print(symName(tree, name)) printTypeParams(tparams); print(rhs) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 97852afe81..eeb910478c 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -41,7 +41,7 @@ trait Trees { val trees: Trees.this.type = Trees.this } with TreeInfo - val copy = new LazyTreeCopier() + val treeCopy = new LazyTreeCopier() // modifiers -------------------------------------------------------- @@ -278,11 +278,11 @@ trait Trees { // ----- auxiliary objects and methods ------------------------------ private lazy val duplicator = new Transformer { - override val copy = new StrictTreeCopier + override val treeCopy = new StrictTreeCopier } private class ShallowDuplicator(orig: Tree) extends Transformer { - override val copy = new StrictTreeCopier + override val treeCopy = new StrictTreeCopier override def transform(tree: Tree) = if (tree eq orig) super.transform(tree) @@ -290,21 +290,6 @@ trait Trees { tree } - private def syntheticParams(owner: Symbol, mtp: Type): List[List[Symbol]] = { - var cnt = 0 - def freshName() = { cnt += 1; newTermName("x$" + cnt) } - def synthetics(mtp: Type): List[List[Symbol]] = mtp match { - case PolyType(_, restp) => - synthetics(restp) - case MethodType(formals, restp) => - (formals map (f => owner.newValueParameter(owner.pos, freshName()).setInfo(f))) :: - synthetics(restp) - case _ => - List() - } - synthetics(mtp) - } - // def nextPhase = if (phase.id > globalPhase.id) phase else phase.next; // ----- tree node alternatives -------------------------------------- @@ -464,12 +449,10 @@ trait Trees { def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef = DefDef(sym, Modifiers(sym.flags), vparamss, rhs) - def DefDef(sym: Symbol, mods: Modifiers, rhs: List[List[Symbol]] => Tree): DefDef = { - val vparamss = syntheticParams(sym, sym.tpe) - DefDef(sym, mods, vparamss map (_.map(ValDef)), rhs(vparamss)) - } + def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef = + DefDef(sym, mods, sym.paramss map (_.map(ValDef)), rhs) - def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = + def DefDef(sym: Symbol, rhs: Tree): DefDef = DefDef(sym, Modifiers(sym.flags), rhs) /** Abstract type, type parameter, or type alias */ @@ -590,16 +573,16 @@ trait Trees { var vparamss1 = vparamss map (vps => vps.map { vd => ValDef( - Modifiers(vd.mods.flags & IMPLICIT | PARAM) withAnnotations vd.mods.annotations, - vd.name, vd.tpt.duplicate, EmptyTree).setOriginal(vd) + Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM) | PARAM) withAnnotations vd.mods.annotations, + vd.name, vd.tpt.duplicate, vd.rhs.duplicate).setOriginal(vd) }) val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef val (lvdefs, gvdefs) = List.unzip { evdefs map { case vdef @ ValDef(mods, name, tpt, rhs) => - (copy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs), - copy.ValDef(vdef, mods, name, TypeTree(), EmptyTree)) + (treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs), + treeCopy.ValDef(vdef, mods, name, TypeTree(), EmptyTree)) } } val constrs = @@ -617,7 +600,11 @@ trait Trees { List( DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(())))) } - Template(parents, self, gvdefs ::: List.flatten(vparamss) ::: constrs ::: etdefs ::: rest) + // remove defaults + val vparamss2 = vparamss map (vps => vps map { vd => + treeCopy.ValDef(vd, vd.mods &~ DEFAULTPARAM, vd.name, vd.tpt, EmptyTree) + }) + Template(parents, self, gvdefs ::: List.flatten(vparamss2) ::: constrs ::: etdefs ::: rest) } /** Block of expressions (semicolon separated expressions) */ @@ -1132,232 +1119,232 @@ trait Trees { new ExistentialTypeTree(tpt, whereClauses).copyAttrs(tree) } - class LazyTreeCopier(copy: TreeCopier) extends TreeCopier { + class LazyTreeCopier(treeCopy: TreeCopier) extends TreeCopier { def this() = this(new StrictTreeCopier) def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = tree match { case t @ ClassDef(mods0, name0, tparams0, impl0) if (mods0 == mods && (name0 == name) && (tparams0 == tparams) && (impl0 == impl)) => t - case _ => copy.ClassDef(tree, mods, name, tparams, impl) + case _ => treeCopy.ClassDef(tree, mods, name, tparams, impl) } def PackageDef(tree: Tree, name: Name, stats: List[Tree]) = tree match { case t @ PackageDef(name0, stats0) if (name0 == name) && (stats0 == stats) => t - case _ => copy.PackageDef(tree, name, stats) + case _ => treeCopy.PackageDef(tree, name, stats) } def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = tree match { case t @ ModuleDef(mods0, name0, impl0) if (mods0 == mods) && (name0 == name) && (impl0 == impl) => t - case _ => copy.ModuleDef(tree, mods, name, impl) + case _ => treeCopy.ModuleDef(tree, mods, name, impl) } def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = tree match { case t @ ValDef(mods0, name0, tpt0, rhs0) if (mods0 == mods) && (name0 == name) && (tpt0 == tpt) && (rhs0 == rhs) => t - case _ => copy.ValDef(tree, mods, name, tpt, rhs) + case _ => treeCopy.ValDef(tree, mods, name, tpt, rhs) } def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = tree match { case t @ DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0) if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (vparamss0 == vparamss) && (tpt0 == tpt) && (rhs == rhs0) => t - case _ => copy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs) + case _ => treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs) } def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) = tree match { case t @ TypeDef(mods0, name0, tparams0, rhs0) if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (rhs0 == rhs) => t - case _ => copy.TypeDef(tree, mods, name, tparams, rhs) + case _ => treeCopy.TypeDef(tree, mods, name, tparams, rhs) } def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = tree match { case t @ LabelDef(name0, params0, rhs0) if (name0 == name) && (params0 == params) && (rhs0 == rhs) => t - case _ => copy.LabelDef(tree, name, params, rhs) + case _ => treeCopy.LabelDef(tree, name, params, rhs) } def Import(tree: Tree, expr: Tree, selectors: List[(Name, Name)]) = tree match { case t @ Import(expr0, selectors0) if (expr0 == expr) && (selectors0 == selectors) => t - case _ => copy.Import(tree, expr, selectors) + case _ => treeCopy.Import(tree, expr, selectors) } def Annotation(tree: Tree, constr: Tree, elements: List[Tree]) = tree match { case t @ Annotation(constr0, elements0) if (constr0 == constr) && (elements0 == elements) => t - case _ => copy.Annotation(tree, constr, elements) + case _ => treeCopy.Annotation(tree, constr, elements) } def DocDef(tree: Tree, comment: String, definition: Tree) = tree match { case t @ DocDef(comment0, definition0) if (comment0 == comment) && (definition0 == definition) => t - case _ => copy.DocDef(tree, comment, definition) + case _ => treeCopy.DocDef(tree, comment, definition) } def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = tree match { case t @ Template(parents0, self0, body0) if (parents0 == parents) && (self0 == self) && (body0 == body) => t - case _ => copy.Template(tree, parents, self, body) + case _ => treeCopy.Template(tree, parents, self, body) } def Block(tree: Tree, stats: List[Tree], expr: Tree) = tree match { case t @ Block(stats0, expr0) if ((stats0 == stats) && (expr0 == expr)) => t - case _ => copy.Block(tree, stats, expr) + case _ => treeCopy.Block(tree, stats, expr) } def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = tree match { case t @ CaseDef(pat0, guard0, body0) if (pat0 == pat) && (guard0 == guard) && (body0 == body) => t - case _ => copy.CaseDef(tree, pat, guard, body) + case _ => treeCopy.CaseDef(tree, pat, guard, body) } def Sequence(tree: Tree, trees: List[Tree]) = tree match { case t @ Sequence(trees0) if trees0 == trees => t - case _ => copy.Sequence(tree, trees) + case _ => treeCopy.Sequence(tree, trees) } def Alternative(tree: Tree, trees: List[Tree]) = tree match { case t @ Alternative(trees0) if trees0 == trees => t - case _ => copy.Alternative(tree, trees) + case _ => treeCopy.Alternative(tree, trees) } def Star(tree: Tree, elem: Tree) = tree match { case t @ Star(elem0) if elem0 == elem => t - case _ => copy.Star(tree, elem) + case _ => treeCopy.Star(tree, elem) } def Bind(tree: Tree, name: Name, body: Tree) = tree match { case t @ Bind(name0, body0) if (name0 == name) && (body0 == body) => t - case _ => copy.Bind(tree, name, body) + case _ => treeCopy.Bind(tree, name, body) } def UnApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { case t @ UnApply(fun0, args0) if (fun0 == fun) && (args0 == args) => t - case _ => copy.UnApply(tree, fun, args) + case _ => treeCopy.UnApply(tree, fun, args) } def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = tree match { case t @ ArrayValue(elemtpt0, trees0) if (elemtpt0 == elemtpt) && (trees0 == trees) => t - case _ => copy.ArrayValue(tree, elemtpt, trees) + case _ => treeCopy.ArrayValue(tree, elemtpt, trees) } def Function(tree: Tree, vparams: List[ValDef], body: Tree) = tree match { case t @ Function(vparams0, body0) if (vparams0 == vparams) && (body0 == body) => t - case _ => copy.Function(tree, vparams, body) + case _ => treeCopy.Function(tree, vparams, body) } def Assign(tree: Tree, lhs: Tree, rhs: Tree) = tree match { case t @ Assign(lhs0, rhs0) if (lhs0 == lhs) && (rhs0 == rhs) => t - case _ => copy.Assign(tree, lhs, rhs) + case _ => treeCopy.Assign(tree, lhs, rhs) } def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match { case t @ If(cond0, thenp0, elsep0) if (cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep) => t - case _ => copy.If(tree, cond, thenp, elsep) + case _ => treeCopy.If(tree, cond, thenp, elsep) } def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = tree match { case t @ Match(selector0, cases0) if (selector0 == selector) && (cases0 == cases) => t - case _ => copy.Match(tree, selector, cases) + case _ => treeCopy.Match(tree, selector, cases) } def Return(tree: Tree, expr: Tree) = tree match { case t @ Return(expr0) if expr0 == expr => t - case _ => copy.Return(tree, expr) + case _ => treeCopy.Return(tree, expr) } def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = tree match { case t @ Try(block0, catches0, finalizer0) if (block0 == block) && (catches0 == catches) && (finalizer0 == finalizer) => t - case _ => copy.Try(tree, block, catches, finalizer) + case _ => treeCopy.Try(tree, block, catches, finalizer) } def Throw(tree: Tree, expr: Tree) = tree match { case t @ Throw(expr0) if expr0 == expr => t - case _ => copy.Throw(tree, expr) + case _ => treeCopy.Throw(tree, expr) } def New(tree: Tree, tpt: Tree) = tree match { case t @ New(tpt0) if tpt0 == tpt => t - case _ => copy.New(tree, tpt) + case _ => treeCopy.New(tree, tpt) } def Typed(tree: Tree, expr: Tree, tpt: Tree) = tree match { case t @ Typed(expr0, tpt0) if (expr0 == expr) && (tpt0 == tpt) => t - case _ => copy.Typed(tree, expr, tpt) + case _ => treeCopy.Typed(tree, expr, tpt) } def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { case t @ TypeApply(fun0, args0) if (fun0 == fun) && (args0 == args) => t - case _ => copy.TypeApply(tree, fun, args) + case _ => treeCopy.TypeApply(tree, fun, args) } def Apply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { case t @ Apply(fun0, args0) if (fun0 == fun) && (args0 == args) => t - case _ => copy.Apply(tree, fun, args) + case _ => treeCopy.Apply(tree, fun, args) } def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = tree match { case t @ ApplyDynamic(qual0, args0) if (qual0 == qual) && (args0 == args) => t - case _ => copy.ApplyDynamic(tree, qual, args) + case _ => treeCopy.ApplyDynamic(tree, qual, args) } def Super(tree: Tree, qual: Name, mix: Name) = tree match { case t @ Super(qual0, mix0) if (qual0 == qual) && (mix0 == mix) => t - case _ => copy.Super(tree, qual, mix) + case _ => treeCopy.Super(tree, qual, mix) } def This(tree: Tree, qual: Name) = tree match { case t @ This(qual0) if qual0 == qual => t - case _ => copy.This(tree, qual) + case _ => treeCopy.This(tree, qual) } def Select(tree: Tree, qualifier: Tree, selector: Name) = tree match { case t @ Select(qualifier0, selector0) if (qualifier0 == qualifier) && (selector0 == selector) => t - case _ => copy.Select(tree, qualifier, selector) + case _ => treeCopy.Select(tree, qualifier, selector) } def Ident(tree: Tree, name: Name) = tree match { case t @ Ident(name0) if name0 == name => t - case _ => copy.Ident(tree, name) + case _ => treeCopy.Ident(tree, name) } def Literal(tree: Tree, value: Constant) = tree match { case t @ Literal(value0) if value0 == value => t - case _ => copy.Literal(tree, value) + case _ => treeCopy.Literal(tree, value) } def TypeTree(tree: Tree) = tree match { case t @ TypeTree() => t - case _ => copy.TypeTree(tree) + case _ => treeCopy.TypeTree(tree) } def Annotated(tree: Tree, annot: Annotation, arg: Tree) = tree match { case t @ Annotated(annot0, arg0) if (annot0==annot) => t - case _ => copy.Annotated(tree, annot, arg) + case _ => treeCopy.Annotated(tree, annot, arg) } def SingletonTypeTree(tree: Tree, ref: Tree) = tree match { case t @ SingletonTypeTree(ref0) if ref0 == ref => t - case _ => copy.SingletonTypeTree(tree, ref) + case _ => treeCopy.SingletonTypeTree(tree, ref) } def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = tree match { case t @ SelectFromTypeTree(qualifier0, selector0) if (qualifier0 == qualifier) && (selector0 == selector) => t - case _ => copy.SelectFromTypeTree(tree, qualifier, selector) + case _ => treeCopy.SelectFromTypeTree(tree, qualifier, selector) } def CompoundTypeTree(tree: Tree, templ: Template) = tree match { case t @ CompoundTypeTree(templ0) if templ0 == templ => t - case _ => copy.CompoundTypeTree(tree, templ) + case _ => treeCopy.CompoundTypeTree(tree, templ) } def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = tree match { case t @ AppliedTypeTree(tpt0, args0) if (tpt0 == tpt) && (args0 == args) => t - case _ => copy.AppliedTypeTree(tree, tpt, args) + case _ => treeCopy.AppliedTypeTree(tree, tpt, args) } def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) = tree match { case t @ TypeBoundsTree(lo0, hi0) if (lo0 == lo) && (hi0 == hi) => t - case _ => copy.TypeBoundsTree(tree, lo, hi) + case _ => treeCopy.TypeBoundsTree(tree, lo, hi) } def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = tree match { case t @ ExistentialTypeTree(tpt0, whereClauses0) if (tpt0 == tpt) && (whereClauses0 == whereClauses) => t - case _ => copy.ExistentialTypeTree(tree, tpt, whereClauses) + case _ => treeCopy.ExistentialTypeTree(tree, tpt, whereClauses) } } abstract class Transformer { - val copy: TreeCopier = new LazyTreeCopier + val treeCopy: TreeCopier = new LazyTreeCopier protected var currentOwner: Symbol = definitions.RootClass protected def currentMethod = currentOwner.enclMethod protected def currentClass = currentOwner.enclClass @@ -1367,107 +1354,107 @@ trait Trees { tree case PackageDef(name, stats) => atOwner(tree.symbol.moduleClass) { - copy.PackageDef(tree, name, transformStats(stats, currentOwner)) + treeCopy.PackageDef(tree, name, transformStats(stats, currentOwner)) } case ClassDef(mods, name, tparams, impl) => atOwner(tree.symbol) { - copy.ClassDef(tree, mods, name, transformTypeDefs(tparams), transformTemplate(impl)) + treeCopy.ClassDef(tree, mods, name, transformTypeDefs(tparams), transformTemplate(impl)) } case ModuleDef(mods, name, impl) => atOwner(tree.symbol.moduleClass) { - copy.ModuleDef(tree, mods, name, transformTemplate(impl)) + treeCopy.ModuleDef(tree, mods, name, transformTemplate(impl)) } case ValDef(mods, name, tpt, rhs) => atOwner(tree.symbol) { - copy.ValDef(tree, mods, name, transform(tpt), transform(rhs)) + treeCopy.ValDef(tree, mods, name, transform(tpt), transform(rhs)) } case DefDef(mods, name, tparams, vparamss, tpt, rhs) => atOwner(tree.symbol) { - copy.DefDef( + treeCopy.DefDef( tree, mods, name, transformTypeDefs(tparams), transformValDefss(vparamss), transform(tpt), transform(rhs)) } case TypeDef(mods, name, tparams, rhs) => atOwner(tree.symbol) { - copy.TypeDef(tree, mods, name, transformTypeDefs(tparams), transform(rhs)) + treeCopy.TypeDef(tree, mods, name, transformTypeDefs(tparams), transform(rhs)) } case LabelDef(name, params, rhs) => - copy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy' + treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy' case Import(expr, selectors) => - copy.Import(tree, transform(expr), selectors) + treeCopy.Import(tree, transform(expr), selectors) case Annotation(constr, elements) => - copy.Annotation(tree, transform(constr), transformTrees(elements)) + treeCopy.Annotation(tree, transform(constr), transformTrees(elements)) case DocDef(comment, definition) => - copy.DocDef(tree, comment, transform(definition)) + treeCopy.DocDef(tree, comment, transform(definition)) case Template(parents, self, body) => - copy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol)) + treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol)) case Block(stats, expr) => - copy.Block(tree, transformStats(stats, currentOwner), transform(expr)) + treeCopy.Block(tree, transformStats(stats, currentOwner), transform(expr)) case CaseDef(pat, guard, body) => - copy.CaseDef(tree, transform(pat), transform(guard), transform(body)) + treeCopy.CaseDef(tree, transform(pat), transform(guard), transform(body)) case Sequence(trees) => - copy.Sequence(tree, transformTrees(trees)) + treeCopy.Sequence(tree, transformTrees(trees)) case Alternative(trees) => - copy.Alternative(tree, transformTrees(trees)) + treeCopy.Alternative(tree, transformTrees(trees)) case Star(elem) => - copy.Star(tree, transform(elem)) + treeCopy.Star(tree, transform(elem)) case Bind(name, body) => - copy.Bind(tree, name, transform(body)) + treeCopy.Bind(tree, name, transform(body)) case UnApply(fun, args) => - copy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala + treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala case ArrayValue(elemtpt, trees) => - copy.ArrayValue(tree, transform(elemtpt), transformTrees(trees)) + treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees)) case Function(vparams, body) => atOwner(tree.symbol) { - copy.Function(tree, transformValDefs(vparams), transform(body)) + treeCopy.Function(tree, transformValDefs(vparams), transform(body)) } case Assign(lhs, rhs) => - copy.Assign(tree, transform(lhs), transform(rhs)) + treeCopy.Assign(tree, transform(lhs), transform(rhs)) case If(cond, thenp, elsep) => - copy.If(tree, transform(cond), transform(thenp), transform(elsep)) + treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep)) case Match(selector, cases) => - copy.Match(tree, transform(selector), transformCaseDefs(cases)) + treeCopy.Match(tree, transform(selector), transformCaseDefs(cases)) case Return(expr) => - copy.Return(tree, transform(expr)) + treeCopy.Return(tree, transform(expr)) case Try(block, catches, finalizer) => - copy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer)) + treeCopy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer)) case Throw(expr) => - copy.Throw(tree, transform(expr)) + treeCopy.Throw(tree, transform(expr)) case New(tpt) => - copy.New(tree, transform(tpt)) + treeCopy.New(tree, transform(tpt)) case Typed(expr, tpt) => - copy.Typed(tree, transform(expr), transform(tpt)) + treeCopy.Typed(tree, transform(expr), transform(tpt)) case TypeApply(fun, args) => - copy.TypeApply(tree, transform(fun), transformTrees(args)) + treeCopy.TypeApply(tree, transform(fun), transformTrees(args)) case Apply(fun, args) => - copy.Apply(tree, transform(fun), transformTrees(args)) + treeCopy.Apply(tree, transform(fun), transformTrees(args)) case ApplyDynamic(qual, args) => - copy.ApplyDynamic(tree, transform(qual), transformTrees(args)) + treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args)) case Super(qual, mix) => - copy.Super(tree, qual, mix) + treeCopy.Super(tree, qual, mix) case This(qual) => - copy.This(tree, qual) + treeCopy.This(tree, qual) case Select(qualifier, selector) => - copy.Select(tree, transform(qualifier), selector) + treeCopy.Select(tree, transform(qualifier), selector) case Ident(name) => - copy.Ident(tree, name) + treeCopy.Ident(tree, name) case Literal(value) => - copy.Literal(tree, value) + treeCopy.Literal(tree, value) case TypeTree() => - copy.TypeTree(tree) + treeCopy.TypeTree(tree) case Annotated(annot, arg) => - copy.Annotated(tree, transform(annot).asInstanceOf[Annotation], transform(arg)) + treeCopy.Annotated(tree, transform(annot).asInstanceOf[Annotation], transform(arg)) case SingletonTypeTree(ref) => - copy.SingletonTypeTree(tree, transform(ref)) + treeCopy.SingletonTypeTree(tree, transform(ref)) case SelectFromTypeTree(qualifier, selector) => - copy.SelectFromTypeTree(tree, transform(qualifier), selector) + treeCopy.SelectFromTypeTree(tree, transform(qualifier), selector) case CompoundTypeTree(templ) => - copy.CompoundTypeTree(tree, transformTemplate(templ)) + treeCopy.CompoundTypeTree(tree, transformTemplate(templ)) case AppliedTypeTree(tpt, args) => - copy.AppliedTypeTree(tree, transform(tpt), transformTrees(args)) + treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args)) case TypeBoundsTree(lo, hi) => - copy.TypeBoundsTree(tree, transform(lo), transform(hi)) + treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi)) case ExistentialTypeTree(tpt, whereClauses) => - copy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses)) + treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses)) case tree : StubTree => tree.symbol = NoSymbol tree.tpe = null diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 3118eb6e6d..a8f6853853 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Burak Emir */ -// $Id: MarkupParsers.scala 17315 2009-03-16 17:46:58Z extempore $ +// $Id: MarkupParsers.scala 17754 2009-05-18 10:54:00Z milessabin $ package scala.tools.nsc.ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index c116b60cee..2c12facda4 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id: Parsers.scala 17415 2009-03-31 13:38:18Z imaier $ +// $Id: Parsers.scala 17756 2009-05-18 14:28:59Z rytz $ //todo: allow infix type patterns @@ -1029,7 +1029,7 @@ self => if (isWildcard(t)) (placeholderParams: @unchecked) match { case (vd @ ValDef(mods, name, _, _)) :: rest => - placeholderParams = copy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest + placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest } // this does not correspond to syntax, but is necessary to // accept closures. We might restrict closures to be between {...} only. @@ -1200,11 +1200,27 @@ self => /** ArgumentExprs ::= `(' [Exprs [`,']] `)' * | [nl] BlockExpr */ - def argumentExprs(): List[Tree] = + def argumentExprs(): List[Tree] = { + // if arg has the form "x$1 => a = x$1" it's treated as "a = x$1" with x$1 + // in placeholderParams. This allows e.g. "val f: Int => Int = foo(a = 1, b = _)" + def convertArg(arg: Tree): Tree = arg match { + case Function( + List(vd @ ValDef(mods, pname1, ptype1, EmptyTree)), + Assign(Ident(aname), rhs)) if (mods hasFlag Flags.SYNTHETIC) => + rhs match { + case Ident(`pname1`) | Typed(Ident(`pname1`), _) => + placeholderParams = vd :: placeholderParams + atPos(arg.pos) { Assign(Ident(aname), Ident(pname1)) } + case _ => arg + } + case _ => arg + } + if (in.token == LBRACE) List(blockExpr()) else - surround(LPAREN, RPAREN)(if (in.token == RPAREN) List() else exprs(), List()) + surround(LPAREN, RPAREN)(if (in.token == RPAREN) List() else (exprs() map convertArg), List()) + } /** BlockExpr ::= `{' (CaseClauses | Block) `}' */ @@ -1611,11 +1627,11 @@ self => /** ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)'] * ParamClause ::= [nl] `(' [Params] ')' * Params ::= Param {`,' Param} - * Param ::= {Annotation} Id [`:' ParamType] + * Param ::= {Annotation} Id [`:' ParamType] [`=' Expr] * ClassParamClauses ::= {ClassParamClause} [[nl] `(' implicit ClassParams `)'] * ClassParamClause ::= [nl] `(' [ClassParams] ')' * ClassParams ::= ClassParam {`,' ClassParam} - * ClassParam ::= {Annotation} [{Modifier} (`val' | `var')] Id [`:' ParamType] + * ClassParam ::= {Annotation} [{Modifier} (`val' | `var')] Id [`:' ParamType] [`=' Expr] */ def paramClauses(owner: Name, implicitViews: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { var implicitmod = 0 @@ -1657,8 +1673,14 @@ self => } paramType() } + val default = + if (in.token == EQUALS) { + in.nextToken() + mods |= Flags.DEFAULTPARAM + expr() + } else EmptyTree atPos(start, if (name == nme.ERROR) start else nameOffset) { - ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, EmptyTree) + ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, default) } } def paramClause(): List[ValDef] = { @@ -2194,9 +2216,9 @@ self => if (in.token == WITH && self.isEmpty) { val earlyDefs: List[Tree] = body flatMap { case vdef @ ValDef(mods, name, tpt, rhs) if !(mods hasFlag Flags.DEFERRED) => - List(copy.ValDef(vdef, mods | Flags.PRESUPER, name, tpt, rhs)) + List(treeCopy.ValDef(vdef, mods | Flags.PRESUPER, name, tpt, rhs)) case tdef @ TypeDef(mods, name, tparams, rhs) => - List(copy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)) + List(treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)) case stat if !stat.isEmpty => syntaxError(stat.pos, "only type definitions and concrete field definitions allowed in early object initialization section", false) List() diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index bd32213837..b15ec75cd7 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id: Scanners.scala 17274 2009-03-10 11:39:04Z michelou $ +// $Id: Scanners.scala 17285 2009-03-11 13:51:56Z rytz $ package scala.tools.nsc.ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index b2c83ae704..27e506b361 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Burak Emir */ -// $Id: SymbolicXMLBuilder.scala 16884 2009-01-09 16:52:09Z cunei $ +// $Id: SymbolicXMLBuilder.scala 17756 2009-05-18 14:28:59Z rytz $ package scala.tools.nsc.ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 3b402bdd36..0c3350aedc 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id: SyntaxAnalyzer.scala 16893 2009-01-13 13:09:22Z cunei $ +// $Id: SyntaxAnalyzer.scala 17080 2009-02-10 17:19:16Z rytz $ package scala.tools.nsc.ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 28cb07b421..728dd99d27 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -47,13 +47,13 @@ abstract class TreeBuilder { }) } case Apply(fn @ Apply(_, _), args) => - copy.Apply(tree, transform(fn), transformTrees(args)) + treeCopy.Apply(tree, transform(fn), transformTrees(args)) case Apply(fn, args) => - copy.Apply(tree, fn, transformTrees(args)) + treeCopy.Apply(tree, fn, transformTrees(args)) case Typed(expr, tpt) => - copy.Typed(tree, transform(expr), tpt) + treeCopy.Typed(tree, transform(expr), tpt) case Bind(name, body) => - copy.Bind(tree, name, transform(body)) + treeCopy.Bind(tree, name, transform(body)) case Sequence(_) | Alternative(_) | Star(_) => super.transform(tree) case _ => diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index b7bdf1de9d..53b3317853 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1707,7 +1707,7 @@ abstract class GenICode extends SubComponent { sym.setInfo(oldLabel.tpe) labels(oldLabel) = sym } - val tree = copy.LabelDef(t, name1, params, transform(rhs)) + val tree = treeCopy.LabelDef(t, name1, params, transform(rhs)) tree.symbol = labels(t.symbol) ctx.labels += (tree.symbol -> (new Label(tree.symbol) setParams(params map (_.symbol)))); diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 39fe0f4733..e9c8680b25 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -1425,10 +1425,11 @@ abstract class GenMSIL extends SubComponent { // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase){ msym.tpe match { - case MethodType(parameterTypes, resultType) - if (parameterTypes.length == 1 && msym.name == nme.view_) => - val isDel = definitions.isCorrespondingDelegate(resultType, parameterTypes(0)) - (isDel, parameterTypes(0), resultType) + case MethodType(params, resultType) + if (params.length == 1 && msym.name == nme.view_) => + val paramType = params(0).tpe + val isDel = definitions.isCorrespondingDelegate(resultType, paramType) + (isDel, paramType, resultType) case _ => (false, null, null) } } @@ -2267,16 +2268,16 @@ abstract class GenMSIL extends SubComponent { // create the static caller method and the delegate object - val (paramTypes, returnType) = delegateType.member(nme.apply).tpe match { + val (params, returnType) = delegateType.member(nme.apply).tpe match { case MethodType(delParams, delReturn) => (delParams, delReturn) case _ => abort("not a delegate type: " + delegateType) } val caller: MethodBuilder = delegateCallers.DefineMethod( "$delegateCaller$$" + nbDelegateCallers, MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static, - msilType(returnType), paramTypes.map(msilType).toArray) - for (i <- 0 until paramTypes.length) - caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) + msilType(returnType), (params map (_.tpe)).map(msilType).toArray) + for (i <- 0 until params.length) + caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) mcode.Emit(OpCodes.Ldnull) mcode.Emit(OpCodes.Ldftn, caller) @@ -2287,9 +2288,9 @@ abstract class GenMSIL extends SubComponent { val functionApply: MethodInfo = getMethod(functionType.member(nme.apply)) val dcode: ILGenerator = caller.GetILGenerator() dcode.Emit(OpCodes.Ldsfld, anonfunField) - for (i <- 0 until paramTypes.length) { + for (i <- 0 until params.length) { loadArg(dcode)(i) - emitBox(dcode, toTypeKind(paramTypes(i))) + emitBox(dcode, toTypeKind(params(i).tpe)) } dcode.Emit(OpCodes.Callvirt, functionApply) emitUnbox(dcode, toTypeKind(returnType)) @@ -2444,7 +2445,7 @@ abstract class GenMSIL extends SubComponent { alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s))) // paramTypes: List[Type], resType: Type - case MethodType(paramTypes, resType) => + case MethodType(params, resType) => mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) case _ => diff --git a/src/compiler/scala/tools/nsc/doc/ModelFrames.scala b/src/compiler/scala/tools/nsc/doc/ModelFrames.scala index bd6c816ea8..5bda711f12 100644 --- a/src/compiler/scala/tools/nsc/doc/ModelFrames.scala +++ b/src/compiler/scala/tools/nsc/doc/ModelFrames.scala @@ -141,10 +141,12 @@ trait ModelFrames extends ModelExtractor { } java.net.URLEncoder.encode(sym.nameString + (sym.tpe match { - case MethodType(paramTypes, _) => + case MethodType(params, _) => + val paramTypes = params map (_.tpe) if (sym hasFlag Flags.JAVA) javaParams(paramTypes) else scalaParams(paramTypes) - case PolyType(_, MethodType(paramTypes, _)) => + case PolyType(_, MethodType(params, _)) => + val paramTypes = params map (_.tpe) if (sym hasFlag Flags.JAVA) javaParams(paramTypes) else scalaParams(paramTypes) case _ => "" diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 15f712413d..b00ea9d68c 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -117,7 +117,7 @@ trait ParallelMatching { final def getAlternativeBranches: List[Tree] = { def get_BIND(pctx: Tree => Tree, p: Tree): List[Tree] = p match { - case b @ Bind(n, p) => get_BIND((x: Tree) => pctx(copy.Bind(b, n, x) setType x.tpe), p) + case b @ Bind(n, p) => get_BIND((x: Tree) => pctx(treeCopy.Bind(b, n, x) setType x.tpe), p) case Alternative(ps) => ps map pctx } get_BIND(x => x, tree) @@ -653,7 +653,7 @@ trait ParallelMatching { } def getAlternativeBranches(p: Tree): List[Tree] = { def get_BIND(pctx:Tree => Tree, p:Tree): List[Tree] = p match { - case b @ Bind(n,p) => get_BIND((x: Tree) => pctx(copy.Bind(b, n, x) setType x.tpe), p) + case b @ Bind(n,p) => get_BIND((x: Tree) => pctx(treeCopy.Bind(b, n, x) setType x.tpe), p) case Alternative(ps) => ps map pctx } get_BIND(x => x, p) @@ -735,15 +735,15 @@ trait ParallelMatching { } if (!isReached(bx)) { // first time this bx is requested // might be bound elsewhere ( see `x @ unapply' ) <-- this comment refers to null check - val (vsyms, argts, vdefs) : (List[Symbol], List[Type], List[Tree]) = unzip3( + val (vsyms, vdefs) : (List[Symbol], List[Tree]) = List.unzip( for (v <- vss(bx) ; substv <- subst(v)) yield - (v, v.tpe, typedValDef(v, substv)) + (v, typedValDef(v, substv)) ) val body = targets(bx) // @bug: typer is not able to digest a body of type Nothing being assigned result type Unit val tpe = if (body.tpe.isNothing) body.tpe else resultType - val label = theOwner.newLabel(body.pos, "body%"+bx) setInfo MethodType(argts, tpe) + val label = theOwner.newLabel(body.pos, "body%"+bx) setInfo MethodType(vsyms, tpe) // TODO - newLabel doesn't get a fresh name, is that okay? or should it be more like this: // val label = theOwner.newLabel(body.pos, cunit.fresh.newName(body.pos, "body%"+bx)) setInfo MethodType(argts, tpe) labels(bx) = label @@ -759,7 +759,7 @@ trait ParallelMatching { val args: List[Ident] = vss(bx).flatMap(subst(_)) val label = labels(bx) val body = targets(bx) - val MethodType(fmls, _) = label.tpe + val fmls = label.tpe.paramTypes // sanity checks if (fmls.length != args.length) { @@ -829,7 +829,8 @@ trait ParallelMatching { // @pre for UnApply_TypeApply: is not right-ignoring (no star pattern) ; no exhaustivity check case UnApply_TypeApply(tptArg, xs) => temp(j) setFlag Flags.TRANS_FLAG makeBind(vs, normalizedListPattern(xs, tptArg.tpe)) - case ua @ UnApply(Apply(fn, _), _) => val MethodType(List(argtpe, _*), _) = fn.tpe + case ua @ UnApply(Apply(fn, _), _) => val MethodType(List(arg, _*), _) = fn.tpe + val argtpe = arg.tpe val npat = if (temp(j).tpe <:< argtpe) ua else Typed(ua, TypeTree(argtpe)) setType argtpe makeBind(vs, npat) setType argtpe diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala index 83fb17c213..3b142affbc 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala @@ -128,7 +128,8 @@ trait PatternNodes { val listType = TypeRef(pre, definitions.ListClass, List(tptArg)) resType = TypeRef(pre, sym , List(tptArg)) - MethodType(List(tptArg, listType), resType) + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy") + MethodType(dummyMethod.newSyntheticValueParams(List(tptArg, listType)), resType) } Apply(TypeTree(consType), List(x,normalizedListPattern(xs,tptArg))) setType resType } diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala index 583adfddff..b7b16fc906 100644 --- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala +++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala @@ -74,7 +74,7 @@ trait TransMatcher { (v, typedValDef(v, ti)) } ) - (tmps, vds, ThrowMatchError(selector.pos, copy.Apply(app, fn, tmps map mkIdent))) + (tmps, vds, ThrowMatchError(selector.pos, treeCopy.Apply(app, fn, tmps map mkIdent))) } // sets temporaries, variable declarations, and the fail tree diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index fdad54ffcb..b28cfc859c 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -128,6 +128,7 @@ trait Definitions { def List_apply = getMember(ListModule, nme.apply) lazy val ArrayClass: Symbol = getClass("scala.Array") def Array_apply = getMember(ArrayClass, nme.apply) + def Array_update = getMember(ArrayClass, nme.update) lazy val ArrayModule: Symbol = getModule("scala.Array") def ArrayModule_apply = getMember(ArrayModule, nme.apply) lazy val SerializableClass: Symbol = getClass(sn.Serializable) @@ -445,13 +446,22 @@ trait Definitions { msym } - private def newMethod(owner: Symbol, name: Name, formals: List[Type], restpe: Type): Symbol = - newMethod(owner, name).setInfo(MethodType(formals, restpe)) - private def newPolyMethod(owner: Symbol, name: Name, tcon: Symbol => Type): Symbol = { + private def newMethod(owner: Symbol, name: Name, formals: List[Type], restpe: Type): Symbol = { + val msym = newMethod(owner, name) + val params = msym.newSyntheticValueParams(formals) + msym.setInfo(MethodType(params, restpe)) + } + + /** tcon receives the type parameter symbol as argument */ + private def newPolyMethod(owner: Symbol, name: Name, tcon: Symbol => Type): Symbol = + newPolyMethodCon(owner, name, tparam => msym => tcon(tparam)) + + /** tcon receives the type parameter symbol and the method symbol as arguments */ + private def newPolyMethodCon(owner: Symbol, name: Name, tcon: Symbol => Symbol => Type): Symbol = { val msym = newMethod(owner, name) val tparam = newTypeParam(msym, 0) - msym.setInfo(PolyType(List(tparam), tcon(tparam))) + msym.setInfo(PolyType(List(tparam), tcon(tparam)(msym))) } private def newParameterlessMethod(owner: Symbol, name: Name, restpe: Type) = @@ -479,7 +489,7 @@ trait Definitions { /** Test whether a method symbol is that of a boxing method. */ def isBox(m: Symbol) = (boxMethod.values contains m) && { m.tpe match { - case MethodType(List(argtpe), _) => (boxMethod get argtpe.typeSymbol) match { + case MethodType(List(arg), _) => (boxMethod get arg.tpe.typeSymbol) match { case Some(`m`) => true case _ => false } @@ -794,9 +804,9 @@ trait Definitions { Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype) setFlag FINAL Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype) setFlag FINAL Object_ne = newMethod(ObjectClass, "ne", anyrefparam, booltype) setFlag FINAL - Object_synchronized = newPolyMethod( + Object_synchronized = newPolyMethodCon( ObjectClass, nme.synchronized_, - tparam => MethodType(List(tparam.typeConstructor), tparam.typeConstructor)) setFlag FINAL + tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL Object_isInstanceOf = newPolyMethod( ObjectClass, "$isInstanceOf", tparam => MethodType(List(), booltype)) setFlag FINAL diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index 654c96a94f..2c7462296a 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -53,6 +53,7 @@ object Flags { final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor) final val TRAIT = 0x02000000 // symbol is a trait + final val DEFAULTPARAM = 0x02000000 // the parameter has a default value final val BRIDGE = 0x04000000 // function is a bridge method. Set by Erasure final val ACCESSOR = 0x08000000 // a value or variable accessor (getter or setter) diff --git a/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala b/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala index e52658baa9..97e883414b 100644 --- a/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala +++ b/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala @@ -259,7 +259,7 @@ trait IdeSupport extends SymbolTable { // added to global, not analyzers. def hasError(infoA : Type) : Boolean = { if (infoA == ErrorType) return true infoA match { - case MethodType(args,ret) => hasError(ret) || args.exists(hasError) + case MethodType(args,ret) => hasError(ret) || infoA.paramTypes.exists(hasError) case PolyType(params,ret) => hasError(ret) case TypeBounds(lo,hi) => hasError(lo) || hasError(hi) case TypeRef(pre,_,args) => hasError(pre) || args.exists(hasError) @@ -638,7 +638,7 @@ trait IdeSupport extends SymbolTable { // added to global, not analyzers. } object lightDuplicator extends Transformer { - override val copy = new StrictTreeCopier + override val treeCopy = new StrictTreeCopier } // make the trees less detailed. override def sanitize(tree : Tree) : Tree = lightDuplicator.transform(tree match { diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index a0b559885a..1dbfb99e95 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -269,6 +269,7 @@ trait StdNames { val forceBoxedArray = newTermName("forceBoxedArray") val checkInitialized = newTermName("checkInitialized") val classOf = newTermName("classOf") + val copy = newTermName("copy") val dottype = newTermName(".type") val drop = newTermName("drop") val elem = newTermName("elem") diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index f9bd2ea831..e0b522f400 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -120,7 +120,6 @@ trait Symbols { */ var privateWithin: Symbol = _ - // Creators ------------------------------------------------------------------- final def newValue(pos: Position, name: Name) = @@ -207,6 +206,28 @@ trait Symbols { final def newTypeParameter(pos: Position, name: Name) = newAbstractType(pos, name).setFlag(PARAM) + /** Synthetic value parameters when parameter symbols are not available + */ + final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[Symbol]] = { + var cnt = 0 + def freshName() = { cnt += 1; newTermName("x$" + cnt) } + def param(tp: Type) = + newValueParameter(owner.pos, freshName()).setFlag(SYNTHETIC).setInfo(tp) + argtypess map (_.map(param)) + } + + /** Synthetic value parameters when parameter symbols are not available. + * Calling this method multiple times will re-use the same parameter names. + */ + final def newSyntheticValueParams(argtypes: List[Type]): List[Symbol] = + newSyntheticValueParamss(List(argtypes)).head + + /** Synthetic value parameter when parameter symbol is not available. + * Calling this method multiple times will re-use the same parameter name. + */ + final def newSyntheticValueParam(argtype: Type): Symbol = + newSyntheticValueParams(List(argtype)).head + /** Type skolems are type parameters ``seen from the inside'' * Given a class C[T] * Then the class has a TypeParameter with name `T' in its typeParams list @@ -790,6 +811,10 @@ trait Symbols { def typeParams: List[Symbol] = if (isMonomorphicType) List() else { rawInfo.load(this); rawInfo.typeParams } + /** The value parameter sections of this symbol. + */ + def paramss: List[List[Symbol]] = info.paramss + def getAttributes(clazz: Symbol): List[AnnotationInfo] = attributes.filter(_.atp.typeSymbol.isNonBottomSubClass(clazz)) @@ -993,6 +1018,13 @@ trait Symbols { */ def alias: Symbol = NoSymbol + /** For parameter symbols: the method computing its default value, NoSymbol + * for all others + */ + def defaultGetter: Symbol = NoSymbol + def defaultGetter_=(getter: Symbol): Unit = + throw new Error("defaultGetter cannot be set for " + this) + /** For a lazy value, it's lazy accessor. NoSymbol for all others */ def lazyAccessor: Symbol = NoSymbol @@ -1402,8 +1434,8 @@ trait Symbols { tp match { case PolyType(tparams, res) => typeParamsString + infoString(res) - case MethodType(pts, res) => - pts.mkString("(", ",", ")") + infoString(res) + case MethodType(params, res) => + params.map(_.defString).mkString("(", ",", ")") + infoString(res) case _ => ": " + tp } @@ -1449,10 +1481,12 @@ trait Symbols { privateWithin = NoSymbol protected var referenced: Symbol = NoSymbol + protected var defGetter: Symbol = NoSymbol def cloneSymbolImpl(owner: Symbol): Symbol = { val clone = new TermSymbol(owner, pos, name) clone.referenced = referenced + clone.defGetter = defGetter clone } @@ -1469,6 +1503,10 @@ trait Symbols { this } + override def defaultGetter = defGetter + override def defaultGetter_=(getter: Symbol): Unit = + defGetter = getter + override def outerSource: Symbol = if (name endsWith nme.OUTER) initialize.referenced else NoSymbol @@ -1769,6 +1807,7 @@ trait Symbols { def cloneSymbolImpl(owner: Symbol): Symbol = throw new Error() } + def cloneSymbols(syms: List[Symbol]): List[Symbol] = { val syms1 = syms map (_.cloneSymbol) for (sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1)) diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 33fdfaf76b..a21dc9b8ac 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -144,6 +144,8 @@ trait Types { override def isVolatile = underlying.isVolatile override def finalResultType = underlying.finalResultType override def paramSectionCount = underlying.paramSectionCount + override def paramss = underlying.paramss + override def params = underlying.params override def paramTypes = underlying.paramTypes override def termSymbol = underlying.termSymbol override def termSymbolDirect = underlying.termSymbolDirect @@ -180,6 +182,8 @@ trait Types { override def resultType(actuals: List[Type]) = maybeRewrap(underlying.resultType(actuals)) override def finalResultType = maybeRewrap(underlying.finalResultType) override def paramSectionCount = 0 + override def paramss: List[List[Symbol]] = List() + override def params: List[Symbol] = List() override def paramTypes: List[Type] = List() override def typeArgs = underlying.typeArgs override def notNull = maybeRewrap(underlying.notNull) @@ -308,6 +312,14 @@ trait Types { * 0 for all other types */ def paramSectionCount: Int = 0 + /** For a method or poly type, a list of its value parameter sections, + * the empty list for all other types */ + def paramss: List[List[Symbol]] = List() + + /** For a method or poly type, its first value parameter section, + * the empty list for all other types */ + def params: List[Symbol] = List() + /** For a method or poly type, the types of its first value parameter section, * the empty list for all other types */ def paramTypes: List[Type] = List() @@ -584,8 +596,8 @@ trait Types { -1 } - /** If this is a polytype, a copy with cloned type parameters owned - * by `owner'. Identity for all other types. + /** If this is a poly- or methodtype, a copy with cloned type / value parameters + * owned by `owner'. Identity for all other types. */ def cloneInfo(owner: Symbol) = this @@ -1608,7 +1620,7 @@ A type's typeSymbol should never be inspected directly. /** A class representing a method type with parameters. */ - case class MethodType(override val paramTypes: List[Type], + case class MethodType(override val params: List[Symbol], override val resultType: Type) extends Type { override val isTrivial: Boolean = paramTypes.forall(_.isTrivial) && resultType.isTrivial @@ -1616,6 +1628,12 @@ A type's typeSymbol should never be inspected directly. //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG override def paramSectionCount: Int = resultType.paramSectionCount + 1 + override def paramss: List[List[Symbol]] = params :: resultType.paramss + + override def paramTypes = params map (_.tpe) + + override def boundSyms = params ::: resultType.boundSyms + override def resultType(actuals: List[Type]) = { val map = new InstantiateDeBruijnMap(actuals) val rawResTpe = map.apply(resultType) @@ -1628,31 +1646,32 @@ A type's typeSymbol should never be inspected directly. override def finalResultType: Type = resultType.finalResultType - protected def paramPrefix = "(" - private def dependentToString(base: Int): String = { val params = for ((pt, n) <- paramTypes.zipWithIndex) yield "x$"+n+":"+pt val res = resultType match { case mt: MethodType => mt.dependentToString(base + params.length) case rt => rt.toString } - params.mkString(paramPrefix, ",", ")")+res + params.mkString("(", ",", ")")+res } override def safeToString: String = if (resultType.isDependent) dependentToString(0) - else paramTypes.mkString(paramPrefix, ",", ")") + resultType + else params.map(_.defString).mkString("(", ",", ")") + resultType + + override def cloneInfo(owner: Symbol) = { + val vparams = cloneSymbols(params, owner) + copyMethodType(this, vparams, resultType.substSym(params, vparams).cloneInfo(owner)) + } override def kind = "MethodType" } - // Lukas: check whether we can eliminate this in favor of implicit flags on parameters + // todo: this class is no longer needed, a method type is implicit if the first + // parameter has the IMPLICIT flag + class ImplicitMethodType(ps: List[Symbol], rt: Type) extends MethodType(ps, rt) - class ImplicitMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt) { - override protected def paramPrefix = "(implicit " - } - - class JavaMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt) + class JavaMethodType(ps: List[Symbol], rt: Type) extends MethodType(ps, rt) /** A class representing a polymorphic type or, if tparams.length == 0, * a parameterless method type. @@ -1667,12 +1686,14 @@ A type's typeSymbol should never be inspected directly. extends Type { override def paramSectionCount: Int = resultType.paramSectionCount + override def paramss: List[List[Symbol]] = resultType.paramss + override def params: List[Symbol] = resultType.params override def paramTypes: List[Type] = resultType.paramTypes override def parents: List[Type] = resultType.parents override def decls: Scope = resultType.decls override def termSymbol: Symbol = resultType.termSymbol override def typeSymbol: Symbol = resultType.typeSymbol - override def boundSyms: List[Symbol] = typeParams + override def boundSyms: List[Symbol] = typeParams ::: resultType.boundSyms override def prefix: Type = resultType.prefix override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth @@ -1698,7 +1719,7 @@ A type's typeSymbol should never be inspected directly. override def cloneInfo(owner: Symbol) = { val tparams = cloneSymbols(typeParams, owner) - PolyType(tparams, resultType.substSym(typeParams, tparams)) + PolyType(tparams, resultType.substSym(typeParams, tparams).cloneInfo(owner)) } override def kind = "PolyType" @@ -1938,6 +1959,14 @@ A type's typeSymbol should never be inspected directly. override def kind = "AnnotatedType" } + /** A class representing types with a name. When an application uses + * named arguments, the named argument types for calling isApplicable + * are represented as NamedType. + */ + case class NamedType(name: Name, tp: Type) extends Type { + override def safeToString: String = name.toString +": "+ tp + } + /** A class representing an as-yet unevaluated type. */ abstract class LazyType extends Type { @@ -2113,12 +2142,19 @@ A type's typeSymbol should never be inspected directly. } /** The canonical creator for implicit method types */ - def ImplicitMethodType(paramTypes: List[Type], resultType: Type): ImplicitMethodType = - new ImplicitMethodType(paramTypes, resultType) // don't unique this! + def ImplicitMethodType(params: List[Symbol], resultType: Type): ImplicitMethodType = + new ImplicitMethodType(params, resultType) // don't unique this! /** The canonical creator for implicit method types */ - def JavaMethodType(paramTypes: List[Type], resultType: Type): JavaMethodType = - new JavaMethodType(paramTypes, resultType) // don't unique this! + def JavaMethodType(params: List[Symbol], resultType: Type): JavaMethodType = + new JavaMethodType(params, resultType) // don't unique this! + + /** Create a new MethodType of the same class as tp, i.e. keep Java / ImplicitMethodType */ + def copyMethodType(tp: Type, params: List[Symbol], restpe: Type): Type = tp match { + case _: ImplicitMethodType => ImplicitMethodType(params, restpe) + case _: JavaMethodType => JavaMethodType(params, restpe) + case _ => MethodType(params, restpe) + } /** A creator for intersection type where intersections of a single type are * replaced by the type itself, and repeated parent classes are merged. @@ -2409,13 +2445,14 @@ A type's typeSymbol should never be inspected directly. if ((parents1 eq parents) && (decls1 eq decls)) tp else cloneDecls(ClassInfoType(parents1, new Scope(), clazz), tp, decls1) */ - case MethodType(paramtypes, result) => + case MethodType(params, result) => variance = -variance - val paramtypes1 = List.mapConserve(paramtypes)(this) + val params1 = mapOver(params) variance = -variance val result1 = this(result) - if ((paramtypes1 eq paramtypes) && (result1 eq result)) tp - else copyMethodType(tp, paramtypes1, result1) + if ((params1 eq params) && (result1 eq result)) tp + // for new dependent types: result1.substSym(params, params1)? + else copyMethodType(tp, params1, result1.substSym(params, params1)) case PolyType(tparams, result) => variance = -variance val tparams1 = mapOver(tparams) @@ -2577,12 +2614,6 @@ A type's typeSymbol should never be inspected directly. tree1.shallowDuplicate.setType(tpe1) } } - - protected def copyMethodType(tp: Type, formals: List[Type], restpe: Type): Type = tp match { - case _: ImplicitMethodType => ImplicitMethodType(formals, restpe) - case _: JavaMethodType => JavaMethodType(formals, restpe) - case _ => MethodType(formals, restpe) - } } /** A type map that always returns the input type unchanged */ @@ -2804,10 +2835,13 @@ A type's typeSymbol should never be inspected directly. else if (matches(from.head, sym)) toType(tp, to.head) else subst(tp, sym, from.tail, to.tail) - private def renameBoundSyms(tp: Type) = tp match { + private def renameBoundSyms(tp: Type): Type = tp match { + case MethodType(ps, restp) => + val ps1 = cloneSymbols(ps) + copyMethodType(tp, ps1, renameBoundSyms(restp.substSym(ps, ps1))) case PolyType(bs, restp) => val bs1 = cloneSymbols(bs) - PolyType(bs1, restp.substSym(bs, bs1)) + PolyType(bs1, renameBoundSyms(restp.substSym(bs, bs1))) case ExistentialType(bs, restp) => val bs1 = cloneSymbols(bs) ExistentialType(bs1, restp.substSym(bs, bs1)) @@ -3182,7 +3216,8 @@ A type's typeSymbol should never be inspected directly. sym } else { var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true)(NoSymbol) - if (rebind0 == NoSymbol) { assert(false, ""+pre+"."+sym+" does no longer exist, phase = "+phase) } + if (rebind0 == NoSymbol) { + assert(false, ""+pre+"."+sym+" does no longer exist, phase = "+phase) } /** The two symbols have the same fully qualified name */ def corresponds(sym1: Symbol, sym2: Symbol): Boolean = sym1.name == sym2.name && (sym1.isPackageClass || corresponds(sym1.owner, sym2.owner)) @@ -3224,6 +3259,10 @@ A type's typeSymbol should never be inspected directly. if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) tp else typeRef(pre1, sym1, args1) } + case MethodType(params, restp) => + val restp1 = this(restp) + if (restp1 eq restp) tp + else copyMethodType(tp, params, restp1) case PolyType(tparams, restp) => val restp1 = this(restp) if (restp1 eq restp) tp @@ -3245,7 +3284,6 @@ A type's typeSymbol should never be inspected directly. else refinedType(parents1, tp.typeSymbol.owner, decls, tp.typeSymbol.owner.pos) case SuperType(_, _) => mapOver(tp) case TypeBounds(_, _) => mapOver(tp) - case MethodType(_, _) => mapOver(tp) case TypeVar(_, _) => mapOver(tp) case AnnotatedType(_,_,_) => mapOver(tp) case NotNullType(_) => mapOver(tp) @@ -3509,9 +3547,9 @@ A type's typeSymbol should never be inspected directly. } //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG isSameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1) - case (MethodType(pts1, res1), MethodType(pts2, res2)) => - (pts1.length == pts2.length && - isSameTypes(pts1, pts2) && + case (MethodType(params1, res1), MethodType(params2, res2)) => + // new dependent types: probably fix this, use substSym as done for PolyType + (isSameTypes(tp1.paramTypes, tp2.paramTypes) && res1 =:= res2 && tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType]) case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => @@ -3674,9 +3712,9 @@ A type's typeSymbol should never be inspected directly. val tp2n = normalizePlus(tp2) ((tp1n ne tp1) || (tp2n ne tp2)) && isSubType(tp1n, tp2n, depth) }) - case (MethodType(pts1, res1), MethodType(pts2, res2)) => - (pts1.length == pts2.length && - matchingParams(pts1, pts2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && + case (MethodType(params1, res1), MethodType(params2, res2)) => + (params1.length == params2.length && + matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && (res1 <:< res2) && tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType]) case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => @@ -3793,8 +3831,8 @@ A type's typeSymbol should never be inspected directly. tparams1.length == tparams2.length && matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) (tp1, tp2) match { - case (MethodType(pts1, res1), MethodType(pts2, res2)) => - matchingParams(pts1, pts2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && + case (MethodType(params1, res1), MethodType(params2, res2)) => + matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && matchesType(res1, res2, alwaysMatchSimple) && tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType] case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => @@ -4047,8 +4085,8 @@ A type's typeSymbol should never be inspected directly. List.map2(tparams, List.transpose(matchingBounds(ts, tparams))) ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds, depth))), lub0(matchingInstTypes(ts, tparams))) - case ts @ MethodType(pts, _) :: rest => - MethodType(pts, lub0(matchingRestypes(ts, pts))) + case ts @ MethodType(params, _) :: rest => + MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe)))) case ts @ TypeBounds(_, _) :: rest => mkTypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth)) case ts0 => @@ -4074,7 +4112,7 @@ A type's typeSymbol should never be inspected directly. val symtypes = (List.map2(narrowts, syms) ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType))); - if (proto.isTerm) + if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class proto.cloneSymbol(lubRefined.typeSymbol).setInfo(lub(symtypes, decr(depth))) else if (symtypes.tail forall (symtypes.head =:=)) proto.cloneSymbol(lubRefined.typeSymbol).setInfo(symtypes.head) @@ -4148,8 +4186,8 @@ A type's typeSymbol should never be inspected directly. List.map2(tparams, List.transpose(matchingBounds(ts, tparams))) ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth))), glb0(matchingInstTypes(ts, tparams))) - case ts @ MethodType(pts, _) :: rest => - MethodType(pts, glb0(matchingRestypes(ts, pts))) + case ts @ MethodType(params, _) :: rest => + MethodType(params, glb0(matchingRestypes(ts, params map (_.tpe)))) case ts @ TypeBounds(_, _) :: rest => mkTypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth)) case ts0 => @@ -4361,7 +4399,7 @@ A type's typeSymbol should never be inspected directly. */ private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] = tps map { - case MethodType(pts1, res) if (isSameTypes(pts1, pts)) => + case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) => res case _ => throw new NoCommonType(tps) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 110bf32a46..9df9dc77f9 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -255,9 +255,9 @@ abstract class ClassfileParser { var tpe = getType(in.getChar(start + 3)) if (name == nme.CONSTRUCTOR) tpe match { - case MethodType(formals, restpe) => + case MethodType(params, restpe) => assert(restpe.typeSymbol == definitions.UnitClass) - tpe = MethodType(formals, ownerTpe) + tpe = MethodType(params, ownerTpe) } p = (name, tpe) @@ -295,8 +295,10 @@ abstract class ClassfileParser { c } - def getType(index: Int): Type = - sigToType(null, getExternalName(index)) + def getType(index: Int): Type = getType(null, index) + + def getType(sym: Symbol, index: Int): Type = + sigToType(sym, getExternalName(index)) def getSuperClass(index: Int): Symbol = if (index == 0) definitions.AnyClass else getClassSymbol(index) @@ -431,10 +433,10 @@ abstract class ClassfileParser { if (isAnnotation) { val value = instanceDefs.lookup(nme.value) if (value != NoSymbol) { - instanceDefs.enter( - clazz.newConstructor(NoPosition) + val constr = clazz.newConstructor(NoPosition) + instanceDefs.enter(constr .setFlag(clazz.flags & ConstrFlags) - .setInfo(MethodType(List(value.tpe.resultType), clazz.tpe))) + .setInfo(MethodType(constr.newSyntheticValueParams(List(value.tpe.resultType)), clazz.tpe))) } } } @@ -488,23 +490,22 @@ abstract class ClassfileParser { in.skip(4); skipAttributes() } else { val name = pool.getName(in.nextChar) - var info = pool.getType(in.nextChar) + val sym = getOwner(jflags).newMethod(NoPosition, name).setFlag(sflags) + var info = pool.getType(sym, (in.nextChar)) if (name == nme.CONSTRUCTOR) info match { - case MethodType(formals, restpe) => - assert(restpe.typeSymbol == definitions.UnitClass) + case MethodType(params, restpe) => // if this is a non-static inner class, remove the explicit outer parameter - val newFormals = innerClasses.get(externalName) match { + val newParams = innerClasses.get(externalName) match { case Some(entry) if !isScalaRaw && (entry.jflags & JAVA_ACC_STATIC) == 0 => - assert(formals.head.typeSymbol == clazz.owner, formals.head.typeSymbol + ": " + clazz.owner) - formals.tail + assert(params.head.tpe.typeSymbol == clazz.owner, params.head.tpe.typeSymbol + ": " + clazz.owner) + params.tail case _ => - formals + params } - info = MethodType(newFormals, clazz.tpe) + info = MethodType(newParams, clazz.tpe) } - val sym = getOwner(jflags) - .newMethod(NoPosition, name).setFlag(sflags).setInfo(info) + sym.setInfo(info) setPrivateWithin(sym, jflags) parseAttributes(sym, info) if ((jflags & JAVA_ACC_VARARGS) != 0) { @@ -518,12 +519,13 @@ abstract class ClassfileParser { /** Convert repeated parameters to arrays if they occur as part of a Java method */ private def arrayToRepeated(tp: Type): Type = tp match { - case MethodType(formals, rtpe) => + case MethodType(params, rtpe) => + val formals = tp.paramTypes assert(formals.last.typeSymbol == definitions.ArrayClass) - MethodType( - formals.init ::: - List(appliedType(definitions.RepeatedParamClass.typeConstructor, List(formals.last.typeArgs.head))), - rtpe) + val method = params.last.owner + val newParams = method.newSyntheticValueParams(formals.init ::: + List(appliedType(definitions.RepeatedParamClass.typeConstructor, List(formals.last.typeArgs.head)))) + MethodType(newParams, rtpe) case PolyType(tparams, rtpe) => PolyType(tparams, arrayToRepeated(rtpe)) } @@ -619,6 +621,8 @@ abstract class ClassfileParser { while ('0' <= sig(index) && sig(index) <= '9') index += 1 appliedType(definitions.ArrayClass.tpe, List(sig2type(tparams, skiptvs))) case '(' => + // we need a method symbol. given in line 486 by calling getType(methodSym, ..) + assert(sym ne null) val paramtypes = new ListBuffer[Type]() while (sig(index) != ')') { paramtypes += objToAny(sig2type(tparams, skiptvs)) @@ -629,7 +633,7 @@ abstract class ClassfileParser { clazz.tpe } else sig2type(tparams, skiptvs) - JavaMethodType(paramtypes.toList, restype) + JavaMethodType(sym.newSyntheticValueParams(paramtypes.toList), restype) case 'T' => val n = subName(';'.==).toTypeName index += 1 diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala index c52cc236fe..905a473a96 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala @@ -134,7 +134,10 @@ abstract class MetaParser{ def parse(): Type = { nextToken(); if (token == "[") PolyType(parseTypeParams(), parse()) - else if (token == "(") MethodType(parseParams(), parse()) + else if (token == "(") { + val formals = parseParams() + MethodType(owner.newSyntheticValueParams(formals), parse()) + } else parseType() } owner.setInfo(parse()) @@ -151,7 +154,10 @@ abstract class MetaParser{ protected def parseConstr() { def parse(): Type = { nextToken() - if (token == "(") MethodType(parseParams(), parse()) + if (token == "(") { + val formals = parseParams() + MethodType(owner.newSyntheticValueParams(formals), parse()) + } else owner.owner.tpe } owner.setInfo(parse()) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala index 28accffa02..799c19c53f 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala @@ -26,7 +26,8 @@ object PickleFormat { * | 5 ALIASsym len_Nat SymbolInfo * | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref] * | 7 MODULEsym len_Nat SymbolInfo - * | 8 VALsym len_Nat SymbolInfo [alias_Ref] + * | 8 VALsym len_Nat SymbolInfo [alias_Ref] // old VALsym, unPickling supported (checkin if minor version < 2) ** @LUC TODO remove + * | 8 VALsym len_Nat [defaultGetter_Ref] SymbolInfo [alias_Ref] * | 9 EXTref len_Nat name_Ref [owner_Ref] * | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref] * | 11 NOtpe len_Nat @@ -38,7 +39,8 @@ object PickleFormat { * | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref * | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref} * | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref} - * | 20 METHODtpe len_Nat tpe_Ref {tpe_Ref} + * | 20 METHODtpe len_Nat tpe_Ref {tpe_Ref} // old method type, unPickling still supported ** @LUC TODO remove + * | 20 METHODtpe len_Nat tpe_Ref {sym_Ref} // new method type * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref} * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {tpe_Ref} * | 24 LITERALunit len_Nat diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 052fe1647e..b82417c4a3 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -133,6 +133,7 @@ abstract class Pickler extends SubComponent { if (sym.thisSym.tpeHK != sym.tpeHK) putType(sym.typeOfThis); putSymbol(sym.alias) + putSymbol(sym.defaultGetter) if (!sym.children.isEmpty) { val (locals, globals) = sym.children.toList.partition(_.isLocalClass) val children = @@ -183,8 +184,8 @@ abstract class Pickler extends SubComponent { putSymbol(rclazz); putTypes(parents); putSymbols(decls.toList) case ClassInfoType(parents, decls, clazz) => putSymbol(clazz); putTypes(parents); putSymbols(decls.toList) - case MethodType(formals, restpe) => - putType(restpe); putTypes(formals) + case MethodType(params, restpe) => + putType(restpe); putSymbols(params) case PolyType(tparams, restpe) => putType(restpe); putSymbols(tparams) case ExistentialType(tparams, restpe) => @@ -522,6 +523,8 @@ abstract class Pickler extends SubComponent { val posOffset = writeSymInfo(sym) (if (sym.isAbstractType) TYPEsym else ALIASsym) + posOffset case sym: TermSymbol => + if (!sym.isModule && sym.defaultGetter != NoSymbol) + writeRef(sym.defaultGetter) val posOffset = writeSymInfo(sym) if (sym.alias != NoSymbol) writeRef(sym.alias) (if (sym.isModule) MODULEsym else VALsym) + posOffset @@ -1004,6 +1007,7 @@ abstract class Pickler extends SubComponent { case sym: TermSymbol => print(if (sym.isModule) "MODULEsym " else "VALsym ") printSymInfo(sym) + if (!sym.isModule) printRef(sym.defaultGetter) if (sym.alias != NoSymbol) printRef(sym.alias) case NoType => print("NOtpe") diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala index 1e368b9664..3db8b4ea6f 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala @@ -197,7 +197,13 @@ abstract class UnPickler { if (tag > PosOffset) readNat else -1 } - val name = readNameRef() + var defaultGetter: Symbol = NoSymbol + var nameref = readNat() + if (tag == VALsym && isSymbolRef(nameref)) { + defaultGetter = at(nameref, readSymbol) + nameref = readNat() + } + val name = at(nameref, readName) val owner = readSymbolRef() val flags = pickledToRawFlags(readLongNat()) var privateWithin: Symbol = NoSymbol @@ -234,6 +240,7 @@ abstract class UnPickler { case VALsym => sym = if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot.resetFlag(MODULE) else owner.newValue(NoPosition, name) + sym.defaultGetter = defaultGetter case _ => errorBadSignature("bad symbol tag: " + tag) } @@ -288,10 +295,38 @@ abstract class UnPickler { ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz) case METHODtpe => val restpe = readTypeRef() - MethodType(until(end, readTypeRef), restpe) + + // compatibility with old format. TODO replace by "until(end, readSymbolRef)" + val params = if (readIndex == end) List[Symbol]() + else { + val index = readNat() + if (isSymbolRef(index)) + at(index, readSymbol) :: until(end, readSymbolRef) + else { + val formals = at(index, readType) :: until(end, readTypeRef) + // @LUC TODO the owner should be the method symbol, and newSyntheticValueParams + // should only be called once, not separately for each parameter list + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "unPickler$dummy") + dummyMethod.newSyntheticValueParams(formals) + } + } + MethodType(params, restpe) case IMPLICITMETHODtpe => val restpe = readTypeRef() - ImplicitMethodType(until(end, readTypeRef), restpe) + val params = if (readIndex == end) List[Symbol]() + else { + val index = readNat() + if (isSymbolRef(index)) + at(index, readSymbol) :: until(end, readSymbolRef) + else { + val formals = until(end, readTypeRef) + // @LUC TODO the owner should be the method symbol, and newSyntheticValueParams + // should only be called once, not separately for each parameter list + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "unPickler$dummy") + dummyMethod.newSyntheticValueParams(formals) + } + } + ImplicitMethodType(params, restpe) case POLYtpe => val restpe = readTypeRef() PolyType(until(end, readSymbolRef), restpe) diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 81b2df32ee..d6f3b37328 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -159,10 +159,11 @@ abstract class TypeParser { gparamsLength = gparams.length; val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; val flags = translateAttributes(getter); - val mtype: Type = if (gparamsLength == 0) PolyType(List(), propType) - else methodType(getter, getter.ReturnType); val owner: Symbol = if (getter.IsStatic) statics else clazz; - val methodSym = owner.newMethod(NoPosition, name).setFlag(flags).setInfo(mtype); + val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) + val mtype: Type = if (gparamsLength == 0) PolyType(List(), propType) + else methodType(getter, getter.ReturnType)(methodSym) + methodSym.setInfo(mtype); methodSym.setFlag(Flags.ACCESSOR); (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) clrTypes.methods(methodSym) = getter; @@ -181,9 +182,10 @@ abstract class TypeParser { val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) else nme.update; val flags = translateAttributes(setter); - val mtype: Type = methodType(setter, definitions.UnitClass.tpe); + val mtype = methodType(setter, definitions.UnitClass.tpe); val owner: Symbol = if (setter.IsStatic) statics else clazz; - val methodSym = owner.newMethod(NoPosition, name).setFlag(flags).setInfo(mtype); + val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) + methodSym.setInfo(mtype(methodSym)) methodSym.setFlag(Flags.ACCESSOR); (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); clrTypes.methods(methodSym) = setter; @@ -234,13 +236,13 @@ abstract class TypeParser { // create the box/unbox methods for value types if (typ.IsValueType) { - val box = statics.newMethod(NoPosition, nme.box). - setInfo(MethodType(List(clazz.tpe), definitions.ObjectClass.tpe)); - definitions.boxMethod(clazz) = box; - val unbox = statics.newMethod(NoPosition, nme.unbox). - setInfo(MethodType(List(definitions.ObjectClass.tpe), clazz.tpe)); - definitions.unboxMethod(clazz) = unbox; - //Console.println(typ.FullName + " : " + parents); + val box = statics.newMethod(NoPosition, nme.box) + box.setInfo(MethodType(box.newSyntheticValueParams(List(clazz.tpe)), definitions.ObjectClass.tpe)) + definitions.boxMethod(clazz) = box + val unbox = statics.newMethod(NoPosition, nme.unbox) + unbox.setInfo(MethodType(unbox.newSyntheticValueParams(List(definitions.ObjectClass.tpe)), clazz.tpe)) + definitions.unboxMethod(clazz) = unbox + //Console.println(typ.FullName + " : " + parents) } // for enumerations introduce comparison and bitwise logical operations; @@ -253,17 +255,17 @@ abstract class TypeParser { val flags = Flags.JAVA | Flags.FINAL for (cmpName <- ENUM_CMP_NAMES) { - val enumCmpType: Type = JavaMethodType(List(clazz.tpe), definitions.BooleanClass.tpe); - val enumCmp: Symbol = clazz.newMethod(NoPosition, cmpName); - enumCmp.setFlag(flags).setInfo(enumCmpType) - instanceDefs.enter(enumCmp); + val enumCmp = clazz.newMethod(NoPosition, cmpName) + val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe) + enumCmp.setFlag(flags).setInfo(enumCmpType) + instanceDefs.enter(enumCmp) } for (bitLogName <- ENUM_BIT_LOG_NAMES) { - val enumBitLogType = JavaMethodType(List(clazz.tpe), classInfo); - val enumBitLog = clazz.newMethod(NoPosition, bitLogName); - enumBitLog.setFlag(flags).setInfo(enumBitLogType); - instanceDefs.enter(enumBitLog); + val enumBitLog = clazz.newMethod(NoPosition, bitLogName) + val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), classInfo) + enumBitLog.setFlag(flags).setInfo(enumBitLogType) + instanceDefs.enter(enumBitLog) } } @@ -277,8 +279,8 @@ abstract class TypeParser { if (mtype == null) return; val flags = translateAttributes(method); val owner = if (method.IsStatic()) statics else clazz; - val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags). - setInfo(mtype); + val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags) + methodSym.setInfo(mtype(methodSym)) (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym); if (method.IsConstructor()) clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo] @@ -286,17 +288,17 @@ abstract class TypeParser { } private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = { - val mtype: Type = methodType(args, getCLSType(retType)); - assert(mtype != null); + val mtype = methodType(args, getCLSType(retType)) + assert(mtype != null) createMethod(name, flags, mtype, method, statik) } - private def createMethod(name: Name, flags: Long, mtype: Type, method: MethodInfo, statik: Boolean): Symbol = { - val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name); - methodSym.setFlag(flags).setInfo(mtype); - (if (statik) staticDefs else instanceDefs).enter(methodSym); + private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = { + val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name) + methodSym.setFlag(flags).setInfo(mtype(methodSym)) + (if (statik) staticDefs else instanceDefs).enter(methodSym) if (method != null) - clrTypes.methods(methodSym) = method; + clrTypes.methods(methodSym) = method methodSym } @@ -312,12 +314,12 @@ abstract class TypeParser { // create the forward view: delegate => function val delegateParamTypes: List[Type] = List(typClrType); // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods) - val forwardViewMethodType = JavaMethodType(delegateParamTypes, funType); + val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType) val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true); // create the backward view: function => delegate val functionParamTypes: List[Type] = List(funType); - val backwardViewMethodType = JavaMethodType(functionParamTypes, typClrType); + val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType) val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true); } @@ -350,23 +352,23 @@ abstract class TypeParser { //########################################################################## - private def methodType(method: MethodBase, rettype: MSILType): Type = { + private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = { val rtype = getCLSType(rettype); if (rtype == null) null else methodType(method, rtype); } /** Return a method type for the given method. */ - private def methodType(method: MethodBase, rettype: Type): Type = + private def methodType(method: MethodBase, rettype: Type): Symbol => Type = methodType(method.GetParameters().map(_.ParameterType), rettype); /** Return a method type for the provided argument types and return type. */ - private def methodType(argtypes: Array[MSILType], rettype: Type): Type = { + private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = method => { def paramType(typ: MSILType): Type = if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe else getCLSType(typ); val ptypes = argtypes.map(paramType).toList; if (ptypes.contains(null)) null - else JavaMethodType(ptypes, rettype); + else JavaMethodType(method.newSyntheticValueParams(ptypes), rettype); } //########################################################################## diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 16821e874f..f009f69f4a 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -225,11 +225,11 @@ abstract class AddInterfaces extends InfoTransform { private def ifaceMemberDef(tree: Tree): Tree = if (!tree.isDef || !isInterfaceMember(tree.symbol)) EmptyTree - else if (needsImplMethod(tree.symbol)) DefDef(tree.symbol, vparamss => EmptyTree) + else if (needsImplMethod(tree.symbol)) DefDef(tree.symbol, EmptyTree) else tree private def ifaceTemplate(templ: Template): Template = - copy.Template(templ, templ.parents, emptyValDef, templ.body map ifaceMemberDef) + treeCopy.Template(templ, templ.parents, emptyValDef, templ.body map ifaceMemberDef) private def implMethodDef(tree: Tree, ifaceMethod: Symbol): Tree = implMethodMap.get(ifaceMethod) match { @@ -251,7 +251,7 @@ abstract class AddInterfaces extends InfoTransform { */ private def addMixinConstructorDef(clazz: Symbol, stats: List[Tree]): List[Tree] = if (treeInfo.firstConstructor(stats) != EmptyTree) stats - else DefDef(clazz.primaryConstructor, vparamss => Block(List(), Literal(()))) :: stats + else DefDef(clazz.primaryConstructor, Block(List(), Literal(()))) :: stats private def implTemplate(clazz: Symbol, templ: Template): Template = atPos(templ.pos) { val templ1 = atPos(templ.pos) { @@ -296,7 +296,7 @@ abstract class AddInterfaces extends InfoTransform { case Block(stats, expr) => val (presuper, supercall :: rest) = stats span (_.symbol.hasFlag(PRESUPER)) //assert(supercall.symbol.isClassConstructor, supercall) - copy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) + treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) } } @@ -309,14 +309,14 @@ abstract class AddInterfaces extends InfoTransform { val tree1 = tree match { case ClassDef(mods, name, tparams, impl) if (sym.needsImplClass) => implClass(sym).initialize // to force lateDEFERRED flags - copy.ClassDef(tree, mods | INTERFACE, name, tparams, ifaceTemplate(impl)) + treeCopy.ClassDef(tree, mods | INTERFACE, name, tparams, ifaceTemplate(impl)) case DefDef(mods, name, tparams, vparamss, tpt, rhs) if (sym.isClassConstructor && sym.isPrimaryConstructor && sym.owner != ArrayClass) => - copy.DefDef(tree, mods, name, tparams, vparamss, tpt, + treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, addMixinConstructorCalls(rhs, sym.owner)) // (3) case Template(parents, self, body) => val parents1 = sym.owner.info.parents map (t => TypeTree(t) setPos tree.pos) - copy.Template(tree, parents1, emptyValDef, body) + treeCopy.Template(tree, parents1, emptyValDef, body) case This(_) => if (sym.needsImplClass) { val impl = implClass(sym) @@ -338,7 +338,7 @@ abstract class AddInterfaces extends InfoTransform { else mix } if (sym.needsImplClass) Super(implClass(sym), mix1) setPos tree.pos - else copy.Super(tree, qual, mix1) + else treeCopy.Super(tree, qual, mix1) */ case _ => tree diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index d99518c6cf..fd3257333c 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -69,11 +69,10 @@ abstract class CleanUp extends Transform { val mdef = localTyper.typed { atPos(pos) { - DefDef(meth, vparamss => - gen.mkCached( - cvar, - Apply( - gen.mkAttributedRef(forName), List(Literal(sig))))) + DefDef(meth, gen.mkCached( + cvar, + Apply( + gen.mkAttributedRef(forName), List(Literal(sig))))) } } @@ -155,12 +154,12 @@ abstract class CleanUp extends Transform { (forBody: Pair[Symbol, List[Symbol]] => Tree): Symbol = { val methSym = currentClass.newMethod(ad.pos, unit.fresh.newName(ad.pos, forName)) .setFlag(STATIC | SYNTHETIC) - .setInfo(MethodType(forArgsTypes, forResultType)) + methSym.setInfo(MethodType(methSym.newSyntheticValueParams(forArgsTypes), forResultType)) currentClass.info.decls.enter(methSym) val methDef = localTyper.typed { atPos(ad.pos) { - DefDef(methSym, { vparamss => forBody(Pair(methSym, vparamss(0))) }) + DefDef(methSym, { forBody(Pair(methSym, methSym.paramss(0))) }) } } newDefs.append(transform(methDef)) @@ -593,12 +592,12 @@ abstract class CleanUp extends Transform { ValDef(tmpVar, transform(qual))), If(Apply(Select(gen.mkAttributedRef(cachedClass), nme.EQ), List(getClass(Ident(tmpVar)))), Block(List(Assign(gen.mkAttributedRef(cachedClass), getClass(Ident(tmpVar)))), - copy.ApplyDynamic(ad, Ident(tmpVar), transformTrees(params))), + treeCopy.ApplyDynamic(ad, Ident(tmpVar), transformTrees(params))), EmptyTree))) } //println(guardCallSite) */ - localTyper.typed(copy.ApplyDynamic(ad, transform(qual), transformTrees(params))) + localTyper.typed(treeCopy.ApplyDynamic(ad, transform(qual), transformTrees(params))) } else { /* ### BODY OF THE TRANSFORMATION -> remember we're in case ad@ApplyDynamic(qual, params) ### */ @@ -625,8 +624,8 @@ abstract class CleanUp extends Transform { * because invoke only returns object and erasure made sure the result is * expected to be an AnyRef. */ val t: Tree = ad.symbol.tpe match { - case MethodType(paramTypes, resType) => - assert(params.length == paramTypes.length) + case MethodType(mparams, resType) => + assert(params.length == mparams.length) atPos(ad.pos)(localTyper.typed { val t1 = newTermName(unit.fresh.newName(ad.pos, "qual")) val sym = currentOwner.newValue(ad.pos, t1) setInfo qual0.tpe @@ -635,9 +634,9 @@ abstract class CleanUp extends Transform { List(ValDef(sym, qual0)), fixResult(if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType) { if (mayRequirePrimitiveReplacement) - callAsOperator(paramTypes, resType) + callAsOperator(mparams map (_.tpe), resType) else - callAsMethod(paramTypes, resType) + callAsMethod(mparams map (_.tpe), resType) } ) }) @@ -651,10 +650,10 @@ abstract class CleanUp extends Transform { "(" + params.map(_.toString).mkString(", ") + ")' with" ) ad.symbol.tpe match { - case MethodType(paramTypes, resType) => + case MethodType(mparams, resType) => Console.println( " - declared parameters' types: " + - (paramTypes.map(_.toString)).mkString("'",", ","'")) + (mparams.map(_.toString)).mkString("'",", ","'")) Console.println( " - passed arguments' types: " + (params.map(_.toString)).mkString("'",", ","'")) @@ -695,14 +694,14 @@ abstract class CleanUp extends Transform { case thePrimaryConstructor@DefDef(mods, name, tparams, vparamss, tpt, rhs) if (thePrimaryConstructor == firstConstructor) => val newRhs = rhs match { case theRhs@Block(stats, expr) => - copy.Block(theRhs, transformTrees(newInits.toList) ::: stats, expr) + treeCopy.Block(theRhs, transformTrees(newInits.toList) ::: stats, expr) } - copy.DefDef(thePrimaryConstructor, mods, name, tparams, vparamss, tpt, newRhs) + treeCopy.DefDef(thePrimaryConstructor, mods, name, tparams, vparamss, tpt, newRhs) case notThePrimaryConstructor => notThePrimaryConstructor } ) - copy.Template(tree, parents, self, newBody) + treeCopy.Template(tree, parents, self, newBody) } else super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 47256ca8bc..d5ace3c4f6 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -179,7 +179,7 @@ abstract class Constructors extends Transform { // all methods except the primary constructor go into template stat.symbol.tpe match { case MethodType(List(), tp @ ConstantType(c)) => - defBuf += copy.DefDef( + defBuf += treeCopy.DefDef( stat, mods, name, tparams, vparamss, tpt, Literal(c) setPos rhs.pos setType tp) case _ => @@ -198,7 +198,7 @@ abstract class Constructors extends Transform { (if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign( stat.symbol, rhs1) } - defBuf += copy.ValDef(stat, mods, name, tpt, EmptyTree) + defBuf += treeCopy.ValDef(stat, mods, name, tpt, EmptyTree) } case ClassDef(_, _, _, _) => // classes are treated recursively, and left in the template @@ -278,9 +278,9 @@ abstract class Constructors extends Transform { } // Assemble final constructor - defBuf += copy.DefDef( + defBuf += treeCopy.DefDef( constr, constr.mods, constr.name, constr.tparams, constr.vparamss, constr.tpt, - copy.Block( + treeCopy.Block( constrBody, paramInits ::: constrPrefixBuf.toList ::: constrStatBuf.toList, constrBody.expr)); @@ -290,14 +290,14 @@ abstract class Constructors extends Transform { if (!mustbeKept(sym)) clazz.info.decls unlink sym // Eliminate all field definitions that can be dropped from template - copy.Template(impl, impl.parents, impl.self, + treeCopy.Template(impl, impl.parents, impl.self, defBuf.toList filter (stat => mustbeKept(stat.symbol))) } // transformClassTemplate override def transform(tree: Tree): Tree = tree match { case ClassDef(mods, name, tparams, impl) if !tree.symbol.hasFlag(INTERFACE) => - copy.ClassDef(tree, mods, name, tparams, transformClassTemplate(impl)) + treeCopy.ClassDef(tree, mods, name, tparams, transformClassTemplate(impl)) case _ => super.transform(tree) } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index e300b81576..7330b9c9e8 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -90,13 +90,13 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { apply(restpe) case ExistentialType(tparams, restpe) => apply(restpe) - case mt @ MethodType(formals, restpe) => + case mt @ MethodType(params, restpe) => MethodType( - formals map apply, + cloneSymbols(params) map (p => p.setInfo(apply(p.tpe))), if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) else if (settings.Xexperimental.value) - apply(mt.resultType(formals)) // this gets rid of DeBruijnTypes + apply(mt.resultType(params map (_.tpe))) // this gets rid of DeBruijnTypes else apply(restpe)) case RefinedType(parents, decls) => @@ -229,8 +229,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { assert(!tparams.isEmpty) def paramSig(tsym: Symbol) = tsym.name+boundSig(hiBounds(tsym.info.bounds)) (if (toplevel) "<"+(tparams map paramSig).mkString+">" else "")+jsig(restpe) - case MethodType(formals, restpe) => - "("+(formals map jsig).mkString+")"+ + case MethodType(params, restpe) => + "("+(params map (_.tpe) map jsig).mkString+")"+ (if (restpe.typeSymbol == UnitClass || sym.isConstructor) VOID_TAG.toString else jsig(restpe)) case RefinedType(parents, decls) if (!parents.isEmpty) => jsig(parents.head) @@ -305,17 +305,27 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { else if (sym.isTerm && sym.owner == ArrayClass) { if (sym.isClassConstructor) tp match { - case MethodType(formals, TypeRef(pre, sym, args)) => - MethodType(formals map erasure, typeRef(erasure(pre), sym, args)) + case MethodType(params, TypeRef(pre, sym, args)) => + MethodType(cloneSymbols(params) map (p => p.setInfo(erasure(p.tpe))), + typeRef(erasure(pre), sym, args)) } else if (sym.name == nme.apply) tp else if (sym.name == nme.update) tp match { case MethodType(List(index, tvar), restpe) => - MethodType(List(erasure(index), tvar), erasedTypeRef(UnitClass)) + MethodType(List(index.cloneSymbol.setInfo(erasure(index.tpe)), tvar), + erasedTypeRef(UnitClass)) } else erasure(tp) + } else if ( + sym.owner != NoSymbol && + sym.owner.owner == ArrayClass && + sym == Array_update.paramss.head(1)) { + // special case for Array.update: the non-erased type remains, i.e. (Int,A)Unit + // since the erasure type map gets applied to every symbol, we have to catch the + // symbol here + tp } else { /* val erased = @@ -359,7 +369,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { private def box(tree: Tree): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = box(rhs) - copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe + treeCopy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe case _ => typed { atPos(tree.pos) { @@ -381,7 +391,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { private def boxArray(tree: Tree): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = boxArray(rhs) - copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe + treeCopy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe case _ => typed { atPos(tree.pos) { @@ -399,7 +409,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { private def unbox(tree: Tree, pt: Type): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = unbox(rhs, pt) - copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe + treeCopy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe case _ => typed { atPos(tree.pos) { @@ -651,7 +661,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { // println("member cast "+tree.symbol+" "+tree.symbol.ownerChain+" "+qual1+" "+qual1.tpe) qual1 = cast(qual1, tree.symbol.owner.tpe) } - copy.Select(tree, qual1, name) + treeCopy.Select(tree, qual1, name) } case _ => tree @@ -685,17 +695,17 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } def adaptCase(cdef: CaseDef): CaseDef = { val body1 = adaptToType(cdef.body, tree1.tpe) - copy.CaseDef(cdef, cdef.pat, cdef.guard, body1) setType body1.tpe + treeCopy.CaseDef(cdef, cdef.pat, cdef.guard, body1) setType body1.tpe } def adaptBranch(branch: Tree): Tree = if (branch == EmptyTree) branch else adaptToType(branch, tree1.tpe); tree1 match { case If(cond, thenp, elsep) => - copy.If(tree1, cond, adaptBranch(thenp), adaptBranch(elsep)) + treeCopy.If(tree1, cond, adaptBranch(thenp), adaptBranch(elsep)) case Match(selector, cases) => - copy.Match(tree1, selector, cases map adaptCase) + treeCopy.Match(tree1, selector, cases map adaptCase) case Try(block, catches, finalizer) => - copy.Try(tree1, adaptBranch(block), catches map adaptCase, finalizer) + treeCopy.Try(tree1, adaptBranch(block), catches map adaptCase, finalizer) case Ident(_) | Select(_, _) => if (tree1.symbol hasFlag OVERLOADED) { val first = tree1.symbol.alternatives.head @@ -737,20 +747,22 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { */ private def checkNoDoubleDefs(root: Symbol) { def doubleDefError(sym1: Symbol, sym2: Symbol) { - val tpe1 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym1)) - val tpe2 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym2)) + // the .toString must also be computed at the earlier phase + def atRefc[T](op: => T) = atPhase[T](currentRun.refchecksPhase.next)(op) + val tpe1 = atRefc(root.thisType.memberType(sym1)) + val tpe2 = atRefc(root.thisType.memberType(sym2)) if (!tpe1.isErroneous && !tpe2.isErroneous) unit.error( if (sym1.owner == root) sym1.pos else root.pos, (if (sym1.owner == sym2.owner) "double definition:\n" else if (sym1.owner == root) "name clash between defined and inherited member:\n" else "name clash between inherited members:\n") + - sym1 + ":" + tpe1 + + sym1 + ":" + atRefc(tpe1.toString) + (if (sym1.owner == root) "" else sym1.locationString) + " and\n" + - sym2 + ":" + tpe2 + + sym2 + ":" + atRefc(tpe2.toString) + (if (sym2.owner == root) " at line " + (sym2.pos).line.get else sym2.locationString) + "\nhave same type" + - (if (tpe1 =:= tpe2) "" else " after erasure: " + atPhase(phase.next)(sym1.tpe))) + (if (atRefc(tpe1 =:= tpe2)) "" else " after erasure: " + atPhase(phase.next)(sym1.tpe))) sym1.setInfo(ErrorType) } @@ -857,7 +869,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { .setPos(owner.pos) .setFlag(member.flags | BRIDGE) .resetFlag(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) - .setInfo(otpe); + // the parameter symbols need to have the new owner + bridge.setInfo(otpe.cloneInfo(bridge)) bridgeTarget(bridge) = member atPhase(phase.next) { owner.info.decls.enter(bridge) } if (other.owner == owner) { @@ -870,11 +883,11 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { atPhase(phase.next) { atPos(bridge.pos) { val bridgeDef = - DefDef(bridge, vparamss => + DefDef(bridge, member.tpe match { case MethodType(List(), ConstantType(c)) => Literal(c) case _ => - (((Select(This(owner), member): Tree) /: vparamss) + (((Select(This(owner), member): Tree) /: bridge.paramss) ((fun, vparams) => Apply(fun, vparams map Ident))) }); if (settings.debug.value) @@ -945,9 +958,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { case ClassDef(mods, name, tparams, impl) => if (settings.debug.value) log("defs of " + tree.symbol + " = " + tree.symbol.info.decls) - copy.ClassDef(tree, mods, name, List(), impl) + treeCopy.ClassDef(tree, mods, name, List(), impl) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - copy.DefDef(tree, mods, name, List(), vparamss, tpt, rhs) + treeCopy.DefDef(tree, mods, name, List(), vparamss, tpt, rhs) case TypeDef(_, _, _, _) => EmptyTree case TypeApply(fun, args) if (fun.symbol.owner != AnyClass && @@ -1045,14 +1058,14 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { assert(!currentOwner.isImplClass) //Console.println("checking no dble defs " + tree)//DEBUG checkNoDoubleDefs(tree.symbol.owner) - copy.Template(tree, parents, emptyValDef, addBridges(body, currentOwner)) + treeCopy.Template(tree, parents, emptyValDef, addBridges(body, currentOwner)) case Match(selector, cases) => Match(Typed(selector, TypeTree(selector.tpe)), cases) case Literal(ct) if ct.tag == ClassTag && ct.typeValue.typeSymbol != definitions.UnitClass => - copy.Literal(tree, Constant(erasure(ct.typeValue))) + treeCopy.Literal(tree, Constant(erasure(ct.typeValue))) case _ => tree diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index d1fb5d9d82..a4125dfa2a 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -99,7 +99,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter * */ def transformInfo(sym: Symbol, tp: Type): Type = tp match { - case MethodType(formals, restpe1) => + case MethodType(params, restpe1) => val restpe = transformInfo(sym, restpe1) if (sym.owner.isTrait && ((sym hasFlag SUPERACCESSOR) || sym.isModule)) { // 5 sym.makeNotPrivate(sym.owner) @@ -108,10 +108,12 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter if (sym.owner.isTrait && (sym hasFlag (ACCESSOR | SUPERACCESSOR))) sym.makeNotPrivate(sym.owner); //(2) if (sym.owner.isTrait && (sym hasFlag PROTECTED)) sym setFlag notPROTECTED // 6 - if (sym.isClassConstructor && isInner(sym.owner)) // 1 - MethodType(sym.owner.outerClass.thisType :: formals, restpe) - else if (restpe ne restpe1) - MethodType(formals, restpe) + if (sym.isClassConstructor && isInner(sym.owner)) { // 1 + val p = sym.newValueParameter(sym.pos, "arg" + nme.OUTER) + .setInfo(sym.owner.outerClass.thisType) + MethodType(p :: params, restpe) + } else if (restpe ne restpe1) + MethodType(params, restpe) else tp case ClassInfoType(parents, decls, clazz) => var decls1 = decls @@ -306,7 +308,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter else Select(This(currentClass), outerField(currentClass)) localTyper.typed { atPos(currentClass.pos) { - DefDef(outerAcc, {vparamss => rhs}) + DefDef(outerAcc, rhs) } } } @@ -329,7 +331,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter localTyper.typed { atPos(currentClass.pos) { // @S: atPos not good enough because of nested atPos in DefDef method, which gives position from wrong class! - DefDef(outerAcc, {vparamss=>rhs}).setPos(currentClass.pos) + DefDef(outerAcc, rhs).setPos(currentClass.pos) } } } @@ -359,7 +361,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter } } super.transform( - copy.Template(tree, parents, self, + treeCopy.Template(tree, parents, self, if (newDefs.isEmpty) decls else decls ::: newDefs.toList) ) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => @@ -375,7 +377,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter sym.newValueParameter(sym.pos, nme.OUTER) setInfo outerField(clazz).info ((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail } else vparamss - super.transform(copy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)) + super.transform(treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)) } } else super.transform(tree) @@ -405,7 +407,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter gen.mkAttributedQualifier(pre) } } - super.transform(copy.Apply(tree, sel, outerVal :: args)) + super.transform(treeCopy.Apply(tree, sel, outerVal :: args)) case mch @ Match(selector, cases) => // <----- transmatch hook val tid = if (settings.debug.value) { @@ -426,14 +428,14 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter fmls += vs1.head.tpe vs1 = vs1.tail } - val tpe = new MethodType(fmls.toList, definitions.BooleanClass.tpe) + val tpe = new MethodType(method.newSyntheticValueParams(fmls.toList), + definitions.BooleanClass.tpe) method setInfo tpe localTyper. typed { DefDef(method, - {vparamss => - new ChangeOwnerTraverser(currentOwner, method).traverse(guard); - new TreeSymSubstituter(vs, vparamss.head).traverse(guard);guard})} + { new ChangeOwnerTraverser(currentOwner, method).traverse(guard); + new TreeSymSubstituter(vs, method.paramss.head).traverse(guard);guard})} } val nguard = new ListBuffer[Tree] diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 4a20175663..fa1c08f80f 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -56,6 +56,9 @@ abstract class Flatten extends InfoTransform { } } ClassInfoType(parents1, decls1, clazz) + case MethodType(params, restp) => + val restp1 = apply(restp) + if (restp1 eq restp) tp else copyMethodType(tp, params, restp1) case PolyType(tparams, restp) => val restp1 = apply(restp); if (restp1 eq restp) tp else PolyType(tparams, restp1) diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 2c2314f880..41b2cc53a7 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -101,9 +101,8 @@ abstract class LambdaLift extends InfoTransform { def localToConstr(sym: Symbol) = if (sym.isLocalDummy) sym.owner.primaryConstructor else sym; var encl = localToConstr(sym) - while (!encl.isMethod && !encl.isClass) { - encl = localToConstr(outer(encl)); - } + while (!encl.isMethod && !encl.isClass) + encl = localToConstr(outer(encl)) encl } @@ -318,12 +317,13 @@ abstract class LambdaLift extends InfoTransform { val freeParams = ps map (p => ValDef(p) setPos tree.pos setType NoType); tree match { case DefDef(mods, name, tparams, List(vparams), tpt, rhs) => + val addParams = cloneSymbols(ps).map(_.setFlag(PARAM)) sym.updateInfo( - lifted(MethodType(sym.info.paramTypes ::: (ps map (_.tpe)), sym.info.resultType))); - copy.DefDef(tree, mods, name, tparams, List(vparams ::: freeParams), tpt, rhs) + lifted(MethodType(sym.info.params ::: addParams, sym.info.resultType))) + treeCopy.DefDef(tree, mods, name, tparams, List(vparams ::: freeParams), tpt, rhs) case ClassDef(mods, name, tparams, impl @ Template(parents, self, body)) => - copy.ClassDef(tree, mods, name, tparams, - copy.Template(impl, parents, self, body ::: freeParams)) + treeCopy.ClassDef(tree, mods, name, tparams, + treeCopy.Template(impl, parents, self, body ::: freeParams)) } case None => tree @@ -358,20 +358,20 @@ abstract class LambdaLift extends InfoTransform { Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(rhs)) } } - copy.ValDef(tree, mods, name, tpt1, rhs1) + treeCopy.ValDef(tree, mods, name, tpt1, rhs1) } else tree case Return(Block(stats, value)) => - Block(stats, copy.Return(tree, value)) setType tree.tpe setPos tree.pos + Block(stats, treeCopy.Return(tree, value)) setType tree.tpe setPos tree.pos case Return(expr) => assert(sym == currentMethod, sym) tree case Apply(fn, args) => - copy.Apply(tree, fn, addFreeArgs(tree.pos, sym, args)) + treeCopy.Apply(tree, fn, addFreeArgs(tree.pos, sym, args)) case Assign(Apply(TypeApply(sel @ Select(qual, _), _), List()), rhs) => // eliminate casts introduced by selecting a captured variable field // on the lhs of an assignment. assert(sel.symbol == Object_asInstanceOf) - copy.Assign(tree, qual, rhs) + treeCopy.Assign(tree, qual, rhs) case Ident(name) => val tree1 = if (sym != NoSymbol && sym.isTerm && !sym.isLabel) @@ -401,13 +401,13 @@ abstract class LambdaLift extends InfoTransform { def addLifted(stat: Tree): Tree = stat match { case ClassDef(mods, name, tparams, impl @ Template(parents, self, body)) => val lifted = liftedDefs(stat.symbol).toList map addLifted - val result = copy.ClassDef( - stat, mods, name, tparams, copy.Template(impl, parents, self, body ::: lifted)) + val result = treeCopy.ClassDef( + stat, mods, name, tparams, treeCopy.Template(impl, parents, self, body ::: lifted)) liftedDefs -= stat.symbol result case DefDef(mods, name, tp, vp, tpt, Block(Nil, expr)) if !stat.symbol.isConstructor => - copy.DefDef(stat, mods, name, tp, vp, tpt, expr) + treeCopy.DefDef(stat, mods, name, tp, vp, tpt, expr) case _ => stat } diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 41c3230bff..ce5329e532 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -60,8 +60,8 @@ abstract class LazyVals extends Transform { rhs1 } else super.transform(rhs) - copy.DefDef(tree, mods, name, tparams, vparams, tpt, - typed(addBitmapDefs(sym, res))) + treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, + typed(addBitmapDefs(sym, res))) case Template(parents, self, body) => val body1 = super.transformTrees(body) @@ -72,11 +72,11 @@ abstract class LazyVals extends Transform { added = true typed(addBitmapDefs(sym, stat)) case ValDef(mods, name, tpt, rhs) => - typed(copy.ValDef(stat, mods, name, tpt, addBitmapDefs(stat.symbol, rhs))) + typed(treeCopy.ValDef(stat, mods, name, tpt, addBitmapDefs(stat.symbol, rhs))) case _ => stat } - copy.Template(tree, parents, self, stats) + treeCopy.Template(tree, parents, self, stats) case _ => super.transform(tree) } @@ -100,7 +100,7 @@ abstract class LazyVals extends Transform { if (name.toString.equals("_" + methSym.name) && List.forall2(params.tail, methSym.tpe.paramTypes) { (ident, tpe) => ident.tpe == tpe }) => val sym = l.symbol - Block(assign, copy.LabelDef(l, name, params, typed(prependStats(bmps, rhs1)))) + Block(assign, treeCopy.LabelDef(l, name, params, typed(prependStats(bmps, rhs1)))) case _ => prependStats(bmps, rhs) } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index f5fbafaf7a..4a13690efd 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -172,7 +172,7 @@ abstract class Mixin extends InfoTransform { val setterName = nme.getterToSetter(nme.getterName(field.name)) val setter = clazz.newMethod(field.pos, setterName) .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | lateDEFERRED) - .setInfo(MethodType(List(field.info), UnitClass.tpe)) + setter.setInfo(MethodType(setter.newSyntheticValueParams(List(field.info)), UnitClass.tpe)) if (needsExpandedSetterName(field)) { //println("creating expanded setter from "+field) setter.name = clazz.expandedSetterName(setter.name) @@ -351,11 +351,12 @@ abstract class Mixin extends InfoTransform { if ((parents1 eq parents) && (decls1 eq decls)) tp else ClassInfoType(parents1, decls1, clazz) - case MethodType(formals, restp) => + case MethodType(params, restp) => toInterfaceMap( - if (isImplementedStatically(sym)) - MethodType(toInterface(sym.owner.typeOfThis) :: formals, restp) - else + if (isImplementedStatically(sym)) { + val ownerParam = sym.newSyntheticValueParam(toInterface(sym.owner.typeOfThis)) + MethodType(ownerParam :: params, restp) + } else tp) case _ => @@ -419,7 +420,7 @@ abstract class Mixin extends InfoTransform { .setFlag(PARAM) .setInfo(toInterface(currentOwner.typeOfThis)); val selfdef = ValDef(self) setType NoType - copy.DefDef(tree, mods, name, tparams, List(selfdef :: vparams), tpt, rhs) + treeCopy.DefDef(tree, mods, name, tparams, List(selfdef :: vparams), tpt, rhs) } else { EmptyTree } @@ -508,7 +509,7 @@ abstract class Mixin extends InfoTransform { * right-hand side */ def addDefDef(sym: Symbol, rhs: List[Symbol] => Tree) { - addDef(position(sym), DefDef(sym, vparamss => rhs(vparamss.head))) + addDef(position(sym), DefDef(sym, rhs(sym.paramss.head))) } /** Add `newdefs' to `stats', removing any abstract method definitions @@ -548,7 +549,7 @@ abstract class Mixin extends InfoTransform { log("complete super acc " + stat.symbol + stat.symbol.locationString + " " + rhs1 + " " + stat.symbol.alias + stat.symbol.alias.locationString + "/" + stat.symbol.alias.owner.hasFlag(lateINTERFACE))//debug - copy.DefDef(stat, mods, name, tparams, List(vparams), tpt, rhs2) + treeCopy.DefDef(stat, mods, name, tparams, List(vparams), tpt, rhs2) case _ => stat } @@ -659,7 +660,7 @@ abstract class Mixin extends InfoTransform { val Block(stats, res) = rhs mkLazyDef(clazz, stats, Select(This(clazz), res.symbol), fieldOffset(sym)) } - copy.DefDef(stat, mods, name, tp, vp, tpt, rhs1) + treeCopy.DefDef(stat, mods, name, tp, vp, tpt, rhs1) case DefDef(mods, name, tp, vp, tpt, rhs) if needsInitFlag(sym) && rhs != EmptyTree && !clazz.isImplClass && !clazz.isTrait => @@ -670,10 +671,10 @@ abstract class Mixin extends InfoTransform { else { mkCheckedAccessor(clazz, rhs, fieldOffset(sym), stat.pos) } - copy.DefDef(stat, mods, name, tp, vp, tpt, rhs1) + treeCopy.DefDef(stat, mods, name, tp, vp, tpt, rhs1) case DefDef(mods, name, tp, vp, tpt, rhs) if sym.isConstructor => - copy.DefDef(stat, mods, name, tp, vp, tpt, addInitBits(clazz, rhs)) + treeCopy.DefDef(stat, mods, name, tp, vp, tpt, addInitBits(clazz, rhs)) case _ => stat } @@ -890,7 +891,7 @@ abstract class Mixin extends InfoTransform { // add all new definitions to current class or interface val body1 = addNewDefs(currentOwner, body) - copy.Template(tree, parents1, self, body1) + treeCopy.Template(tree, parents1, self, body1) case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if (tree.symbol == Object_asInstanceOf && (qual.tpe <:< targ.tpe)) => diff --git a/src/compiler/scala/tools/nsc/transform/Reifiers.scala b/src/compiler/scala/tools/nsc/transform/Reifiers.scala index 5973fa07e8..300649aa4d 100644 --- a/src/compiler/scala/tools/nsc/transform/Reifiers.scala +++ b/src/compiler/scala/tools/nsc/transform/Reifiers.scala @@ -72,8 +72,8 @@ trait Reifiers { if (_log_reify_type_) println("cannot handle RefinedType "+tp); reflect.NoType case ClassInfoType(parents, defs, clazz) => if (_log_reify_type_) println("cannot handle ClassInfoType "+tp); reflect.NoType - case MethodType(paramtypes, result) => - reflect.MethodType(paramtypes.map(reify), reify(result)) + case MethodType(params, result) => + reflect.MethodType(params.map(reify), reify(result)) case PolyType(tparams, result) => val boundss = for { @@ -139,8 +139,8 @@ trait Reifiers { appliedType(untpe, args.map(unreify)) case reflect.TypeBounds(lo, hi) => TypeBounds(unreify(lo), unreify(hi)) - case reflect.MethodType(formals, restpe) => - MethodType(formals.map(unreify), unreify(restpe)) + case reflect.MethodType(params, restpe) => + MethodType(params.map(unreify), unreify(restpe)) case reflect.PolyType(typeParams, typeBounds, resultType) => PolyType(typeParams.map(unreify), unreify(resultType)) //todo: treat ExistentialType diff --git a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala index b29f82e588..ad4e322ab1 100644 --- a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala @@ -30,7 +30,7 @@ abstract class SampleTransform extends Transform { expr case Block(defs, sup @ Super(qual, mix)) => // A hypthothetic transformation, which replaces // {super} by {super.sample} - copy.Block( // `copy' is the usual lazy tree copier + treeCopy.Block( // `copy' is the usual lazy tree copier tree1, defs, typed( // `typed' assigns types to its tree argument atPos(tree1.pos)( // `atPos' fills in position of its tree argument diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 3df490caac..af6c65ece2 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -157,7 +157,8 @@ abstract class TailCalls extends Transform val newCtx = mkContext(ctx) newCtx.currentMethod = tree.symbol newCtx.makeLabel() - newCtx.label.setInfo(MethodType(currentClass.tpe :: tree.symbol.tpe.paramTypes, tree.symbol.tpe.finalResultType)) + val currentClassParam = tree.symbol.newSyntheticValueParam(currentClass.tpe) + newCtx.label.setInfo(MethodType(currentClassParam :: tree.symbol.tpe.params, tree.symbol.tpe.finalResultType)) newCtx.tailPos = true val t1 = if (newCtx.currentMethod.isFinal || @@ -187,11 +188,11 @@ abstract class TailCalls extends Transform LabelDef(newCtx.label, newThis :: (List.flatten(vparams) map (_.symbol)), newRHS)))); - copy.DefDef(tree, mods, name, tparams, vparams, tpt, newRHS); + treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, newRHS); } else - copy.DefDef(tree, mods, name, tparams, vparams, tpt, newRHS); + treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, newRHS); } else { - copy.DefDef(tree, mods, name, tparams, vparams, tpt, transform(rhs, newCtx)) + treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, transform(rhs, newCtx)) } if (!isTransformed && tailrecRequired(dd)) @@ -218,12 +219,12 @@ abstract class TailCalls extends Transform super.transform(tree) case Block(stats, expr) => - copy.Block(tree, - transformTrees(stats, mkContext(ctx, false)), - transform(expr)) + treeCopy.Block(tree, + transformTrees(stats, mkContext(ctx, false)), + transform(expr)) case CaseDef(pat, guard, body) => - copy.CaseDef(tree, pat, guard, transform(body)) + treeCopy.CaseDef(tree, pat, guard, transform(body)) case Sequence(_) | Alternative(_) | Star(_) | Bind(_, _) => @@ -237,24 +238,24 @@ abstract class TailCalls extends Transform super.transform(tree) case If(cond, thenp, elsep) => - copy.If(tree, cond, transform(thenp), transform(elsep)) + treeCopy.If(tree, cond, transform(thenp), transform(elsep)) case Match(selector, cases) => //super.transform(tree); - copy.Match(tree, transform(selector, mkContext(ctx, false)), transformTrees(cases).asInstanceOf[List[CaseDef]]) + treeCopy.Match(tree, transform(selector, mkContext(ctx, false)), transformTrees(cases).asInstanceOf[List[CaseDef]]) case Return(expr) => super.transform(tree) case Try(block, catches, finalizer) => // no calls inside a try are in tail position, but keep recursing for nested functions - copy.Try(tree, transform(block, mkContext(ctx, false)), - transformTrees(catches, mkContext(ctx, false)).asInstanceOf[List[CaseDef]], - transform(finalizer, mkContext(ctx, false))) + treeCopy.Try(tree, transform(block, mkContext(ctx, false)), + transformTrees(catches, mkContext(ctx, false)).asInstanceOf[List[CaseDef]], + transform(finalizer, mkContext(ctx, false))) case Throw(expr) => super.transform(tree) case New(tpt) => super.transform(tree) case Typed(expr, tpt) => super.transform(tree) case Apply(tapply @ TypeApply(fun, targs), vargs) => - lazy val defaultTree = copy.Apply(tree, tapply, transformTrees(vargs, mkContext(ctx, false))) + lazy val defaultTree = treeCopy.Apply(tree, tapply, transformTrees(vargs, mkContext(ctx, false))) if ( ctx.currentMethod.isFinal && ctx.tailPos && isSameTypes(ctx.tparams, targs map (_.tpe.typeSymbol)) && @@ -280,10 +281,10 @@ abstract class TailCalls extends Transform case Apply(fun, args) if (fun.symbol == definitions.Boolean_or || fun.symbol == definitions.Boolean_and) => - copy.Apply(tree, fun, transformTrees(args)) + treeCopy.Apply(tree, fun, transformTrees(args)) case Apply(fun, args) => - lazy val defaultTree = copy.Apply(tree, fun, transformTrees(args, mkContext(ctx, false))) + lazy val defaultTree = treeCopy.Apply(tree, fun, transformTrees(args, mkContext(ctx, false))) if (ctx.currentMethod.isFinal && ctx.tailPos && isRecursiveCall(fun)) { diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index fd853e3ea3..15684c23d4 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -51,13 +51,13 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { def apply(tp0: Type): Type = { val tp = expandAlias(tp0) tp match { - case MethodType(formals, MethodType(formals1, restpe)) => - apply(MethodType(formals ::: formals1, restpe)) + case MethodType(params, MethodType(params1, restpe)) => + apply(MethodType(params ::: params1, restpe)) case MethodType(formals, ExistentialType(tparams, restpe @ MethodType(_, _))) => assert(false, "unexpected curried method types with intervening exitential") tp0 case mt: ImplicitMethodType => - apply(MethodType(mt.paramTypes, mt.resultType)) + apply(MethodType(mt.params, mt.resultType)) case PolyType(List(), restpe) => apply(MethodType(List(), restpe)) case PolyType(tparams, restpe) => @@ -91,11 +91,11 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { /** Convert repeated parameters to arrays if they occur as part of a Java method */ private def repeatedToArray(tp: Type): Type = tp match { - case MethodType(formals, rtpe) - if (!formals.isEmpty && formals.last.typeSymbol == RepeatedParamClass) => - MethodType(formals.init ::: - List(appliedType(ArrayClass.typeConstructor, List(formals.last.typeArgs.head))), - rtpe) + case MethodType(params, rtpe) + if (!params.isEmpty && params.last.tpe.typeSymbol == RepeatedParamClass) => + val arrayParam = params.last.owner.newSyntheticValueParams(List( + appliedType(ArrayClass.typeConstructor, List(params.last.tpe.typeArgs.head)))) + MethodType(params.init ::: arrayParam, rtpe) case PolyType(tparams, rtpe) => val rtpe1 = repeatedToArray(rtpe) if (rtpe1 eq rtpe) tp @@ -304,8 +304,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { val restpe = fun.tpe.typeArgs.last anonClass setInfo ClassInfoType( List(ObjectClass.tpe, fun.tpe, ScalaObjectClass.tpe), newScope, anonClass); - val applyMethod = anonClass.newMethod(fun.pos, nme.apply) - .setFlag(FINAL).setInfo(MethodType(formals, restpe)); + val applyMethod = anonClass.newMethod(fun.pos, nme.apply).setFlag(FINAL) + applyMethod.setInfo(MethodType(applyMethod.newSyntheticValueParams(formals), restpe)) anonClass.info.decls enter applyMethod; for (vparam <- fun.vparams) vparam.symbol.owner = applyMethod; new ChangeOwnerTraverser(fun.symbol, applyMethod).traverse(fun.body); @@ -334,8 +334,9 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { } val members = { if (fun.tpe.typeSymbol == PartialFunctionClass) { - val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt) - .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe)) + val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt).setFlag(FINAL) + isDefinedAtMethod.setInfo(MethodType(isDefinedAtMethod.newSyntheticValueParams(formals), + BooleanClass.tpe)) anonClass.info.decls enter isDefinedAtMethod def idbody(idparam: Symbol) = fun.body match { case Match(_, cases) => @@ -352,7 +353,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false)))) } List(applyMethodDef(mkUnchecked(fun.body)), - DefDef(isDefinedAtMethod, vparamss => mkUnchecked(idbody(vparamss.head.head)))) + DefDef(isDefinedAtMethod, mkUnchecked(idbody(isDefinedAtMethod.paramss.head.head)))) } else { List(applyMethodDef(fun.body)) } @@ -475,9 +476,9 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { val rest = stats drop presupers.length val supercalls = rest take 1 map transformInConstructor val others = rest drop 1 map transform - copy.Block(rhs, presupers ::: supercalls ::: others, transform(expr)) + treeCopy.Block(rhs, presupers ::: supercalls ::: others, transform(expr)) } - copy.DefDef( + treeCopy.DefDef( tree, mods, name, transformTypeDefs(tparams), transformValDefss(vparamss), transform(tpt), rhs1) } @@ -521,7 +522,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { else if (fn.symbol.name == nme.unapplySeq) transformArgs(tree.pos, args, analyzer.unapplyTypeListFromReturnTypeSeq(fn.tpe), false) else { assert(false,"internal error: UnApply node has wrong symbol"); null }) - copy.UnApply(tree, fn1, args1) + treeCopy.UnApply(tree, fn1, args1) case Apply(fn, args) => if (settings.noassertions.value && @@ -530,12 +531,12 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { fn.symbol.owner == PredefModule.moduleClass) { Literal(()).setPos(tree.pos).setType(UnitClass.tpe) } else if (fn.symbol == Object_synchronized && shouldBeLiftedAnyway(args.head)) { - transform(copy.Apply(tree, fn, List(liftTree(args.head)))) + transform(treeCopy.Apply(tree, fn, List(liftTree(args.head)))) } else { withNeedLift(true) { val formals = fn.tpe.paramTypes; val isJava = fn.symbol hasFlag JAVA // in case we need a varargs transformation - copy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, args, formals, isJava))) + treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, args, formals, isJava))) } } @@ -552,7 +553,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { inPattern = true val pat1 = transform(pat) inPattern = false - copy.CaseDef(tree, pat1, transform(guard), transform(body)) + treeCopy.CaseDef(tree, pat1, transform(guard), transform(body)) case fun @ Function(_, _) => mainTransform(transformFunction(fun)) @@ -592,7 +593,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { case None => rhs case Some(k) => atPos(rhs.pos)(nonLocalReturnTry(rhs, k, tree.symbol)) } - copy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs1) + treeCopy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs1) case Try(body, catches, finalizer) => if (catches forall treeInfo.isCatchCase) tree else { @@ -617,10 +618,10 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { if (settings.debug.value) log("rewrote try: " + catches + " ==> " + catchall); val catches1 = localTyper.typedCases( tree, List(catchall), ThrowableClass.tpe, WildcardType); - copy.Try(tree, body, catches1, finalizer) + treeCopy.Try(tree, body, catches1, finalizer) } case Apply(Apply(fn, args), args1) => - copy.Apply(tree, fn, args ::: args1) + treeCopy.Apply(tree, fn, args ::: args1) case Ident(name) => assert(name != nme.WILDCARD_STAR.toTypeName) applyUnary(tree); diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index a2e567282f..f341dd0df9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -18,6 +18,7 @@ trait Analyzer extends AnyRef with EtaExpansion with SyntheticMethods with Unapplies + with NamesDefaults { val global : Global import global._ diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 4a16da2b55..5b98b070ce 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -102,6 +102,8 @@ trait Contexts { self: Analyzer => var imports: List[ImportInfo] = List() // currently visible imports var openImplicits: List[Type] = List() // types for which implicit arguments // are currently searched + // for a named application block (Tree) the corresponding NamedApplyInfo + var namedApplyBlockInfo: Option[(Tree, NamedApplyInfo)] = None var prefix: Type = NoPrefix var inConstructorSuffix = false // are we in a secondary constructor // after the this constructor call? diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala index 3dede2a699..ed1c35c1f1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala +++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala @@ -259,9 +259,9 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { protected def paramTypesAndIndices(tpe: Type, start: Int): List[List[(Type, Int)]] = tpe match { case PolyType(_, restpe) => paramTypesAndIndices(restpe, start) - case MethodType(formals, restpe) => - val end = start + formals.length - (formals zip List.range(start, end)) :: paramTypesAndIndices(restpe, end) + case MethodType(params, restpe) => + val end = start + params.length + (tpe.paramTypes zip List.range(start, end)) :: paramTypesAndIndices(restpe, end) case _ => List() } @@ -398,7 +398,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { .setInfo(PolyType(List(), pt)) cclazz.info.decls enter pfield atPos(factory.pos) { - DefDef(pfield, vparamss => Ident(fixParamName(i))) + DefDef(pfield, Ident(fixParamName(i))) } } } @@ -436,14 +436,14 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { val abstpeSym = abstractType(clazz) localTyper.typed { atPos(factorySym.pos) { - DefDef(factorySym, vparamss => + DefDef(factorySym, Block( List(cclazzDef), TypeApply( Select( gen.mkForwarder( Select(New(TypeTree(cclazzDef.symbol.tpe)), nme.CONSTRUCTOR), - vparamss), + factorySym.paramss), Any_asInstanceOf), List( TypeTree( @@ -463,7 +463,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { .resetFlag(notOVERRIDE | notFINAL) cclazz.info.decls.enter(bridge) val superRef: Tree = Select(Super(cclazz, nme.EMPTY.toTypeName), meth) - DefDef(bridge, vparamss => gen.mkForwarder(superRef, vparamss)) + DefDef(bridge, gen.mkForwarder(superRef, bridge.paramss)) } /** Replace definitions of virtual classes by definitions of corresponding @@ -526,13 +526,13 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { val pfield = paramField(sym.owner, paramFieldCount) paramFieldCount += 1 pfield setPos pacc.pos - paramFields += localTyper.typed(DefDef(pfield, vparamss => EmptyTree)) + paramFields += localTyper.typed(DefDef(pfield, EmptyTree)) val pfieldRef = localTyper.typed { atPos(pacc.pos) { Select(This(sym.owner), pfield) } } - paramFieldAccessors += copy.ValDef(pacc, mods, name, tpt, pfieldRef) + paramFieldAccessors += treeCopy.ValDef(pacc, mods, name, tpt, pfieldRef) case _ => stat.symbol resetFlag PARAMACCESSOR // ??? can we do this others += stat @@ -540,11 +540,11 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { else (if (stat.symbol != null && (stat.symbol hasFlag PRESUPER)) presupers else others) += stat } - copy.Template(tree, parents, self, - paramFieldAccessors.toList ::: - presupers.toList ::: - paramFields.toList ::: - others.toList) + treeCopy.Template(tree, parents, self, + paramFieldAccessors.toList ::: + presupers.toList ::: + paramFields.toList ::: + others.toList) case _ => tree setType atPhase(ownPhase)(devirtualizeMap(tree.tpe)) } diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index f7c8e6d528..68f486a600 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -80,11 +80,11 @@ trait EtaExpansion { self: Analyzer => } tree match { case Apply(fn, args) => - copy.Apply(tree, liftoutPrefix(fn), List.mapConserve(args)(liftout)) setType null + treeCopy.Apply(tree, liftoutPrefix(fn), List.mapConserve(args)(liftout)) setType null case TypeApply(fn, args) => - copy.TypeApply(tree, liftoutPrefix(fn), args) setType null + treeCopy.TypeApply(tree, liftoutPrefix(fn), args) setType null case Select(qual, name) => - copy.Select(tree, liftout(qual), name) setSymbol NoSymbol setType null + treeCopy.Select(tree, liftout(qual), name) setSymbol NoSymbol setType null case Ident(name) => tree } @@ -99,14 +99,14 @@ trait EtaExpansion { self: Analyzer => def expand(tree: Tree, tpe: Type): Tree = tpe match { case mt: ImplicitMethodType => tree - case MethodType(formals, restpe) => + case MethodType(paramSyms, restpe) => var cnt0 = 0 def cnt = { cnt0 += 1 cnt0 - 1 } - val params = formals map (formal => - ValDef(Modifiers(SYNTHETIC | PARAM), freshName(tree.pos, cnt), TypeTree(formal), EmptyTree)) + val params = paramSyms map (sym => + ValDef(Modifiers(SYNTHETIC | PARAM), sym.name, TypeTree(sym.tpe), EmptyTree)) atPos(tree.pos)(Function(params, expand(Apply(tree, params map gen.paramToArg), restpe))) //atPos(tree.pos)(Function(params, expand(Apply(tree, args), restpe))) case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 81c1acb3be..b41aff1155 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -158,7 +158,7 @@ self: Analyzer => */ private def containsError(tp: Type): Boolean = tp match { case PolyType(tparams, restpe) => containsError(restpe) - case MethodType(formals, restpe) => (formals exists (_.isError)) || containsError(restpe) + case MethodType(params, restpe) => (params map (_.tpe) exists (_.isError)) || containsError(restpe) case _ => tp.isError } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 9bec522e0c..7a340176d9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -37,15 +37,20 @@ trait Infer { /** The formal parameter types corresponding to formals. * If formals has a repeated last parameter, a list of * (nargs - params.length + 1) copies of its type is returned. + * By-name types are replaced with their underlying type. * * @param formals ... * @param nargs ... */ - def formalTypes(formals: List[Type], nargs: Int): List[Type] = { - val formals1 = formals map { + def formalTypes(formals: List[Type], nargs: Int): List[Type] = + formalTypes(formals, nargs, true) + + /** This variant allows keeping ByName parameters. Useed in NamesDefaults. */ + def formalTypes(formals: List[Type], nargs: Int, removeByName: Boolean): List[Type] = { + val formals1 = if (removeByName) formals map { case TypeRef(_, sym, List(arg)) if (sym == ByNameParamClass) => arg case formal => formal - } + } else formals if (isVarArgs(formals1)) { val ft = formals1.last.normalize.typeArgs.head formals1.init ::: (for (i <- List.range(formals1.length - 1, nargs)) yield ft) @@ -173,9 +178,9 @@ trait Infer { * Implicit parameters are skipped. */ def normalize(tp: Type): Type = skipImplicit(tp) match { - case MethodType(formals, restpe) if (!restpe.isDependent) => + case MethodType(params, restpe) if (!restpe.isDependent) => if (util.Statistics.enabled) normM += 1 - functionType(formals, normalize(restpe)) + functionType(params map (_.tpe), normalize(restpe)) case PolyType(List(), restpe) => if (util.Statistics.enabled) normP += 1 normalize(restpe) @@ -392,7 +397,8 @@ trait Infer { isPlausiblyCompatible(mt.resultType, pt) case ExistentialType(tparams, qtpe) => isPlausiblyCompatible(qtpe, pt) - case MethodType(formals, _) => + case MethodType(params, _) => + val formals = tp.paramTypes pt.normalize match { case TypeRef(pre, sym, args) => !sym.isClass || { @@ -458,7 +464,7 @@ trait Infer { // See test pos/jesper.scala val varianceType = restpe match { case mt: ImplicitMethodType if isFullyDefined(pt) => - MethodType(mt.paramTypes, AnyClass.tpe) + MethodType(mt.params, AnyClass.tpe) case _ => restpe } @@ -543,6 +549,8 @@ trait Infer { * Undetermined type arguments are represented by `definitions.NothingClass.tpe'. * No check that inferred parameters conform to their bounds is made here. * + * bq: was private, but need it for unapply checking + * * @param tparams the type parameters of the method * @param formals the value parameter types of the method * @param restp the result type of the method @@ -556,7 +564,6 @@ trait Infer { * @return ... * @throws NoInstance */ - // bq: was private, but need it for unapply checking def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type, argtpes: List[Type], pt: Type, uninstantiated: ListBuffer[Symbol]): List[Type] = { @@ -612,14 +619,60 @@ trait Infer { case _ => formalTypes(tp.paramTypes, n).length == n } + /** + * Verifies whether the named application is valid. The logic is very + * similar to the one in NamesDefaults.removeNames. + * + * @return a triple (argtpes1, argPos, namesOk) where + * - argtpes1 the argument types in named application (assignments to + * non-parameter names are treated as assignments, i.e. type Unit) + * - argPos a Function1[Int, Int] mapping arguments from their current + * to the corresponding position in params + * - namesOK is false when there's an invalid use of named arguments + */ + private def checkNames(argtpes: List[Type], params: List[Symbol]) = { + val argPos = (new Array[Int](argtpes.length)) map (x => -1) + var positionalAllowed = true + var namesOK = true + var index = 0 + val argtpes1 = argtpes map { + case NamedType(name, tp) => // a named argument + var res = tp + val pos = params.findIndexOf(p => p.name == name && !p.hasFlag(SYNTHETIC)) + if (pos == -1) { + if (positionalAllowed) { // treat assignment as positional argument + argPos(index) = index + res = UnitClass.tpe + } else // unknown parameter name + namesOK = false + } else if (argPos.contains(pos)) { // parameter specified twice + namesOK = false + } else { + positionalAllowed = false + argPos(index) = pos + } + index += 1 + res + case tp => // a positional argument + argPos(index) = index + if (!positionalAllowed) + namesOK = false // positional after named + index += 1 + tp + } + (argtpes1, argPos, namesOK) + } /** Is there an instantiation of free type variables undetparams * such that function type ftpe is applicable to * argtpes and its result conform to pt? * * @param undetparams ... - * @param ftpe ... - * @param argtpes ... + * @param ftpe the type of the function (often a MethodType) + * @param argtpes the argument types; a NamedType(name, tp) for named + * arguments. For each NamedType, if `name' does not exist in `ftpe', that + * type is set to `Unit', i.e. the corresponding argument is treated as + * an assignment expression (@see checkNames). * @param pt ... * @return ... */ @@ -630,24 +683,75 @@ trait Infer { alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt)) case ExistentialType(tparams, qtpe) => isApplicable(undetparams, qtpe, argtpes0, pt) - case MethodType(formals0, _) => - val formals = formalTypes(formals0, argtpes0.length) - val argtpes = actualTypes(argtpes0, formals.length) - val restpe = ftpe.resultType(argtpes) - if (undetparams.isEmpty) { - (formals.length == argtpes.length && - isCompatible(argtpes, formals) && - isWeaklyCompatible(restpe, pt)) + case MethodType(params, _) => + // repeat varargs as needed, remove ByName + val formals = formalTypes(params map (_.tpe), argtpes0.length) + + def tryTupleApply: Boolean = { + // if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0 + val tupleArgTpe = actualTypes(argtpes0 map { + // no assignment is treated as named argument here + case NamedType(name, tp) => UnitClass.tpe + case tp => tp + }, formals.length) + + argtpes0.length != tupleArgTpe.length && + isApplicable(undetparams, ftpe, tupleArgTpe, pt) + } + def typesCompatible(argtpes: List[Type]) = { + val restpe = ftpe.resultType(argtpes) + if (undetparams.isEmpty) { + (isCompatible(argtpes, formals) && + isWeaklyCompatible(restpe, pt)) + } else { + try { + val uninstantiated = new ListBuffer[Symbol] + val targs = methTypeArgs(undetparams, formals, restpe, argtpes, pt, uninstantiated) + (exprTypeArgs(uninstantiated.toList, restpe.instantiateTypeParams(undetparams, targs), pt) ne null) && + isWithinBounds(NoPrefix, NoSymbol, undetparams, targs) + } catch { + case ex: NoInstance => false + } + } + } + + // very similar logic to doTypedApply in typechecker + if (argtpes0.length > formals.length) tryTupleApply + else if (argtpes0.length == formals.length) { + if (!argtpes0.exists(_.isInstanceOf[NamedType])) { + // fast track if no named arguments are used + typesCompatible(argtpes0) + } else { + // named arguments are used + val (argtpes1, argPos, namesOK) = checkNames(argtpes0, params) + if (!namesOK) false + // when using named application, the vararg param has to be specified exactly once + else if (!isIdentity(argPos) && (formals.length != params.length)) false + else { + // nb. arguments and names are OK, check if types are compatible + typesCompatible(reorderArgs(argtpes1, argPos)) + } + } } else { - try { - val uninstantiated = new ListBuffer[Symbol] - val targs = methTypeArgs(undetparams, formals, restpe, argtpes, pt, uninstantiated) - (exprTypeArgs(uninstantiated.toList, restpe.instantiateTypeParams(undetparams, targs), pt) ne null) && - isWithinBounds(NoPrefix, NoSymbol, undetparams, targs) - } catch { - case ex: NoInstance => false + // not enough arguments, check if applicable using defaults + val namedArgtpes = argtpes0.dropWhile { + case NamedType(name, _) => params.forall(_.name != name) + case _ => true + } + val namedParams = params.drop(argtpes0.length - namedArgtpes.length) + val missingParams = namedParams.filter(p => namedArgtpes.forall { + case NamedType(name, _) => name != p.name + case _ => true + }) + if (missingParams.exists(!_.hasFlag(DEFAULTPARAM))) tryTupleApply + else { + val argtpes1 = argtpes0 ::: missingParams.map { + p => NamedType(p.name, p.tpe) // add defaults as named arguments + } + isApplicable(undetparams, ftpe, argtpes1, pt) } } + case PolyType(tparams, restpe) => val tparams1 = cloneSymbols(tparams) isApplicable(tparams1 ::: undetparams, restpe.substSym(tparams, tparams1), argtpes0, pt) @@ -657,7 +761,8 @@ trait Infer { false } - private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = { + private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type, + argtpes0: List[Type], pt: Type): Boolean = { val reportAmbiguousErrors = context.reportAmbiguousErrors context.reportAmbiguousErrors = false try { @@ -683,10 +788,10 @@ trait Infer { alts exists (alt => isAsSpecific(pre.memberType(alt), ftpe2)) case et: ExistentialType => et.withTypeVars(isAsSpecific(_, ftpe2)) // !!! why isStrictly? - case MethodType(formals @ (x :: xs), _) => - isApplicable(List(), ftpe2, formals, WildcardType) - case PolyType(_, MethodType(formals @ (x :: xs), _)) => - isApplicable(List(), ftpe2, formals, WildcardType) + case MethodType(params @ (x :: xs), _) => + isApplicable(List(), ftpe2, params map (_.tpe), WildcardType) + case PolyType(_, MethodType(params @ (x :: xs), _)) => + isApplicable(List(), ftpe2, params map (_.tpe), WildcardType) case ErrorType => true case _ => @@ -1014,7 +1119,7 @@ trait Infer { */ def inferMethodInstance(fn: Tree, undetparams: List[Symbol], args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match { - case MethodType(formals0, _) => + case MethodType(params0, _) => if (inferInfo) println("infer method instance "+fn+"\n"+ " undetparams = "+undetparams+"\n"+ @@ -1022,7 +1127,7 @@ trait Infer { " pt = "+pt0) try { val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 - val formals = formalTypes(formals0, args.length) + val formals = formalTypes(params0 map (_.tpe), args.length) val argtpes = actualTypes(args map (_.tpe.deconst), formals.length) val restpe = fn.tpe.resultType(argtpes) val uninstantiated = new ListBuffer[Symbol] @@ -1393,24 +1498,57 @@ trait Infer { /** Assign tree the type of an alternative which is applicable * to argtpes, and whose result type is compatible with `pt'. - * If several applicable alternatives exist, take the - * most specialized one. + * If several applicable alternatives exist, drop the alternatives which use + * default arguments, then select the most specialized one. * If no applicable alternative exists, and pt != WildcardType, try again * with pt = WildcardType. * Otherwise, if there is no best alternative, error. + * + * @param argtpes contains the argument types. If an argument is named, as + * "a = 3", the corresponding type is `NamedType("a", Int)'. If the name + * of some NamedType does not exist in an alternative's parameter names, + * the type is replaces by `Unit', i.e. the argument is treated as an + * assignment expression. */ - def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt0: Type): Unit = tree.tpe match { + def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], + argtpes: List[Type], pt0: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 tryTwice { - if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt) - val applicable = alts filter (alt => isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) + if (settings.debug.value) + log("infer method alt "+ tree.symbol +" with alternatives "+ + (alts map pre.memberType) +", argtpes = "+ argtpes +", pt = "+ pt) + + val allApplicable = alts filter (alt => + isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) + + // if there are multiple, drop those that use a default + // (keep those that use vararg / tupling conversion) + val applicable = + if (allApplicable.length <= 1) allApplicable + else allApplicable filter (alt => { + val mtypes = followApply(alt.tpe) match { + case OverloadedType(_, alts) => + // for functional values, the `apply' method might be overloaded + alts map (_.tpe) + case t => List(t) + } + mtypes.exists(t => t.paramTypes.length < argtpes.length || // tupling (*) + hasExactlyNumParams(t, argtpes.length)) // same nb or vararg + // (*) more arguments than parameters, but still applicable: tuplig conversion works. + // todo: should not return "false" when paramTypes = (Unit) no argument is given + // (tupling would work) + }) + + def improves(sym1: Symbol, sym2: Symbol) = sym2 == NoSymbol || sym2.isError || - isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), followApply(pre.memberType(sym2)), sym1, sym2) + isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), + followApply(pre.memberType(sym2)), sym1, sym2) + val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) => if (improves(alt, best)) alt else best) - val competing = applicable dropWhile (alt => best == alt || improves(best, alt)) + val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { if (pt == WildcardType) { errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index ff60039e1f..d9dc0969f4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -44,10 +44,24 @@ trait Namers { self: Analyzer => private class NormalNamer(context : Context) extends Namer(context) def newNamer(context : Context) : Namer = new NormalNamer(context) + // In the typeCompleter (templateSig) of a case class (resp it's module), + // synthetic `copy' (reps `apply', `unapply') methods are added. To compute + // their signatures, the corresponding ClassDef is needed. + // During naming, for each case class module symbol, the corresponding ClassDef + // is stored in this map. private[typechecker] val caseClassOfModuleClass = new HashMap[Symbol, ClassDef] + // Default getters of constructors are added to the companion object in the + // typeCompleter of the constructor (methodSig). To compute the signature, + // we need the ClassDef. To create and enter the symbols into the companion + // object, we need the templateNamer of that module class. + // This map is extended during naming of classes, the Namer is added in when + // it's available, i.e. in the type completer (templateSig) of the module class. + private[typechecker] val classAndNamerOfModule = new HashMap[Symbol, (ClassDef, Namer)] + def resetNamer() { caseClassOfModuleClass.clear + classAndNamerOfModule.clear } abstract class Namer(val context: Context) { @@ -266,10 +280,10 @@ trait Namers { self: Analyzer => * class definition tree. * @return the companion object symbol. */ - def ensureCompanionObject(tree: ClassDef, creator: ClassDef => Tree): Symbol = { + def ensureCompanionObject(tree: ClassDef, creator: => Tree): Symbol = { val m: Symbol = context.scope.lookupWithContext(tree.name.toTermName)(context.owner).filter(! _.isSourceMethod) if (m.isModule && inCurrentScope(m) && currentRun.compiles(m)) m - else enterSyntheticSym(creator(tree)) + else enterSyntheticSym(creator) } def enterSym(tree: Tree): Context = try { @@ -284,10 +298,26 @@ trait Namers { self: Analyzer => //@M x is only in scope in `A[x <: B]' if(!sym.isAbstractType) //@M TODO: change to isTypeMember ? newNamer(context.makeNewScope(tree, sym)(FinishWithScopeKind)).enterSyms(tparams) + ltype = new PolyTypeCompleter(tparams, ltype, tree, sym, context) //@M if (sym.isTerm) skolemize(tparams) } - setInfo(sym)(ltype) + if ((sym.name == nme.copy || sym.name.startsWith(nme.copy + "$default$")) && + sym.hasFlag(SYNTHETIC)) { + // the 'copy' method of case classes needs a special type completer to make bug0054.scala (and others) + // work. the copy method has to take exactly the same parameter types as the primary constructor. + setInfo(sym)(mkTypeCompleter(tree)(copySym => { + val constrType = copySym.owner.primaryConstructor.tpe + val subst = new SubstSymMap(copySym.owner.typeParams, tparams map (_.symbol)) + for ((params, cparams) <- tree.asInstanceOf[DefDef].vparamss.zip(constrType.paramss); + (param, cparam) <- params.zip(cparams)) { + // need to clone the type cparam.tpe??? problem is: we don't have the new owner yet (the new param symbol) + param.tpt.setType(subst(cparam.tpe)) + () // @LUC TODO workaround for #1996 + } + ltype.complete(sym) + })) + } else setInfo(sym)(ltype) } def finish = finishWith(List()) @@ -303,9 +333,21 @@ trait Namers { self: Analyzer => tree.symbol = enterClassSymbol(tree) finishWith(tparams) if ((mods.flags & CASE) != 0) { - val m = ensureCompanionObject(tree, caseModuleDef) + val m = ensureCompanionObject(tree, caseModuleDef(tree)) caseClassOfModuleClass(m.moduleClass) = tree } + val constrs = impl.body filter { + case DefDef(_, name, _, _, _, _) => name == nme.CONSTRUCTOR + case _ => false + } + val hasDefault = constrs.exists(c => { + val DefDef(_, _, _, vparamss, _, _) = c + vparamss.exists(_.exists(_.mods hasFlag DEFAULTPARAM)) + }) + if (hasDefault) { + val m = ensureCompanionObject(tree, companionModuleDef(tree, List(gen.scalaScalaObjectConstr))) + classAndNamerOfModule(m) = (tree, null) + } case tree @ ModuleDef(mods, name, _) => tree.symbol = enterModuleSymbol(tree) tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter((tree))) @@ -440,9 +482,10 @@ trait Namers { self: Analyzer => } def setterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => - if (settings.debug.value) log("defining " + sym); - sym.setInfo(MethodType(List(typeSig(tree)), UnitClass.tpe)) - if (settings.debug.value) log("defined " + sym); + if (settings.debug.value) log("defining " + sym) + val param = sym.newSyntheticValueParam(typeSig(tree)) + sym.setInfo(MethodType(List(param), UnitClass.tpe)) + if (settings.debug.value) log("defined " + sym) validate(sym) } @@ -478,12 +521,13 @@ trait Namers { self: Analyzer => else tpe } + // sets each ValDef's symbol def enterValueParams(owner: Symbol, vparamss: List[List[ValDef]]): List[List[Symbol]] = { def enterValueParam(param: ValDef): Symbol = { param.symbol = setInfo( enterInScope{ val sym = owner.newValueParameter(param.pos, param.name). - setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) + setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT | DEFAULTPARAM)) setPrivateWithin(param, sym, param.mods) })(typeCompleter(param)) param.symbol @@ -595,24 +639,49 @@ trait Namers { self: Analyzer => */ // add apply and unapply methods to companion objects of case classes, - // unless they exist already + // unless they exist already; here, "clazz" is the module class Namers.this.caseClassOfModuleClass get clazz match { case Some(cdef) => addApplyUnapply(cdef, templateNamer) caseClassOfModuleClass -= clazz case None => } + + // add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because + // the namer phase must traverse this copy method to create default getters for its parameters. + Namers.this.caseClassOfModuleClass get clazz.linkedModuleOfClass.moduleClass match { + case Some(cdef) => + def hasCopy(decls: Scope) = { + decls.elements exists (_.name == nme.copy) + } + if (!hasCopy(decls) && + !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) && + !parents.flatMap(_.baseClasses).removeDuplicates.exists(bc => hasCopy(bc.info.decls))) + addCopyMethod(cdef, templateNamer) + case None => + } + + // if default getters (for constructor defaults) need to be added to that module, + // here's the namer to use + val module = clazz.sourceModule + if (classAndNamerOfModule contains module) { + val (cdef, _) = classAndNamerOfModule(module) + classAndNamerOfModule(module) = (cdef, templateNamer) + } + ClassInfoType(parents, decls, clazz) } private def classSig(tparams: List[TypeDef], impl: Template): Type = polyType(typer.reenterTypeParams(tparams), templateSig(impl)) - private def methodSig(tparams: List[TypeDef], vparamss: List[List[ValDef]], - tpt: Tree, rhs: Tree): Type = { + private def methodSig(mods: Modifiers, tparams: List[TypeDef], + vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): Type = { val meth = context.owner + // enters the skolemized version into scope, returns the deSkolemized symbols val tparamSyms = typer.reenterTypeParams(tparams) + // since the skolemized tparams are in scope, the TypeRefs in vparamSymss refer to skolemized tparams var vparamSymss = enterValueParams(meth, vparamss) if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) { @@ -624,8 +693,8 @@ trait Namers { self: Analyzer => methodArgumentNames(meth) = vparamss.map(_.map(_.symbol)); def convertToDeBruijn(vparams: List[Symbol], level: Int): TypeMap = new TypeMap { - def debruijnFor(param: Symbol) = - DeBruijnIndex(level, vparams indexOf param) + def debruijnFor(param: Symbol) = + DeBruijnIndex(level, vparams indexOf param) def apply(tp: Type) = { tp match { case SingleType(_, sym) => @@ -636,35 +705,38 @@ trait Namers { self: Analyzer => ErrorType } else */ - debruijnFor(sym) + debruijnFor(sym) } else tp - case MethodType(formals, restpe) => - val formals1 = List.mapConserve(formals)(this) + case MethodType(params, restpe) => + val params1 = this.mapOver(params) val restpe1 = convertToDeBruijn(vparams, level + 1)(restpe) - if ((formals1 eq formals) && (restpe1 eq restpe)) tp - else copyMethodType(tp, formals1, restpe1) + if ((params1 eq params) && (restpe1 eq restpe)) tp + else copyMethodType(tp, params1, restpe1) case _ => mapOver(tp) } } - object treeTrans extends TypeMapTransformer { - override def transform(tree: Tree): Tree = - tree match { - case Ident(name) if (vparams contains tree.symbol) => - val dtpe = debruijnFor(tree.symbol) - val dsym = - newLocalDummy(context.owner, tree.symbol.pos) - .newValue(tree.symbol.pos, name) - - dsym.setFlag(PARAM) - dsym.setInfo(dtpe) - Ident(name).setSymbol(dsym).copyAttrs(tree).setType(dtpe) - case tree => super.transform(tree) - } - } - - override def mapOver(arg: Tree) = Some(treeTrans.transform(arg)) + // AnnotatedTypes can contain trees in the AnnotationArguments. When accessing a + // parameter in an annotation, set the type of the Ident to the DeBruijnIndex + object treeTrans extends TypeMapTransformer { + override def transform(tree: Tree): Tree = + tree match { + case Ident(name) if (vparams contains tree.symbol) => + val dtpe = debruijnFor(tree.symbol) + val dsym = + newLocalDummy(context.owner, tree.symbol.pos) + .newValue(tree.symbol.pos, name) + + dsym.setFlag(PARAM) + dsym.setInfo(dtpe) + Ident(name).setSymbol(dsym).copyAttrs(tree).setType(dtpe) + case tree => super.transform(tree) + } + } + + // for type annotations (which may contain trees) + override def mapOver(arg: Tree) = Some(treeTrans.transform(arg)) } val checkDependencies: TypeTraverser = new TypeTraverser { @@ -685,27 +757,44 @@ trait Namers { self: Analyzer => } } + /** Called for all value parameter lists, right to left + * @param vparams the symbols of one parameter list + * @param restpe the result type (possibly a MethodType) + */ def makeMethodType(vparams: List[Symbol], restpe: Type) = { - val formals = vparams map (vparam => - if (meth hasFlag JAVA) objToAny(vparam.tpe) else vparam.tpe) - val restpe1 = convertToDeBruijn(vparams, 1)(restpe) + // new dependent method types: probably OK already, since 'enterValueParams' above + // enters them in scope, and all have a lazy type. so they may depend on other params. but: need to + // check that params only depend on ones in earlier sections, not the same. (done by checkDependencies, + // so re-use / adapt that) + val params = vparams map (vparam => + if (meth hasFlag JAVA) vparam.setInfo(objToAny(vparam.tpe)) else vparam) + val restpe1 = convertToDeBruijn(vparams, 1)(restpe) // new dependent types: replace symbols in restpe with the ones in vparams if (!vparams.isEmpty && vparams.head.hasFlag(IMPLICIT)) - ImplicitMethodType(formals, restpe1) - else if (meth hasFlag JAVA) JavaMethodType(formals, restpe1) - else MethodType(formals, restpe1) + ImplicitMethodType(params, restpe1) + else if (meth hasFlag JAVA) JavaMethodType(params, restpe1) + else MethodType(params, restpe1) } def thisMethodType(restpe: Type) = polyType( - tparamSyms, + tparamSyms, // deSkolemized symbols if (vparamSymss.isEmpty) PolyType(List(), restpe) + // vparamss refer (if they do) to skolemized tparams else checkDependencies((vparamSymss :\ restpe) (makeMethodType))) var resultPt = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe val site = meth.owner.thisType - def overriddenSymbol = intersectionType(meth.owner.info.parents).member(meth.name).filter(sym => - sym != NoSymbol && (site.memberType(sym) matches thisMethodType(resultPt))) + def overriddenSymbol = intersectionType(meth.owner.info.parents).member(meth.name).filter(sym => { + // luc: added .syubstSym from skolemized to deSkolemized + // site.memberType(sym): PolyType(tparams, MethodType(..., ...)) ==> all references to tparams are deSkolemized + // thisMethodType: tparams in PolyType are deSkolemized, the references in the MethodTypes are skolemized. ==> the two didn't match + // for instance, B.foo would not override A.foo, and the default on parameter b would not be inherited + // class A { def foo[T](a: T)(b: T = a) = a } + // class B extends A { override def foo[U](a: U)(b: U) = b } + // (new B).foo(1)() + sym != NoSymbol && (site.memberType(sym) matches thisMethodType(resultPt).substSym(tparams map (_.symbol), tparamSyms)) + }) // fill in result type and parameter types from overridden symbol if there is a unique one. if (meth.owner.isClass && (tpt.isEmpty || vparamss.exists(_.exists(_.tpt.isEmpty)))) { @@ -743,7 +832,7 @@ trait Namers { self: Analyzer => } } } - // Add a () parameter section if this overrides dome method with () parameters. + // Add a () parameter section if this overrides some method with () parameters. if (meth.owner.isClass && vparamss.isEmpty && overriddenSymbol.alternatives.exists( _.info.isInstanceOf[MethodType])) { vparamSymss = List(List()) @@ -753,9 +842,104 @@ trait Namers { self: Analyzer => vparam.tpt.tpe = ErrorType } + + // add the getter methods for default arguments. + + /** Adding the "override" and "defaultparam" (for inherited defaults) flags + * has to be done here. Typer is too late, if an inherited default is used + * before the method is typechecked, the corresponding param would not yet + * have the "defaultparam" flag. + */ + val isConstr = meth.isConstructor + val overridden = if (isConstr || !meth.owner.isClass) NoSymbol + else overriddenSymbol + val overrides = overridden != NoSymbol && !(overridden hasFlag OVERLOADED) + // value parameters of the base class (whose defaults might be overridden) + var baseParamss = overridden.tpe.paramss + // match empty and missing parameter list + if (vparamss.isEmpty && baseParamss == List(Nil)) baseParamss = Nil + if (vparamss == List(Nil) && baseParamss.isEmpty) baseParamss = List(Nil) + assert(!overrides || vparamss.length == baseParamss.length, ""+ meth.fullNameString + ", "+ overridden.fullNameString) + + var ownerNamer: Option[Namer] = None + var moduleNamer: Option[(ClassDef, Namer)] = None + + var posCounter = 1 + + // for each value parameter, create the getter method if it has a default argument. previous + // denotes the parameter lists which are on the left side of the current one. these get added + // to the default getter. Example: "def foo(a: Int)(b: Int = a)" gives "foo$default$1(a: Int) = a" + (List[List[ValDef]]() /: (vparamss))((previous: List[List[ValDef]], vparams: List[ValDef]) => { + assert(!overrides || vparams.length == baseParamss.head.length, ""+ meth.fullNameString + ", "+ overridden.fullNameString) + var baseParams = if (overrides) baseParamss.head else Nil + for (vparam <- vparams) { + val sym = vparam.symbol + // true if the corresponding parameter of the base class has a default argument + val baseHasDefault = overrides && (baseParams.head hasFlag DEFAULTPARAM) + if (sym hasFlag DEFAULTPARAM) { + // generate a default getter for that argument + val oflag = if (baseHasDefault) OVERRIDE else 0 + val name = (if (isConstr) "init" else meth.name) +"$default$"+ posCounter + + // Create trees for the defaultGetter. Uses tools from Unapplies.scala + var deftParams = tparams map copyUntyped[TypeDef] + val defvParamss = previous map (_.map(p => { + // in the default getter, remove the default parameter + val p1 = atPos(p.pos) { ValDef(p.mods &~ DEFAULTPARAM, p.name, p.tpt.duplicate, EmptyTree) } + UnTyper.traverse(p1) + p1 + })) + // let the compiler infer the return type of the defaultGetter. needed in "foo[T](a: T = 1)" + val defTpt = TypeTree() + val defRhs = copyUntyped(vparam.rhs) + + val parentNamer = if (isConstr) { + val (cdef, nmr) = moduleNamer.getOrElse { + val module = meth.owner.linkedModuleOfClass + module.initialize // call type completer (typedTemplate), adds the + // module's templateNamer to classAndNamerOfModule + val (cdef, nmr) = classAndNamerOfModule(module) + moduleNamer = Some(cdef, nmr) + (cdef, nmr) + } + deftParams = cdef.tparams map copyUntypedInvariant + nmr + } else { + ownerNamer.getOrElse { + val ctx = context.nextEnclosing(c => c.scope.toList.contains(meth)) + assert(ctx != NoContext) + val nmr = newNamer(ctx) + ownerNamer = Some(nmr) + nmr + } + } + + val defaultTree = atPos(vparam.pos) { + DefDef( + Modifiers(meth.flags & (PRIVATE | PROTECTED | FINAL)) | SYNTHETIC | DEFAULTPARAM | oflag, + name, deftParams, defvParamss, defTpt, defRhs) + } + meth.owner.resetFlag(INTERFACE) + val default = parentNamer.enterSyntheticSym(defaultTree) + sym.defaultGetter = default + } else if (baseHasDefault) { + // the parameter does not have a default itself, but the corresponding parameter + // in the base class does. + sym.setFlag(DEFAULTPARAM) + sym.defaultGetter = baseParams.head.defaultGetter + } + posCounter += 1 + if (overrides) baseParams = baseParams.tail + } + if (overrides) baseParamss = baseParamss.tail + previous ::: List(vparams) + }) + thisMethodType( if (tpt.isEmpty) { + // replace deSkolemized symbols with skolemized ones (for resultPt computed by looking at overridden symbol, right?) val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol)) + // compute result type from rhs tpt.tpe = widenIfNotFinal(meth, typer.computeType(rhs, pt), pt) tpt setPos meth.pos tpt.tpe @@ -794,20 +978,16 @@ trait Namers { self: Analyzer => } /** Given a case class - * * case class C[Ts] (ps: Us) - * * Add the following methods to toScope: - * * 1. if case class is not abstract, add - * * def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps) - * * 2. add a method - * * def unapply[Ts](x: C[Ts]) = - * * where is the caseClassUnapplyReturnValue of class C (see UnApplies.scala) + * + * @param cdef is the class definition of the case class + * @param namer is the namer of the module class (the comp. obj) */ def addApplyUnapply(cdef: ClassDef, namer: Namer) { if (!(cdef.symbol hasFlag ABSTRACT)) @@ -815,8 +995,14 @@ trait Namers { self: Analyzer => namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef)) } + def addCopyMethod(cdef: ClassDef, namer: Namer) { + caseClassCopyMeth(cdef) foreach (namer.enterSyntheticSym(_)) + } + def typeSig(tree: Tree): Type = { val sym: Symbol = tree.symbol + // For definitions, transform Annotation trees to AnnotationInfos, assign + // them to the sym's attributes. Type annotations: see Typer.typedAnnotated tree match { case defn: MemberDef => val ainfos = for { @@ -843,9 +1029,8 @@ trait Namers { self: Analyzer => //clazz.typeOfThis = singleType(sym.owner.thisType, sym); clazz.tpe - case DefDef(_, _, tparams, vparamss, tpt, rhs) => - //val result = - newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs) + case DefDef(mods, _, tparams, vparamss, tpt, rhs) => + newNamer(context.makeNewScope(tree, sym)).methodSig(mods, tparams, vparamss, tpt, rhs) case vdef @ ValDef(mods, _, tpt, rhs) => val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala new file mode 100644 index 0000000000..55a409775b --- /dev/null +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -0,0 +1,376 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2009 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: NamesDefaults.scala 17081 2009-02-10 17:45:38Z rytz $ + +package scala.tools.nsc.typechecker + +import scala.collection.mutable.ListBuffer + import symtab.Flags._ + +/** + * @author Lukas Rytz + * @version 1.0 + */ +trait NamesDefaults { self: Analyzer => + + import global._ + import definitions._ + + case class NamedApplyInfo(qual: Option[Tree], targs: List[Tree], + vargss: List[List[Tree]], blockTyper: Typer) + val noApplyInfo = NamedApplyInfo(None, Nil, Nil, null) + + def nameOf(arg: Tree) = arg match { + case Assign(Ident(name), rhs) => Some(name) + case _ => None + } + def isNamed(arg: Tree) = nameOf(arg).isDefined + + + /** @param pos maps indicies from old to new */ + def reorderArgs[T](args: List[T], pos: Int => Int): List[T] = { + val res = new Array[T](args.length) + // (hopefully) faster than zipWithIndex + (0 /: args) { case (index, arg) => res(pos(index)) = arg; index + 1 } + res.toList + } + + /** @param pos maps indicies from new to old (!) */ + def reorderArgsInv[T](args: List[T], pos: Int => Int): List[T] = { + val argsArray = args.toArray + val res = new ListBuffer[T] + for (i <- 0 until argsArray.length) + res += argsArray(pos(i)) + res.toList + } + + /** returns `true' if every element is equal to its index */ + def isIdentity(a: Array[Int]) = (0 until a.length).forall(i => a(i) == i) + + /** + * Transform a function application into a Block, and assigns typer.context + * .namedApplyBlockInfo to the new block as side-effect. If tree has the form + * Apply(fun, args) + * first the function "fun" (which might be an application itself!) is transformed into a + * block of the form + * { + * val qual$1 = qualifier_of_fun + * val x$1 = arg_1_of_fun + * ... + * val x$n = arg_n_of_fun + * qual$1.fun[targs](x$1, ...)...(..., x$n) + * } + * then for each argument in args, a value is created and entered into the block. finally + * the application expression of the block is updated. + * { + * val qual$1 = .. + * ... + * val x$n = ... + * > val qual$n+1 = arg(1) + * > ... + * > val qual$n+m = arg(m) + * > qual$1.fun[targs](x$1, ...)...(..., x$n)(x$n+1, ..., x$n+m) + * } + * + * @param typer the typer calling this method; this method calls + * typer.doTypedApply + * @param mode the mode to use for calling typer.doTypedApply + * @param pt the expected type for calling typer.doTypedApply + * + * @param tree: the function application tree + * @argPos: a function mapping arguments from their current position to the + * position specified by the method type. example: + * def foo(a: Int, b: String) + * foo(b = "1", a = 2) + * calls + * transformNamedApplication(Apply(foo, List("1", 2), { 0 => 1, 1 => 0 }) + * + * @return the transformed application (a Block) together with the NamedApplyInfo. + * if isNamedApplyBlock(tree), returns the existing context.namedApplyBlockInfo + */ + def transformNamedApplication(typer: Typer, mode: Int, pt: Type) + (tree: Tree, argPos: Int => Int): Tree = { + import typer._ + import typer.infer._ + val context = typer.context + import context.unit + + /** + * Transform a function into a block, and assing context.namedApplyBlockInfo to + * the new block as side-effect. + * Fun is transformed in the following way: + * - Ident(f) ==> Block(Nil, Ident(f)) + * - Select(qual, f) if (qual is stable) ==> Block(Nil, Select(qual, f)) + * - Select(qual, f) otherwise ==> Block(ValDef(qual$1, qual), Select(qual$1, f)) + * - TypeApply(fun, targs) ==> Block(Nil or qual$1, TypeApply(fun, targs)) + * - Select(New(TypeTree()), ) ==> Block(Nil, Select(New(TypeTree()), )) + * - Select(New(Select(qual, typeName)), ) if (qual is stable) + * ==> Block(Nil, Select(...)) + * - Select(New(Select(qual, typeName)), ) otherwise + * ==> Block(ValDef(qual$1, qual), Select(New(Select(qual$1, typeName)), )) + */ + def baseFunBlock(baseFun: Tree): Tree = { + val isConstr = baseFun.symbol.isConstructor + val blockTyper = newTyper(context.makeNewScope(tree, context.owner)(BlockScopeKind(context.depth))) + + // baseFun1: the extract the function from a potential TypeApply + // defaultTargs: type arguments to be used for calling defaultGetters + // funTargs: type arguments on baseFun, used to reconstruct TypeApply in blockWith(Out)Qualifier + val (baseFun1, defaultTargs, funTargs) = baseFun match { + case TypeApply(fun, targs) => + val targsInSource = + if (targs.forall(a => context.undetparams contains a.symbol)) Nil + else targs + (fun, targsInSource, targs) + + case Select(New(tpt @ TypeTree()), _) if isConstr => + val targs = tpt.tpe match { + case TypeRef(pre, sym, args) if (args forall (a => context.undetparams contains a)) => + args.map(TypeTree(_)) + case _ => Nil + } + (baseFun, targs, Nil) + + case _ => (baseFun, Nil, Nil) + } + + def blockWithQualifier(qual: Tree, fun: Symbol => Tree, defaultQual: Symbol => Option[Tree]) = { + val sym = blockTyper.context.owner.newValue(baseFun1.pos, + unit.fresh.newName(baseFun1.pos, "qual$")) + .setInfo(qual.tpe) + blockTyper.context.scope.enter(sym) + val vd = atPos(sym.pos) { ValDef(sym, qual).setType(NoType) } + var baseFunTransformed: Tree = fun(sym) + if (!funTargs.isEmpty) + baseFunTransformed = treeCopy.TypeApply(baseFun, baseFunTransformed, funTargs) + val b = atPos(baseFun1.pos) { Block(List(vd), baseFunTransformed) + .setType(baseFunTransformed.tpe) } + context.namedApplyBlockInfo = + Some((b, NamedApplyInfo(defaultQual(sym), defaultTargs, Nil, blockTyper))) + b + } + + def blockWithoutQualifier(fun: Tree, defaultQual: Option[Tree]) = { + val fun1 = if (funTargs.isEmpty) fun + else treeCopy.TypeApply(baseFun, fun, funTargs) + val b = atPos(baseFun.pos) { Block(Nil, fun1).setType(fun1.tpe) } + context.namedApplyBlockInfo = + Some((b, NamedApplyInfo(defaultQual, defaultTargs, Nil, blockTyper))) + b + } + + baseFun1 match { + // constructor calls + + case Select(New(TypeTree()), _) if isConstr => + val module = baseFun.symbol.owner.linkedModuleOfClass + val defaultQual = if (module == NoSymbol) None + + else Some(gen.mkAttributedRef(module)) + blockWithoutQualifier(baseFun1, defaultQual) + + case Select(New(Ident(_)), _) if isConstr => + blockWithoutQualifier(baseFun1, None) + + case Select(nev @ New(sel @ Select(qual, typeName)), constr) if isConstr => + val module = baseFun.symbol.owner.linkedModuleOfClass + val defaultQual = if (module == NoSymbol) None + else Some(gen.mkAttributedRef(module)) + if (treeInfo.isPureExpr(qual)) { + blockWithoutQualifier(baseFun1, defaultQual) + } else { + val fun: Symbol => Tree = + sym => treeCopy.Select(baseFun1, + treeCopy.New(nev, + treeCopy.Select(sel, gen.mkAttributedRef(sym), typeName)), + constr) + blockWithQualifier(qual, fun, sym => defaultQual) + } + + // other method calls + + case Ident(_) => + blockWithoutQualifier(baseFun1, None) + + case Select(qual, name) => + assert(!isConstr, baseFun1) + if (treeInfo.isPureExpr(qual)) + blockWithoutQualifier(baseFun1, Some(qual.duplicate)) + else + blockWithQualifier(qual, + sym => treeCopy.Select(baseFun1, gen.mkAttributedRef(sym), name), + sym => Some(gen.mkAttributedRef(sym))) + } + } + + /** + * For each argument (arg: T), create a local value + * x$n: T = arg + * + * assumes "args" are typed. owner of the definitions in the block is the owner of + * the block (see typedBlock), but the symbols have to be entered into the block's scope. + * + * For by-name parameters, create a value + * x$n: () => T = () => arg + */ + def argValDefs(args: List[Tree], paramTypes: List[Type], blockTyper: Typer): List[ValDef] = { + val context = blockTyper.context + val symPs = List.map2(args, paramTypes)((arg, tpe) => { + val byName = tpe.typeSymbol == ByNameParamClass + val s = context.owner.newValue(arg.pos, unit.fresh.newName(arg.pos, "x$")) + val valType = if (byName) functionType(List(), arg.tpe) + else arg.tpe + s.setInfo(valType) + (context.scope.enter(s), byName) + }) + List.map2(symPs, args)((symP, arg) => { + val (sym, byName) = symP + val body = if (byName) blockTyper.typed(Function(List(), arg)) + else arg + ValDef(sym, body).setType(NoType) + }) + } + + // begin transform + if (treeInfo.isSelfConstrCall(tree)) { + errorTree(tree, "using named or default arguments in a self constructor call is not allowed") + } else if (treeInfo.isSuperConstrCall(tree)) { + errorTree(tree, "using named or default arguments in a super constructor call is not allowed") + } else if (isNamedApplyBlock(tree)) { + context.namedApplyBlockInfo.get._1 + } else tree match { + // we know that Apply(Apply(...)) can only be an application of a curried method; + // for functions, it's transformed to applying the .apply() method already. + case Apply(fun, namelessArgs) => + val transformedFun = transformNamedApplication(typer, mode, pt)(fun, x => x) + if (transformedFun.isErroneous) setError(tree) + else { + assert(isNamedApplyBlock(transformedFun), transformedFun) + val NamedApplyInfo(qual, targs, vargss, blockTyper) = + context.namedApplyBlockInfo.get._2 + val existingBlock @ Block(stats, funOnly) = transformedFun + + // type the application without names; put the arguments in definition-site order + val typedApp = doTypedApply(tree, funOnly, reorderArgs(namelessArgs, argPos), mode, pt) + + if (typedApp.tpe.isError) setError(tree) + else typedApp match { + // Extract the typed arguments, restore the call-site evaluation order (using + // ValDef's in the block), change the arguments to these local values. + case Apply(expr, typedArgs) => + // typedArgs: definition-site order + val formals = formalTypes(expr.tpe.paramTypes, typedArgs.length, false) + // valDefs: call-site order + val valDefs = argValDefs(reorderArgsInv(typedArgs, argPos), + reorderArgsInv(formals, argPos), + blockTyper) + // refArgs: definition-site order again + val refArgs = List.map2(reorderArgs(valDefs, argPos), formals)((vDef, tpe) => { + val ref = gen.mkAttributedRef(vDef.symbol) + // for by-name parameters, the local value is a nullary function returning the argument + if (tpe.typeSymbol == ByNameParamClass) Apply(ref, List()) + else ref + }) + // cannot call blockTyper.typedBlock here, because the method expr might be partially applied only + val res = blockTyper.doTypedApply(tree, expr, refArgs, mode, pt) + val block = treeCopy.Block(existingBlock, stats ::: valDefs, res).setType(res.tpe) + context.namedApplyBlockInfo = + Some((block, NamedApplyInfo(qual, targs, vargss ::: List(refArgs), blockTyper))) + block + } + } + + // case ApplyDynamic??? case AppliedTypeTree??? + + case baseFun => // also treats "case TypeApply(fun, targs)" and "case Select(New(..), )" + baseFunBlock(baseFun) + + } + } + + + /** + * Extend the argument list `givenArgs' with default arguments. Defaults are added + * as named arguments calling the corresponding default getter. + * + * Example: given + * def foo(x: Int = 2, y: String = "def") + * foo(1) + * the argument list (y = "lt") is transformed to (y = "lt", x = foo$default$1()) + */ + def addDefaults(givenArgs: List[Tree], qual: Option[Tree], targs: List[Tree], + previousArgss: List[List[Tree]], params: List[Symbol]): (List[Tree], List[Symbol]) = { + if (givenArgs.length < params.length) { + val namedArgs = givenArgs.dropWhile( arg => { + val n = nameOf(arg) + !(n.isDefined && params.exists(p => p.name == n.get)) + }) + val namedParams = params.drop(givenArgs.length - namedArgs.length) + + def missing(p: Symbol): Boolean = !namedArgs.exists { + case Assign(Ident(name), _) => name == p.name + case _ => false + } + + val missingParams = namedParams filter missing + + if (missingParams forall (_.hasFlag(DEFAULTPARAM))) { + val defaultArgs = missingParams map (p => { + var default1 = qual match { + case Some(q) => gen.mkAttributedSelect(q.duplicate, p.defaultGetter) + case None => gen.mkAttributedRef(p.defaultGetter) + } + default1 = if (targs.isEmpty) default1 + else TypeApply(default1, targs.map(_.duplicate)).setPos(p.pos) + val default2 = (default1 /: previousArgss)((tree, args) => + Apply(tree, args.map(_.duplicate)).setPos(p.pos)) + Assign(Ident(p.name), default2) + }) + (givenArgs ::: defaultArgs, Nil) + } else (givenArgs, missingParams filter (! _.hasFlag(DEFAULTPARAM))) + } else (givenArgs, Nil) + } + + /** + * Removes name assignments from args. Additionally, returns an array mapping + * argument indicies from call-site-order to definition-site-order. + * + * Verifies that names are not specified twice, positional args don't appear + * after named ones. + */ + def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = { + import typer.infer.errorTree + + // maps indicies from (order written by user) to (order of definition) + val argPos = (new Array[Int](args.length)) map (x => -1) + var positionalAllowed = true + // @LUC TODO: make faster (don't use zipWithIndex) + val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match { + case Assign(Ident(name), rhs) => + val pos = params.findIndexOf(p => p.name == name && !p.hasFlag(SYNTHETIC)) + if (pos == -1) { + if (positionalAllowed) { + argPos(index) = index + // prevent isNamed from being true when calling doTypedApply recursively, + // treat the arg as an assignment of type Unit + Block(List(), arg) + } else { + errorTree(arg, "unknown parameter name: "+ name) + } + } else if (argPos contains pos) { + errorTree(arg, "parameter specified twice: "+ name) + } else { + positionalAllowed = false + argPos(index) = pos + rhs + } + case _ => + argPos(index) = index + if (positionalAllowed) arg + else errorTree(arg, "positional after named argument.") + } + (namelessArgs, argPos) + } +} diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 686824a7f5..0403e50dcd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -709,7 +709,7 @@ abstract class RefChecks extends InfoTransform { assert(lazyDefSym != NoSymbol, vsym) val ownerTransformer = new ChangeOwnerTraverser(vsym, lazyDefSym) val lazyDef = atPos(tree.pos)( - DefDef(lazyDefSym, vparamss => ownerTransformer( + DefDef(lazyDefSym, ownerTransformer( if (tree.symbol.owner.isTrait // for traits, this is further tranformed in mixins || hasUnitType) rhs else Block(List( @@ -849,7 +849,7 @@ abstract class RefChecks extends InfoTransform { tree match { case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAttribute(definitions.NativeAttr) => tree.symbol.resetFlag(DEFERRED) - result = transform(copy.DefDef(tree, mods, name, tparams, vparams, tpt, + result = transform(treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, typed(Apply(gen.mkAttributedRef(definitions.Predef_error), List(Literal("native method stub")))))) case DefDef(_, _, _, _, _, _) => @@ -942,7 +942,7 @@ abstract class RefChecks extends InfoTransform { inPattern = true val pat1 = transform(pat) inPattern = false - copy.CaseDef(tree, pat1, transform(guard), transform(body)) + treeCopy.CaseDef(tree, pat1, transform(guard), transform(body)) case _ => super.transform(result) } diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 7b84b70041..f19cdd7d95 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -114,7 +114,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT superAcc.setInfo(superAccTpe.cloneInfo(superAcc)) //println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG clazz.info.decls enter superAcc; - accDefBuf(clazz) += typed(DefDef(superAcc, vparamss => EmptyTree)) + accDefBuf(clazz) += typed(DefDef(superAcc, EmptyTree)) } atPos(sup.pos) { Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe; @@ -154,7 +154,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT curTree = tree val body1 = atOwner(currentOwner) { transformTrees(body) } accDefs = accDefs.tail; - copy.Template(tree, parents, self, ownAccDefs.toList ::: body1); + treeCopy.Template(tree, parents, self, ownAccDefs.toList ::: body1); case TypeApply(sel @ Select(This(_), name), args) => val sym = tree.symbol @@ -220,10 +220,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case Apply(fn, args) => assert(fn.tpe != null, tree) - copy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) + treeCopy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) case Function(vparams, body) => withInvalidOwner { - copy.Function(tree, vparams, transform(body)) + treeCopy.Function(tree, vparams, transform(body)) } case _ => super.transform(tree) @@ -260,7 +260,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT /** Return a list of list of types of all value parameter sections. */ def allParamTypes(tpe: Type): List[List[Type]] = tpe match { case PolyType(_, restpe) => allParamTypes(restpe) - case MethodType(pts, res) => pts :: allParamTypes(res) + case MethodType(params, res) => params.map(_.tpe) :: allParamTypes(res) case _ => Nil } @@ -274,21 +274,25 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT // if the result type depends on the this type of an enclosing class, the accessor // has to take an object of exactly this type, otherwise it's more general val objType = if (isThisType(memberType.finalResultType)) clazz.thisType else clazz.typeOfThis - val accType = memberType match { + val accType = (protAcc: Symbol) => memberType match { case PolyType(tparams, restpe) => - PolyType(tparams, MethodType(List(objType), restpe.asSeenFrom(qual.tpe, sym.owner))) + // luc: question to author: should the tparams symbols not be cloned and get a new owner (protAcc)? + PolyType(tparams, MethodType(List(protAcc.newSyntheticValueParam(objType)), + restpe.cloneInfo(protAcc).asSeenFrom(qual.tpe, sym.owner))) case _ => - MethodType(List(objType), memberType.asSeenFrom(qual.tpe, sym.owner)) + MethodType(List(protAcc.newSyntheticValueParam(objType)), + memberType.cloneInfo(protAcc).asSeenFrom(qual.tpe, sym.owner)) } if (settings.debug.value) log("accType: " + accType) - var protAcc = clazz.info.decl(accName).suchThat(_.tpe == accType) + var protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s)) if (protAcc == NoSymbol) { - protAcc = clazz.newMethod(tree.pos, nme.protName(sym.originalName)).setInfo(accType) + protAcc = clazz.newMethod(tree.pos, nme.protName(sym.originalName)) + protAcc.setInfo(accType(protAcc)) clazz.info.decls.enter(protAcc); - val code = DefDef(protAcc, vparamss => { - val obj = vparamss.head.head // receiver - vparamss.tail.zip(allParamTypes(sym.tpe)).foldLeft(Select(Ident(obj), sym): Tree) ( + val code = DefDef(protAcc, { + val obj = protAcc.paramss.head.head // receiver + protAcc.paramss.tail.zip(allParamTypes(sym.tpe)).foldLeft(Select(Ident(obj), sym): Tree) ( (fun, pvparams) => { Apply(fun, (List.map2(pvparams._1, pvparams._2) { (v, origTpe) => makeArg(v, obj, origTpe) } )) }) @@ -362,10 +366,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT var protAcc = clazz.info.decl(accName) if (protAcc == NoSymbol) { protAcc = clazz.newMethod(field.pos, nme.protSetterName(field.originalName)) - .setInfo(MethodType(List(clazz.typeOfThis, field.tpe), definitions.UnitClass.tpe)); + protAcc.setInfo(MethodType(protAcc.newSyntheticValueParams(List(clazz.typeOfThis, field.tpe)), + definitions.UnitClass.tpe)) clazz.info.decls.enter(protAcc) - val code = DefDef(protAcc, vparamss => { - val obj :: value :: Nil = vparamss.head; + val code = DefDef(protAcc, { + val obj :: value :: Nil = protAcc.paramss.head; atPos(tree.pos) { Assign( Select(Ident(obj), field.name), diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 00468abc8e..eae6eedc00 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -59,13 +59,13 @@ trait SyntheticMethods { self: Analyzer => } } - def syntheticMethod(name: Name, flags: Int, tpe: Type) = - newSyntheticMethod(name, flags | OVERRIDE, tpe) + def syntheticMethod(name: Name, flags: Int, tpeCons: Symbol => Type) = + newSyntheticMethod(name, flags | OVERRIDE, tpeCons) - def newSyntheticMethod(name: Name, flags: Int, tpe: Type) = { + def newSyntheticMethod(name: Name, flags: Int, tpeCons: Symbol => Type) = { var method = clazz.newMethod(clazz.pos, name) .setFlag(flags | SYNTHETICMETH) - .setInfo(tpe) + method.setInfo(tpeCons(method)) method = clazz.info.decls.enter(method).asInstanceOf[TermSymbol] method } @@ -77,31 +77,32 @@ trait SyntheticMethods { self: Analyzer => } */ def productPrefixMethod: Tree = { - val method = syntheticMethod(nme.productPrefix, 0, PolyType(List(), StringClass.tpe)) - typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + val method = syntheticMethod(nme.productPrefix, 0, sym => PolyType(List(), StringClass.tpe)) + typer.typed(DefDef(method, Literal(Constant(clazz.name.decode)))) } def productArityMethod(nargs:Int ): Tree = { - val method = syntheticMethod(nme.productArity, 0, PolyType(List(), IntClass.tpe)) - typer.typed(DefDef(method, vparamss => Literal(Constant(nargs)))) + val method = syntheticMethod(nme.productArity, 0, sym => PolyType(List(), IntClass.tpe)) + typer.typed(DefDef(method, Literal(Constant(nargs)))) } def productElementMethod(accs: List[Symbol]): Tree = { //val retTpe = lub(accs map (_.tpe.resultType)) - val method = syntheticMethod(nme.productElement, 0, MethodType(List(IntClass.tpe), AnyClass.tpe/*retTpe*/)) - typer.typed(DefDef(method, vparamss => Match(Ident(vparamss.head.head), { + val method = syntheticMethod(nme.productElement, 0, + sym => MethodType(sym.newSyntheticValueParams(List(IntClass.tpe)), AnyClass.tpe/*retTpe*/)) + typer.typed(DefDef(method, Match(Ident(method.paramss.head.head), { (for ((sym,i) <- accs.zipWithIndex) yield { CaseDef(Literal(Constant(i)),EmptyTree, Ident(sym)) }):::List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(New(TypeTree(IndexOutOfBoundsExceptionClass.tpe), List(List( - Select(Ident(vparamss.head.head), nme.toString_) + Select(Ident(method.paramss.head.head), nme.toString_) )))))) }))) } def moduleToStringMethod: Tree = { - val method = syntheticMethod(nme.toString_, FINAL, MethodType(List(), StringClass.tpe)) - typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + val method = syntheticMethod(nme.toString_, FINAL, sym => MethodType(List(), StringClass.tpe)) + typer.typed(DefDef(method, Literal(Constant(clazz.name.decode)))) } def forwardingMethod(name: Name): Tree = { @@ -110,13 +111,14 @@ trait SyntheticMethods { self: Analyzer => if (target.tpe.paramTypes.isEmpty) List() else target.tpe.paramTypes.tail val method = syntheticMethod( - name, 0, MethodType(paramtypes, target.tpe.resultType)) - typer.typed(DefDef(method, vparamss => - Apply(gen.mkAttributedRef(target), This(clazz) :: (vparamss.head map Ident)))) + name, 0, sym => MethodType(sym.newSyntheticValueParams(paramtypes), target.tpe.resultType)) + typer.typed(DefDef(method, + Apply(gen.mkAttributedRef(target), This(clazz) :: (method.paramss.head map Ident)))) } def equalsSym = - syntheticMethod(nme.equals_, 0, MethodType(List(AnyClass.tpe), BooleanClass.tpe)) + syntheticMethod(nme.equals_, 0, + sym => MethodType(sym.newSyntheticValueParams(List(AnyClass.tpe)), BooleanClass.tpe)) /** The equality method for case modules: * def equals(that: Any) = this eq that @@ -124,13 +126,13 @@ trait SyntheticMethods { self: Analyzer => def equalsModuleMethod: Tree = { val method = equalsSym val methodDef = - DefDef(method, vparamss => + DefDef(method, Apply( Select(This(clazz), Object_eq), List( TypeApply( Select( - Ident(vparamss.head.head), + Ident(method.paramss.head.head), Any_asInstanceOf), List(TypeTree(AnyRefClass.tpe)))))) localTyper.typed(methodDef) @@ -149,9 +151,8 @@ trait SyntheticMethods { self: Analyzer => val method = equalsSym val methodDef = DefDef( - method, - { vparamss => - val that = Ident(vparamss.head.head) + method, { + val that = Ident(method.paramss.head.head) val constrParamTypes = clazz.primaryConstructor.tpe.paramTypes val hasVarArgs = !constrParamTypes.isEmpty && constrParamTypes.last.typeSymbol == RepeatedParamClass if (false && clazz.isStatic) { @@ -165,7 +166,7 @@ trait SyntheticMethods { self: Analyzer => Boolean_and), List( Apply(gen.mkAttributedRef(target), - This(clazz) :: (vparamss.head map Ident)))) + This(clazz) :: (method.paramss.head map Ident)))) } else { val (pat, guard) = { val guards = new ListBuffer[Tree] @@ -215,8 +216,8 @@ trait SyntheticMethods { self: Analyzer => // !!! the synthetic method "readResolve" should be private, // but then it is renamed !!! val method = newSyntheticMethod(nme.readResolve, PROTECTED, - MethodType(List(), ObjectClass.tpe)) - typer.typed(DefDef(method, vparamss => gen.mkAttributedRef(clazz.sourceModule))) + sym => MethodType(List(), ObjectClass.tpe)) + typer.typed(DefDef(method, gen.mkAttributedRef(clazz.sourceModule))) } def newAccessorMethod(tree: Tree): Tree = tree match { @@ -225,7 +226,7 @@ trait SyntheticMethods { self: Analyzer => newAcc.name = context.unit.fresh.newName(tree.symbol.pos, tree.symbol.name + "$") newAcc.setFlag(SYNTHETIC).resetFlag(ACCESSOR | PARAMACCESSOR | PRIVATE) newAcc = newAcc.owner.info.decls enter newAcc - val result = typer.typed(DefDef(newAcc, vparamss => rhs.duplicate)) + val result = typer.typed(DefDef(newAcc, rhs.duplicate)) log("new accessor method " + result) result } @@ -246,9 +247,10 @@ trait SyntheticMethods { self: Analyzer => context.unit.error(sym.pos, "a definition of `"+name1+"' already exists in " + clazz) NoSymbol } else { - clazz.newMethod(sym.pos, name1) - .setInfo(sym.info) - .setFlag(sym.getFlag(DEFERRED | OVERRIDE | STATIC)) + val m = clazz.newMethod(sym.pos, name1) + m.setInfo(sym.info.cloneInfo(clazz)) + .setFlag(sym.getFlag(DEFERRED | OVERRIDE | STATIC)) + m } } @@ -260,7 +262,7 @@ trait SyntheticMethods { self: Analyzer => clazz.info.decls.enter(getter) ts += typer.typed(DefDef( getter, - vparamss => if (sym hasFlag DEFERRED) EmptyTree else gen.mkAttributedRef(sym))) + if (sym hasFlag DEFERRED) EmptyTree else gen.mkAttributedRef(sym))) } } @@ -270,9 +272,8 @@ trait SyntheticMethods { self: Analyzer => clazz.info.decls.enter(setter) ts += typer.typed(DefDef( setter, - vparamss => - if (sym hasFlag DEFERRED) EmptyTree - else Apply(gen.mkAttributedRef(sym), List(Ident(vparamss.head.head))))) + if (sym hasFlag DEFERRED) EmptyTree + else Apply(gen.mkAttributedRef(sym), List(Ident(setter.paramss.head.head))))) } } @@ -338,7 +339,7 @@ trait SyntheticMethods { self: Analyzer => } } val synthetics = ts.toList - copy.Template( + treeCopy.Template( templ, templ.parents, templ.self, if (synthetics.isEmpty) templ.body else templ.body ::: synthetics) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 002830bd0c..e6aa3119e1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -37,8 +37,11 @@ trait Typers { self: Analyzer => var failedOpEqs = 0L var failedSilent = 0L + // namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result + // is cached here and re-used in typedDefDef / typedValDef private val transformed = new HashMap[Tree, Tree] + // currently not used at all (March 09) private val superDefs = new HashMap[Symbol, ListBuffer[Tree]] def resetTyper() { @@ -172,14 +175,14 @@ trait Typers { self: Analyzer => /** Find implicit arguments and pass them to given tree. */ def applyImplicitArgs(tree: Tree): Tree = tree.tpe match { - case MethodType(formals, _) => + case MethodType(params, _) => def implicitArg(pt: Type): SearchResult = { val result = inferImplicit(tree, pt, true, context) if (result == SearchFailure) context.error(tree.pos, "no implicit argument matching parameter type "+pt+" was found.") result } - val argResults = formals map implicitArg + val argResults = params map (_.tpe) map implicitArg val args = argResults map (_.tree) for (s <- argResults map (_.subst)) { s traverse tree @@ -206,14 +209,15 @@ trait Typers { self: Analyzer => case OverloadedType(_, _) => EmptyTree case PolyType(_, _) => EmptyTree case _ => - def wrapImplicit(from: Type): Tree = { + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy") + def wrapImplicit(from: Symbol): Tree = { val result = inferImplicit(tree, MethodType(List(from), to), reportAmbiguous, context) if (result.subst != EmptyTreeTypeSubstituter) result.subst traverse tree result.tree } - val result = wrapImplicit(from) + val result = wrapImplicit(dummyMethod.newSyntheticValueParam(from)) if (result != EmptyTree) result - else wrapImplicit(appliedType(ByNameParamClass.typeConstructor, List(from))) + else wrapImplicit(dummyMethod.newSyntheticValueParam(appliedType(ByNameParamClass.typeConstructor, List(from)))) } } @@ -683,10 +687,12 @@ trait Typers { self: Analyzer => val context1 = context.makeSilent(context.reportAmbiguousErrors) context1.undetparams = context.undetparams context1.savedTypeBounds = context.savedTypeBounds + context1.namedApplyBlockInfo = context.namedApplyBlockInfo val typer1 = newTyper(context1) val result = op(typer1) context.undetparams = context1.undetparams context.savedTypeBounds = context1.savedTypeBounds + context.namedApplyBlockInfo = context1.namedApplyBlockInfo result } else { op(this) @@ -737,7 +743,7 @@ trait Typers { self: Analyzer => case atp @ AnnotatedType(_, _, _) if canAdaptAnnotations(tree, mode, pt) => // (-1) adaptAnnotations(tree, mode, pt) case ct @ ConstantType(value) if ((mode & (TYPEmode | FUNmode)) == 0 && (ct <:< pt)) => // (0) - copy.Literal(tree, value) + treeCopy.Literal(tree, value) case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1) inferExprAlternative(tree, pt) adapt(tree, mode, pt) @@ -774,16 +780,39 @@ trait Typers { self: Analyzer => case mt: MethodType if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) && (context.undetparams.isEmpty || (mode & POLYmode) != 0)) => - val meth = tree.symbol + // if (isNamedApplyBlock(tree)), we know that `tree' is a transformed + // named application and has the following form: + // { val x$1 = arg1 + // [...] + // val x$n = argn + // fun(x$1, ..)..(.., x$n) } + // Eta-Expansion needs to be performed on the method `fun', not on + // the entire block, so we extract the fun (`tree1') apply eta-expansion, + // and re-construct the block at the end: + // { val x$1 = arg1 + // [...] + // val x$n = argn + // (y$1, .., y$n) => fun(x$1, ..)..(.., x$n)(y$1, ..)..(.., y$n) } + val (tree1, meth, isExpanded) = tree match { + case Block(_, tree1) if isNamedApplyBlock(tree) => + context.namedApplyBlockInfo = None + (tree1, tree1.symbol, true) + case _ => (tree, tree.symbol, false) + } if (!meth.isConstructor && //isCompatible(tparamsToWildcards(mt, context.undetparams), pt) && isFunctionType(pt))/* && (pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType)))*/ { // (4.2) - if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt) - checkParamsConvertible(tree.pos, tree.tpe) - val tree1 = etaExpand(context.unit, tree) -// println("eta "+tree+" ---> "+tree1+":"+tree1.tpe) - typed(tree1, mode, pt) + if (settings.debug.value) log("eta-expanding "+tree1+":"+tree1.tpe+" to "+pt) + checkParamsConvertible(tree1.pos, tree1.tpe) + val tree2 = etaExpand(context.unit, tree1) + //println("eta "+tree1+" ---> "+tree2+":"+tree2.tpe) + val typedFun = typed(tree2, mode, pt) + tree match { + case Block(stats, fun) if (isExpanded) => + treeCopy.Block(tree, stats, typedFun).setType(typedFun.tpe) + case _ => typedFun + } } else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3) adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt) } else if (context.implicitsEnabled) { @@ -1018,9 +1047,9 @@ trait Typers { self: Analyzer => // A method to replace a super reference by a New in a supercall def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { case Apply(fn, args) => - copy.Apply(scall, transformSuperCall(fn), args map (_.duplicate)) + treeCopy.Apply(scall, transformSuperCall(fn), args map (_.duplicate)) case Select(Super(_, _), nme.CONSTRUCTOR) => - copy.Select( + treeCopy.Select( scall, New(TypeTree(supertpe) setOriginal supertpt) setType supertpe setPos supertpt.pos, nme.CONSTRUCTOR) @@ -1033,11 +1062,11 @@ trait Typers { self: Analyzer => val scall = if (cstats.isEmpty) EmptyTree else cstats.last val cbody1 = scall match { case Apply(_, _) => - copy.Block(cbody, cstats1.init, + treeCopy.Block(cbody, cstats1.init, if (supertparams.isEmpty) cunit.duplicate else transformSuperCall(scall)) case _ => - copy.Block(cbody, cstats1, cunit.duplicate) + treeCopy.Block(cbody, cstats1, cunit.duplicate) } val outercontext = context.outer @@ -1190,7 +1219,7 @@ trait Typers { self: Analyzer => "implementation restriction: subclassing Classfile does not\n"+ "make your annotation visible at runtime. If that is what\n"+ "you want, you must write the annotation class in Java.") - copy.ClassDef(cdef, typedMods, cdef.name, tparams1, impl2) + treeCopy.ClassDef(cdef, typedMods, cdef.name, tparams1, impl2) .setType(NoType) } @@ -1208,7 +1237,7 @@ trait Typers { self: Analyzer => .typedTemplate(mdef.impl, parentTypes(mdef.impl)) val impl2 = addSyntheticMethods(impl1, clazz, context) - copy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType + treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType } /** @@ -1220,7 +1249,7 @@ trait Typers { self: Analyzer => if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL) && !stat.symbol.isModuleVar && !stat.symbol.hasFlag(LAZY) => - val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) + val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) val value = vdef.symbol val getter = if ((mods hasFlag DEFERRED)) value else value.getter(value.owner) assert(getter != NoSymbol, stat) @@ -1228,14 +1257,14 @@ trait Typers { self: Analyzer => error(getter.pos, getter+" is defined twice") val getterDef: DefDef = atPos(vdef) { getter.attributes = value.initialize.attributes - val result = DefDef(getter, vparamss => + val result = DefDef(getter, if (mods hasFlag DEFERRED) EmptyTree else typed( atPos(vdef) { gen.mkCheckInit(Select(This(value.owner), value)) }, EXPRmode, value.tpe)) result.tpt.asInstanceOf[TypeTree] setOriginal tpt /* setPos tpt.pos */ checkNoEscaping.privates(getter, result.tpt) - copy.DefDef(result, result.mods withAnnotations mods.annotations, result.name, + treeCopy.DefDef(result, result.mods withAnnotations mods.annotations, result.name, result.tparams, result.vparamss, result.tpt, result.rhs) //todo: withAnnotations is probably unnecessary } @@ -1243,13 +1272,13 @@ trait Typers { self: Analyzer => val setr = getter.setter(value.owner) setr.attributes = value.attributes val result = atPos(vdef)( - DefDef(setr, vparamss => + DefDef(setr, if ((mods hasFlag DEFERRED) || (setr hasFlag OVERLOADED)) EmptyTree else typed(Assign(Select(This(value.owner), value), - Ident(vparamss.head.head))))) - copy.DefDef(result, result.mods withAnnotations mods.annotations, result.name, + Ident(setr.paramss.head.head))))) + treeCopy.DefDef(result, result.mods withAnnotations mods.annotations, result.name, result.tparams, result.vparamss, result.tpt, result.rhs) } val gs = if (mods hasFlag MUTABLE) List(getterDef, setterDef) @@ -1290,7 +1319,7 @@ trait Typers { self: Analyzer => val self1 = templ.self match { case vd @ ValDef(mods, name, tpt, EmptyTree) => val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt)) - copy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType + treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType } if (self1.name != nme.WILDCARD) context.scope enter self1.symbol val selfType = @@ -1310,7 +1339,7 @@ trait Typers { self: Analyzer => templ.body flatMap addGetterSetter else templ.body val body1 = typedStats(body, templ.symbol) - copy.Template(templ, parents1, self1, body1) setType clazz.tpe + treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe } /** Type check the annotations within a set of modifiers. */ @@ -1338,9 +1367,23 @@ trait Typers { self: Analyzer => error(vdef.pos, "local variables must be initialized") vdef.rhs } else { - newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe) + val tpt2 = if (sym hasFlag DEFAULTPARAM) { + // When typechecking default parameter, replace all type parameters in the expected type by Wildcarad. + // This allows defining "def foo[T](a: T = 1)" + val tparams = + if (sym.owner.isConstructor) sym.owner.owner.info.typeParams + else sym.owner.tpe.typeParams + val subst = new SubstTypeMap(tparams, tparams map (_ => WildcardType)) { + override def matches(sym: Symbol, sym1: Symbol) = + if (sym.isSkolem) matches(sym.deSkolemize, sym1) + else if (sym1.isSkolem) matches(sym, sym1.deSkolemize) + else super[SubstTypeMap].matches(sym, sym1) + } + subst(tpt1.tpe) + } else tpt1.tpe + newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt2) } - copy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs1)) setType NoType + treeCopy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs1)) setType NoType } /** Enter all aliases of local parameter accessors. @@ -1463,7 +1506,20 @@ trait Typers { self: Analyzer => for (vparams <- ddef.vparamss; vparam <- vparams) checkStructuralCondition(meth.owner, vparam) - copy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType + // only one overloaded method is allowed to have defaults + if (meth.owner.isClass && meth.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM)))) { + val overloads = meth.owner.info.member(meth.name) + val otherHasDefault = overloads.filter(alt => { + alt != meth && alt.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM))) + }) != NoSymbol + if (otherHasDefault) + error(meth.pos, "multiple overloaded alternatives of "+ meth +" define default arguments") + + if (meth.paramss.exists(_.exists(_.tpe.typeSymbol == RepeatedParamClass))) + error(meth.pos, "methods with `*'-parameters are not allowed to have default arguments") + } + + treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType } def typedTypeDef(tdef: TypeDef): TypeDef = { @@ -1479,7 +1535,7 @@ trait Typers { self: Analyzer => error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1) case _ => } - copy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType + treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType } private def enterLabelDef(stat: Tree) { @@ -1496,7 +1552,7 @@ trait Typers { self: Analyzer => val restpe = ldef.symbol.tpe.resultType val rhs1 = typed(ldef.rhs, restpe) ldef.params foreach (param => param.tpe = param.symbol.tpe) - copy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType restpe + treeCopy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType restpe } protected def typedFunctionIDE(fun : Function, txt : Context) = {} @@ -1517,7 +1573,7 @@ trait Typers { self: Analyzer => block.stats foreach enterLabelDef val stats1 = typedStats(block.stats, context.owner) val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt) - val block1 = copy.Block(block, stats1, expr1) + val block1 = treeCopy.Block(block, stats1, expr1) .setType(if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst) //checkNoEscaping.locals(context.scope, pt, block1) block1 @@ -1546,7 +1602,7 @@ trait Typers { self: Analyzer => } } // body1 = checkNoEscaping.locals(context.scope, pt, body1) - copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe + treeCopy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe } def typedCases(tree: Tree, cases: List[CaseDef], pattp0: Type, pt: Type): List[CaseDef] = { @@ -1636,7 +1692,7 @@ trait Typers { self: Analyzer => val restpe = packedType(body, fun.symbol).deconst val funtpe = typeRef(clazz.tpe.prefix, clazz, formals ::: List(restpe)) // body = checkNoEscaping.locals(context.scope, restpe, body) - val fun1 = copy.Function(fun, vparams, body).setType(funtpe) + val fun1 = treeCopy.Function(fun, vparams, body).setType(funtpe) if (codeExpected) { val liftPoint = Apply(Select(Ident(CodeModule), nme.lift_), List(fun1)) typed(atPos(fun.pos)(liftPoint)) @@ -1662,7 +1718,6 @@ trait Typers { self: Analyzer => def typedImport(imp : Import) : Import = imp def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { - val inBlock = exprOwner == context.owner val localTarget = context.unit != null && @@ -1706,32 +1761,43 @@ trait Typers { self: Analyzer => def checkNoDoubleDefsAndAddSynthetics(stats: List[Tree]): List[Tree] = { val scope = if (inBlock) context.scope else context.owner.info.decls; val newStats = new ListBuffer[Tree] - var e = scope.elems; - while ((e ne null) && e.owner == scope) { - - // check no double def - var e1 = scope.lookupNextEntry(e); - while ((e1 ne null) && e1.owner == scope) { - if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) && - (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe))) - if (!e.sym.isErroneous && !e1.sym.isErroneous) - error(e.sym.pos, e1.sym+" is defined twice"+ - {if(!settings.debug.value) "" else " in "+unit.toString}) - e1 = scope.lookupNextEntry(e1); - } + var needsCheck = true + var moreToAdd = true + while (moreToAdd) { + val initSize = scope.size + var e = scope.elems; + while ((e ne null) && e.owner == scope) { + + // check no double def + if (needsCheck) { + var e1 = scope.lookupNextEntry(e); + while ((e1 ne null) && e1.owner == scope) { + if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) && + (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe))) + if (!e.sym.isErroneous && !e1.sym.isErroneous) + error(e.sym.pos, e1.sym+" is defined twice"+ + {if(!settings.debug.value) "" else " in "+unit.toString}) + e1 = scope.lookupNextEntry(e1); + } + } // add synthetics context.unit.synthetics get e.sym match { case Some(tree) => - newStats += tree - context.unit.synthetics -= e.sym + newStats += typedStat(tree) // might add even more synthetics to the scope + context.unit.synthetics -= e.sym case _ => } e = e.next } + needsCheck = false + // the type completer of a synthetic might add more synthetics. example: if the + // factory method of a case class (i.e. the constructor) has a default. + moreToAdd = initSize != scope.size + } if (newStats.isEmpty) stats - else stats ::: (newStats.toList map typedStat) + else stats ::: newStats.toList } val result = List.mapConserve(stats)(typedStat) if (phase.erasedTypes) result @@ -1809,6 +1875,15 @@ trait Typers { self: Analyzer => } } + /** Is `tree' a block created by a named application? + */ + def isNamedApplyBlock(tree: Tree) = + context.namedApplyBlockInfo match { + case Some((block, _)) => block == tree + case None => false + } + + /** * @param tree ... * @param fun0 ... @@ -1820,22 +1895,33 @@ trait Typers { self: Analyzer => def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = { var fun = fun0 if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) { - // preadapt symbol to number and shape of arguments given - def shapeType(arg: Tree): Type = arg match { - case Function(vparams, body) => - functionType(vparams map (vparam => AnyClass.tpe), shapeType(body)) - case _ => - NothingClass.tpe + // remove alternatives with wrong number of parameters without looking at types. + // less expensive than including them in inferMethodAlternatvie (see below). + def shapeType(arg: Tree): Type = { + def shape(arg1: Tree, toplevel: Boolean): Type = arg1 match { + case Function(vparams, body) => + functionType(vparams map (vparam => AnyClass.tpe), shape(body, false)) + case Assign(Ident(name), rhs) if toplevel => + NamedType(name, shape(rhs, false)) + case _ => + NothingClass.tpe + } + shape(arg, true) } val argtypes = args map shapeType val pre = fun.symbol.tpe.prefix + var sym = fun.symbol filter { alt => isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt) } - //println("narrowed to "+sym+":"+sym.info+"/"+argtypes) if (sym hasFlag OVERLOADED) { - // eliminate functions that would result from tupling transforms - val sym1 = sym filter (alt => hasExactlyNumParams(followApply(alt.tpe), argtypes.length)) + val sym1 = sym filter (alt => { + // eliminate functions that would result from tupling transforms + // keeps alternatives with repeated params + hasExactlyNumParams(followApply(alt.tpe), argtypes.length) || + // also keep alts which define at least one default + alt.tpe.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM))) + }) if (sym1 != NoSymbol) sym = sym1 } if (sym != NoSymbol) @@ -1845,35 +1931,116 @@ trait Typers { self: Analyzer => case OverloadedType(pre, alts) => val undetparams = context.extractUndetparams() - /* Lukas: - - var m: Map[Tree, Name] = Map() - val args1 = List.mapConserve(args) { - case Assign(name, rhs) => m += (rhs -> name) - case arg => arg + val argtpes = new ListBuffer[Type] + val amode = argMode(fun, mode) + val args1 = args map { + case Assign(Ident(name), rhs) => + // named args: only type the righthand sides ("unknown identifier" errors otherwise) + val rhs1 = typedArg(rhs, amode, 0, WildcardType) + argtpes += NamedType(name, rhs1.tpe.deconst) + Assign(Ident(name), rhs1) // untyped; that's ok because we call doTypedApply + case arg => + val arg1 = typedArg(arg, amode, 0, WildcardType) + argtpes += arg1.tpe.deconst + arg1 } - */ - - val args1 = typedArgs(args, argMode(fun, mode)) context.undetparams = undetparams - inferMethodAlternative(fun, undetparams, args1 map (_.tpe.deconst), pt) + inferMethodAlternative(fun, undetparams, argtpes.toList, pt) doTypedApply(tree, adapt(fun, funMode(mode), WildcardType), args1, mode, pt) - case mt @ MethodType(formals0, _) => - val formals = formalTypes(formals0, args.length) - var args1 = actualArgs(tree.pos, args, formals.length) - if (args1.length != args.length) { - silent(_.doTypedApply(tree, fun, args1, mode, pt)) match { - case t: Tree => t - case ex => errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) - } - } else if (formals.length != args1.length) { + + case mt @ MethodType(params, _) => + // repeat vararg as often as needed, remove by-name + val formals = formalTypes(mt.paramTypes, args.length) + + /** 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: Option[Tree] = { + // if 1 formal, 1 arg (a tuple), otherwise unmodified args + val tupleArgs = actualArgs(tree.pos, args, formals.length) + + if (tupleArgs.length != args.length) { + // 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)) match { + case t: Tree => Some(t) + case ex => + context.undetparams = savedUndetparams + None + } + } else None + } + + /** Treats an application which uses named or default arguments. + * Also works if names + a vararg used: when names are used, the vararg + * parameter has to be specified exactly once. Note that combining varargs + * and defaults is ruled out by typedDefDef. + */ + def tryNamesDefaults: Tree = { if (mt.isErroneous) setError(tree) - else errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) + else if (args.length > formals.length) { + tryTupleApply.getOrElse { + errorTree(tree, "too many arguments for "+treeSymTypeMsg(fun)) + } + } else if (args.length == formals.length) { + // we don't need defaults. names were used, so this application is transformed + // into a block (@see transformNamedApplication in NamesDefaults) + val (namelessArgs, argPos) = removeNames(Typer.this)(args, params) + if (namelessArgs exists (_.isErroneous)) { + setError(tree) + } else if (!isIdentity(argPos) && (formals.length != params.length)) + // !isIdentity indicates that named arguments are used to re-order arguments + errorTree(tree, "when using named arguments, the vararg parameter "+ + "has to be specified exactly once") + else if (isIdentity(argPos) && !isNamedApplyBlock(fun)) { + // if there's no re-ordering, and fun is not transformed, no need to transform + // more than an optimization, e.g. important in "synchronized { x = update-x }" + doTypedApply(tree, fun, namelessArgs, mode, pt) + } else { + transformNamedApplication(Typer.this, mode, pt)( + treeCopy.Apply(tree, fun, namelessArgs), argPos) + } + } else { + // defaults are needed. they are added to the argument list in named style as + // calls to the default getters. Example: + // foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a)) + val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x) + if (fun1.isErroneous) setError(tree) + else { + assert(isNamedApplyBlock(fun1), fun1) + val NamedApplyInfo(qual, targs, previousArgss, _) = + context.namedApplyBlockInfo.get._2 + val (allArgs, missing) = addDefaults(args, qual, targs, previousArgss, mt.params) + if (allArgs.length == formals.length) { + // a default for each missing argument was found + val (namelessArgs, argPos) = removeNames(Typer.this)(allArgs, params) + transformNamedApplication(Typer.this, mode, pt)( + treeCopy.Apply(tree, fun1, namelessArgs), argPos) + } else { + tryTupleApply.getOrElse { + val suffix = + if (missing.isEmpty) "" + else ", unspecified parameter"+ (if (missing.length > 1) "s: " else ": ") + + (missing.take(3).mkString(", ")) + (if (missing.length > 3) ", ..." else "") + errorTree(tree, "not enough arguments for "+treeSymTypeMsg(fun) + suffix) + } + } + } + } + } + + if (formals.length != args.length || // wrong nb of arguments + args.exists(isNamed(_)) || // uses a named argument + isNamedApplyBlock(fun)) { // fun was transformed to a named apply block => + // integrate this application into the block + tryNamesDefaults } else { val tparams = context.extractUndetparams() - if (tparams.isEmpty) { - val args2 = typedArgs(args1, argMode(fun, mode), formals0, formals) - val restpe = mt.resultType(args2 map (_.tpe)) + if (tparams.isEmpty) { // all type params are defined + val args1 = typedArgs(args, argMode(fun, mode), mt.paramTypes, formals) + val restpe = mt.resultType(args1 map (_.tpe)) // instantiate dependent method types def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp case _ => tp @@ -1893,7 +2060,7 @@ trait Typers { self: Analyzer => // the compiler thinks, the PLUS method takes only one argument, // but he thinks it's an instance method -> still two ref's on the stack // -> translated by backend - val rhs = copy.Apply(tree, f, args1) + val rhs = treeCopy.Apply(tree, f, args) return typed(Assign(qual, rhs)) } case _ => () @@ -1903,20 +2070,20 @@ trait Typers { self: Analyzer => if (fun.symbol == List_apply && args.isEmpty) { atPos(tree.pos) { gen.mkNil setType restpe } } else { - constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe))) + constfold(treeCopy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe))) } /* Would like to do the following instead, but curiously this fails; todo: investigate if (fun.symbol.name == nme.apply && fun.symbol.owner == ListClass && args.isEmpty) { atPos(tree.pos) { gen.mkNil setType restpe } } else { - constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe))) + constfold(treeCopy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe))) } */ - } else if (needsInstantiation(tparams, formals, args1)) { + } else if (needsInstantiation(tparams, formals, args)) { //println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info))) inferExprInstance(fun, tparams, WildcardType, true) - doTypedApply(tree, fun, args1, mode, pt) + doTypedApply(tree, fun, args, mode, pt) } else { assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt) @@ -1932,12 +2099,14 @@ trait Typers { self: Analyzer => } arg1 } - val args2 = List.map2(args1, formals)(typedArgToPoly) - if (args2 exists (_.tpe.isError)) setError(tree) + val args1 = List.map2(args, formals)(typedArgToPoly) + if (args1 exists (_.tpe.isError)) setError(tree) else { - if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args2.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info));//debug - val undetparams = inferMethodInstance(fun, tparams, args2, pt) - val result = doTypedApply(tree, fun, args2, mode, pt) + if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info));//debug + // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun" + // returns those undetparams which have not been instantiated. + val undetparams = inferMethodInstance(fun, tparams, args1, pt) + val result = doTypedApply(tree, fun, args1, mode, pt) context.undetparams = undetparams result } @@ -1948,7 +2117,7 @@ trait Typers { self: Analyzer => doTypedApply(tree, fun setType fun.tpe.widen, args, mode, pt) case ErrorType => - setError(copy.Apply(tree, fun, args)) + setError(treeCopy.Apply(tree, fun, args)) /* --- begin unapply --- */ case otpe if (mode & PATTERNmode) != 0 && unapplyMember(otpe).exists => @@ -1967,8 +2136,8 @@ trait Typers { self: Analyzer => if (!isApplicableSafe(List(), unappType, List(arg.tpe), WildcardType)) { //Console.println("UNAPP: need to typetest, arg.tpe = "+arg.tpe+", unappType = "+unappType) def freshArgType(tp: Type): (Type, List[Symbol]) = tp match { - case MethodType(formals, _) => - (formals(0), List()) + case MethodType(params, _) => + (params(0).tpe, List()) case PolyType(tparams, restype) => val tparams1 = cloneSymbols(tparams) (freshArgType(restype)._1.substSym(tparams, tparams1), tparams1) @@ -2481,14 +2650,14 @@ trait Typers { self: Analyzer => trackSetInfo(vble)( if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) else body1.tpe) - copy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // buraq, was: pt + treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // buraq, was: pt } } def typedArrayValue(elemtpt: Tree, elems: List[Tree]) = { val elemtpt1 = typedType(elemtpt, mode) val elems1 = List.mapConserve(elems)(elem => typed(elem, mode, elemtpt1.tpe)) - copy.ArrayValue(tree, elemtpt1, elems1) + treeCopy.ArrayValue(tree, elemtpt1, elems1) .setType( (if (isFullyDefined(pt) && !phase.erasedTypes) pt else appliedType(ArrayClass.typeConstructor, List(elemtpt1.tpe))).notNull) @@ -2516,7 +2685,7 @@ trait Typers { self: Analyzer => } if ((varsym ne null) && (varsym.isVariable || varsym.isValue && phase.erasedTypes)) { val rhs1 = typed(rhs, lhs1.tpe) - copy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe + treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe } else { if (!lhs1.tpe.isError) { //println(lhs1+" = "+rhs+" "+varsym+" "+mayBeVarGetter(varsym)+" "+varsym.ownerChain+" "+varsym.info)// DEBUG @@ -2532,11 +2701,11 @@ trait Typers { self: Analyzer => val cond1 = checkDead(typed(cond, BooleanClass.tpe)) if (elsep.isEmpty) { // in the future, should be unecessary val thenp1 = typed(thenp, UnitClass.tpe) - copy.If(tree, cond1, thenp1, elsep) setType thenp1.tpe + treeCopy.If(tree, cond1, thenp1, elsep) setType thenp1.tpe } else { val thenp1 = typed(thenp, pt) val elsep1 = typed(elsep, pt) - copy.If(tree, cond1, thenp1, elsep1) setType ptOrLub(List(thenp1.tpe, elsep1.tpe)) + treeCopy.If(tree, cond1, thenp1, elsep1) setType ptOrLub(List(thenp1.tpe, elsep1.tpe)) } } @@ -2556,7 +2725,7 @@ trait Typers { self: Analyzer => } else { context.enclMethod.returnsSeen = true val expr1: Tree = typed(expr, restpt0.tpe) - copy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType NothingClass.tpe + treeCopy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType NothingClass.tpe } } } @@ -2594,7 +2763,7 @@ trait Typers { self: Analyzer => " cannot be instantiated because it does not conform to its self-type "+ tpt1.tpe.typeOfThis) } - copy.New(tree, tpt1).setType(tpt1.tpe) + treeCopy.New(tree, tpt1).setType(tpt1.tpe) } def typedEta(expr1: Tree): Tree = expr1.tpe match { @@ -2673,7 +2842,7 @@ trait Typers { self: Analyzer => // this must preserve m's type argument, so that we end up with List[Int], and not List[a] //@M related bug: #1438 //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe) - copy.TypeApply(tree, fun, args) setType resultpe + treeCopy.TypeApply(tree, fun, args) setType resultpe } } else { errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun)) @@ -2732,7 +2901,8 @@ trait Typers { self: Analyzer => if ((args1 ne null) && !pt.isError) { def templateArgType(arg: Tree) = new BoundedWildcardType(mkTypeBounds(arg.tpe, AnyClass.tpe)) - adaptToMember(qual, name, MethodType(args1 map templateArgType, pt)) + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy") + adaptToMember(qual, name, MethodType(dummyMethod.newSyntheticValueParams(args1 map templateArgType), pt)) } else qual if (qual1 ne qual) { val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos @@ -2932,7 +3102,7 @@ trait Typers { self: Analyzer => } if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) { val qual1 = adaptToName(qual, name) - if (qual1 ne qual) return typed(copy.Select(tree, qual1, name), mode, pt) + if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt) } if (!sym.exists) { if (settings.debug.value) Console.err.println("qual = "+qual+":"+qual.tpe+"\nSymbol="+qual.tpe.termSymbol+"\nsymbol-info = "+qual.tpe.termSymbol.info+"\nscope-id = "+qual.tpe.termSymbol.info.decls.hashCode()+"\nmembers = "+qual.tpe.members+"\nname = "+name+"\nfound = "+sym+"\nowner = "+context.enclClass.owner) @@ -2950,8 +3120,8 @@ trait Typers { self: Analyzer => setError(tree) } else { val tree1 = tree match { - case Select(_, _) => copy.Select(tree, qual, name) - case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name) + case Select(_, _) => treeCopy.Select(tree, qual, name) + case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) } //if (name.toString == "Elem") println("typedSelect "+qual+":"+qual.tpe+" "+sym+"/"+tree1+":"+tree1.tpe) val (tree2, pre2) = makeAccessible(tree1, sym, qual.tpe, qual) @@ -3187,7 +3357,7 @@ trait Typers { self: Analyzer => assert(sym.moduleClass ne NoSymbol) val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls)) .typedStats(stats, NoSymbol) - copy.PackageDef(tree, name, stats1) setType NoType + treeCopy.PackageDef(tree, name, stats1) setType NoType case tree @ ClassDef(_, _, _, _) => newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree) @@ -3215,7 +3385,7 @@ trait Typers { self: Analyzer => case Annotation(constr, elements) => val typedConstr = typed(constr, mode, WildcardType) val typedElems = elements.map(typed(_, mode, WildcardType)) - (copy.Annotation(tree, typedConstr, typedElems) + (treeCopy.Annotation(tree, typedConstr, typedElems) setType typedConstr.tpe) case Annotated(annot, arg) => @@ -3228,16 +3398,16 @@ trait Typers { self: Analyzer => case Sequence(elems) => checkRegPatOK(tree.pos, mode) val elems1 = List.mapConserve(elems)(elem => typed(elem, mode, pt)) - copy.Sequence(tree, elems1) setType pt + treeCopy.Sequence(tree, elems1) setType pt case Alternative(alts) => val alts1 = List.mapConserve(alts)(alt => typed(alt, mode | ALTmode, pt)) - copy.Alternative(tree, alts1) setType pt + treeCopy.Alternative(tree, alts1) setType pt case Star(elem) => checkRegPatOK(tree.pos, mode) val elem1 = typed(elem, mode, pt) - copy.Star(tree, elem1) setType pt + treeCopy.Star(tree, elem1) setType pt case Bind(name, body) => typedBind(name, body) @@ -3246,7 +3416,7 @@ trait Typers { self: Analyzer => val fun1 = typed(fun) val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe), args.length) val args1 = List.map2(args, tpes)(typedPattern(_, _)) - copy.UnApply(tree, fun1, args1) setType pt + treeCopy.UnApply(tree, fun1, args1) setType pt case ArrayValue(elemtpt, elems) => typedArrayValue(elemtpt, elems) @@ -3273,12 +3443,12 @@ trait Typers { self: Analyzer => } val ids = for (p <- params) yield Ident(p.name) val selector1 = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) } - val body = copy.Match(tree, selector1, cases) + val body = treeCopy.Match(tree, selector1, cases) typed1(atPos(tree.pos) { Function(params, body) }, mode, pt) } else { val selector1 = checkDead(typed(selector)) val cases1 = typedCases(tree, cases, selector1.tpe.widen, pt) - copy.Match(tree, selector1, cases1) setType ptOrLub(cases1 map (_.tpe)) + treeCopy.Match(tree, selector1, cases1) setType ptOrLub(cases1 map (_.tpe)) } case Return(expr) => @@ -3289,12 +3459,12 @@ trait Typers { self: Analyzer => val catches1 = typedCases(tree, catches, ThrowableClass.tpe, pt) val finalizer1 = if (finalizer.isEmpty) finalizer else typed(finalizer, UnitClass.tpe) - copy.Try(tree, block1, catches1, finalizer1) + treeCopy.Try(tree, block1, catches1, finalizer1) .setType(ptOrLub(block1.tpe :: (catches1 map (_.tpe)))) case Throw(expr) => val expr1 = typed(expr, ThrowableClass.tpe) - copy.Throw(tree, expr1) setType NothingClass.tpe + treeCopy.Throw(tree, expr1) setType NothingClass.tpe case New(tpt: Tree) => typedNew(tpt) @@ -3307,7 +3477,7 @@ trait Typers { self: Analyzer => val expr1 = typed(expr, mode & stickyModes, seqType(pt)) expr1.tpe.baseType(SeqClass) match { case TypeRef(_, _, List(elemtp)) => - copy.Typed(tree, expr1, tpt setType elemtp) setType elemtp + treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp case _ => setError(tree) } @@ -3318,7 +3488,7 @@ trait Typers { self: Analyzer => if ((mode & PATTERNmode) != 0) inferTypedPattern(tpt1.pos, tpt1.tpe, pt) else tpt1.tpe //Console.println(typed pattern: "+tree+":"+", tp = "+tpt1.tpe+", pt = "+pt+" ==> "+owntype)//DEBUG - copy.Typed(tree, expr1, tpt1) setType owntype + treeCopy.Typed(tree, expr1, tpt1) setType owntype } case TypeApply(fun, args) => @@ -3367,7 +3537,7 @@ trait Typers { self: Analyzer => val reflectiveCalls = !(settings.refinementMethodDispatch.value == "invoke-dynamic") val qual1 = typed(qual, AnyRefClass.tpe) val args1 = List.mapConserve(args)(arg => if (reflectiveCalls) typed(arg, AnyRefClass.tpe) else typed(arg)) - copy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType) + treeCopy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType) case Super(qual, mix) => typedSuper(qual, mix) @@ -3386,7 +3556,7 @@ trait Typers { self: Analyzer => var qual1 = checkDead(typedQualifier(qual, mode)) if (name.isTypeName) qual1 = checkStable(qual1) val tree1 = typedSelect(qual1, name) - if (qual1.symbol == RootPackage) copy.Ident(tree1, name) + if (qual1.symbol == RootPackage) treeCopy.Ident(tree1, name) else tree1 case Ident(name) => @@ -3421,7 +3591,7 @@ trait Typers { self: Analyzer => case TypeBoundsTree(lo, hi) => val lo1 = typedType(lo, mode) val hi1 = typedType(hi, mode) - copy.TypeBoundsTree(tree, lo1, hi1) setType mkTypeBounds(lo1.tpe, hi1.tpe) + treeCopy.TypeBoundsTree(tree, lo1, hi1) setType mkTypeBounds(lo1.tpe, hi1.tpe) case etpt @ ExistentialTypeTree(_, _) => newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt, mode) @@ -3448,7 +3618,6 @@ trait Typers { self: Analyzer => * @return ... */ def typed(tree: Tree, mode: Int, pt: Type): Tree = { - def dropExistential(tp: Type): Type = tp match { case ExistentialType(tparams, tpe) => if (settings.debug.value) println("drop ex "+tree+" "+tp) diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 4f4c39a0c0..0bb1f87ed4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -94,12 +94,19 @@ trait Unapplies { self: Analyzer => unapp } - private def copyUntyped[T <: Tree](tree: T): T = { + def copyUntyped[T <: Tree](tree: T): T = { val tree1 = tree.duplicate UnTyper.traverse(tree1) tree1 } + def copyUntypedInvariant(td: TypeDef): TypeDef = { + val tree1 = treeCopy.TypeDef(td, td.mods &~ (COVARIANT | CONTRAVARIANT), + td.name, td.tparams map (_.duplicate), td.rhs.duplicate) + UnTyper.traverse(tree1) + tree1 + } + private def classType(cdef: ClassDef, tparams: List[TypeDef]): Tree = { val tycon = gen.mkAttributedRef(cdef.symbol) if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map (x => Ident(x.name))) @@ -151,7 +158,7 @@ trait Unapplies { self: Analyzer => /** The apply method corresponding to a case class */ def caseModuleApplyMeth(cdef: ClassDef): DefDef = { - val tparams = cdef.tparams map copyUntyped[TypeDef] + val tparams = cdef.tparams map copyUntypedInvariant val cparamss = constrParamss(cdef) atPos(cdef.pos) { DefDef( @@ -167,7 +174,7 @@ trait Unapplies { self: Analyzer => /** The unapply method corresponding to a case class */ def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = { - val tparams = cdef.tparams map copyUntyped[TypeDef] + val tparams = cdef.tparams map copyUntypedInvariant val unapplyParamName = newTermName("x$0") val hasVarArg = constrParamss(cdef) match { case (cps @ (_ :: _)) :: _ => treeInfo.isRepeatedParamType(cps.last.tpt) @@ -184,4 +191,28 @@ trait Unapplies { self: Analyzer => caseClassUnapplyReturnValue(unapplyParamName, cdef.symbol)) } } + + def caseClassCopyMeth(cdef: ClassDef): Option[DefDef] = { + val cparamss = constrParamss(cdef) + if (cparamss.length == 1 && cparamss.head.isEmpty || // no copy method if there are no arguments + cdef.symbol.hasFlag(ABSTRACT) || + cparamss.exists(_.exists(vd => + treeInfo.isRepeatedParamType(vd.tpt) || + treeInfo.isByNameParamType(vd.tpt)))) + None + else { + val tparams = cdef.tparams map copyUntypedInvariant + // the parameter types have to be exactly the same as the constructor's parameter types; so it's + // not good enough to just duplicated the (untyped) tpt tree; the parameter types are removed here + // and re-added in ``finishWith'' in the namer. + val paramss = cparamss map (_.map(vd => + treeCopy.ValDef(vd, vd.mods | DEFAULTPARAM, vd.name, + TypeTree().setOriginal(vd.tpt), Ident(vd.name)))) + val classTpe = classType(cdef, tparams) + Some(atPos(cdef.pos) { + DefDef(Modifiers(SYNTHETIC), nme.copy, tparams, paramss, classTpe, + New(classTpe, paramss map (_ map (p => Ident(p.name))))) + }) + } + } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala index a02b4b04a1..920b856094 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala @@ -87,8 +87,8 @@ trait Variances { flip(varianceInType(lo)(tparam)) & varianceInType(hi)(tparam) case RefinedType(parents, defs) => varianceInTypes(parents)(tparam) & varianceInSyms(defs.toList)(tparam) - case MethodType(formals, restpe) => - flip(varianceInTypes(formals)(tparam)) & varianceInType(restpe)(tparam) + case MethodType(params, restpe) => + flip(varianceInSyms(params)(tparam)) & varianceInType(restpe)(tparam) case PolyType(tparams, restpe) => flip(varianceInSyms(tparams)(tparam)) & varianceInType(restpe)(tparam) case ExistentialType(tparams, restpe) => -- cgit v1.2.3