From 185b1c828a7f859b32b136e873373a9b79edc304 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 4 May 2010 14:40:10 +0000 Subject: close #3384. --- .../scala/tools/nsc/typechecker/Contexts.scala | 9 ++ .../scala/tools/nsc/typechecker/Namers.scala | 15 +-- .../tools/nsc/typechecker/NamesDefaults.scala | 102 ++++++++++----------- test/files/pos/t3384.scala | 14 +++ 4 files changed, 74 insertions(+), 66 deletions(-) create mode 100644 test/files/pos/t3384.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 8758dd834c..82c4c01b79 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -487,6 +487,15 @@ trait Contexts { self: Analyzer => implicitsCache } + /** + * Find a symbol in this context or one of its outers. + * + * Used to find symbols are owned by methods (or fields), they can't be + * found in some scope. + * + * Examples: companion module of classes owned by a method, default getter + * methods of nested methods. See NamesDefaults.scala + */ def lookup(name: Name, expectedOwner: Symbol) = { var res: Symbol = NoSymbol var ctx = this diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index a7f573f98b..37f8a21bf8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -607,17 +607,6 @@ 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 = { @@ -738,7 +727,7 @@ trait Namers { self: Analyzer => // @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 { + Namers.this.caseClassOfModuleClass get companionModuleOf(clazz, context).moduleClass match { case Some(cdef) => def hasCopy(decls: Scope) = { decls.iterator exists (_.name == nme.copy) @@ -997,7 +986,7 @@ trait Namers { self: Analyzer => val parentNamer = if (isConstr) { val (cdef, nmr) = moduleNamer.getOrElse { - val module = companionModuleOf(meth.owner) + val module = companionModuleOf(meth.owner, context) module.initialize // call type completer (typedTemplate), adds the // module's templateNamer to classAndNamerOfModule val (cdef, nmr) = classAndNamerOfModule(module) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 18102a8bb4..ef2c3c3071 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -178,60 +178,52 @@ trait NamesDefaults { self: Analyzer => b } - def moduleQual(pos: Position, tree: Symbol => Tree) = { - val module = baseFun.symbol.owner.companionModule - if (module == NoSymbol) None - else Some(atPos(pos.focus)(tree(module))) + def moduleQual(pos: Position, classType: Type) = { + // prefix does 'normalize', which fixes #3384 + val pre = classType.prefix + if (pre == NoType) { + None + } else { + val module = companionModuleOf(baseFun.symbol.owner, context) + if (module == NoSymbol) None + else Some(atPos(pos.focus)(gen.mkAttributedRef(pre, module))) + } } baseFun1 match { // constructor calls 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) + // 'moduleQual' fixes #3338. Same qualifier for selecting the companion object as for the class. + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) 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) + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) - case Select(New(Ident(_)), _) if isConstr => - blockWithoutQualifier(None) - case Select(TypeApply(New(Ident(_)), _), _) if isConstr => - blockWithoutQualifier(None) + case Select(New(tp @ Ident(_)), _) if isConstr => + // 'moduleQual' fixes #3344 + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) + case Select(TypeApply(New(tp @ Ident(_)), _), _) if isConstr => + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) - case Select(New(Select(qual, _)), _) if isConstr => + case Select(New(tp @ Select(qual, _)), _) if isConstr => // in `new q.C()', q is always stable assert(treeInfo.isPureExpr(qual), qual) - // #2057 - val defaultQual = moduleQual(qual.pos, mod => gen.mkAttributedSelect(qual.duplicate, mod)) - blockWithoutQualifier(defaultQual) - - case Select(TypeApply(New(Select(qual, _)), _), _) if isConstr => + // 'moduleQual' fixes #2057 + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) + case Select(TypeApply(New(tp @ Select(qual, _)), _), _) if isConstr => assert(treeInfo.isPureExpr(qual), qual) - val defaultQual = moduleQual(qual.pos, mod => gen.mkAttributedSelect(qual.duplicate, mod)) - blockWithoutQualifier(defaultQual) + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) // super constructor calls case Select(sp @ Super(_, _), _) if isConstr => - // fix for #3207. selection of the companion module of the superclass - // needs to have the same prefix as the the superclass. - val superprefix = sp.symbol.tpe.parents.head.prefix - val defaultQual = moduleQual(baseFun.pos, mod => gen.mkAttributedRef(superprefix, mod)) - blockWithoutQualifier(defaultQual) + // 'moduleQual' fixes #3207. selection of the companion module of the + // superclass needs to have the same prefix as the the superclass. + blockWithoutQualifier(moduleQual(baseFun.pos, sp.symbol.tpe.parents.head)) // self constructor calls (in secondary constructors) - case Select(qual, name) if isConstr => - assert(treeInfo.isPureExpr(qual), qual) - blockWithoutQualifier(None) + case Select(tp, name) if isConstr => + assert(treeInfo.isPureExpr(tp), tp) + blockWithoutQualifier(moduleQual(tp.pos, tp.tpe)) // other method calls @@ -361,11 +353,8 @@ 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)._1) - case None => - val (m, q) = defaultGetter(p, context) - if (q.isDefined) gen.mkAttributedSelect(q.get, m) - else gen.mkAttributedRef(m) + case Some(q) => gen.mkAttributedSelect(q.duplicate, defaultGetter(p, context)) + case None => gen.mkAttributedRef(defaultGetter(p, context)) } default1 = if (targs.isEmpty) default1 else TypeApply(default1, targs.map(_.duplicate)) @@ -383,32 +372,28 @@ trait NamesDefaults { self: Analyzer => /** * For a parameter with default argument, find the method symbol of - * the default getter. Can return a qualifier tree for the selecting - * the method's symbol (part of #3334 fix). + * the default getter. */ - def defaultGetter(param: Symbol, context: Context): (Symbol, Option[Tree]) = { + def defaultGetter(param: Symbol, context: Context): Symbol = { 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 - 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))) + val mod = companionModuleOf(param.owner.owner, context) + mod.info.member(defGetterName) } 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), None) + param.owner.owner.toInterface.info.member(defGetterName) } else { // the owner of the method is another method. find the default // getter in the context. - (context.lookup(defGetterName, param.owner.owner), None) + context.lookup(defGetterName, param.owner.owner) } } - } else (NoSymbol, None) + } else NoSymbol } /** @@ -487,4 +472,15 @@ trait NamesDefaults { self: Analyzer => } (namelessArgs, argPos) } + + /** + * Finds the companion module of a class symbol. Calling .companionModule + * does not work for classes defined inside methods. + */ + def companionModuleOf(clazz: Symbol, context: Context) = { + var res = clazz.companionModule + if (res == NoSymbol) + res = context.lookup(clazz.name.toTermName, clazz.owner) + res + } } diff --git a/test/files/pos/t3384.scala b/test/files/pos/t3384.scala new file mode 100644 index 0000000000..4d4a81d69d --- /dev/null +++ b/test/files/pos/t3384.scala @@ -0,0 +1,14 @@ +package test + +package p { + class A(a: String = "") +} + +package object po { + type A = p.A +} + +import po._ +class C { + val a = new A() //p.A.init$default$1) +} -- cgit v1.2.3