Skip to content

Reject structural applications of polymorphic methods #15090

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

Merged
merged 3 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -578,12 +578,12 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
pre
case _ =>
tree1

val countsAsPure =
if dropOp(tree1).symbol.isInlineVal
then isIdempotentExpr(tree1)
else isPureExpr(tree1)

if countsAsPure then Literal(value).withSpan(tree.span)
else
val pre = dropOp(tree1)
Expand Down Expand Up @@ -864,8 +864,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* that is not a member of an underlying class or trait?
*/
def isStructuralTermSelectOrApply(tree: Tree)(using Context): Boolean = {
def isStructuralTermSelect(tree: Select) = {
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match {
def isStructuralTermSelect(tree: Select) =
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match
case RefinedType(parent, rname, rinfo) =>
rname == tree.name || hasRefinement(parent)
case tp: TypeProxy =>
Expand All @@ -876,17 +876,21 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
hasRefinement(tp.tp1) || hasRefinement(tp.tp2)
case _ =>
false
!tree.symbol.exists
&& tree.isTerm
&& {
val qualType = tree.qualifier.tpe
hasRefinement(qualType) && !qualType.derivesFrom(defn.PolyFunctionClass)
}
!tree.symbol.exists && tree.isTerm && hasRefinement(tree.qualifier.tpe)
}
def loop(tree: Tree): Boolean = tree match {
def loop(tree: Tree): Boolean = tree match
case TypeApply(fun, _) =>
loop(fun)
case Apply(fun, _) =>
loop(fun)
case tree: Select =>
isStructuralTermSelect(tree)
case _ =>
false
}
loop(tree)
}

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/fatal-warnings/structural.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object RClose {
package p3 {

object Test {
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
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

def main(args: Array[String]): Unit = {
idMap(Some(5)) // error: type mismatch: found Some[Int], required Object{map: [U](f: Any => U): Any}
Expand Down
8 changes: 8 additions & 0 deletions tests/neg/i15065.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
trait Foo extends reflect.Selectable

val foo = new Foo:
def bar[A](): Int = ???

val x = foo.bar() // error: Structural access not allowed on method bar because it is polymorphic

val y = foo.bar[Int]() // error: Structural access not allowed on method bar because it is polymorphic
2 changes: 1 addition & 1 deletion tests/neg/structural.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object Test3 {
val y: { type T = Int; def t = 4; def f(a:T) = true } // error: illegal refinement // error: illegal refinement
= new { type T = Int; def t = 4; def f(a:T) = true }

def h(x: { def f[T](a: T): Int }) = x.f[Int](4) // error: polymorphic refinement method ... no longer allowed
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

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