Skip to content

Commit d428b87

Browse files
committed
Denote prefix of constructor pats in type params 1/2
One part of the problem was that when you drill down to the info of a member of a polymorphic class, you should remember to push down the type params of the class by re-wrapping the info of the member in a PolyType, so that, then when you relativize the info of the member relative to the class and its corresponding prefix (used as its this type, which should thus have kind *), you also rewrite the info of the type params, which may be affected as illustrated by the test case (coming in 2/2). Dotty has a neat solution through denotations, we need to take care...
1 parent 40416be commit d428b87

File tree

2 files changed

+23
-19
lines changed

2 files changed

+23
-19
lines changed

src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,25 @@ trait PatternTypers {
224224
*/
225225
private def convertToCaseConstructor(tree: Tree, caseClass: Symbol, ptIn: Type): Tree = {
226226
val variantToSkolem = new VariantToSkolemMap
227-
val caseClassType = tree.tpe.prefix memberType caseClass
228-
val caseConstructorType = caseClassType memberType caseClass.primaryConstructor
229-
val tree1 = TypeTree(caseConstructorType) setOriginal tree
227+
228+
// `caseClassType` is the prefix from which we're seeing the constructor info, so it must be kind *.
229+
// Need the `initialize` call to make sure we see any type params.
230+
val caseClassType = caseClass.initialize.tpe_*.asSeenFrom(tree.tpe.prefix, caseClass.owner)
231+
assert(!caseClassType.isHigherKinded, s"Unexpected type constructor $caseClassType")
232+
233+
// If the case class is polymorphic, need to capture those type params in the type that we relativize using asSeenFrom,
234+
// as they may also be sensitive to the prefix (see test/files/pos/t11103.scala).
235+
// Note that undetParams may thus be different from caseClass.typeParams.
236+
// (For a monomorphic case class, GenPolyType will not create/destruct a PolyType.)
237+
val (undetparams, caseConstructorType) =
238+
GenPolyType.unapply {
239+
val ctorUnderClassTypeParams = GenPolyType(caseClass.typeParams, caseClass.primaryConstructor.info)
240+
ctorUnderClassTypeParams.asSeenFrom(caseClassType, caseClass)
241+
}.get
242+
243+
// println(s"convertToCaseConstructor(${tree.tpe}, $caseClass, $ptIn) // $caseClassType // ${caseConstructorType.typeParams.map(_.info)}")
244+
245+
val tree1 = TypeTree(caseConstructorType) setOriginal tree
230246

231247
// have to open up the existential and put the skolems in scope
232248
// can't simply package up pt in an ExistentialType, because that takes us back to square one (List[_ <: T] == List[T] due to covariance)
@@ -237,7 +253,7 @@ trait PatternTypers {
237253
// as instantiateTypeVar's bounds would end up there
238254
val ctorContext = context.makeNewScope(tree, context.owner)
239255
freeVars foreach ctorContext.scope.enter
240-
newTyper(ctorContext).infer.inferConstructorInstance(tree1, caseClass.typeParams, ptSafe)
256+
newTyper(ctorContext).infer.inferConstructorInstance(tree1, undetparams, ptSafe)
241257

242258
// simplify types without losing safety,
243259
// so that we get rid of unnecessary type slack, and so that error messages don't unnecessarily refer to skolems

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4049,23 +4049,11 @@ trait Types
40494049

40504050
/** A creator and extractor for type parameterizations that strips empty type parameter lists.
40514051
* Use this factory method to indicate the type has kind * (it's a polymorphic value)
4052-
* until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty).
4053-
*
4054-
* PP to AM: I've co-opted this for where I know tparams may well be empty, and
4055-
* expecting to get back `tpe` in such cases. Re being "forgiving" below,
4056-
* can we instead say this is the canonical creator for polyTypes which
4057-
* may or may not be poly? (It filched the standard "canonical creator" name.)
40584052
*/
40594053
object GenPolyType {
4060-
def apply(tparams: List[Symbol], tpe: Type): Type = {
4061-
tpe match {
4062-
case MethodType(_, _) =>
4063-
assert(tparams forall (_.isInvariant), "Trying to create a method with variant type parameters: " + ((tparams, tpe)))
4064-
case _ =>
4065-
}
4066-
if (tparams.nonEmpty) typeFun(tparams, tpe)
4067-
else tpe // it's okay to be forgiving here
4068-
}
4054+
def apply(tparams: List[Symbol], tpe: Type): Type =
4055+
if (tparams.isEmpty) tpe else PolyType(tparams, tpe)
4056+
40694057
def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match {
40704058
case PolyType(tparams, restpe) => Some((tparams, restpe))
40714059
case _ => Some((Nil, tpe))

0 commit comments

Comments
 (0)