summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2010-04-25 06:23:11 +0000
committerLukas Rytz <lukas.rytz@epfl.ch>2010-04-25 06:23:11 +0000
commita29eafaf4bbb439ef4893bf1442782d5d50dd5f5 (patch)
tree84b6005c7fa6f72a9c0708f957234577e80f887c
parent810deda16afc1d9b13e43c68e895b683549951d6 (diff)
downloadscala-a29eafaf4bbb439ef4893bf1442782d5d50dd5f5.tar.gz
scala-a29eafaf4bbb439ef4893bf1442782d5d50dd5f5.tar.bz2
scala-a29eafaf4bbb439ef4893bf1442782d5d50dd5f5.zip
close #3338, close #3334, close #3345.
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala58
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala53
-rw-r--r--src/library/scala/transient.scala3
-rw-r--r--src/library/scala/volatile.scala3
-rw-r--r--test/files/jvm/annotations.scala3
-rw-r--r--test/files/run/names-defaults.scala21
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)