From 5b2990c5119ae58d2c9d90d6b4822d906559aeef Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 18 Dec 2012 14:50:55 +0100 Subject: SI-6745 Fix lookup We should only consult the decls of the enclosing class. Members of the self type, enclosing scopes, or imports should not be considered. --- .../scala/tools/nsc/typechecker/Contexts.scala | 45 ++++++++++++++++------ test/files/neg/t4460a.check | 4 ++ test/files/neg/t4460a.scala | 7 ++++ test/files/neg/t4460b.check | 4 ++ test/files/neg/t4460b.scala | 9 +++++ test/files/neg/t4460c.check | 7 ++++ test/files/neg/t4460c.scala | 7 ++++ test/files/pos/t6745.scala | 4 ++ 8 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 test/files/neg/t4460a.check create mode 100644 test/files/neg/t4460a.scala create mode 100644 test/files/neg/t4460b.check create mode 100644 test/files/neg/t4460b.scala create mode 100644 test/files/neg/t4460c.check create mode 100644 test/files/neg/t4460c.scala create mode 100644 test/files/pos/t6745.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index c0d2f44c7b..01c8030f64 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -802,6 +802,12 @@ trait Contexts { self: Analyzer => case _ => LookupSucceeded(qual, sym) } ) + def finishDefSym(sym: Symbol, pre0: Type): NameLookup = + if (requiresQualifier(sym)) + finish(gen.mkAttributedQualifier(pre0), sym) + else + finish(EmptyTree, sym) + def isPackageOwnedInDifferentUnit(s: Symbol) = ( s.isDefinedInPackage && ( !currentRun.compiles(s) @@ -825,17 +831,36 @@ trait Contexts { self: Analyzer => found1 } + + def lookupInScope(scope: Scope) = + (scope lookupUnshadowedEntries name filter (e => qualifies(e.sym))).toList + + def newOverloaded(owner: Symbol, pre: Type, entries: List[ScopeEntry]) = + logResult(s"!!! lookup overloaded")(owner.newOverloaded(pre, entries map (_.sym))) + + // Constructor lookup should only look in the decls of the enclosing class + // not in the self-type, nor in the enclosing context, nor in imports (SI-4460, SI-6745) + if (name == nme.CONSTRUCTOR) return { + val enclClassSym = cx.enclClass.owner + val scope = cx.enclClass.prefix.baseType(enclClassSym).decls + val constructorSym = lookupInScope(scope) match { + case Nil => NoSymbol + case hd :: Nil => hd.sym + case entries => newOverloaded(enclClassSym, cx.enclClass.prefix, entries) + } + finishDefSym(constructorSym, cx.enclClass.prefix) + } + // cx.scope eq null arises during FixInvalidSyms in Duplicators while (defSym == NoSymbol && (cx ne NoContext) && (cx.scope ne null)) { - pre = cx.enclClass.prefix - val entries = (cx.scope lookupUnshadowedEntries name filter (e => qualifies(e.sym))).toList - defSym = entries match { - case Nil => searchPrefix - case hd :: tl => + pre = cx.enclClass.prefix + defSym = lookupInScope(cx.scope) match { + case Nil => searchPrefix + case entries @ (hd :: tl) => // we have a winner: record the symbol depth symbolDepth = (cx.depth - cx.scope.nestingLevel) + hd.depth if (tl.isEmpty) hd.sym - else logResult(s"!!! lookup overloaded")(cx.owner.newOverloaded(pre, entries map (_.sym))) + else newOverloaded(cx.owner, pre, entries) } if (!defSym.exists) cx = cx.outer // push further outward @@ -873,12 +898,8 @@ trait Contexts { self: Analyzer => } // At this point only one or the other of defSym and impSym might be set. - if (defSym.exists) { - if (requiresQualifier(defSym)) - finish(gen.mkAttributedQualifier(pre), defSym) - else - finish(EmptyTree, defSym) - } + if (defSym.exists) + finishDefSym(defSym, pre) else if (impSym.exists) { // We continue walking down the imports as long as the tail is non-empty, which gives us: // imports == imp1 :: imp2 :: _ diff --git a/test/files/neg/t4460a.check b/test/files/neg/t4460a.check new file mode 100644 index 0000000000..b711e7acb1 --- /dev/null +++ b/test/files/neg/t4460a.check @@ -0,0 +1,4 @@ +t4460a.scala:6: error: called constructor's definition must precede calling constructor's definition + def this() = this() // was binding to Predef. !! + ^ +one error found diff --git a/test/files/neg/t4460a.scala b/test/files/neg/t4460a.scala new file mode 100644 index 0000000000..0a7a22178d --- /dev/null +++ b/test/files/neg/t4460a.scala @@ -0,0 +1,7 @@ +trait A + +class B(val x: Int) { + self: A => + + def this() = this() // was binding to Predef. !! +} diff --git a/test/files/neg/t4460b.check b/test/files/neg/t4460b.check new file mode 100644 index 0000000000..f0e703fd10 --- /dev/null +++ b/test/files/neg/t4460b.check @@ -0,0 +1,4 @@ +t4460b.scala:7: error: called constructor's definition must precede calling constructor's definition + def this() = this() // was binding to Predef. !! + ^ +one error found diff --git a/test/files/neg/t4460b.scala b/test/files/neg/t4460b.scala new file mode 100644 index 0000000000..1233017dd4 --- /dev/null +++ b/test/files/neg/t4460b.scala @@ -0,0 +1,9 @@ +trait A + +class Outer() { + class B(val x: Int) { + self: A => + + def this() = this() // was binding to Predef. !! + } +} diff --git a/test/files/neg/t4460c.check b/test/files/neg/t4460c.check new file mode 100644 index 0000000000..4e96711b8b --- /dev/null +++ b/test/files/neg/t4460c.check @@ -0,0 +1,7 @@ +t4460c.scala:4: error: overloaded method constructor B with alternatives: + (a: String)B + (x: Int)B + cannot be applied to () + def this(a: String) = this() + ^ +one error found diff --git a/test/files/neg/t4460c.scala b/test/files/neg/t4460c.scala new file mode 100644 index 0000000000..1ae258508e --- /dev/null +++ b/test/files/neg/t4460c.scala @@ -0,0 +1,7 @@ +class B(val x: Int) { + self: A => + + def this(a: String) = this() +} + +class A() diff --git a/test/files/pos/t6745.scala b/test/files/pos/t6745.scala new file mode 100644 index 0000000000..2ab8e6d39a --- /dev/null +++ b/test/files/pos/t6745.scala @@ -0,0 +1,4 @@ +class Bar(val i: Int) { + self: Any with AnyRef => + def this() = this(0) +} -- cgit v1.2.3