summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala6
-rw-r--r--src/compiler/scala/reflect/internal/TypeDebugging.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala56
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala8
5 files changed, 50 insertions, 24 deletions
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 69b00a5949..937ba0e42a 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1116,13 +1116,13 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
this == that || this.isError || that.isError ||
info.baseTypeIndex(that) >= 0
- final def isSubClass(that: Symbol): Boolean = {
+ final def isSubClass(that: Symbol): Boolean = (
isNonBottomSubClass(that) ||
this == NothingClass ||
this == NullClass &&
(that == AnyClass ||
- that != NothingClass && (that isSubClass AnyRefClass))
- }
+ that != NothingClass && (that isSubClass ObjectClass))
+ )
final def isNumericSubClass(that: Symbol): Boolean =
definitions.isNumericSubClass(this, that)
diff --git a/src/compiler/scala/reflect/internal/TypeDebugging.scala b/src/compiler/scala/reflect/internal/TypeDebugging.scala
index 3680a7996e..d56e2e1991 100644
--- a/src/compiler/scala/reflect/internal/TypeDebugging.scala
+++ b/src/compiler/scala/reflect/internal/TypeDebugging.scala
@@ -84,7 +84,7 @@ trait TypeDebugging {
case TypeBounds(lo, hi) => ">: "+ debug(lo) +" <: "+ debug(hi)
case tv @ TypeVar(_, _) => tv.toString
case ExistentialType(tparams, qtpe) => "forSome "+ str.brackets(tparams) + " " + debug(qtpe)
- case _ => tp.toString
+ case _ => "?"+tp.getClass.getName+"?"//tp.toString might produce cyclic error...
}
def debugString(tp: Type) = debug(tp)
}
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 0e9f2c44e1..7db76fbf59 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -581,7 +581,8 @@ trait Types /*extends reflect.generic.Types*/ { self: SymbolTable =>
* symbols `from' in this type.
*/
def subst(from: List[Symbol], to: List[Type]): Type =
- new SubstTypeMap(from, to) apply this
+ if (from.isEmpty) this
+ else new SubstTypeMap(from, to) apply this
/** Substitute symbols `to' for occurrences of symbols
* `from' in this type.
@@ -1679,9 +1680,18 @@ trait Types /*extends reflect.generic.Types*/ { self: SymbolTable =>
private var parentsCache: List[Type] = _
private var parentsPeriod = NoPeriod
+
private var baseTypeSeqCache: BaseTypeSeq = _
private var baseTypeSeqPeriod = NoPeriod
+ private var symInfoCache: Type = _
+ private var memberInfoCache: Type = _
+ private var thisInfoCache: Type = _
+ private var relativeInfoCache: Type = _
+
+ private var normalized: Type = null
+
+
override def isStable: Boolean = {
sym == NothingClass ||
sym == SingletonClass ||
@@ -1733,12 +1743,28 @@ trait Types /*extends reflect.generic.Types*/ { self: SymbolTable =>
//@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs)
def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies)
- def thisInfo =
+ def thisInfo: Type =
if (sym.isAliasType) normalize
- else if (sym.isNonClassType) transformInfo(sym.info)
- else sym.info
+ else if (!sym.isNonClassType) sym.info
+ else {
+ val symInfo = sym.info
+ if (thisInfoCache == null || (symInfo ne symInfoCache)) {
+ symInfoCache = symInfo
+ thisInfoCache = transformInfo(symInfo)
+ }
+ thisInfoCache
+ }
- def relativeInfo = if (sym.isNonClassType) transformInfo(pre.memberInfo(sym)) else pre.memberInfo(sym)
+ def relativeInfo: Type =
+ if (!sym.isNonClassType) pre.memberInfo(sym)
+ else {
+ val memberInfo = pre.memberInfo(sym)
+ if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) {
+ memberInfoCache = memberInfo
+ relativeInfoCache = transformInfo(memberInfo)
+ }
+ relativeInfoCache
+ }
override def typeSymbol = if (sym.isAliasType) normalize.typeSymbol else sym
override def termSymbol = if (sym.isAliasType) normalize.termSymbol else super.termSymbol
@@ -1826,8 +1852,6 @@ A type's typeSymbol should never be inspected directly.
super.instantiateTypeParams(formals, actuals)
- private var normalized: Type = null
-
@inline private def betaReduce: Type = {
assert(sameLength(sym.info.typeParams, typeArgs), this)
// isHKSubType0 introduces synthetic type params so that betaReduce can first apply sym.info to typeArgs before calling asSeenFrom
@@ -1847,7 +1871,7 @@ A type's typeSymbol should never be inspected directly.
betaReduce.dealias
} else this
- def normalize0: Type =
+ private def normalize0: Type =
if (pre eq WildcardType) WildcardType // arises when argument-dependent types are approximated (see def depoly in implicits)
else if (isHigherKinded) etaExpand // eta-expand, subtyping relies on eta-expansion of higher-kinded types
else if (sym.isAliasType && sameLength(sym.info.typeParams, args))
@@ -3461,7 +3485,7 @@ A type's typeSymbol should never be inspected directly.
/** A base class to compute all substitutions */
abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap {
- val fromContains = from.toSet // avoiding repeatedly traversing from
+ val fromContains = (x: Symbol) => from.contains(x) //from.toSet <-- traversing short lists seems to be faster than allocating sets
assert(sameLength(from, to), "Unsound substitution from "+ from +" to "+ to)
/** Are `sym' and `sym1' the same.
@@ -3472,12 +3496,6 @@ A type's typeSymbol should never be inspected directly.
/** Map target to type, can be tuned by subclasses */
protected def toType(fromtp: Type, tp: T): Type
- def subst(tp: Type, sym: Symbol, from: List[Symbol], to: List[T]): Type =
- if (from.isEmpty) tp
- // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(tp, from))
- else if (matches(from.head, sym)) toType(tp, to.head)
- else subst(tp, sym, from.tail, to.tail)
-
protected def renameBoundSyms(tp: Type): Type = tp match {
case MethodType(ps, restp) =>
val ps1 = cloneSymbols(ps)
@@ -3493,6 +3511,12 @@ A type's typeSymbol should never be inspected directly.
}
def apply(tp0: Type): Type = if (from.isEmpty) tp0 else {
+ @tailrec def subst(tp: Type, sym: Symbol, from: List[Symbol], to: List[T]): Type =
+ if (from.isEmpty) tp
+ // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(tp, from))
+ else if (matches(from.head, sym)) toType(tp, to.head)
+ else subst(tp, sym, from.tail, to.tail)
+
val boundSyms = tp0.boundSyms
val tp1 = if (boundSyms exists fromContains) renameBoundSyms(tp0) else tp0
val tp = mapOver(tp1)
@@ -3526,7 +3550,7 @@ A type's typeSymbol should never be inspected directly.
case SingleType(pre, _) => singleType(pre, sym)
}
override def apply(tp: Type): Type = if (from.isEmpty) tp else {
- def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol =
+ @tailrec def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol =
if (from.isEmpty) sym
// else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(sym, from))
else if (matches(from.head, sym)) to.head
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index da07723b89..e30f69e858 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1075,7 +1075,7 @@ trait Implicits {
def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass)
def mot(tp0: Type, from: List[Symbol], to: List[Type]): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
- if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
+ if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to))
val tp1 = tp0.normalize
tp1 match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index fbad63d2c9..c879f06f00 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -317,7 +317,7 @@ trait Infer {
val MethodType(params, restpe) = tp
val TypeRef(pre, sym, args) = pt
- if (sym.isAliasType) apply(tp, pt.dealias)
+ if (sym.isAliasType) apply(tp, pt.normalize)
else if (sym.isAbstractType) apply(tp, pt.bounds.lo)
else {
val len = args.length - 1
@@ -353,7 +353,7 @@ trait Infer {
}
object isPlausiblyCompatible extends CompatibilityChecker {
- def resultTypeCheck(restpe: Type, arg: Type) = isPlausiblySubType(restpe, arg)
+ def resultTypeCheck(restpe: Type, arg: Type) = isPlausiblyCompatible(restpe, arg)
def argumentCheck(arg: Type, param: Type) = isPlausiblySubType(arg, param)
def lastChanceCheck(tp: Type, pt: Type) = false
}
@@ -373,12 +373,14 @@ trait Infer {
*/
private def isPlausiblySubType(tp1: Type, tp2: Type) = !isImpossibleSubType(tp1, tp2)
private def isImpossibleSubType(tp1: Type, tp2: Type) = {
- (tp1.dealias, tp2.dealias) match {
+ (tp1.normalize.widen, tp2.normalize.widen) match {
case (TypeRef(_, sym1, _), TypeRef(_, sym2, _)) =>
sym1.isClass &&
sym2.isClass &&
!(sym1 isSubClass sym2) &&
!(sym1 isNumericSubClass sym2)
+ case (tp1@TypeRef(_, sym1, _), tp2@RefinedType(_,decls)) =>
+ !decls.toList.forall(s => tp1.member(s.name) != NoSymbol)
case _ =>
false
}