Skip to content

Commit 1fb965c

Browse files
committed
Handle signatures over uninstantiated type variables
Taking the signature over a type with uninstantiated type variables means that the signature can change later, once we instantiate the type variable. We handle this by recording uninstantiated positions of signatures and fixing them in PostTyper, when type variables are instantiated.
1 parent 82d042f commit 1fb965c

File tree

5 files changed

+39
-3
lines changed

5 files changed

+39
-3
lines changed

src/dotty/tools/dotc/core/Signature.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
2929
/** Does this signature coincide with that signature on their parameter parts? */
3030
final def sameParams(that: Signature): Boolean = this.paramsSig == that.paramsSig
3131

32+
/** Does this signature coincide with that signature on their parameter parts?
33+
* This is the case if all parameter names are _consistent_, i.e. they are either
34+
* equal or on of them is tpnme.Uninstantiated.
35+
*/
36+
final def consistentParams(that: Signature): Boolean = {
37+
def consistent(name1: TypeName, name2: TypeName) =
38+
name1 == name2 || name1 == tpnme.Uninstantiated || name2 == tpnme.Uninstantiated
39+
def loop(names1: List[TypeName], names2: List[TypeName]): Boolean =
40+
if (names1.isEmpty) names2.isEmpty
41+
else names2.nonEmpty && consistent(names1.head, names2.head) && loop(names1.tail, names2.tail)
42+
loop(this.paramsSig, that.paramsSig)
43+
}
44+
3245
/** The degree to which this signature matches `that`.
3346
* If both parameter and result type names match (i.e. they are the same
3447
* or one is a wildcard), the result is `FullMatch`.
@@ -52,6 +65,13 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
5265
def prepend(params: List[Type], isJava: Boolean)(implicit ctx: Context) =
5366
Signature((params.map(sigName(_, isJava))) ++ paramsSig, resSig)
5467

68+
/** A signature is under-defined if its paramsSig part contains at least one
69+
* `tpnme.Uninstantited`. Under-defined signatures arise when taking a signature
70+
* of a type that still contains uninstantiated type variables. They are eliminated
71+
* by `fixSignature` in `PostTyper`.
72+
*/
73+
def isUnderDefined(implicit ctx: Context) =
74+
paramsSig.contains(tpnme.Uninstantiated) || resSig == tpnme.Uninstantiated
5575
}
5676

5777
object Signature {

src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,8 @@ object StdNames {
743743
(0 until num).map(syntheticLambdaParamName)(breakOut)
744744

745745
final val Conforms = encode("<:<")
746+
747+
final val Uninstantiated: TypeName = "?$"
746748
}
747749

748750
abstract class JavaNames[N <: Name] extends DefinedNames[N] {

src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
476476
sigName(tp.widen)
477477
case ExprType(rt) =>
478478
sigName(defn.FunctionOf(Nil, rt))
479+
case tp: TypeVar =>
480+
val inst = tp.instanceOpt
481+
if (inst.exists) sigName(inst) else tpnme.Uninstantiated
479482
case tp: TypeProxy =>
480483
sigName(tp.underlying)
481484
case ErrorType | WildcardType =>

src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2354,7 +2354,7 @@ object Types {
23542354
final override def signature(implicit ctx: Context): Signature = {
23552355
if (ctx.runId != mySignatureRunId) {
23562356
mySignature = computeSignature
2357-
mySignatureRunId = ctx.runId
2357+
if (!mySignature.isUnderDefined) mySignatureRunId = ctx.runId
23582358
}
23592359
mySignature
23602360
}

src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
115115
}
116116
}
117117

118+
/** If the type of `tree` is a TermRefWithSignature with an underdefined
119+
* signature, narrow the type by re-computing the signature (which should
120+
* be fully-defined by now).
121+
*/
122+
private def fixSignature[T <: Tree](tree: T)(implicit ctx: Context): T = tree.tpe match {
123+
case tpe: TermRefWithSignature if tpe.signature.isUnderDefined =>
124+
println(i"fixing $tree with type ${tree.tpe.widen.toString} with sig ${tpe.signature} to ${tpe.widen.signature}")
125+
tree.withType(TermRef.withSig(tpe.prefix, tpe.name, tpe.widen.signature)).asInstanceOf[T]
126+
case _ => tree
127+
}
128+
118129
class PostTyperTransformer extends Transformer {
119130

120131
private var inJavaAnnot: Boolean = false
@@ -192,10 +203,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
192203
case tree: Ident =>
193204
tree.tpe match {
194205
case tpe: ThisType => This(tpe.cls).withPos(tree.pos)
195-
case _ => paramFwd.adaptRef(tree)
206+
case _ => paramFwd.adaptRef(fixSignature(tree))
196207
}
197208
case tree: Select =>
198-
transformSelect(paramFwd.adaptRef(tree), Nil)
209+
transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil)
199210
case tree: TypeApply =>
200211
val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
201212
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])

0 commit comments

Comments
 (0)