Skip to content

Commit 7720bc6

Browse files
authored
Merge pull request #15090 from dotty-staging/fix-15065
Reject structural applications of polymorphic methods
2 parents d829f7c + 01ae042 commit 7720bc6

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -578,12 +578,12 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
578578
pre
579579
case _ =>
580580
tree1
581-
581+
582582
val countsAsPure =
583583
if dropOp(tree1).symbol.isInlineVal
584584
then isIdempotentExpr(tree1)
585585
else isPureExpr(tree1)
586-
586+
587587
if countsAsPure then Literal(value).withSpan(tree.span)
588588
else
589589
val pre = dropOp(tree1)
@@ -864,8 +864,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
864864
* that is not a member of an underlying class or trait?
865865
*/
866866
def isStructuralTermSelectOrApply(tree: Tree)(using Context): Boolean = {
867-
def isStructuralTermSelect(tree: Select) = {
868-
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match {
867+
def isStructuralTermSelect(tree: Select) =
868+
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match
869869
case RefinedType(parent, rname, rinfo) =>
870870
rname == tree.name || hasRefinement(parent)
871871
case tp: TypeProxy =>
@@ -876,17 +876,21 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
876876
hasRefinement(tp.tp1) || hasRefinement(tp.tp2)
877877
case _ =>
878878
false
879+
!tree.symbol.exists
880+
&& tree.isTerm
881+
&& {
882+
val qualType = tree.qualifier.tpe
883+
hasRefinement(qualType) && !qualType.derivesFrom(defn.PolyFunctionClass)
879884
}
880-
!tree.symbol.exists && tree.isTerm && hasRefinement(tree.qualifier.tpe)
881-
}
882-
def loop(tree: Tree): Boolean = tree match {
885+
def loop(tree: Tree): Boolean = tree match
886+
case TypeApply(fun, _) =>
887+
loop(fun)
883888
case Apply(fun, _) =>
884889
loop(fun)
885890
case tree: Select =>
886891
isStructuralTermSelect(tree)
887892
case _ =>
888893
false
889-
}
890894
loop(tree)
891895
}
892896

tests/neg-custom-args/fatal-warnings/structural.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ object RClose {
4040
package p3 {
4141

4242
object Test {
43-
def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t) // error: polymorphic refinement method map without matching type in parent Object is no longer allowed
43+
def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t) // error: polymorphic refinement method map without matching type in parent Object is no longer allowed // error: Structural access not allowed
4444

4545
def main(args: Array[String]): Unit = {
4646
idMap(Some(5)) // error: type mismatch: found Some[Int], required Object{map: [U](f: Any => U): Any}

tests/neg/i15065.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Foo extends reflect.Selectable
2+
3+
val foo = new Foo:
4+
def bar[A](): Int = ???
5+
6+
val x = foo.bar() // error: Structural access not allowed on method bar because it is polymorphic
7+
8+
val y = foo.bar[Int]() // error: Structural access not allowed on method bar because it is polymorphic

tests/neg/structural.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Test3 {
66
val y: { type T = Int; def t = 4; def f(a:T) = true } // error: illegal refinement // error: illegal refinement
77
= new { type T = Int; def t = 4; def f(a:T) = true }
88

9-
def h(x: { def f[T](a: T): Int }) = x.f[Int](4) // error: polymorphic refinement method ... no longer allowed
9+
def h(x: { def f[T](a: T): Int }) = x.f[Int](4) // error: polymorphic refinement method ... no longer allowed // error: Structural access not allowed
1010

1111
type A = { def foo(x: Int): Unit; def foo(x: String): Unit } // error: overloaded definition // error: overloaded definition
1212
type B = { val foo: Int; def foo: Int } // error: duplicate foo

0 commit comments

Comments
 (0)