package dotty.tools.dotc.core
import Types._, Symbols._, Contexts._
/** Substitution operations on types. See the corresponding `subst` and
* `substThis` methods on class Type for an explanation.
*/
trait Substituters { this: Context =>
final def subst(tp: Type, from: PolyType, to: PolyType, map: SubstPolyMap = null): Type =
tp match {
case tp @ PolyParam(pt, n) =>
if (pt eq from) PolyParam(to, n) else tp
case tp: NamedType =>
if (tp.symbol.isStatic) tp
else tp.derivedNamedType(subst(tp.prefix, from, to, map), tp.name)
case ThisType(_)
| MethodParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new SubstPolyMap(from, to)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
final def subst(tp: Type, from: MethodType, to: MethodType, map: SubstMethodMap): Type =
tp match {
case tp @ MethodParam(mt, n) =>
if (mt eq from) MethodParam(to, n) else tp
case tp: NamedType =>
if (tp.symbol.isStatic) tp
else tp.derivedNamedType(subst(tp.prefix, from, to, map), tp.name)
case ThisType(_)
| PolyParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new SubstMethodMap(from, to)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
final def subst1(tp: Type, from: Symbol, to: Type, map: Subst1Map): Type = {
tp match {
case tp: NamedType =>
val sym = tp.symbol
if (tp.prefix eq NoPrefix) {
if (sym eq from)
return if (to.exists) to else tp
}
if (sym.isStatic) tp
else tp.derivedNamedType(subst1(tp.prefix, from, to, map), tp.name)
case ThisType(_)
| MethodParam(_, _)
| PolyParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new Subst1Map(from, to)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
}
final def subst2(tp: Type, from1: Symbol, to1: Type, from2: Symbol, to2: Type, map: Subst2Map): Type = {
tp match {
case tp: NamedType =>
val sym = tp.symbol
if (tp.prefix eq NoPrefix) {
if (sym eq from1)
return if (to1.exists) to1 else tp
if (sym eq from2)
return if (to2.exists) to2 else tp
}
if (sym.isStatic) tp
else tp.derivedNamedType(subst2(tp.prefix, from1, to1, from2, to2, map), tp.name)
case ThisType(_)
| MethodParam(_, _)
| PolyParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new Subst2Map(from1, to1, from2, to2)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
}
final def subst(tp: Type, from: List[Symbol], to: List[Type], map: SubstMap): Type = {
tp match {
case tp: NamedType =>
val sym = tp.symbol
if (tp.prefix eq NoPrefix) {
var fs = from
var ts = to
while (fs.nonEmpty) {
if (fs.head eq sym)
return if (ts.head.exists) ts.head else tp
fs = fs.tail
ts = ts.tail
}
}
if (sym.isStatic) tp
else tp.derivedNamedType(subst(tp.prefix, from, to, map), tp.name)
case ThisType(_)
| MethodParam(_, _)
| PolyParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new SubstMap(from, to)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
}
final def substThis(tp: Type, from: ClassSymbol, to: Type, map: SubstThisMap): Type =
tp match {
case tp @ ThisType(clazz) =>
if (clazz eq from) to else tp
case tp: NamedType =>
if (tp.symbol.isStatic) tp
else tp.derivedNamedType(substThis(tp.prefix, from, to, map), tp.name)
case MethodParam(_, _)
| PolyParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new SubstThisMap(from, to)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
final def substThis(tp: Type, from: RefinedType, to: Type, map: SubstRefinedThisMap): Type =
tp match {
case tp @ RefinedThis(rt) =>
if (rt eq from) to else tp
case tp: NamedType =>
if (tp.symbol.isStatic) tp
else tp.derivedNamedType(substThis(tp.prefix, from, to, map), tp.name)
case ThisType(_)
| MethodParam(_, _)
| PolyParam(_, _)
| NoPrefix => tp
case _ =>
val substMap = if (map != null) map else new SubstRefinedThisMap(from, to)
tp match {
case tp: AppliedType =>
tp.derivedAppliedType(
substMap(tp.tycon), tp.typeArgs mapConserve substMap)
case _ =>
substMap mapOver tp
}
}
final class SubstPolyMap(from: PolyType, to: PolyType) extends TypeMap {
def apply(tp: Type) = subst(tp, from, to, this)
}
final class SubstMethodMap(from: MethodType, to: MethodType) extends TypeMap {
def apply(tp: Type) = subst(tp, from, to, this)
}
final class Subst1Map(from: Symbol, to: Type) extends TypeMap {
def apply(tp: Type) = subst1(tp, from, to, this)
}
final class Subst2Map(from1: Symbol, to1: Type, from2: Symbol, to2: Type) extends TypeMap {
def apply(tp: Type) = subst2(tp, from1, to1, from2, to2, this)
}
final class SubstMap(from: List[Symbol], to: List[Type]) extends TypeMap {
def apply(tp: Type): Type = subst(tp, from, to, this)
}
final class SubstThisMap(from: ClassSymbol, to: Type) extends TypeMap {
def apply(tp: Type): Type = substThis(tp, from, to, this)
}
final class SubstRefinedThisMap(from: RefinedType, to: Type) extends TypeMap {
def apply(tp: Type): Type = substThis(tp, from, to, this)
}
}