Skip to content

Commit

Permalink
Closes #14340
Browse files Browse the repository at this point in the history
- add dynamic access to value classes field
  • Loading branch information
s.bazarsadaev authored and G1ng3r committed Feb 12, 2023
1 parent bf808b3 commit 4b8a31f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 10 deletions.
32 changes: 22 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/Dynamic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ package dotty.tools
package dotc
package typer

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.Trees.*
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.ast.untpd
import dotty.tools.dotc.core.Constants.Constant
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Contexts.*
import dotty.tools.dotc.core.Names.{Name, TermName}
import dotty.tools.dotc.core.StdNames._
import dotty.tools.dotc.core.Types._
import dotty.tools.dotc.core.Decorators._
import dotty.tools.dotc.core.StdNames.*
import dotty.tools.dotc.core.Types.*
import dotty.tools.dotc.core.Decorators.*
import dotty.tools.dotc.core.TypeErasure
import util.Spans._
import core.Symbols._
import ErrorReporting._
import reporting._
import util.Spans.*
import core.Symbols.*
import ErrorReporting.*
import dotty.tools.dotc.transform.ValueClasses
import dotty.tools.dotc.transform.TypeUtils.isPrimitiveValueType
import reporting.*

object Dynamic {
private def isDynamicMethod(name: Name): Boolean =
Expand Down Expand Up @@ -215,6 +217,12 @@ trait Dynamic {
errorTree(tree, em"Structural access not allowed on method $name because it $reason")

fun.tpe.widen match {
case tpe: ValueType if ValueClasses.isDerivedValueClass(tpe.classSymbol) =>
val underlying = ValueClasses.valueClassUnbox(tpe.classSymbol.asClass).info.resultType.asSeenFrom(tpe, tpe.classSymbol)
val wrapped = structuralCall(nme.selectDynamic, Nil)
val resultTree = if wrapped.tpe.isExactlyAny then New(tpe, wrapped.cast(underlying) :: Nil) else wrapped
resultTree.cast(tpe)

case tpe: ValueType =>
structuralCall(nme.selectDynamic, Nil).cast(tpe)

Expand All @@ -236,7 +244,11 @@ trait Dynamic {
fail(i"has a parameter type with an unstable erasure") :: Nil
else
TypeErasure.erasure(tpe).asInstanceOf[MethodType].paramInfos.map(clsOf(_))
structuralCall(nme.applyDynamic, classOfs).cast(tpe.finalResultType)
val finalTpe = tpe.finalResultType
if ValueClasses.isDerivedValueClass(finalTpe.classSymbol) then
New(finalTpe, structuralCall(nme.applyDynamic, classOfs).cast(finalTpe)
.cast(ValueClasses.valueClassUnbox(finalTpe.classSymbol.asClass).info.resultType.asSeenFrom(finalTpe, finalTpe.classSymbol)) :: Nil)
else structuralCall(nme.applyDynamic, classOfs).cast(finalTpe)
}

// (@allanrenucci) I think everything below is dead code
Expand Down
4 changes: 4 additions & 0 deletions tests/run/i14340.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1
2
3
qux
20 changes: 20 additions & 0 deletions tests/run/i14340.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Foo(val value: Int) extends AnyVal
class Bar[A](val value: A) extends AnyVal

class Container1 extends reflect.Selectable

class Container2 extends Selectable:
def selectDynamic(name: String) = Bar(name)

val cont1 = new Container1:
def foo = new Foo(1)
val bar = new Bar(Foo(2))
def fooFromInt(i: Int) = new Foo(i)

val cont2 = (new Container2).asInstanceOf[Container2 { def qux: Bar[String] }]

@main def Test: Unit =
println(cont1.foo.value)
println(cont1.bar.value.value)
println(cont1.fooFromInt(3).value)
println(cont2.qux.value)

0 comments on commit 4b8a31f

Please sign in to comment.