From a92652ce2b698e20c7d410c1887a6bc208b062ef Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 12 Jul 2017 19:14:19 +0200 Subject: [PATCH 1/2] Fix #2856 Drop special treatment of packages in findRef This aligns behavior with scalac. --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 14 +------------- tests/neg/i1641.scala | 2 +- tests/pos/i2856.scala | 7 +++++++ 3 files changed, 9 insertions(+), 14 deletions(-) create mode 100644 tests/pos/i2856.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 23a63512d0da..23158078bd05 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -243,20 +243,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (ctx.scope == null) previous else { var result: Type = NoType - val curOwner = ctx.owner - - // Can this scope contain new definitions? This is usually the first - // context where either the scope or the owner changes wrt the - // context immediately nested in it. But for package contexts, it's - // the opposite: the last context before the package changes. This distinction - // is made so that top-level imports following a package clause are - // logically nested in that package clause. - val isNewDefScope = - if (curOwner is Package) curOwner ne ctx.outer.owner - else (ctx.scope ne lastCtx.scope) || (curOwner ne lastCtx.owner) - - if (isNewDefScope) { + if ((ctx.scope ne lastCtx.scope) || (curOwner ne lastCtx.owner)) { val defDenot = ctx.denotNamed(name) if (qualifies(defDenot)) { val found = diff --git a/tests/neg/i1641.scala b/tests/neg/i1641.scala index db1daf79166a..659816b3bb5d 100644 --- a/tests/neg/i1641.scala +++ b/tests/neg/i1641.scala @@ -2,7 +2,7 @@ package bar { object bippy extends (Double => String) { def apply(x: Double): St package object println { def bippy(x: Int, y: Int, z: Int) = "(Int, Int, Int)" } object Test { def main(args: Array[String]): Unit = { - println(bar.bippy(5.5)) + println(bar.bippy(5.5)) // error println(bar.bippy(1, 2, 3)) // error } } diff --git a/tests/pos/i2856.scala b/tests/pos/i2856.scala new file mode 100644 index 000000000000..3ad748c28a51 --- /dev/null +++ b/tests/pos/i2856.scala @@ -0,0 +1,7 @@ +package io.grpc { + trait Grpc +} +package bar { + import io.grpc.Grpc + object a extends Grpc +} From f50bf57876f0f3b24f388e52e9106c4c020afe3b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 13 Jul 2017 13:55:08 +0200 Subject: [PATCH 2/2] Fix #2856: Prioritize root package members over root imports The fix is more complex than I would like (see comment in source code). If someone can reproduce the error locally without this commit and rack it down this would help enormously. --- .../src/dotty/tools/dotc/typer/Typer.scala | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 23158078bd05..289ec44c0a3c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -243,8 +243,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (ctx.scope == null) previous else { var result: Type = NoType + val curOwner = ctx.owner - if ((ctx.scope ne lastCtx.scope) || (curOwner ne lastCtx.owner)) { + + // Can this scope contain new definitions? This is usually the first + // context where either the scope or the owner changes wrt the + // context immediately nested in it. But for package contexts, it's + // the opposite: the last context before the package changes. This distinction + // is made so that top-level imports following a package clause are + // logically nested in that package clause. Finally, for the root package + // we switch back to the original test. This means that rop-level packages in + // the root package take priority over root imports. For instance, + // a top-level io package takes priority over scala.io. + // It would be nice if we could drop all this complication, and + // always use the second condition. Unfortunately compileStdLib breaks + // with an error on CI which I cannot replicate locally (not even + // with the exact list of files given). + val isNewDefScope = + if (curOwner.is(Package) && !curOwner.isRoot) curOwner ne ctx.outer.owner + else (ctx.scope ne lastCtx.scope) || (curOwner ne lastCtx.owner) + + if (isNewDefScope) { val defDenot = ctx.denotNamed(name) if (qualifies(defDenot)) { val found =