summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-11-12 16:12:16 +0000
committerMartin Odersky <odersky@gmail.com>2009-11-12 16:12:16 +0000
commit9ed068ec0091c0f4f9dee0539540408d89e96776 (patch)
treec6db8b9755360ba6536c3a23eafa12e45b50e3d9
parent39fb348121e43dd3d48b378f43a68ed8fc5fc157 (diff)
downloadscala-9ed068ec0091c0f4f9dee0539540408d89e96776.tar.gz
scala-9ed068ec0091c0f4f9dee0539540408d89e96776.tar.bz2
scala-9ed068ec0091c0f4f9dee0539540408d89e96776.zip
Fixed #2517
Fixed #2606 Fixed #2598 Fixed #1836
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Constants.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala25
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala18
4 files changed, 51 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Constants.scala b/src/compiler/scala/tools/nsc/symtab/Constants.scala
index 2a4d3e1fa1..53ada529e1 100644
--- a/src/compiler/scala/tools/nsc/symtab/Constants.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Constants.scala
@@ -80,7 +80,15 @@ trait Constants {
* @return ...
*/
override def equals(other: Any): Boolean = other match {
- case that: Constant => this.tag == that.tag && this.value == that.value
+ case that: Constant =>
+ this.tag == that.tag &&
+ (this.value == that.value || isNaN(this.value) && isNaN(that.value))
+ case _ => false
+ }
+
+ def isNaN(value: Any) = value match {
+ case f: Float => f.isNaN
+ case d: Double => d.isNaN
case _ => false
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 1c22a6fdaf..579696feae 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -284,9 +284,9 @@ trait Symbols {
newSyntheticValueParams(List(argtype)).head
/** Type skolems are type parameters ``seen from the inside''
- * Given a class C[T]
- * Then the class has a TypeParameter with name `T' in its typeParams list
- * While type checking the class, there's a local copy of `T' which is a TypeSkolem
+ * Assuming a polymorpphic method m[T], its type is a PolyType which has a TypeParameter
+ * with name `T' in its typeParams list. While type checking the parameters, result type and
+ * body of the method, there's a local copy of `T' which is a TypeSkolem.
*/
final def newTypeSkolem: Symbol =
new TypeSkolem(owner, pos, name, this)
@@ -1813,7 +1813,19 @@ trait Symbols {
if (util.Statistics.enabled) typeSymbolCount = typeSymbolCount + 1
}
- /** A class for type parameters viewed from inside their scopes */
+ /** A class for type parameters viewed from inside their scopes
+ *
+ * @param origin Can be either a tree, or a symbol, or null.
+ * If skolem got created from newTypeSkolem (called in Namers), origin denotes
+ * the type parameter from which the skolem was created. If it got created from
+ * skolemizeExistential, origin is either null or a Tree. If it is a Tree, it indicates
+ * where the skolem was introduced (this is important for knowing when to pack it
+ * again into ab Existential). origin is `null' only in skolemizeExistentials called
+ * from <:< or isAsSpecific, because here its value does not matter.
+ * I elieve the following invariant holds:
+ *
+ * origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
+ */
class TypeSkolem(initOwner: Symbol, initPos: Position,
initName: Name, origin: AnyRef)
extends TypeSymbol(initOwner, initPos, initName) {
@@ -1822,11 +1834,16 @@ trait Symbols {
val level = skolemizationLevel
override def isSkolem = true
+
+ /** If typeskolem comes from a type parameter, that parameter, otherwise skolem itself */
override def deSkolemize = origin match {
case s: Symbol => s
case _ => this
}
+
+ /** If type skolem comes from an existential, the tree where it was created */
override def unpackLocation = origin
+
override def typeParams = info.typeParams //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo
override def cloneSymbolImpl(owner: Symbol): Symbol =
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 676f19205a..6840f4ac4c 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -391,8 +391,18 @@ trait Types {
*/
def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = this.subst(formals, actuals)
+ /** If this type is an existential, turn all existentially bound variables to type skolems.
+ * @param owner The owner of the created type skolems
+ * @param origin The tree whose type was an existential for which the skolem was created.
+ */
def skolemizeExistential(owner: Symbol, origin: AnyRef): Type = this
+
+ /** A simple version of skolemizeExistential for situations where
+ * owner or unpack location do not matter (typically used in subtype tests)
+ */
+ def skolemizeExistential: Type = skolemizeExistential(NoSymbol, null)
+
/** Reduce to beta eta-long normal form. Expands type aliases and converts higher-kinded TypeRef's to PolyTypes. @M */
def normalize = this // @MAT
@@ -4065,7 +4075,7 @@ A type's typeSymbol should never be inspected directly.
case ExistentialType(_, _) =>
try {
skolemizationLevel += 1
- tp1.skolemizeExistential(NoSymbol, null) <:< tp2
+ tp1.skolemizeExistential <:< tp2
} finally {
skolemizationLevel -= 1
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 8ed799ed60..898ad238a1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -884,7 +884,8 @@ trait Infer {
case OverloadedType(pre, alts) =>
alts exists (alt => isAsSpecific(pre.memberType(alt), ftpe2))
case et: ExistentialType =>
- et.withTypeVars(isAsSpecific(_, ftpe2))
+ isAsSpecific(ftpe1.skolemizeExistential, ftpe2)
+ //et.withTypeVars(isAsSpecific(_, ftpe2))
case mt: ImplicitMethodType =>
isAsSpecific(ftpe1.resultType, ftpe2)
case MethodType(params @ (x :: xs), _) =>
@@ -1380,8 +1381,8 @@ trait Infer {
}
def checkCheckable(pos: Position, tp: Type, kind: String) {
- def patternWarning(tp: Type, prefix: String) = {
- context.unit.uncheckedWarning(pos, prefix+tp+" in type"+kind+" is unchecked since it is eliminated by erasure")
+ def patternWarning(tp0: Type, prefix: String) = {
+ context.unit.uncheckedWarning(pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure")
}
def check(tp: Type, bound: List[Symbol]) {
def isLocalBinding(sym: Symbol) =
@@ -1395,13 +1396,13 @@ trait Infer {
case SingleType(pre, _) =>
check(pre, bound)
case TypeRef(pre, sym, args) =>
- if (sym.isAbstractType)
+ if (sym.isAbstractType) {
if (!isLocalBinding(sym)) patternWarning(tp, "abstract type ")
- else if (sym.isAliasType)
+ } else if (sym.isAliasType) {
check(tp.normalize, bound)
- else if (sym == NothingClass || sym == NullClass || sym == AnyValClass)
+ } else if (sym == NothingClass || sym == NullClass || sym == AnyValClass) {
error(pos, "type "+tp+" cannot be used in a type pattern or isInstanceOf test")
- else
+ } else {
for (arg <- args) {
if (sym == ArrayClass) check(arg, bound)
else arg match {
@@ -1411,6 +1412,7 @@ trait Infer {
patternWarning(arg, "non variable type-argument ")
}
}
+ }
check(pre, bound)
case RefinedType(parents, decls) =>
if (decls.isEmpty) for (p <- parents) check(p, bound)
@@ -1447,7 +1449,7 @@ trait Infer {
def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = {
val pt = widen(pt0)
- checkCheckable(pos, pattp, " pattern")
+ checkCheckable(pos, pattp, "pattern ")
if (!(pattp <:< pt)) {
val tpparams = freeTypeParamsOfTerms.collect(pattp)
if (settings.debug.value) log("free type params (1) = " + tpparams)