Skip to content

Commit 4ff6561

Browse files
authored
Merge pull request #2215 from dotty-staging/#2142
Fix #2142: Skolemize arguments of dependent methods if necessary
2 parents 0bd7821 + 0cf17c5 commit 4ff6561

File tree

7 files changed

+71
-15
lines changed

7 files changed

+71
-15
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,11 @@ object Types {
107107
final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda]
108108

109109
/** Does this type denote a stable reference (i.e. singleton type)? */
110-
@tailrec final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
111-
case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable
110+
final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
111+
case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable || tp.info.isStable
112112
case _: SingletonType | NoPrefix => true
113113
case tp: RefinedOrRecType => tp.parent.isStable
114+
case tp: ExprType => tp.resultType.isStable
114115
case _ => false
115116
}
116117

compiler/src/dotty/tools/dotc/printing/Formatting.scala

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ object Formatting {
107107
else nonSensicalStartTag + str + nonSensicalEndTag
108108
}
109109

110-
private type Recorded = AnyRef /*Symbol | TypeParamRef*/
110+
private type Recorded = AnyRef /*Symbol | TypeParamRef | SkolemType */
111111

112112
private class Seen extends mutable.HashMap[String, List[Recorded]] {
113113

@@ -135,8 +135,13 @@ object Formatting {
135135
if ((sym is ModuleClass) && sym.sourceModule.exists) simpleNameString(sym.sourceModule)
136136
else seen.record(super.simpleNameString(sym), sym)
137137

138-
override def TypeParamRefNameString(param: TypeParamRef): String =
139-
seen.record(super.TypeParamRefNameString(param), param)
138+
override def ParamRefNameString(param: ParamRef): String =
139+
seen.record(super.ParamRefNameString(param), param)
140+
141+
override def toTextRef(tp: SingletonType): Text = tp match {
142+
case tp: SkolemType => seen.record(tp.repr, tp)
143+
case _ => super.toTextRef(tp)
144+
}
140145
}
141146

142147
/** Create explanation for single `Recorded` type or symbol */
@@ -165,6 +170,8 @@ object Formatting {
165170
s"is a type variable${addendum("constraint", ctx.typeComparer.bounds(param))}"
166171
case sym: Symbol =>
167172
s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", sym.info)}"
173+
case tp: SkolemType =>
174+
s"is an unknown value of type ${tp.widen.show}"
168175
}
169176
}
170177

@@ -176,6 +183,7 @@ object Formatting {
176183
private def explanations(seen: Seen)(implicit ctx: Context): String = {
177184
def needsExplanation(entry: Recorded) = entry match {
178185
case param: TypeParamRef => ctx.typerState.constraint.contains(param)
186+
case skolem: SkolemType => true
179187
case _ => false
180188
}
181189

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
134134
case tp: TypeType =>
135135
toTextRHS(tp)
136136
case tp: TermRef
137-
if !tp.denotationIsCurrent && !homogenizedView || // always print underyling when testing picklers
137+
if !tp.denotationIsCurrent && !homogenizedView || // always print underlying when testing picklers
138138
tp.symbol.is(Module) ||
139139
tp.symbol.name.isImportName =>
140140
toTextRef(tp) ~ ".type"
@@ -183,7 +183,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
183183
toTextGlobal(tp.resultType)
184184
}
185185
case tp: TypeParamRef =>
186-
TypeParamRefNameString(tp) ~ lambdaHash(tp.binder)
186+
ParamRefNameString(tp) ~ lambdaHash(tp.binder)
187+
case tp: TermParamRef =>
188+
ParamRefNameString(tp) ~ ".type"
187189
case AnnotatedType(tpe, annot) =>
188190
toTextLocal(tpe) ~ " " ~ toText(annot)
189191
case HKApply(tycon, args) =>
@@ -206,10 +208,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
206208
}
207209
}.close
208210

209-
protected def TypeParamRefNameString(name: TypeName): String = name.toString
211+
protected def ParamRefNameString(name: Name): String = name.toString
210212

211-
protected def TypeParamRefNameString(param: TypeParamRef): String =
212-
TypeParamRefNameString(param.binder.paramNames(param.paramNum))
213+
protected def ParamRefNameString(param: ParamRef): String =
214+
ParamRefNameString(param.binder.paramNames(param.paramNum))
213215

214216
/** The name of the symbol without a unique id. Under refined printing,
215217
* the decoded original name.

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
604604
def optText[T >: Untyped](tree: List[Tree[T]])(encl: Text => Text): Text =
605605
if (tree.exists(!_.isEmpty)) encl(blockText(tree)) else ""
606606

607-
override protected def TypeParamRefNameString(name: TypeName): String =
607+
override protected def ParamRefNameString(name: Name): String =
608608
name.unexpandedName.toString
609609

610610
override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
395395
def addTyped(arg: Arg, formal: Type): Type => Type = {
396396
addArg(typedArg(arg, formal), formal)
397397
if (methodType.isParamDependent)
398-
_.substParam(methodType.newParamRef(n), typeOfArg(arg))
399-
else
400-
identity
398+
safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg))
399+
else identity
401400
}
402401

403402
def missingArg(n: Int): Unit = {

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,28 @@ trait TypeAssigner {
315315
}
316316
}
317317

318+
/** Substitute argument type `argType` for parameter `pref` in type `tp`,
319+
* skolemizing the argument type if it is not stable and `pref` occurs in `tp`.
320+
*/
321+
def safeSubstParam(tp: Type, pref: ParamRef, argType: Type)(implicit ctx: Context) = {
322+
val tp1 = tp.substParam(pref, argType)
323+
if ((tp1 eq tp) || argType.isStable) tp1
324+
else tp.substParam(pref, SkolemType(argType.widen))
325+
}
326+
318327
def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
319328
val ownType = fn.tpe.widen match {
320329
case fntpe: MethodType =>
321-
if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
330+
def safeSubstParams(tp: Type, params: List[ParamRef], args: List[Tree]): Type = params match {
331+
case param :: params1 =>
332+
val tp1 = safeSubstParam(tp, param, args.head.tpe)
333+
safeSubstParams(tp1, params1, args.tail)
334+
case Nil =>
335+
tp
336+
}
337+
if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping)
338+
if (fntpe.isDependent) safeSubstParams(fntpe.resultType, fntpe.paramRefs, args)
339+
else fntpe.resultType
322340
else
323341
errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.pos)
324342
case t =>

tests/neg/i2142.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
object Foo {
2+
3+
class A
4+
val a1 = new A()
5+
val a2 = new A()
6+
7+
def f(x: A, y: x.type) = ()
8+
f(a1, a1) // ok
9+
f(a1, a2) // error
10+
f(new A(), new A()) // error
11+
f(new A(), a1) // error
12+
13+
def g(x: A)(y: x.type) = ()
14+
g(a1)(a1) // ok
15+
g(a1)(a2) // error
16+
g(new A())(new A()) // error
17+
g(new A())(a1) // error
18+
19+
val x0 = g(new A()) _
20+
x0 (new A()) // error
21+
22+
class C[T]
23+
24+
def h(x: A): C[x.type] = ???
25+
val x = h(a1)
26+
val y = h(new A())
27+
28+
}

0 commit comments

Comments
 (0)