Skip to content

Capture leak by selection chain #23207

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

Open
noti0na1 opened this issue May 20, 2025 · 0 comments
Open

Capture leak by selection chain #23207

noti0na1 opened this issue May 20, 2025 · 0 comments
Assignees
Labels
area:experimental:cc Capture checking related itype:bug

Comments

@noti0na1
Copy link
Member

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^?)
      }
  }
}
@noti0na1 noti0na1 added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label area:experimental:cc Capture checking related and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels May 20, 2025
@bracevac bracevac self-assigned this Jun 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:experimental:cc Capture checking related itype:bug
Projects
None yet
Development

No branches or pull requests

2 participants