@@ -1621,126 +1621,140 @@ object SymDenotations {
1621
1621
1622
1622
/** Compute tp.baseType(this) */
1623
1623
final def baseTypeOf (tp : Type )(implicit ctx : Context ): Type = {
1624
+ val btrCache = baseTypeCache
1625
+ def inCache (tp : Type ) = btrCache.get(tp) != null
1624
1626
1625
- def foldGlb ( bt : Type , ps : List [ Type ]) : Type = ps match {
1626
- case p :: ps1 => foldGlb(bt & baseTypeOf(p), ps1 )
1627
- case _ => bt
1627
+ def ensureAcyclic ( baseTp : Type ) = {
1628
+ if (baseTp `eq` NoPrefix ) throw CyclicReference ( this )
1629
+ baseTp
1628
1630
}
1629
1631
1630
- /** We cannot cache:
1631
- * - type variables which are uninstantiated or whose instances can
1632
- * change, depending on typerstate.
1633
- * - types where the underlying type is an ErasedValueType, because
1634
- * this underlying type will change after ElimErasedValueType,
1635
- * and this changes subtyping relations. As a shortcut, we do not
1636
- * cache ErasedValueType at all.
1637
- */
1638
- def isCachable (tp : Type , btrCache : BaseTypeMap ): Boolean = {
1639
- def inCache (tp : Type ) = btrCache.containsKey(tp) && isCachable(tp, btrCache)
1632
+ def recur (tp : Type ): Type = try {
1640
1633
tp match {
1641
- case tp : TypeRef if tp.symbol.isClass => true
1642
- case tp : TypeVar => tp.inst.exists && inCache(tp.inst)
1643
- case tp : TypeParamRef if ctx.typerState.constraint.contains(tp) => false
1644
- // case tp: TypeProxy => inCache(tp.underlying) // disabled, can re-enable insyead of last two lines for performance testing
1645
- case tp : TypeProxy => isCachable(tp.underlying, btrCache)
1646
- case tp : AndType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache)
1647
- case tp : OrType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache)
1648
- case _ : TypeErasure .ErasedValueType => false
1649
- case _ => true
1634
+ case tp : CachedType =>
1635
+ val baseTp = btrCache.get(tp)
1636
+ if (baseTp != null ) return ensureAcyclic(baseTp)
1637
+ case _ =>
1650
1638
}
1651
- }
1652
-
1653
- def computeBaseTypeOf (tp : Type ): Type = {
1654
1639
if (Stats .monitored) {
1655
1640
Stats .record(" computeBaseType, total" )
1656
1641
Stats .record(s " computeBaseType, ${tp.getClass}" )
1657
1642
}
1658
- if (symbol.isStatic && tp.derivesFrom(symbol) && symbol.typeParams.isEmpty)
1659
- symbol.typeRef
1660
- else tp match {
1643
+ tp match {
1661
1644
case tp @ TypeRef (prefix, _) =>
1662
- val subsym = tp.symbol
1663
- if (subsym eq symbol) tp
1664
- else subsym.denot match {
1665
- case clsd : ClassDenotation =>
1666
- val owner = clsd.owner
1667
- val isOwnThis = prefix match {
1668
- case prefix : ThisType => prefix.cls eq owner
1669
- case NoPrefix => true
1670
- case _ => false
1671
- }
1672
- if (isOwnThis)
1673
- if (clsd.baseClassSet.contains(symbol)) foldGlb(NoType , clsd.classParents)
1674
- else NoType
1675
- else
1676
- baseTypeOf(clsd.typeRef).asSeenFrom(prefix, owner)
1677
- case _ =>
1678
- baseTypeOf(tp.superType)
1645
+
1646
+ def foldGlb (bt : Type , ps : List [Type ]): Type = ps match {
1647
+ case p :: ps1 => foldGlb(bt & recur(p), ps1)
1648
+ case _ => bt
1679
1649
}
1650
+
1651
+ def computeTypeRef = {
1652
+ btrCache.put(tp, NoPrefix )
1653
+ tp.symbol.denot match {
1654
+ case clsd : ClassDenotation =>
1655
+ def isOwnThis = prefix match {
1656
+ case prefix : ThisType => prefix.cls `eq` clsd.owner
1657
+ case NoPrefix => true
1658
+ case _ => false
1659
+ }
1660
+ val baseTp =
1661
+ if (tp.symbol eq symbol)
1662
+ tp
1663
+ else if (isOwnThis)
1664
+ if (clsd.baseClassSet.contains(symbol))
1665
+ if (symbol.isStatic && symbol.typeParams.isEmpty) symbol.typeRef
1666
+ else foldGlb(NoType , clsd.classParents)
1667
+ else NoType
1668
+ else
1669
+ recur(clsd.typeRef).asSeenFrom(prefix, clsd.owner)
1670
+ if (baseTp.exists) btrCache.put(tp, baseTp) else btrCache.remove(tp)
1671
+ baseTp
1672
+ case _ =>
1673
+ val superTp = tp.superType
1674
+ val baseTp = recur(superTp)
1675
+ if (baseTp.exists && inCache(superTp) && tp.symbol.maybeOwner.isType)
1676
+ btrCache.put(tp, baseTp) // typeref cannot be a GADT, so cache is stable
1677
+ else
1678
+ btrCache.remove(tp)
1679
+ baseTp
1680
+ }
1681
+ }
1682
+ computeTypeRef
1683
+
1680
1684
case tp @ AppliedType (tycon, args) =>
1681
- val subsym = tycon.typeSymbol
1682
- if (subsym eq symbol) tp
1683
- else (tycon.typeParams: @ unchecked) match {
1684
- case LambdaParam (_, _) :: _ =>
1685
- baseTypeOf(tp.superType)
1686
- case tparams : List [Symbol @ unchecked] =>
1687
- baseTypeOf(tycon).subst(tparams, args)
1685
+
1686
+ def computeApplied = {
1687
+ btrCache.put(tp, NoPrefix )
1688
+ val baseTp =
1689
+ if (tycon.typeSymbol eq symbol) tp
1690
+ else (tycon.typeParams: @ unchecked) match {
1691
+ case LambdaParam (_, _) :: _ =>
1692
+ recur(tp.superType)
1693
+ case tparams : List [Symbol @ unchecked] =>
1694
+ recur(tycon).subst(tparams, args)
1695
+ }
1696
+ if (baseTp.exists) btrCache.put(tp, baseTp) else btrCache.remove(tp)
1697
+ baseTp
1688
1698
}
1689
- case tp : TypeParamRef =>
1690
- baseTypeOf(ctx.typeComparer.bounds(tp).hi)
1699
+ computeApplied
1700
+
1701
+ case tp : TypeParamRef => // uncachable, since baseType depends on context bounds
1702
+ recur(ctx.typeComparer.bounds(tp).hi)
1691
1703
case tp : TypeProxy =>
1692
- baseTypeOf(tp.superType)
1693
- case AndType (tp1, tp2) =>
1694
- baseTypeOf(tp1) & baseTypeOf(tp2) match {
1695
- case AndType (tp1a, tp2a) if (tp1a eq tp1) && (tp2a eq tp2) => tp
1696
- case res => res
1704
+
1705
+ def computeTypeProxy = {
1706
+ val superTp = tp.superType
1707
+ val baseTp = recur(superTp)
1708
+ tp match {
1709
+ case tp : CachedType if baseTp.exists && inCache(superTp) =>
1710
+ // Note: This also works for TypeVars: If they are not instantiated, their supertype
1711
+ // is a TypeParamRef, which is never cached. So uninstantiated TypeVars are not cached either.
1712
+ btrCache.put(tp, baseTp)
1713
+ case _ =>
1714
+ }
1715
+ baseTp
1697
1716
}
1698
- case OrType (tp1, tp2) =>
1699
- baseTypeOf(tp1) | baseTypeOf(tp2) match {
1700
- case OrType (tp1a, tp2a) if (tp1a eq tp1) && (tp2a eq tp2) => tp
1701
- case res => res
1717
+ computeTypeProxy
1718
+
1719
+ case tp : AndOrType =>
1720
+
1721
+ def computeAndOrType = {
1722
+ val tp1 = tp.tp1
1723
+ val tp2 = tp.tp2
1724
+ val baseTp =
1725
+ if (symbol.isStatic && tp.derivesFrom(symbol) && symbol.typeParams.isEmpty)
1726
+ symbol.typeRef
1727
+ else {
1728
+ val baseTp1 = recur(tp1)
1729
+ val baseTp2 = recur(tp2)
1730
+ val combined = if (tp.isAnd) baseTp1 & baseTp2 else baseTp1 | baseTp2
1731
+ combined match {
1732
+ case combined : AndOrType
1733
+ if (combined.tp1 eq tp1) && (combined.tp2 eq tp2) && (combined.isAnd == tp.isAnd) => tp
1734
+ case _ => combined
1735
+ }
1736
+ }
1737
+ if (baseTp.exists && inCache(tp1) && inCache(tp2)) btrCache.put(tp, baseTp)
1738
+ baseTp
1702
1739
}
1740
+ computeAndOrType
1741
+
1703
1742
case JavaArrayType (_) if symbol == defn.ObjectClass =>
1704
1743
this .typeRef
1705
1744
case _ =>
1706
1745
NoType
1707
1746
}
1708
1747
}
1748
+ catch {
1749
+ case ex : Throwable =>
1750
+ btrCache.remove(tp)
1751
+ throw ex
1752
+ }
1753
+
1709
1754
1710
1755
/* >|>*/ trace.onDebug(s " $tp.baseType( $this) " ) /* <|<*/ {
1711
1756
Stats .record(" baseTypeOf" )
1712
- tp.stripTypeVar match {
1713
- case tp : CachedType =>
1714
- val btrCache = baseTypeCache
1715
- if (! isCachable(tp, btrCache))
1716
- computeBaseTypeOf(tp)
1717
- else
1718
- try {
1719
- var basetp = btrCache.get(tp)
1720
- if (basetp == null ) {
1721
- btrCache.put(tp, NoPrefix )
1722
- basetp = computeBaseTypeOf(tp)
1723
- if (basetp.exists) {
1724
- Stats .record(" cached base type exists" )
1725
- btrCache.put(tp, basetp)
1726
- }
1727
- else {
1728
- Stats .record(" cached base type missing" )
1729
- btrCache.remove(tp)
1730
- }
1731
- }
1732
- else if (basetp `eq` NoPrefix )
1733
- throw CyclicReference (this )
1734
- basetp
1735
- }
1736
- catch {
1737
- case ex : Throwable =>
1738
- btrCache.put(tp, null )
1739
- throw ex
1740
- }
1741
- case tp =>
1742
- computeBaseTypeOf(tp)
1743
- }
1757
+ recur(tp)
1744
1758
}
1745
1759
}
1746
1760
0 commit comments