Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make members of the empty package invisible from inside other packages #13593

Merged
merged 2 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 17 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,32 @@ class Typer extends Namer
if !suppressErrors then report.error(msg, pos)

/** A symbol qualifies if it really exists and is not a package class.
* In addition, if we are in a constructor of a pattern, we ignore all definitions
* which are methods and not accessors (note: if we don't do that
* case x :: xs in class List would return the :: method).
*
* Package classes are part of their parent's scope, because otherwise
* we could not reload them via `_.member`. On the other hand, accessing a
* package as a type from source is always an error.

* In addition:
* - if we are in a constructor of a pattern, we ignore all definitions
* which are methods and not accessors (note: if we don't do that
* case x :: xs in class List would return the :: method).
* - Members of the empty package can be accessed only from within the empty package.
* Note: it would be cleaner to never nest package definitions in empty package definitions,
* but then we'd have to give up the fiction that a compilation unit consists of
* a single tree (because a source file may have both toplevel classes which go
* into the empty package and package definitions, which would have to stay outside).
* Since the principle of a single tree per compilation unit is assumed by many
* tools, we did not want to take that step.
*/
def qualifies(denot: Denotation): Boolean =
reallyExists(denot)
&& (!pt.isInstanceOf[UnapplySelectionProto]
|| denot.hasAltWith(sd => !sd.symbol.is(Method, butNot = Accessor)))
&& !denot.symbol.is(PackageClass)
&& {
var owner = denot.symbol.maybeOwner
if owner.isPackageObject then owner = owner.owner
!owner.isEmptyPackage || ctx.owner.enclosingPackageClass.isEmptyPackage
}

/** Find the denotation of enclosing `name` in given context `ctx`.
* @param previous A denotation that was found in a more deeply nested scope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,8 @@ class CompletionTest {
}

@Test def completeFromPackageObjectWithInheritance: Unit = {
code"""trait Foo[A] { def xxxx(a: A) = a }
code"""package test
|trait Foo[A] { def xxxx(a: A) = a }
|package object foo extends Foo[Int] {}
|object Test {
| foo.xx$m1
Expand Down
3 changes: 3 additions & 0 deletions tests/neg/i13114/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def f = 42

class C
7 changes: 7 additions & 0 deletions tests/neg/i13114/B.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class D2 extends C
dwijnand marked this conversation as resolved.
Show resolved Hide resolved

package p {
class D extends C // error: not found

@main def test = println(new D)
}
6 changes: 6 additions & 0 deletions tests/neg/i7891.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// was previously ok in one compilation unit
def f22 = "hello, world"

package p {
@main def m = println(f22) // error
}
9 changes: 6 additions & 3 deletions tests/neg/implicit-package-object.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
trait ToString[A] {
def print(a: A): Unit
}
package toString:
trait ToString[A] {
def print(a: A): Unit
}

import toString._

package A {
case class AA(text: String)
Expand Down
2 changes: 2 additions & 0 deletions tests/pos/i0239.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package i0239

package p {
class C[A] {
implicit def foo: M[A] = ???
Expand Down
1 change: 1 addition & 0 deletions tests/pos/i5978.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
package test
import scala.language.implicitConversions

opaque type Position[Buffer] = Int
Expand Down
2 changes: 2 additions & 0 deletions tests/pos/pos_valueclasses/t5953.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package t5953

trait CBF[-F, -A, +C]
trait GenTraversable[+A]
trait Traversable[+A] extends GenTraversable[A]
Expand Down
15 changes: 9 additions & 6 deletions tests/run-staging/i4730.scala
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import scala.quoted.*
import scala.quoted.staging.*

object Test {

package i4730:
given Compiler = Compiler.make(getClass.getClassLoader)
def ret(using Quotes): Expr[Int => Int] = '{ (x: Int) =>
${
val z = run('{x + 1}) // throws scala.quoted.runtime.impl.ScopeException =>
Expr(z)
}
}
def main(args: Array[String]): Unit = {
scala.mytest.myTest()
}
}

package scala {
package mytest {
def myTest()(using Compiler) = {
try {
run(Test.ret).apply(10)
run(i4730.ret).apply(10)
throw new Exception
} catch {
case ex: Exception if ex.getClass.getName == "scala.quoted.runtime.impl.ScopeException" =>
Expand All @@ -27,3 +24,9 @@ package scala {
}
}
}
object Test {
import i4730.given
def main(args: Array[String]): Unit = {
scala.mytest.myTest()
}
}
15 changes: 8 additions & 7 deletions tests/run-staging/i6992/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
import scala.quoted.*
import scala.quoted.staging.*

package macros:

object macros {
inline def mcr(x: => Any): Any = ${mcrImpl('x)}
object macros {
inline def mcr(x: => Any): Any = ${mcrImpl('x)}

class Foo { val x = 10 }
class Foo { val x = 10 }

def mcrImpl(body: Expr[Any])(using ctx: Quotes): Expr[Any] =
MyTest.mcrImpl(body)
}
def mcrImpl(body: Expr[Any])(using ctx: Quotes): Expr[Any] =
MyTest.mcrImpl(body)
}

package scala {
object MyTest {
import macros.*
import macros.macros.*

given Compiler = Compiler.make(getClass.getClassLoader)

Expand Down
2 changes: 1 addition & 1 deletion tests/run-staging/i6992/Test_2.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import macros.*
import macros.macros.*

object Test {
val foo = new Foo
Expand Down