diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 22 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 12 | ||||
-rw-r--r-- | test/files/pos/t2377b/Q.java | 13 | ||||
-rw-r--r-- | test/files/pos/t2377b/a.scala | 5 |
5 files changed, 41 insertions, 22 deletions
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 01ca8033ac..22460b6ca8 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -600,26 +600,8 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { Import(Ident(cdef.name.toTermName), ImportSelector.wildList) } - // Importing the companion object members cannot be done uncritically: see - // ticket #2377 wherein a class contains two static inner classes, each of which - // has a static inner class called "Builder" - this results in an ambiguity error - // when each performs the import in the enclosing class's scope. - // - // To address this I moved the import Companion._ inside the class, as the first - // statement. This should work without compromising the enclosing scope, but may (?) - // end up suffering from the same issues it does in scala - specifically that this - // leaves auxiliary constructors unable to access members of the companion object - // as unqualified identifiers. - def addCompanionObject(statics: List[Tree], cdef: ClassDef): List[Tree] = { - def implWithImport(importStmt: Tree) = deriveTemplate(cdef.impl)(importStmt :: _) - // if there are no statics we can use the original cdef, but we always - // create the companion so import A._ is not an error (see ticket #1700) - val cdefNew = - if (statics.isEmpty) cdef - else deriveClassDef(cdef)(_ => implWithImport(importCompanionObject(cdef))) - - List(makeCompanionObject(cdefNew, statics), cdefNew) - } + def addCompanionObject(statics: List[Tree], cdef: ClassDef): List[Tree] = + List(makeCompanionObject(cdef, statics), cdef) def importDecl(): List[Tree] = { accept(IMPORT) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 16ef75c863..c73ea54c3d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1016,7 +1016,16 @@ trait Contexts { self: Analyzer => || unit.exists && s.sourceFile != unit.source.file ) ) - def lookupInPrefix(name: Name) = pre member name filter qualifies + def lookupInPrefix(name: Name) = { + val sym = pre.member(name).filter(qualifies) + def isNonPackageNoModuleClass(sym: Symbol) = + sym.isClass && !sym.isModuleClass && !sym.isPackageClass + if (!sym.exists && unit.isJava && isNonPackageNoModuleClass(pre.typeSymbol)) { + // TODO factor out duplication with Typer::inCompanionForJavaStatic + val pre1 = companionSymbolOf(pre.typeSymbol, this).typeOfThis + pre1.member(name).filter(qualifies).andAlso(_ => pre = pre1) + } else sym + } def accessibleInPrefix(s: Symbol) = isAccessible(s, pre, superAccess = false) def searchPrefix = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d412b5ef33..7c176c8047 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4719,6 +4719,16 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree } + + // For Java, instance and static members are in the same scope, but we put the static ones in the companion object + // so, when we can't find a member in the class scope, check the companion + def inCompanionForJavaStatic(pre: Type, cls: Symbol, name: Name): Symbol = + if (!(context.unit.isJava && cls.isClass && !cls.isModuleClass)) NoSymbol else { + val companion = companionSymbolOf(cls, context) + if (!companion.exists) NoSymbol + else member(gen.mkAttributedRef(pre, companion), name) // assert(res.isStatic, s"inCompanionJavaStatic($pre, $cls, $name) = $res ${res.debugFlagString}") + } + /* Attribute a selection where `tree` is `qual.name`. * `qual` is already attributed. */ @@ -4745,7 +4755,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper dyna.wrapErrors(t, (_.typed1(t, mode, pt))) } - val sym = tree.symbol orElse member(qual, name) orElse { + val sym = tree.symbol orElse member(qual, name) orElse inCompanionForJavaStatic(qual.tpe.prefix, qual.symbol, name) orElse { // symbol not found? --> try to convert implicitly to a type that does have the required // member. Added `| PATTERNmode` to allow enrichment in patterns (so we can add e.g., an // xml member to StringContext, which in turn has an unapply[Seq] method) diff --git a/test/files/pos/t2377b/Q.java b/test/files/pos/t2377b/Q.java new file mode 100644 index 0000000000..fbf9c776e9 --- /dev/null +++ b/test/files/pos/t2377b/Q.java @@ -0,0 +1,13 @@ +public class Q { + + public static class Builder {} + + public static class Inner { + public static class Builder { public void innerMethod() {} } + public Builder foo() { return new Builder(); } // this line gives an error, that Builder is ambiguous + + public Inner.Builder viaSelect() { return new Builder(); } // this line gives an error, that Builder is ambiguous + } + +} + diff --git a/test/files/pos/t2377b/a.scala b/test/files/pos/t2377b/a.scala new file mode 100644 index 0000000000..3053841589 --- /dev/null +++ b/test/files/pos/t2377b/a.scala @@ -0,0 +1,5 @@ +object Test { + (new Q.Inner).foo.innerMethod + (new Q.Inner).viaSelect.innerMethod + +} |