Skip to content

Commit

Permalink
Rule Out Exports of Member of the Current Class (#22545)
Browse files Browse the repository at this point in the history
Fix #22147 

Supersedes #22503

Co-authored-by: Jan-Pieter van den Heuvel
<jan-pieter@users.noreply.github.com>
Co-authored-by: Willem W Bakker <wwbakker@users.noreply.github.com>
  • Loading branch information
odersky and wwbakker authored Feb 12, 2025
2 parents e88bf19 + 5e8eb74 commit b995bdc
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
17 changes: 16 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1177,11 +1177,26 @@ class Namer { typer: Typer =>
def canForward(mbr: SingleDenotation, alias: TermName): CanForward = {
import CanForward.*
val sym = mbr.symbol
/**
* The export selects a member of the current class (issue #22147).
* Assumes that cls.classInfo.selfType.derivesFrom(sym.owner) is true.
*/
def isCurrentClassMember: Boolean = expr match
case id: (Ident | This) => // Access through self type or this
/* Given the usage context below, where cls's self type is a subtype of sym.owner,
it suffices to check if symbol is the same class. */
cls == id.symbol
case _ => false
if !sym.isAccessibleFrom(pathType) then
No("is not accessible")
else if sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge) || sym.is(ConstructorProxy) || sym.isAllOf(JavaModule) then
Skip
else if cls.derivesFrom(sym.owner) && (sym.owner == cls || !sym.is(Deferred)) then
// if the cls is a subclass or mixes in the owner of the symbol
// and either
// * the symbols owner is the cls itself
// * the symbol is not a deferred symbol
// * the symbol is a member of the current class (#22147)
else if cls.classInfo.selfType.derivesFrom(sym.owner) && (sym.owner == cls || !sym.is(Deferred) || isCurrentClassMember) then
No(i"is already a member of $cls")
else if pathMethod.exists && mbr.isType then
No("is a type, so it cannot be exported as extension method")
Expand Down
41 changes: 41 additions & 0 deletions tests/neg/exports3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
trait P:
def foo: Int

class A extends P:
export this.foo // error

trait Q extends P:
def bar: Int

trait R extends P:
def baz: Int
val a1: A
val a2: A

abstract class B extends R:
self =>
export this.baz // error
export self.bar // error
export this.a1.foo
export self.a2.foo // error
export a2.foo // error

abstract class D extends P:
val p: P
export p.foo

abstract class E:
self: P =>
export self.foo // error

abstract class F:
self: P =>
export this.foo // error

class G(p: P):
self: P =>
export p.foo

class H(p: P):
self: P =>
export this.p.foo
14 changes: 14 additions & 0 deletions tests/neg/i20245.check
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,17 @@
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
|
| longer explanation available when compiling with `-explain`
-- [E046] Cyclic Error: tests/neg/i20245/Typer_2.scala:10:7 ------------------------------------------------------------
10 |import effekt.source.{ resolve } // error
| ^
| Cyclic reference involving class Context
|
| The error occurred while trying to compute the base classes of class Context
| which required to compute the base classes of trait TyperOps
| which required to compute the signature of trait TyperOps
| which required to elaborate the export clause export unification.requireSubtype
| which required to compute the base classes of class Context
|
| Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace.
|
| longer explanation available when compiling with `-explain`
2 changes: 1 addition & 1 deletion tests/neg/i20245/Typer_2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import effekt.util.messages.ErrorReporter
import effekt.context.{ Context }

// This import is also NECESSARY for the cyclic error
import effekt.source.{ resolve }
import effekt.source.{ resolve } // error


trait TyperOps extends ErrorReporter { self: Context =>
Expand Down

0 comments on commit b995bdc

Please sign in to comment.