From ad1e2e870a55ec63cbd0c63a16e7852ef5e66cfa Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 13 Jul 2017 11:36:35 +0200 Subject: [PATCH] Fix #2858: Handle intersection selection when symbol only exists on one side --- .../dotty/tools/dotc/core/Denotations.scala | 29 ++++++++++--------- .../tools/dotc/core/SymDenotations.scala | 2 +- tests/pos/i2858.scala | 8 +++++ 3 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 tests/pos/i2858.scala diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 3aec60c657b4..74a9138ca3b8 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -386,25 +386,28 @@ object Denotations { /** Establish a partial order "preference" order between symbols. * Give preference to `sym1` over `sym2` if one of the following * conditions holds, in decreasing order of weight: - * 1. sym1 is concrete and sym2 is abstract - * 2. The owner of sym1 comes before the owner of sym2 in the linearization + * 1. sym2 doesn't exist + * 2. sym1 is concrete and sym2 is abstract + * 3. The owner of sym1 comes before the owner of sym2 in the linearization * of the type of the prefix `pre`. - * 3. The access boundary of sym2 is properly contained in the access + * 4. The access boundary of sym2 is properly contained in the access * boundary of sym1. For protected access, we count the enclosing * package as access boundary. - * 4. sym1 a method but sym2 is not. + * 5. sym1 a method but sym2 is not. * The aim of these criteria is to give some disambiguation on access which * - does not depend on textual order or other arbitrary choices * - minimizes raising of doubleDef errors */ def preferSym(sym1: Symbol, sym2: Symbol) = sym1.eq(sym2) || - sym1.isAsConcrete(sym2) && - (!sym2.isAsConcrete(sym1) || - precedes(sym1.owner, sym2.owner) || - accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) || - sym1.is(Method) && !sym2.is(Method)) || - sym1.info.isErroneous + sym1.exists && + (!sym2.exists || + sym1.isAsConcrete(sym2) && + (!sym2.isAsConcrete(sym1) || + precedes(sym1.owner, sym2.owner) || + accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) || + sym1.is(Method) && !sym2.is(Method)) || + sym1.info.isErroneous) /** Sym preference provided types also override */ def prefer(sym1: Symbol, sym2: Symbol, info1: Type, info2: Type) = @@ -425,9 +428,7 @@ object Denotations { else if (isDoubleDef(sym1, sym2)) handleDoubleDef else { val sym = - if (!sym1.exists) sym2 - else if (!sym2.exists) sym1 - else if (preferSym(sym2, sym1)) sym2 + if (preferSym(sym2, sym1)) sym2 else sym1 val jointInfo = try infoMeet(info1, info2) @@ -1243,4 +1244,4 @@ object Denotations { util.Stats.record("stale symbol") override def getMessage() = msg } -} \ No newline at end of file +} diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 7671d2246c28..3a6eaef14a4b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -781,7 +781,7 @@ object SymDenotations { sym.owner == defn.AnyClass || sym == defn.Object_clone || sym.owner.is(Scala2x) - test(symbol) || allOverriddenSymbols.exists(test) + this.exists && (test(symbol) || allOverriddenSymbols.exists(test)) } // ------ access to related symbols --------------------------------- diff --git a/tests/pos/i2858.scala b/tests/pos/i2858.scala new file mode 100644 index 000000000000..d0474d9df81b --- /dev/null +++ b/tests/pos/i2858.scala @@ -0,0 +1,8 @@ +class Cont[A0](x0: A0) { type A = A0; val x: A = x0 } + +object Test { + def test: Unit = { + val c: Cont[_] & { type A = Int } = new Cont(1) + c.x + } +}