diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 13 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 58 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 53 | ||||
-rw-r--r-- | src/library/scala/transient.scala | 3 | ||||
-rw-r--r-- | src/library/scala/volatile.scala | 3 | ||||
-rw-r--r-- | test/files/jvm/annotations.scala | 3 | ||||
-rw-r--r-- | test/files/run/names-defaults.scala | 21 |
8 files changed, 115 insertions, 42 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 3640b6825b..531c92a2a1 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -221,9 +221,8 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable => var vparamss1 = vparamss map (vps => vps.map { vd => atPos(vd.pos.focus) { - val pa = if (vd.hasFlag(PRIVATE | LOCAL)) 0L else PARAMACCESSOR ValDef( - Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | pa) withAnnotations vd.mods.annotations, + Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR) withAnnotations vd.mods.annotations, vd.name, vd.tpt.duplicate, vd.rhs.duplicate) }}) val (edefs, rest) = body span treeInfo.isEarlyDef diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 759457cb70..8758dd834c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -486,6 +486,19 @@ trait Contexts { self: Analyzer => } implicitsCache } + + def lookup(name: Name, expectedOwner: Symbol) = { + var res: Symbol = NoSymbol + var ctx = this + while(res == NoSymbol && ctx.outer != ctx) { + val s = ctx.scope.lookup(name) + if (s != NoSymbol && s.owner == expectedOwner) + res = s + else + ctx = ctx.outer + } + res + } } class ImportInfo(val tree: Import, val depth: Int) { /** The prefix expression */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index a78ee61ee2..a7f573f98b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -607,6 +607,17 @@ trait Namers { self: Analyzer => vparamss.map(_.map(enterValueParam)) } + /** + * Finds the companion module of a class symbol. Calling .companionModule + * does not work for classes defined inside methods. + */ + private def companionModuleOf(clazz: Symbol) = { + var res = clazz.companionModule + if (res == NoSymbol) + res = context.lookup(clazz.name.toTermName, clazz.owner) + res + } + private def templateSig(templ: Template): Type = { val clazz = context.owner def checkParent(tpt: Tree): Type = { @@ -712,29 +723,36 @@ trait Namers { self: Analyzer => // add apply and unapply methods to companion objects of case classes, // 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 => + if (clazz.isModuleClass) { + 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.companionModule.moduleClass match { - case Some(cdef) => - def hasCopy(decls: Scope) = { - decls.iterator exists (_.name == nme.copy) - } - if (!hasCopy(decls) && - !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) && - !parents.flatMap(_.baseClasses).distinct.exists(bc => hasCopy(bc.info.decls))) - addCopyMethod(cdef, templateNamer) - case None => + // here, clazz is the ClassSymbol of the case class (not the module). + // @check: this seems to work only if the type completer of the class runs before the one of the + // module class: the one from the module class removes the entry form caseClassOfModuleClass (see above). + if (clazz.isClass && !clazz.hasFlag(MODULE)) { + Namers.this.caseClassOfModuleClass get companionModuleOf(clazz).moduleClass match { + case Some(cdef) => + def hasCopy(decls: Scope) = { + decls.iterator exists (_.name == nme.copy) + } + if (!hasCopy(decls) && + !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) && + !parents.flatMap(_.baseClasses).distinct.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 + // if default getters (for constructor defaults) need to be added to that module, here's the namer + // to use. clazz is the ModuleClass. sourceModule works also for classes defined in methods. val module = clazz.sourceModule if (classAndNamerOfModule contains module) { val (cdef, _) = classAndNamerOfModule(module) @@ -947,6 +965,7 @@ trait Namers { self: Analyzer => if (vparamss == List(Nil) && baseParamss.isEmpty) baseParamss = List(Nil) assert(!overrides || vparamss.length == baseParamss.length, ""+ meth.fullName + ", "+ overridden.fullName) + // cache the namer used for entering the default getter symbols var ownerNamer: Option[Namer] = None var moduleNamer: Option[(ClassDef, Namer)] = None @@ -978,7 +997,7 @@ trait Namers { self: Analyzer => val parentNamer = if (isConstr) { val (cdef, nmr) = moduleNamer.getOrElse { - val module = meth.owner.companionModule + val module = companionModuleOf(meth.owner) module.initialize // call type completer (typedTemplate), adds the // module's templateNamer to classAndNamerOfModule val (cdef, nmr) = classAndNamerOfModule(module) @@ -1029,7 +1048,8 @@ trait Namers { self: Analyzer => Modifiers(meth.flags & (PRIVATE | PROTECTED | FINAL)) | SYNTHETIC | DEFAULTPARAM | oflag, name, deftParams, defvParamss, defTpt, defRhs) } - meth.owner.resetFlag(INTERFACE) // there's a concrete member now + if (!isConstr) + meth.owner.resetFlag(INTERFACE) // there's a concrete member now val default = parentNamer.enterSyntheticSym(defaultTree) } else if (baseHasDefault) { // the parameter does not have a default itself, but the corresponding parameter diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 89b4f910e5..18102a8bb4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -187,10 +187,21 @@ trait NamesDefaults { self: Analyzer => baseFun1 match { // constructor calls - case Select(New(TypeTree()), _) if isConstr => - blockWithoutQualifier(None) - case Select(TypeApply(New(TypeTree()), _), _) if isConstr => - blockWithoutQualifier(None) + case Select(New(tp @ TypeTree()), _) if isConstr => + // fixes #3338. Same qualifier for selecting the companion object as for the class. + val dq = tp.tpe match { + case TypeRef(pre, _, _) if (!pre.typeSymbol.isEmptyPackageClass) => + moduleQual(tp.pos, mod => gen.mkAttributedSelect(gen.mkAttributedQualifier(pre), mod)) + case _ => None + } + blockWithoutQualifier(dq) + case Select(TypeApply(New(tp @ TypeTree()), _), _) if isConstr => + val dq = tp.tpe match { + case TypeRef(pre, _, _) if (!pre.typeSymbol.isEmptyPackageClass) => + moduleQual(tp.pos, mod => gen.mkAttributedSelect(gen.mkAttributedQualifier(pre), mod)) + case _ => None + } + blockWithoutQualifier(dq) case Select(New(Ident(_)), _) if isConstr => blockWithoutQualifier(None) @@ -350,8 +361,11 @@ trait NamesDefaults { self: Analyzer => if (missing forall (_.hasFlag(DEFAULTPARAM))) { val defaultArgs = missing map (p => { var default1 = qual match { - case Some(q) => gen.mkAttributedSelect(q.duplicate, defaultGetter(p, context)) - case None => gen.mkAttributedRef(defaultGetter(p, context)) + case Some(q) => gen.mkAttributedSelect(q.duplicate, defaultGetter(p, context)._1) + case None => + val (m, q) = defaultGetter(p, context) + if (q.isDefined) gen.mkAttributedSelect(q.get, m) + else gen.mkAttributedRef(m) } default1 = if (targs.isEmpty) default1 else TypeApply(default1, targs.map(_.duplicate)) @@ -369,35 +383,32 @@ trait NamesDefaults { self: Analyzer => /** * For a parameter with default argument, find the method symbol of - * the default getter. + * the default getter. Can return a qualifier tree for the selecting + * the method's symbol (part of #3334 fix). */ - def defaultGetter(param: Symbol, context: Context) = { + def defaultGetter(param: Symbol, context: Context): (Symbol, Option[Tree]) = { val i = param.owner.paramss.flatten.findIndexOf(p => p.name == param.name) + 1 if (i > 0) { if (param.owner.isConstructor) { val defGetterName = "init$default$"+ i - param.owner.owner.companionModule.info.member(defGetterName) + var mod = param.owner.owner.companionModule + // if the class's owner is a method, .companionModule does not work + if (mod == NoSymbol) + mod = context.lookup(param.owner.owner.name.toTermName, param.owner.owner.owner) + (mod.info.member(defGetterName), Some(gen.mkAttributedRef(mod))) } else { val defGetterName = param.owner.name +"$default$"+ i + // isClass also works for methods in objects, owner is the ModuleClassSymbol if (param.owner.owner.isClass) { // .toInterface: otherwise we get the method symbol of the impl class - param.owner.owner.toInterface.info.member(defGetterName) + (param.owner.owner.toInterface.info.member(defGetterName), None) } else { // the owner of the method is another method. find the default // getter in the context. - var res: Symbol = NoSymbol - var ctx = context - while(res == NoSymbol && ctx.outer != ctx) { - val s = ctx.scope.lookup(defGetterName) - if (s != NoSymbol && s.owner == param.owner.owner) - res = s - else - ctx = ctx.outer - } - res + (context.lookup(defGetterName, param.owner.owner), None) } } - } else NoSymbol + } else (NoSymbol, None) } /** diff --git a/src/library/scala/transient.scala b/src/library/scala/transient.scala index d8b8ee4d86..aea7ba7b5f 100644 --- a/src/library/scala/transient.scala +++ b/src/library/scala/transient.scala @@ -11,4 +11,7 @@ package scala +import annotation.target._ + +@field class transient extends StaticAnnotation diff --git a/src/library/scala/volatile.scala b/src/library/scala/volatile.scala index dda0493bf9..005cd6628c 100644 --- a/src/library/scala/volatile.scala +++ b/src/library/scala/volatile.scala @@ -11,4 +11,7 @@ package scala +import annotation.target._ + +@field class volatile extends StaticAnnotation diff --git a/test/files/jvm/annotations.scala b/test/files/jvm/annotations.scala index 227bd919c1..12760beb4e 100644 --- a/test/files/jvm/annotations.scala +++ b/test/files/jvm/annotations.scala @@ -160,6 +160,9 @@ object Test5 { } } +// #3345 +class A3345(@volatile private var i:Int) + object Test { def main(args: Array[String]) { Test1.run diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala index 3442ecafc3..ee9186c35f 100644 --- a/test/files/run/names-defaults.scala +++ b/test/files/run/names-defaults.scala @@ -324,6 +324,27 @@ object Test extends Application { } } + // #3344 + def m3344_1 = { case class C(x: Int); C(1).copy(2).x } + m3344_1 + def m3344_2 = { class C(val x: Int = 1); new C().x } + m3344_2 + + // #3338 + object t3338 { + class Container { + class GenericClass[T](arg: String = "") + } + + object Container extends Container + + class Test { + val a = new Container.GenericClass() + } + } + (new t3338.Test).a + + // DEFINITIONS def test1(a: Int, b: String) = println(a +": "+ b) |