Skip to content

Commit

Permalink
Allow selectDynamic and applyDynamic to be an extension methods
Browse files Browse the repository at this point in the history
Allow selectDynamic and applyDynamic to be an extension methods when dispatching structurally.

Fixes scala#17100
  • Loading branch information
odersky committed Mar 15, 2023
1 parent 89a744f commit b5b491f
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 4 deletions.
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Dynamic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ trait Dynamic {
// ($qual: Selectable).$selectorName("$name")
val base =
untpd.Apply(
untpd.TypedSplice(selectable.select(selectorName)).withSpan(fun.span),
untpd.Select(untpd.TypedSplice(selectable), selectorName).withSpan(fun.span),
(Literal(Constant(name.encode.toString)) :: Nil).map(untpd.TypedSplice(_)))

val scall =
Expand Down Expand Up @@ -219,19 +219,19 @@ trait Dynamic {
extension (tree: Tree)
/** The implementations of `selectDynamic` and `applyDynamic` in `scala.reflect.SelectDynamic` have no information about the expected return type of a value/method which was declared in the refinement,
* only the JVM type after erasure can be obtained through reflection, e.g.
*
*
* class Foo(val i: Int) extends AnyVal
* class Reflective extends reflect.Selectable
* val reflective = new Reflective {
* def foo = Foo(1) // Foo at compile time, java.lang.Integer in reflection
* }
*
*
* Because of that reflective access cannot be implemented properly in `scala.reflect.SelectDynamic` itself
* because it's not known there if the value should be wrapped in a value class constructor call or not.
* Hence the logic of wrapping is performed here, relying on the fact that the implementations of `selectDynamic` and `applyDynamic` in `scala.reflect.SelectDynamic` are final.
*/
def maybeBoxingCast(tpe: Type) =
val maybeBoxed =
val maybeBoxed =
if ValueClasses.isDerivedValueClass(tpe.classSymbol) && qual.tpe <:< defn.ReflectSelectableTypeRef then
val genericUnderlying = ValueClasses.valueClassUnbox(tpe.classSymbol.asClass)
val underlying = tpe.select(genericUnderlying).widen.resultType
Expand Down
10 changes: 10 additions & 0 deletions tests/pos/i17100.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
trait Sel extends Selectable

extension (s: Sel)
def selectDynamic(name: String) = ???
def applyDynamic(name: String)(x: Int) = ???

val sel = (new Sel {}).asInstanceOf[Sel{ def foo: String; def bar(x: Int): Int }]
val foo = sel.selectDynamic("foo")
val foo2 = sel.foo
val foo3 = sel.bar(2)

0 comments on commit b5b491f

Please sign in to comment.