Skip to content

Commit 3ac185b

Browse files
committed
Refactor existential related code out of types.
For imminent reuse in the subsequent commit. The binary compatibility whitelist is updated to ignore these, as they live in reflect.internal.
1 parent f7c9adc commit 3ac185b

File tree

4 files changed

+150
-69
lines changed

4 files changed

+150
-69
lines changed

bincompat-backward.whitelist.conf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,30 @@ filter {
159159
matchName="scala.reflect.internal.Names#NameOps.name"
160160
problemName=MissingFieldProblem
161161
},
162+
{
163+
matchName="scala.reflect.internal.ExistentialsAndSkolems.existentialTransform$default$3"
164+
problemName=MissingMethodProblem
165+
},
166+
{
167+
matchName="scala.reflect.internal.ExistentialsAndSkolems.existentialTransform"
168+
problemName=MissingMethodProblem
169+
},
170+
{
171+
matchName="scala.reflect.internal.ExistentialsAndSkolems.packSymbols"
172+
problemName=MissingMethodProblem
173+
},
174+
{
175+
matchName="scala.reflect.internal.ExistentialsAndSkolems.packSymbols$default$3"
176+
problemName=MissingMethodProblem
177+
},
178+
{
179+
matchName="scala.reflect.internal.ExistentialsAndSkolems.isRawParameter"
180+
problemName=MissingMethodProblem
181+
},
182+
{
183+
matchName="scala.reflect.internal.Trees.substituteInfoParamsIntoDefDef"
184+
problemName=MissingMethodProblem
185+
},
162186
{
163187
matchName="scala.reflect.internal.ClassfileConstants.xxxunusedxxxx"
164188
problemName=MissingMethodProblem

bincompat-forward.whitelist.conf

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,54 @@ filter {
355355
matchName="scala.reflect.internal.StdNames#TermNames.SelectFromTypeTree"
356356
problemName=MissingMethodProblem
357357
},
358+
{
359+
matchName="scala.reflect.internal.ExistentialsAndSkolems.existentialTransform$default$3"
360+
problemName=MissingMethodProblem
361+
},
362+
{
363+
matchName="scala.reflect.internal.ExistentialsAndSkolems.existentialTransform"
364+
problemName=MissingMethodProblem
365+
},
366+
{
367+
matchName="scala.reflect.internal.ExistentialsAndSkolems.packSymbols"
368+
problemName=MissingMethodProblem
369+
},
370+
{
371+
matchName="scala.reflect.internal.ExistentialsAndSkolems.packSymbols$default$3"
372+
problemName=MissingMethodProblem
373+
},
374+
{
375+
matchName="scala.reflect.internal.ExistentialsAndSkolems.isRawParameter"
376+
problemName=MissingMethodProblem
377+
},
378+
{
379+
matchName="scala.reflect.internal.Trees.substituteInfoParamsIntoDefDef"
380+
problemName=MissingMethodProblem
381+
},
382+
{
383+
matchName="scala.reflect.internal.SymbolTable.existentialTransform$default$3"
384+
problemName=MissingMethodProblem
385+
},
386+
{
387+
matchName="scala.reflect.internal.SymbolTable.existentialTransform"
388+
problemName=MissingMethodProblem
389+
},
390+
{
391+
matchName="scala.reflect.internal.SymbolTable.substituteInfoParamsIntoDefDef"
392+
problemName=MissingMethodProblem
393+
},
394+
{
395+
matchName="scala.reflect.internal.SymbolTable.packSymbols"
396+
problemName=MissingMethodProblem
397+
},
398+
{
399+
matchName="scala.reflect.internal.SymbolTable.packSymbols$default$3"
400+
problemName=MissingMethodProblem
401+
},
402+
{
403+
matchName="scala.reflect.internal.SymbolTable.isRawParameter"
404+
problemName=MissingMethodProblem
405+
},
358406
{
359407
matchName="scala.reflect.internal.ClassfileConstants.CONSTANT_INVOKEDYNAMIC"
360408
problemName=MissingMethodProblem

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

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3767,77 +3767,9 @@ trait Typers extends Modes with Adaptations with Tags {
37673767
} else res
37683768
}
37693769

3770-
def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
3771-
sym.isTypeParameter && sym.owner.isJavaDefined
3772-
3773-
/** If we map a set of hidden symbols to their existential bounds, we
3774-
* have a problem: the bounds may themselves contain references to the
3775-
* hidden symbols. So this recursively calls existentialBound until
3776-
* the typeSymbol is not amongst the symbols being hidden.
3777-
*/
3778-
def existentialBoundsExcludingHidden(hidden: List[Symbol]): Map[Symbol, Type] = {
3779-
def safeBound(t: Type): Type =
3780-
if (hidden contains t.typeSymbol) safeBound(t.typeSymbol.existentialBound.bounds.hi) else t
3781-
3782-
def hiBound(s: Symbol): Type = safeBound(s.existentialBound.bounds.hi) match {
3783-
case tp @ RefinedType(parents, decls) =>
3784-
val parents1 = parents mapConserve safeBound
3785-
if (parents eq parents1) tp
3786-
else copyRefinedType(tp, parents1, decls)
3787-
case tp => tp
3788-
}
3789-
3790-
// Hanging onto lower bound in case anything interesting
3791-
// happens with it.
3792-
mapFrom(hidden)(s => s.existentialBound match {
3793-
case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s))
3794-
case _ => hiBound(s)
3795-
})
3796-
}
3797-
3798-
/** Given a set `rawSyms` of term- and type-symbols, and a type
3799-
* `tp`, produce a set of fresh type parameters and a type so that
3800-
* it can be abstracted to an existential type. Every type symbol
3801-
* `T` in `rawSyms` is mapped to a clone. Every term symbol `x` of
3802-
* type `T` in `rawSyms` is given an associated type symbol of the
3803-
* following form:
3804-
*
3805-
* type x.type <: T with Singleton
3806-
*
3807-
* The name of the type parameter is `x.type`, to produce nice
3808-
* diagnostics. The Singleton parent ensures that the type
3809-
* parameter is still seen as a stable type. Type symbols in
3810-
* rawSyms are fully replaced by the new symbols. Term symbols are
3811-
* also replaced, except for term symbols of an Ident tree, where
3812-
* only the type of the Ident is changed.
3813-
*/
3814-
protected def existentialTransform[T](rawSyms: List[Symbol], tp: Type)(creator: (List[Symbol], Type) => T): T = {
3815-
val allBounds = existentialBoundsExcludingHidden(rawSyms)
3816-
val typeParams: List[Symbol] = rawSyms map { sym =>
3817-
val name = sym.name match {
3818-
case x: TypeName => x
3819-
case x => tpnme.singletonName(x)
3820-
}
3821-
val bound = allBounds(sym)
3822-
val sowner = if (isRawParameter(sym)) context.owner else sym.owner
3823-
val quantified = sowner.newExistential(name, sym.pos)
3824-
3825-
quantified setInfo bound.cloneInfo(quantified)
3826-
}
3827-
// Higher-kinded existentials are not yet supported, but this is
3828-
// tpeHK for when they are: "if a type constructor is expected/allowed,
3829-
// tpeHK must be called instead of tpe."
3830-
val typeParamTypes = typeParams map (_.tpeHK)
3831-
def doSubst(info: Type) = info.subst(rawSyms, typeParamTypes)
3832-
3833-
creator(typeParams map (_ modifyInfo doSubst), doSubst(tp))
3834-
}
3835-
38363770
/** Compute an existential type from raw hidden symbols `syms` and type `tp`
38373771
*/
3838-
def packSymbols(hidden: List[Symbol], tp: Type): Type =
3839-
if (hidden.isEmpty) tp
3840-
else existentialTransform(hidden, tp)(existentialAbstraction)
3772+
def packSymbols(hidden: List[Symbol], tp: Type): Type = global.packSymbols(hidden, tp, Some(context0.owner))
38413773

38423774
def isReferencedFrom(ctx: Context, sym: Symbol): Boolean =
38433775
ctx.owner.isTerm &&

src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,81 @@ trait ExistentialsAndSkolems {
3232
}
3333
(new Deskolemizer).typeSkolems
3434
}
35+
36+
def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
37+
sym.isTypeParameter && sym.owner.isJavaDefined
38+
39+
/** If we map a set of hidden symbols to their existential bounds, we
40+
* have a problem: the bounds may themselves contain references to the
41+
* hidden symbols. So this recursively calls existentialBound until
42+
* the typeSymbol is not amongst the symbols being hidden.
43+
*/
44+
private def existentialBoundsExcludingHidden(hidden: List[Symbol]): Map[Symbol, Type] = {
45+
def safeBound(t: Type): Type =
46+
if (hidden contains t.typeSymbol) safeBound(t.typeSymbol.existentialBound.bounds.hi) else t
47+
48+
def hiBound(s: Symbol): Type = safeBound(s.existentialBound.bounds.hi) match {
49+
case tp @ RefinedType(parents, decls) =>
50+
val parents1 = parents mapConserve safeBound
51+
if (parents eq parents1) tp
52+
else copyRefinedType(tp, parents1, decls)
53+
case tp => tp
54+
}
55+
56+
// Hanging onto lower bound in case anything interesting
57+
// happens with it.
58+
mapFrom(hidden)(s => s.existentialBound match {
59+
case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s))
60+
case _ => hiBound(s)
61+
})
62+
}
63+
64+
/** Given a set `rawSyms` of term- and type-symbols, and a type
65+
* `tp`, produce a set of fresh type parameters and a type so that
66+
* it can be abstracted to an existential type. Every type symbol
67+
* `T` in `rawSyms` is mapped to a clone. Every term symbol `x` of
68+
* type `T` in `rawSyms` is given an associated type symbol of the
69+
* following form:
70+
*
71+
* type x.type <: T with Singleton
72+
*
73+
* The name of the type parameter is `x.type`, to produce nice
74+
* diagnostics. The Singleton parent ensures that the type
75+
* parameter is still seen as a stable type. Type symbols in
76+
* rawSyms are fully replaced by the new symbols. Term symbols are
77+
* also replaced, except for term symbols of an Ident tree, where
78+
* only the type of the Ident is changed.
79+
*/
80+
final def existentialTransform[T](rawSyms: List[Symbol], tp: Type, rawOwner: Option[Symbol] = None)(creator: (List[Symbol], Type) => T): T = {
81+
val allBounds = existentialBoundsExcludingHidden(rawSyms)
82+
val typeParams: List[Symbol] = rawSyms map { sym =>
83+
val name = sym.name match {
84+
case x: TypeName => x
85+
case x => tpnme.singletonName(x)
86+
}
87+
def rawOwner0 = rawOwner.getOrElse(abort(s"no owner provided for existential transform over raw parameter: $sym"))
88+
val bound = allBounds(sym)
89+
val sowner = if (isRawParameter(sym)) rawOwner0 else sym.owner
90+
val quantified = sowner.newExistential(name, sym.pos)
91+
92+
quantified setInfo bound.cloneInfo(quantified)
93+
}
94+
// Higher-kinded existentials are not yet supported, but this is
95+
// tpeHK for when they are: "if a type constructor is expected/allowed,
96+
// tpeHK must be called instead of tpe."
97+
val typeParamTypes = typeParams map (_.tpeHK)
98+
def doSubst(info: Type) = info.subst(rawSyms, typeParamTypes)
99+
100+
creator(typeParams map (_ modifyInfo doSubst), doSubst(tp))
101+
}
102+
103+
/**
104+
* Compute an existential type from hidden symbols `hidden` and type `tp`.
105+
* @param hidden The symbols that will be existentially abstracted
106+
* @param hidden The original type
107+
* @param rawOwner The owner for Java raw types.
108+
*/
109+
final def packSymbols(hidden: List[Symbol], tp: Type, rawOwner: Option[Symbol] = None): Type =
110+
if (hidden.isEmpty) tp
111+
else existentialTransform(hidden, tp, rawOwner)(existentialAbstraction)
35112
}

0 commit comments

Comments
 (0)