diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 6166991a5d61..2c65dac8ec61 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -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) @@ -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 => @@ -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) } diff --git a/tests/neg-custom-args/fatal-warnings/structural.scala b/tests/neg-custom-args/fatal-warnings/structural.scala index 6cc2c5be7e33..e24eeeae105b 100644 --- a/tests/neg-custom-args/fatal-warnings/structural.scala +++ b/tests/neg-custom-args/fatal-warnings/structural.scala @@ -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} diff --git a/tests/neg/i15065.scala b/tests/neg/i15065.scala new file mode 100644 index 000000000000..63570eb6cc87 --- /dev/null +++ b/tests/neg/i15065.scala @@ -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 diff --git a/tests/neg/structural.scala b/tests/neg/structural.scala index c9892abe03ae..de70092c0396 100644 --- a/tests/neg/structural.scala +++ b/tests/neg/structural.scala @@ -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