Skip to content

Commit d411515

Browse files
authored
Merge pull request scala#8055 from retronym/ticket/11523
Avoid bad generic signatures when mixin forwarders tparams shadow
2 parents 2ef2f9f + 1c15b20 commit d411515

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

src/compiler/scala/tools/nsc/transform/Mixin.scala

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import symtab._
1717
import Flags._
1818
import scala.annotation.tailrec
1919
import scala.collection.mutable
20+
import scala.reflect.NameTransformer
2021

2122

2223
abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
@@ -192,11 +193,37 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
192193
// Optimize: no need if mixinClass has no typeparams.
193194
// !!! JZ Really? What about the effect of abstract types, prefix?
194195
if (mixinClass.typeParams.isEmpty) sym
195-
else sym modifyInfo (_ => forwarderInfo)
196+
else {
197+
sym modifyInfo (_ => forwarderInfo)
198+
avoidTypeParamShadowing(mixinMember, sym)
199+
sym
200+
}
196201
}
197202
newSym
198203
}
199204

205+
// scala/bug#11523 rename method type parameters that shadow enclosing class type parameters in the host class
206+
// of the mixin forwarder
207+
private def avoidTypeParamShadowing(mixinMember: Symbol, forwarder: Symbol): Unit = {
208+
def isForwarderTparam(sym: Symbol) = {
209+
val owner = sym.owner
210+
// TODO fix forwarder's info should not refer to tparams of mixinMember, fix cloning in caller!
211+
// try forwarderInfo.cloneInfo(sym)
212+
owner == forwarder || owner == mixinMember
213+
}
214+
215+
val symTparams: mutable.Map[Name, Symbol] = mutable.Map.from(forwarder.typeParams.iterator.map(t => (t.name, t)))
216+
forwarder.info.foreach {
217+
case TypeRef(_, tparam, _) if tparam.isTypeParameter && !isForwarderTparam(tparam) =>
218+
symTparams.get(tparam.name).foreach{ symTparam =>
219+
debuglog(s"Renaming ${symTparam} (owned by ${symTparam.owner}, a mixin forwarder hosted in ${forwarder.enclClass.fullNameString}) to avoid shadowing enclosing type parameter of ${tparam.owner.fullNameString})")
220+
symTparam.name = symTparam.name.append(NameTransformer.NAME_JOIN_STRING)
221+
symTparams.remove(tparam.name) // only rename once
222+
}
223+
case _ =>
224+
}
225+
}
226+
200227
def publicizeTraitMethods(clazz: Symbol): Unit = {
201228
if (treatedClassInfos(clazz) != clazz.info) {
202229
treatedClassInfos(clazz) = clazz.info

test/files/pos/t11525a/A.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package example
2+
3+
4+
trait PartialFunction[-A, +B] extends Function1[A,B] { self =>
5+
def isDefinedAt(x: A): Boolean
6+
def compose[CLASH](k: PartialFunction[CLASH, A]): PartialFunction[CLASH, B] = null
7+
}
8+
9+
trait Function1[-T1, +R] extends AnyRef { self =>
10+
def apply(v1: T1): R
11+
def compose[A](g: Function1[A, T1]): Function1[A , R] = null
12+
}
13+
14+
abstract class AbstractPartialFunction[-T1, +CLASH] extends Function1[T1, CLASH] with PartialFunction[T1, CLASH] { self =>
15+
def apply(x: T1): CLASH = ???
16+
}

test/files/pos/t11525a/Test.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class Test {
2+
class D extends example.AbstractPartialFunction<String, String> {
3+
public boolean isDefinedAt(String s) { return false; }
4+
};
5+
}

test/files/pos/t11525b/Test.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class Test {
2+
class D extends scala.runtime.AbstractPartialFunction<String, String> {
3+
public boolean isDefinedAt(String s) { return false; }
4+
};
5+
}

0 commit comments

Comments
 (0)