Skip to content

Capture leak by selection chain #23207

Open
@noti0na1

Description

@noti0na1

Compiler version

nightly

3.7.2-RC1-bin-20250519-d36e423-NIGHTLY-git-d36e423

Minimized code

import language.experimental.captureChecking
import caps.*

case class Box[T](x: T)

class A:
  def getBox: Box[this.type] = Box(this)

def leak(io: AnyRef^): A =
  class B extends A:
    val hide: AnyRef^{io} = io

  val b = new B
  // val box = b.getBox
  // box.x // error here, ok
  b.getBox.x // should not compile

Output

Run: scala compile --server=false -S 3.nightly Stest.scala.

Expect error, but sucess.

If we assign box to a variable then get x, we will get expected error: Found: A^{io} Required: A.

With -Xprint:cc

package <empty> {
  import language.experimental.captureChecking
  import caps.*
  @SourceFile("Stest.scala") case class Box[T](x: T) extends Object(), Product, 
    Serializable {
    override def hashCode(): Int =
      scala.util.hashing.MurmurHash3.productHash(this, -610376758, true)
    override def equals(x$0: Any): Boolean =
      (this eq x$0.$asInstanceOf[Object]) ||
        (matchResult1[Boolean]: 
          {
            case val x1: (x$0 : Any) = x$0
            if x1.$isInstanceOf[Box[T] @unchecked] then
              {
                case val x$0: Box[T] = x1.$asInstanceOf[Box[T] @unchecked]
                return[matchResult1] this.x == x$0.x && x$0.canEqual(this)
              }
             else ()
            return[matchResult1] false
          }
        )
    override def toString(): String = scala.runtime.ScalaRunTime._toString(this)
    override def canEqual(that: Any): Boolean =
      that.isInstanceOf[Box[T] @unchecked]
    override def productArity: Int = 1
    override def productPrefix: String = "Box"
    override def productElement(n: Int): Any =
      matchResult2[T]: 
        {
          case val x3: (n : Int) = n
          if 0 == x3 then return[matchResult2] this._1 else ()
          throw new IndexOutOfBoundsException(n.toString())
        }
    override def productElementName(n: Int): String =
      matchResult3[("x" : String)]: 
        {
          case val x4: (n : Int) = n
          if 0 == x4 then return[matchResult3] "x" else ()
          throw new IndexOutOfBoundsException(n.toString())
        }
    T
    val x: T
    def copy[T](x: T): Box[T] = new Box[T](x)
    def copy$default$1[T]: T = Box.this.x
    def _1: T = this.x
  }
  final lazy module val Box: Box = new Box()
  @SourceFile("Stest.scala") final module class Box() extends AnyRef(), 
    scala.deriving.Mirror.Product {
    private[this] type $this = Box.type
    private def writeReplace(): AnyRef =
      new scala.runtime.ModuleSerializationProxy(classOf[Box.type])
    def apply[T](x: T): Box[T] = new Box[T](x)
    def unapply[T](x$1: Box[T]): Box[T] = x$1
    override def toString: String = "Box"
    type MirroredMonoType = Box[? <: AnyKind]
    def fromProduct(x$0: Product): Box.MirroredMonoType =
      {
        val x$1: Any = x$0.productElement(0)
        new Box[Any](x$1)
      }
  }
  @SourceFile("Stest.scala") class A() extends Object() {
    def getBox: Box[(A.this : A^)] = Box.apply[(A.this : A^)](this)
  }
  final lazy module val Stest$package: Stest$package = new Stest$package()
  @SourceFile("Stest.scala") final module class Stest$package() extends Object()
     {
    private[this] type $this = Stest$package.type
    private def writeReplace(): AnyRef =
      new scala.runtime.ModuleSerializationProxy(classOf[Stest$package.type])
    def leak(io: AnyRef^): A =
      {
        class B() extends A() {
          val hide: AnyRef^{io} = io
        }
        val b: B^{io} = new B()
        b.getBox.x:(A^?)
      }
  }
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions