aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeApplications.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-29 09:50:27 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:35:06 +0200
commit6bd7ba9ea4484ee2065dd16077cba6c26b2050d9 (patch)
tree7b13e292f072fed02e0ba9a8a431eef92f71cf57 /src/dotty/tools/dotc/core/TypeApplications.scala
parenta23c1a476296a25566d7aa08de676a1217b243cb (diff)
downloaddotty-6bd7ba9ea4484ee2065dd16077cba6c26b2050d9.tar.gz
dotty-6bd7ba9ea4484ee2065dd16077cba6c26b2050d9.tar.bz2
dotty-6bd7ba9ea4484ee2065dd16077cba6c26b2050d9.zip
Remove refinement encoding of hk types
Remove the code that implemented the encoding of hk types using refinements. Drop the notion that RefinedTypes can be type parameters. This is no longer true under the new representation. Also, refactoring MemberBinding -> TypeParamInfo
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeApplications.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala344
1 files changed, 37 insertions, 307 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index e989e42b7..a09039521 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -46,67 +46,16 @@ object TypeApplications {
/** Does the variance of type parameter `tparam1` conform to the variance of type parameter `tparam2`?
*/
- def varianceConforms(tparam1: MemberBinding, tparam2: MemberBinding)(implicit ctx: Context): Boolean =
- varianceConforms(tparam1.memberVariance, tparam2.memberVariance)
+ def varianceConforms(tparam1: TypeParamInfo, tparam2: TypeParamInfo)(implicit ctx: Context): Boolean =
+ varianceConforms(tparam1.paramVariance, tparam2.paramVariance)
/** Doe the variances of type parameters `tparams1` conform to the variances
* of corresponding type parameters `tparams2`?
* This is only the case of `tparams1` and `tparams2` have the same length.
*/
- def variancesConform(tparams1: List[MemberBinding], tparams2: List[MemberBinding])(implicit ctx: Context): Boolean =
+ def variancesConform(tparams1: List[TypeParamInfo], tparams2: List[TypeParamInfo])(implicit ctx: Context): Boolean =
tparams1.corresponds(tparams2)(varianceConforms)
- def fallbackTypeParamsOLD(variances: List[Int])(implicit ctx: Context): List[MemberBinding] = {
- def memberBindings(vs: List[Int]): Type = vs match {
- case Nil => NoType
- case v :: vs1 =>
- RefinedType(
- memberBindings(vs1),
- tpnme.hkArgOLD(vs1.length),
- TypeBounds.empty.withBindingKind(BindingKind.fromVariance(v)))
- }
- def decompose(t: Type, acc: List[MemberBinding]): List[MemberBinding] = t match {
- case t: RefinedType => decompose(t.parent, t :: acc)
- case NoType => acc
- }
- decompose(memberBindings(variances), Nil)
- }
-
- /** Extractor for
- *
- * [v1 X1: B1, ..., vn Xn: Bn] -> T
- * ==>
- * ([X_i := this.$hk_i] T) { type v_i $hk_i: (new)B_i }
- */
- object TypeLambdaOLD {
- def apply(argBindingFns: List[RecType => TypeBounds],
- bodyFn: RecType => Type)(implicit ctx: Context): Type = {
- val argNames = argBindingFns.indices.toList.map(tpnme.hkArgOLD)
- var idx = 0
- RecType.closeOver(rt =>
- (bodyFn(rt) /: argBindingFns) { (parent, argBindingFn) =>
- val res = RefinedType(parent, tpnme.hkArgOLD(idx), argBindingFn(rt))
- idx += 1
- res
- })
- }
-
- def unapply(tp: Type)(implicit ctx: Context): Option[( /*List[Int], */ List[TypeBounds], Type)] = {
- def decompose(t: Type, acc: List[TypeBounds]): (List[TypeBounds], Type) = t match {
- case t @ RefinedType(p, rname, rinfo: TypeBounds) if t.isTypeParam =>
- decompose(p, rinfo.bounds :: acc)
- case t: RecType =>
- decompose(t.parent, acc)
- case _ =>
- (acc, t)
- }
- decompose(tp, Nil) match {
- case (Nil, _) => None
- case x => Some(x)
- }
- }
- }
-
/** Extractor for
*
* [v1 X1: B1, ..., vn Xn: Bn] -> C[X1, ..., Xn]
@@ -118,33 +67,14 @@ object TypeApplications {
*/
object EtaExpansion {
def apply(tycon: Type)(implicit ctx: Context) = {
- if (Config.newHK) assert(tycon.typeParams.nonEmpty, tycon)
- else assert(tycon.isEtaExpandableOLD)
+ assert(tycon.typeParams.nonEmpty, tycon)
tycon.EtaExpand(tycon.typeParamSymbols)
}
- def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] =
- if (Config.newHK)
- tp match {
- case tp @ TypeLambda(tparams, AppliedType(fn: TypeRef, args))
- if (args == tparams.map(_.toArg)) => Some(fn)
- case _ => None
- }
- else {
- def argsAreForwarders(args: List[Type], n: Int): Boolean = args match {
- case Nil =>
- n == 0
- case TypeRef(RecThis(rt), sel) :: args1 if false =>
- rt.eq(tp) && sel == tpnme.hkArgOLD(n - 1) && argsAreForwarders(args1, n - 1)
- case _ =>
- false
- }
- tp match {
- case TypeLambdaOLD(argBounds, AppliedType(fn: TypeRef, args))
- if argsAreForwarders(args, tp.typeParams.length) => Some(fn)
- case _ => None
- }
- }
+ def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match {
+ case tp @ TypeLambda(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn)
+ case _ => None
+ }
}
/** Extractor for type application T[U_1, ..., U_n]. This is the refined type
@@ -165,13 +95,13 @@ object TypeApplications {
refinements = rt :: refinements
tycon = rt.parent.stripTypeVar
}
- def collectArgs(tparams: List[MemberBinding],
+ def collectArgs(tparams: List[TypeParamInfo],
refinements: List[RefinedType],
argBuf: mutable.ListBuffer[Type]): Option[(Type, List[Type])] = refinements match {
case Nil if tparams.isEmpty && argBuf.nonEmpty =>
Some((tycon, argBuf.toList))
case RefinedType(_, rname, rinfo) :: refinements1
- if tparams.nonEmpty && rname == tparams.head.memberName =>
+ if tparams.nonEmpty && rname == tparams.head.paramName =>
collectArgs(tparams.tail, refinements1, argBuf += rinfo.argInfo)
case _ =>
None
@@ -186,44 +116,16 @@ object TypeApplications {
/** Adapt all arguments to possible higher-kinded type parameters using etaExpandIfHK
*/
- def etaExpandIfHK(tparams: List[MemberBinding], args: List[Type])(implicit ctx: Context): List[Type] =
+ def etaExpandIfHK(tparams: List[TypeParamInfo], args: List[Type])(implicit ctx: Context): List[Type] =
if (tparams.isEmpty) args
else {
- def bounds(tparam: MemberBinding) = tparam match {
+ def bounds(tparam: TypeParamInfo) = tparam match {
case tparam: Symbol => tparam.infoOrCompleter
- case tparam: RefinedType if !Config.newHK => tparam.memberBounds
- case tparam: LambdaParam => tparam.memberBounds
+ case tparam: LambdaParam => tparam.paramBounds
}
args.zipWithConserve(tparams)((arg, tparam) => arg.etaExpandIfHK(bounds(tparam)))
}
- /** The references `<rt>.this.$hk0, ..., <rt>.this.$hk<n-1>`. */
- def argRefsOLD(rt: RecType, n: Int)(implicit ctx: Context) =
- List.range(0, n).map(i => RecThis(rt).select(tpnme.hkArgOLD(i)))
-
- private class InstMapOLD(fullType: Type)(implicit ctx: Context) extends TypeMap {
- var localRecs: Set[RecType] = Set.empty
- var keptRefs: Set[Name] = Set.empty
- var tyconIsHK: Boolean = true
- def apply(tp: Type): Type = tp match {
- case tp @ TypeRef(RecThis(rt), sel) if sel.isHkArgNameOLD && localRecs.contains(rt) =>
- fullType.member(sel).info match {
- case TypeAlias(alias) => apply(alias)
- case _ => keptRefs += sel; tp
- }
- case tp: TypeVar if !tp.inst.exists =>
- val bounds = tp.instanceOpt.orElse(ctx.typeComparer.bounds(tp.origin))
- bounds.foreachPart {
- case TypeRef(RecThis(rt), sel) if sel.isHkArgNameOLD && localRecs.contains(rt) =>
- keptRefs += sel
- case _ =>
- }
- tp
- case _ =>
- mapOver(tp)
- }
- }
-
/** A type map that tries to reduce a (part of) the result type of the type lambda `tycon`
* with the given `args`(some of which are wildcard arguments represented by type bounds).
* Non-wildcard arguments are substituted everywhere as usual. A wildcard argument
@@ -281,7 +183,7 @@ class TypeApplications(val self: Type) extends AnyVal {
* with the bounds on its hk args. See `LambdaAbstract`, where these
* types get introduced, and see `isBoundedLambda` below for the test.
*/
- final def typeParams(implicit ctx: Context): List[MemberBinding] = /*>|>*/ track("typeParams") /*<|<*/ {
+ final def typeParams(implicit ctx: Context): List[TypeParamInfo] = /*>|>*/ track("typeParams") /*<|<*/ {
self match {
case self: ClassInfo =>
self.cls.typeParams
@@ -293,8 +195,7 @@ class TypeApplications(val self: Type) extends AnyVal {
else if (!tsym.isCompleting) tsym.info.typeParams
else Nil
case self: RefinedType =>
- val precedingParams = self.parent.typeParams.filterNot(_.memberName == self.refinedName)
- if (self.isTypeParam) precedingParams :+ self else precedingParams
+ self.parent.typeParams.filterNot(_.paramName == self.refinedName)
case self: RecType =>
self.parent.typeParams
case _: HKApply | _: SingletonType =>
@@ -309,7 +210,7 @@ class TypeApplications(val self: Type) extends AnyVal {
}
/** If `self` is a higher-kinded type, its type parameters $hk_i, otherwise Nil */
- final def hkTypeParams(implicit ctx: Context): List[MemberBinding] =
+ final def hkTypeParams(implicit ctx: Context): List[TypeParamInfo] =
if (isHK) typeParams else Nil
/** If `self` is a generic class, its type parameter symbols, otherwise Nil */
@@ -384,7 +285,7 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Is self type higher-kinded (i.e. of kind != "*")? */
def isHK(implicit ctx: Context): Boolean = self.dealias match {
case self: TypeRef => self.info.isHK
- case self: RefinedType => !Config.newHK && self.isTypeParam
+ case self: RefinedType => false
case self: TypeLambda => true
case self: HKApply => false
case self: SingletonType => false
@@ -410,8 +311,7 @@ class TypeApplications(val self: Type) extends AnyVal {
if (!tsym.isCompleting || tsym.isAliasType) tsym.info.knownHK
else 0
}
- case self: RefinedType =>
- if (!Config.newHK && self.isTypeParam) 1 else -1
+ case self: RefinedType => -1
case self: TypeLambda => 1
case self: HKApply => -1
case self: SingletonType => -1
@@ -423,12 +323,6 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => -1
}
- /** is receiver a higher-kinded application? */
- def isHKApplyOLD(implicit ctx: Context): Boolean = self match {
- case self @ RefinedType(_, name, _) => name.isHkArgNameOLD && !self.isTypeParam
- case _ => false
- }
-
/** True if it can be determined without forcing that the class symbol
* of this application exists. Equivalent to
*
@@ -457,25 +351,6 @@ class TypeApplications(val self: Type) extends AnyVal {
self
}
- /** Replace references to type parameters with references to hk arguments `this.$hk_i`
- * Care is needed not to cause cyclic reference errors, hence `SafeSubstMap`.
- */
- def recursifyOLD[T <: Type](tparams: List[MemberBinding])(implicit ctx: Context): RecType => T =
- tparams match {
- case (_: Symbol) :: _ =>
- (rt: RecType) =>
- new ctx.SafeSubstMap(tparams.asInstanceOf[List[Symbol]], argRefsOLD(rt, tparams.length))
- .apply(self).asInstanceOf[T]
- case _ =>
- def mapRefs(rt: RecType) = new TypeMap {
- def apply(t: Type): Type = t match {
- case rthis: RecThis if tparams contains rthis.binder.parent => RecThis(rt)
- case _ => mapOver(t)
- }
- }
- mapRefs(_).apply(self).asInstanceOf[T]
- }
-
/** Lambda abstract `self` with given type parameters. Examples:
*
* type T[X] = U becomes type T = [X] -> U
@@ -485,124 +360,18 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
def LambdaAbstract(tparams: List[Symbol])(implicit ctx: Context): Type = {
def expand(tp: Type) =
- if (Config.newHK)
- TypeLambda(
- tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.variance))(
- tl => tparams.map(tparam => tl.lifted(tparams, tparam.info).bounds),
- tl => tl.lifted(tparams, tp))
- else
- TypeLambdaOLD(
- tparams.map(tparam =>
- tparam.memberBoundsAsSeenFrom(self)
- .withBindingKind(BindingKind.fromVariance(tparam.variance))
- .recursifyOLD(tparams)),
- tp.recursifyOLD(tparams))
-
+ TypeLambda(
+ tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.variance))(
+ tl => tparams.map(tparam => tl.lifted(tparams, tparam.info).bounds),
+ tl => tl.lifted(tparams, tp))
assert(!isHK, self)
- if (Config.newHK) self match {
+ self match {
case self: TypeAlias =>
self.derivedTypeAlias(expand(self.alias))
case self @ TypeBounds(lo, hi) =>
self.derivedTypeBounds(lo, expand(hi))
case _ => expand(self)
}
- else self match {
- case self: TypeAlias =>
- self.derivedTypeAlias(expand(self.alias.normalizeHkApplyOLD))
- case self @ TypeBounds(lo, hi) =>
- self.derivedTypeBounds(lo, expand(hi.normalizeHkApplyOLD))
- case _ => expand(self)
- }
- }
-
- /** If `self` is a * type, perform the following rewritings:
- *
- * 1. For every occurrence of `z.$hk_i`, where `z` is a RecThis type that refers
- * to some recursive type in `self`, if the member of `self.hk$i` has an alias
- * type `= U`:
- *
- * z.$hk_i --> U
- *
- * 2. For every top-level binding `type A = z.$hk_i$, where `z` is a RecThis type that refers
- * to some recursive type in `self`, if the member of `self` has bounds `S..U`:
- *
- * type A = z.$hk_i --> type A >: S <: U
- *
- * 3. If the type constructor preceding all bindings is a * type, delete every top-level
- * binding `{ type $hk_i ... }` where `$hk_i` does not appear in the prefix of the binding.
- * I.e.
- *
- * T { type $hk_i ... } --> T
- *
- * If `$hk_i` does not appear in `T`.
- *
- * A binding is top-level if it can be reached by
- *
- * - following aliases unless the type is a LazyRef
- * (need to keep cycle breakers around, see i974.scala)
- * - dropping refinements and rec-types
- * - going from a wildcard type to its upper bound
- */
- def normalizeHkApplyOLD(implicit ctx: Context): Type = self.strictDealias match {
- case self1 @ RefinedType(_, rname, _) if rname.isHkArgNameOLD && self1.typeParams.isEmpty =>
- val inst = new InstMapOLD(self)
-
- def instTop(tp: Type): Type = tp.strictDealias match {
- case tp: RecType =>
- inst.localRecs += tp
- tp.rebind(instTop(tp.parent))
- case tp @ RefinedType(parent, rname, rinfo) =>
- rinfo match {
- case TypeAlias(TypeRef(RecThis(rt), sel)) if sel.isHkArgNameOLD && inst.localRecs.contains(rt) =>
- val bounds @ TypeBounds(_, _) = self.member(sel).info
- instTop(tp.derivedRefinedType(parent, rname, bounds.withBindingKind(NoBinding)))
- case _ =>
- val parent1 = instTop(parent)
- if (rname.isHkArgNameOLD &&
- !inst.tyconIsHK &&
- !inst.keptRefs.contains(rname)) parent1
- else tp.derivedRefinedType(parent1, rname, inst(rinfo))
- }
- case tp @ WildcardType(bounds @ TypeBounds(lo, hi)) =>
- tp.derivedWildcardType(bounds.derivedTypeBounds(inst(lo), instTop(hi)))
- case tp: LazyRef =>
- instTop(tp.ref)
- case tp =>
- inst.tyconIsHK = tp.isHK
- inst(tp)
- }
-
- def isLazy(tp: Type): Boolean = tp.strictDealias match {
- case tp: RefinedOrRecType => isLazy(tp.parent)
- case tp @ WildcardType(bounds @ TypeBounds(lo, hi)) => isLazy(hi)
- case tp: LazyRef => true
- case _ => false
- }
-
- val reduced =
- if (isLazy(self1)) {
- // A strange dance is needed here to make 974.scala compile.
- val res = LazyRef(() => instTop(self))
- res.ref // without this line, pickling 974.scala fails with an assertion error
- // saying that we address a RecThis outside its Rec (in the case of RecThis of pickleNewType)
- res // without this line, typing 974.scala gives a stackoverflow in asSeenFrom.
- }
- else instTop(self)
- if (reduced ne self) {
- hk.println(i"reduce $self --> $reduced / ${inst.tyconIsHK}")
- //hk.println(s"reduce $self --> $reduced")
- }
- reduced
- case _ => self
- }
-
- /** A type ref is eta expandable if it refers to a non-lambda class.
- * In that case we can look for parameterized base types of the type
- * to eta expand them.
- */
- def isEtaExpandableOLD(implicit ctx: Context) = self match {
- case self: TypeRef => self.symbol.isClass
- case _ => false
}
/** Convert a type constructor `TC` which has type parameters `T1, ..., Tn`
@@ -681,23 +450,12 @@ class TypeApplications(val self: Type) extends AnyVal {
else {
def adaptArg(arg: Type): Type = arg match {
case arg @ TypeLambda(tparams, body) if
- !tparams.corresponds(hkParams)(_.memberVariance == _.memberVariance) &&
+ !tparams.corresponds(hkParams)(_.paramVariance == _.paramVariance) &&
tparams.corresponds(hkParams)(varianceConforms) =>
- TypeLambda(tparams.map(_.memberName), hkParams.map(_.memberVariance))(
+ TypeLambda(tparams.map(_.paramName), hkParams.map(_.paramVariance))(
tl => arg.paramBounds.map(_.subst(arg, tl).bounds),
tl => arg.resultType.subst(arg, tl)
)
- case arg @ TypeLambdaOLD(tparamBounds, body) if
- !arg.typeParams.corresponds(hkParams)(_.memberVariance == _.memberVariance) &&
- arg.typeParams.corresponds(hkParams)(varianceConforms) =>
- def adjustVariance(bounds: TypeBounds, tparam: MemberBinding): TypeBounds =
- bounds.withBindingKind(BindingKind.fromVariance(tparam.memberVariance))
- def lift[T <: Type](tp: T): (RecType => T) = arg match {
- case rt0: RecType => tp.subst(rt0, _).asInstanceOf[T]
- case _ => (x => tp)
- }
- val adjusted = (tparamBounds, hkParams).zipped.map(adjustVariance)
- TypeLambdaOLD(adjusted.map(lift), lift(body))
case arg @ TypeAlias(alias) =>
arg.derivedTypeAlias(adaptArg(alias))
case arg @ TypeBounds(lo, hi) =>
@@ -731,16 +489,6 @@ class TypeApplications(val self: Type) extends AnyVal {
self.instantiate(args)
case EtaExpansion(self1) =>
self1.appliedTo(args)
- case TypeLambdaOLD(_, body) if !args.exists(_.isInstanceOf[TypeBounds]) =>
- def substHkArgs = new TypeMap {
- def apply(tp: Type): Type = tp match {
- case TypeRef(RecThis(rt), name) if rt.eq(self) && name.isHkArgNameOLD =>
- args(name.hkArgIndexOLD)
- case _ =>
- mapOver(tp)
- }
- }
- substHkArgs(body)
case self1: WildcardType =>
self1
case _ =>
@@ -753,12 +501,12 @@ class TypeApplications(val self: Type) extends AnyVal {
* @param args = `U1, ..., Un`
* @param tparams are assumed to be the type parameters of `T`.
*/
- final def appliedTo(args: List[Type], typParams: List[MemberBinding])(implicit ctx: Context): Type = {
- def matchParams(t: Type, tparams: List[MemberBinding], args: List[Type])(implicit ctx: Context): Type = args match {
+ final def appliedTo(args: List[Type], typParams: List[TypeParamInfo])(implicit ctx: Context): Type = {
+ def matchParams(t: Type, tparams: List[TypeParamInfo], args: List[Type])(implicit ctx: Context): Type = args match {
case arg :: args1 =>
try {
val tparam :: tparams1 = tparams
- matchParams(RefinedType(t, tparam.memberName, arg.toBounds(tparam)), tparams1, args1)
+ matchParams(RefinedType(t, tparam.paramName, arg.toBounds(tparam)), tparams1, args1)
} catch {
case ex: MatchError =>
println(s"applied type mismatch: $self with underlying ${self.underlyingIfProxy}, args = $args, typeParams = $typParams") // !!! DEBUG
@@ -790,12 +538,7 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] =>
HKApply(self, args)
case dealiased =>
- matchParams(dealiased, typParams, args) match {
- case refined @ RefinedType(_, pname, _) if !Config.newHK && pname.isHkArgNameOLD =>
- refined.betaReduceOLD
- case refined =>
- refined
- }
+ matchParams(dealiased, typParams, args)
}
}
@@ -810,34 +553,21 @@ class TypeApplications(val self: Type) extends AnyVal {
* up hk type parameters matching the arguments. This is needed when unpickling
* Scala2 files such as `scala.collection.generic.Mapfactory`.
*/
- final def safeAppliedTo(args: List[Type])(implicit ctx: Context) =
- if (Config.newHK)
- self match {
- case self: TypeRef if !self.symbol.isClass && self.symbol.isCompleting =>
- HKApply(self, args)
- case _ =>
- appliedTo(args, typeParams)
- }
- else {
- val safeTypeParams = self match {
- case self: TypeRef if !self.symbol.isClass && self.symbol.isCompleting =>
- // This happens when unpickling e.g. scala$collection$generic$GenMapFactory$$CC
- ctx.warning(i"encountered F-bounded higher-kinded type parameters for ${self.symbol}; assuming they are invariant")
- fallbackTypeParamsOLD(args map alwaysZero)
- case _ =>
- typeParams
- }
- appliedTo(args, safeTypeParams)
- }
+ final def safeAppliedTo(args: List[Type])(implicit ctx: Context) = self match {
+ case self: TypeRef if !self.symbol.isClass && self.symbol.isCompleting =>
+ HKApply(self, args)
+ case _ =>
+ appliedTo(args, typeParams)
+ }
/** Turn this type, which is used as an argument for
* type parameter `tparam`, into a TypeBounds RHS
*/
- final def toBounds(tparam: MemberBinding)(implicit ctx: Context): TypeBounds = self match {
+ final def toBounds(tparam: TypeParamInfo)(implicit ctx: Context): TypeBounds = self match {
case self: TypeBounds => // this can happen for wildcard args
self
case _ =>
- val v = tparam.memberVariance
+ val v = tparam.paramVariance
/* Not neeeded.
if (v > 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.upper(self)
else if (v < 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.lower(self)