Skip to content

Commit 6b342c1

Browse files
committed
Fix #2152: Instantiate dependent result type parameters
#2152 shows that dependent result type parameters can end up in the types of terms, so we have to eliminate them. If we don't we get orphan parameters in pickling. Fix method name and comment
1 parent 1058278 commit 6b342c1

File tree

5 files changed

+22
-10
lines changed

5 files changed

+22
-10
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ object NameKinds {
206206
val InlineAccessorName = new UniqueNameKind("$_inlineAccessor_$")
207207
val TempResultName = new UniqueNameKind("ev$")
208208
val EvidenceParamName = new UniqueNameKind("evidence$")
209-
val DepParamName = new UniqueNameKind("<param>")
209+
val DepParamName = new UniqueNameKind("(param)")
210210
val LazyImplicitName = new UniqueNameKind("$_lazy_implicit_$")
211211
val LazyLocalName = new UniqueNameKind("$lzy")
212212
val LazyLocalInitName = new UniqueNameKind("$lzyINIT")

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

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import SymDenotations._, Denotations.SingleDenotation
77
import config.Printers.typr
88
import util.Positions._
99
import NameOps._
10+
import NameKinds.DepParamName
1011
import Decorators._
1112
import StdNames._
1213
import Annotations._
@@ -169,6 +170,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
169170
simplify(l, theMap) & simplify(r, theMap)
170171
case OrType(l, r) =>
171172
simplify(l, theMap) | simplify(r, theMap)
173+
case tp: TypeVar if tp.origin.paramName.is(DepParamName) =>
174+
val effectiveVariance = if (theMap == null) 1 else theMap.variance
175+
tp.instanceOpt orElse tp.instantiate(fromBelow = effectiveVariance != -1)
172176
case _ =>
173177
(if (theMap != null) theMap else new SimplifyMap).mapOver(tp)
174178
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -3508,7 +3508,7 @@ object Types {
35083508

35093509
def apply(tp: Type): Type
35103510

3511-
protected var variance = 1
3511+
protected[core] var variance = 1
35123512

35133513
protected def derivedSelect(tp: NamedType, pre: Type): Type =
35143514
tp.derivedSelect(pre)

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

+9-8
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,10 @@ object ProtoTypes {
377377
* Also, if `owningTree` is non-empty, add a type variable for each parameter.
378378
* @return The added type lambda, and the list of created type variables.
379379
*/
380-
def constrained(tl: TypeLambda, owningTree: untpd.Tree)(implicit ctx: Context): (TypeLambda, List[TypeTree]) = {
380+
def constrained(tl: TypeLambda, owningTree: untpd.Tree, alwaysAddTypeVars: Boolean = false)(implicit ctx: Context): (TypeLambda, List[TypeTree]) = {
381381
val state = ctx.typerState
382-
assert(!(ctx.typerState.isCommittable && owningTree.isEmpty),
382+
val addTypeVars = alwaysAddTypeVars || !owningTree.isEmpty
383+
assert(!(ctx.typerState.isCommittable && !addTypeVars),
383384
s"inconsistent: no typevars were added to committable constraint ${state.constraint}")
384385

385386
def newTypeVars(tl: TypeLambda): List[TypeTree] =
@@ -392,21 +393,21 @@ object ProtoTypes {
392393
val added =
393394
if (state.constraint contains tl) tl.newLikeThis(tl.paramNames, tl.paramInfos, tl.resultType)
394395
else tl
395-
val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
396+
val tvars = if (addTypeVars) newTypeVars(added) else Nil
396397
ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]])
397398
(added, tvars)
398399
}
399400

400401
/** Same as `constrained(tl, EmptyTree)`, but returns just the created type lambda */
401402
def constrained(tl: TypeLambda)(implicit ctx: Context): TypeLambda = constrained(tl, EmptyTree)._1
402403

403-
/** Create a new TypeParamRef that represents a dependent method parameter singleton */
404-
def newDepTypeParamRef(tp: Type)(implicit ctx: Context): TypeParamRef = {
404+
/** Create a new TypeVar that represents a dependent method parameter singleton */
405+
def newDepTypeVar(tp: Type)(implicit ctx: Context): TypeVar = {
405406
val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)(
406407
pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil,
407408
pt => defn.AnyType)
408-
ctx.typeComparer.addToConstraint(poly, Nil)
409-
TypeParamRef(poly, 0)
409+
constrained(poly, untpd.EmptyTree, alwaysAddTypeVars = true)
410+
._2.head.tpe.asInstanceOf[TypeVar]
410411
}
411412

412413
/** The result type of `mt`, where all references to parameters of `mt` are
@@ -415,7 +416,7 @@ object ProtoTypes {
415416
def resultTypeApprox(mt: MethodType)(implicit ctx: Context): Type =
416417
if (mt.isDependent) {
417418
def replacement(tp: Type) =
418-
if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeParamRef(tp)
419+
if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeVar(tp)
419420
mt.resultType.substParams(mt, mt.paramInfos.map(replacement))
420421
}
421422
else mt.resultType

tests/pos/i2152.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Contra[-D](task: AnyRef)
2+
object Test {
3+
def narrow(task: AnyRef): Contra[task.type] = new Contra(task)
4+
def ident[Before](elems: Contra[Before]): Contra[Before] = elems
5+
val foo = null
6+
ident(narrow(foo))
7+
}

0 commit comments

Comments
 (0)