diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b77c21893ef7..4533e74283c9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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, diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index dedcf67ea9f7..ebeff2f44a29 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -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 diff --git a/tests/neg/i13114/A.scala b/tests/neg/i13114/A.scala new file mode 100644 index 000000000000..30d3cecc795f --- /dev/null +++ b/tests/neg/i13114/A.scala @@ -0,0 +1,3 @@ +def f = 42 + +class C diff --git a/tests/neg/i13114/B.scala b/tests/neg/i13114/B.scala new file mode 100644 index 000000000000..be778f749ace --- /dev/null +++ b/tests/neg/i13114/B.scala @@ -0,0 +1,7 @@ +class D2 extends C + +package p { + class D extends C // error: not found + + @main def test = println(new D) +} diff --git a/tests/neg/i7891.scala b/tests/neg/i7891.scala new file mode 100644 index 000000000000..4f305f74cad1 --- /dev/null +++ b/tests/neg/i7891.scala @@ -0,0 +1,6 @@ +// was previously ok in one compilation unit +def f22 = "hello, world" + +package p { + @main def m = println(f22) // error +} diff --git a/tests/neg/implicit-package-object.scala b/tests/neg/implicit-package-object.scala index 1af3b413e04a..7b73d620b9b8 100644 --- a/tests/neg/implicit-package-object.scala +++ b/tests/neg/implicit-package-object.scala @@ -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) diff --git a/tests/pos/i0239.scala b/tests/pos/i0239.scala index 258c3c987adc..5b01cd224af1 100644 --- a/tests/pos/i0239.scala +++ b/tests/pos/i0239.scala @@ -1,3 +1,5 @@ +package i0239 + package p { class C[A] { implicit def foo: M[A] = ??? diff --git a/tests/pos/i5978.scala b/tests/pos/i5978.scala index 630a0ec4ea6c..f1954b8c8275 100644 --- a/tests/pos/i5978.scala +++ b/tests/pos/i5978.scala @@ -1,3 +1,4 @@ +package test import scala.language.implicitConversions opaque type Position[Buffer] = Int diff --git a/tests/pos/pos_valueclasses/t5953.scala b/tests/pos/pos_valueclasses/t5953.scala index 84e2243d1d6d..e05ec5b48976 100644 --- a/tests/pos/pos_valueclasses/t5953.scala +++ b/tests/pos/pos_valueclasses/t5953.scala @@ -1,3 +1,5 @@ +package t5953 + trait CBF[-F, -A, +C] trait GenTraversable[+A] trait Traversable[+A] extends GenTraversable[A] diff --git a/tests/run-staging/i4730.scala b/tests/run-staging/i4730.scala index 4c3d9b23cb10..cc9b6d52fb9b 100644 --- a/tests/run-staging/i4730.scala +++ b/tests/run-staging/i4730.scala @@ -1,7 +1,8 @@ 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) => ${ @@ -9,16 +10,12 @@ object Test { 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" => @@ -27,3 +24,9 @@ package scala { } } } +object Test { + import i4730.given + def main(args: Array[String]): Unit = { + scala.mytest.myTest() + } +} diff --git a/tests/run-staging/i6992/Macro_1.scala b/tests/run-staging/i6992/Macro_1.scala index 09cacfd9e1eb..d0a670c5827a 100644 --- a/tests/run-staging/i6992/Macro_1.scala +++ b/tests/run-staging/i6992/Macro_1.scala @@ -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) diff --git a/tests/run-staging/i6992/Test_2.scala b/tests/run-staging/i6992/Test_2.scala index 01ce6977c72c..4e814dcc7de8 100644 --- a/tests/run-staging/i6992/Test_2.scala +++ b/tests/run-staging/i6992/Test_2.scala @@ -1,4 +1,4 @@ -import macros.* +import macros.macros.* object Test { val foo = new Foo