Skip to content

Commit 4b8a31f

Browse files
s.bazarsadaevG1ng3r
s.bazarsadaev
authored andcommitted
Closes #14340
- add dynamic access to value classes field
1 parent bf808b3 commit 4b8a31f

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

compiler/src/dotty/tools/dotc/typer/Dynamic.scala

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@ package dotty.tools
22
package dotc
33
package typer
44

5-
import dotty.tools.dotc.ast.Trees._
5+
import dotty.tools.dotc.ast.Trees.*
66
import dotty.tools.dotc.ast.tpd
77
import dotty.tools.dotc.ast.untpd
88
import dotty.tools.dotc.core.Constants.Constant
9-
import dotty.tools.dotc.core.Contexts._
9+
import dotty.tools.dotc.core.Contexts.*
1010
import dotty.tools.dotc.core.Names.{Name, TermName}
11-
import dotty.tools.dotc.core.StdNames._
12-
import dotty.tools.dotc.core.Types._
13-
import dotty.tools.dotc.core.Decorators._
11+
import dotty.tools.dotc.core.StdNames.*
12+
import dotty.tools.dotc.core.Types.*
13+
import dotty.tools.dotc.core.Decorators.*
1414
import dotty.tools.dotc.core.TypeErasure
15-
import util.Spans._
16-
import core.Symbols._
17-
import ErrorReporting._
18-
import reporting._
15+
import util.Spans.*
16+
import core.Symbols.*
17+
import ErrorReporting.*
18+
import dotty.tools.dotc.transform.ValueClasses
19+
import dotty.tools.dotc.transform.TypeUtils.isPrimitiveValueType
20+
import reporting.*
1921

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

217219
fun.tpe.widen match {
220+
case tpe: ValueType if ValueClasses.isDerivedValueClass(tpe.classSymbol) =>
221+
val underlying = ValueClasses.valueClassUnbox(tpe.classSymbol.asClass).info.resultType.asSeenFrom(tpe, tpe.classSymbol)
222+
val wrapped = structuralCall(nme.selectDynamic, Nil)
223+
val resultTree = if wrapped.tpe.isExactlyAny then New(tpe, wrapped.cast(underlying) :: Nil) else wrapped
224+
resultTree.cast(tpe)
225+
218226
case tpe: ValueType =>
219227
structuralCall(nme.selectDynamic, Nil).cast(tpe)
220228

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

242254
// (@allanrenucci) I think everything below is dead code

tests/run/i14340.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
1
2+
2
3+
3
4+
qux

tests/run/i14340.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class Foo(val value: Int) extends AnyVal
2+
class Bar[A](val value: A) extends AnyVal
3+
4+
class Container1 extends reflect.Selectable
5+
6+
class Container2 extends Selectable:
7+
def selectDynamic(name: String) = Bar(name)
8+
9+
val cont1 = new Container1:
10+
def foo = new Foo(1)
11+
val bar = new Bar(Foo(2))
12+
def fooFromInt(i: Int) = new Foo(i)
13+
14+
val cont2 = (new Container2).asInstanceOf[Container2 { def qux: Bar[String] }]
15+
16+
@main def Test: Unit =
17+
println(cont1.foo.value)
18+
println(cont1.bar.value.value)
19+
println(cont1.fooFromInt(3).value)
20+
println(cont2.qux.value)

0 commit comments

Comments
 (0)