summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-07-10 14:59:55 +0000
committerMartin Odersky <odersky@gmail.com>2008-07-10 14:59:55 +0000
commitd3744118959edcbb8fb061d106078864f83fb7b2 (patch)
tree9ff868237e2b1be920b26d1591350d09688bb6fa
parentf12e0645fff0039e5cb681cb766a1b2be884e61d (diff)
downloadscala-d3744118959edcbb8fb061d106078864f83fb7b2.tar.gz
scala-d3744118959edcbb8fb061d106078864f83fb7b2.tar.bz2
scala-d3744118959edcbb8fb061d106078864f83fb7b2.zip
fixed t0851 and t1101.
-rwxr-xr-xsrc/compiler/scala/tools/nsc/javac/JavaParsers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala145
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala6
-rw-r--r--test/files/neg/bug1279a.check6
-rw-r--r--test/files/neg/lazy-override.check9
-rw-r--r--test/files/neg/lazy-override.scala19
-rwxr-xr-xtest/files/pos/t0851.scala14
9 files changed, 157 insertions, 47 deletions
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
index 96247563c1..f2cacb38cf 100755
--- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
@@ -707,13 +707,14 @@ trait JavaParsers extends JavaScanners {
val statics = new ListBuffer[Tree]
val members = new ListBuffer[Tree]
while (in.token != RBRACE && in.token != EOF) {
- val mods = modifiers(inInterface)
+ var mods = modifiers(inInterface)
if (in.token == LBRACE) {
skipAhead() // skip init block, we just assume we have seen only static
accept(RBRACE)
} else if (in.token == SEMI) {
in.nextToken
} else {
+ if (in.token == ENUM) mods |= Flags.STATIC
(if (mods hasFlag Flags.STATIC) statics else members) ++= memberDecl(mods, parentToken)
}
}
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 42d9b36f98..70e22cd70e 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -34,6 +34,7 @@ trait ParallelMatching {
// used as argument to `EqualsPatternClass'
case class PseudoType(o: Tree) extends SimpleTypeProxy {
override def underlying: Type = o.tpe
+ override def safeToString: String = "PseudoType("+o+")"
}
/** picks which rewrite rule to apply
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 2444cbea22..5758676b8f 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -251,7 +251,10 @@ trait Types {
*/
def narrow: Type =
if (phase.erasedTypes) this
- else refinedType(List(this), commonOwner(this), EmptyScope, commonOwner(this).pos).narrow
+ else {
+ val cowner = commonOwner(this)
+ refinedType(List(this), cowner, EmptyScope, cowner.pos).narrow
+ }
/** For a TypeBounds type, itself;
* for a reference denoting an abstract type, its bounds,
@@ -592,6 +595,20 @@ trait Types {
else str
}
+ /** A test whether a type contains any unification type variables */
+ def isGround: Boolean = this match {
+ case TypeVar(_, constr) =>
+ constr.inst != NoType && constr.inst.isGround
+ case TypeRef(pre, sym, args) =>
+ sym.isPackageClass || pre.isGround && (args forall (_.isGround))
+ case SingleType(pre, sym) =>
+ sym.isPackageClass || pre.isGround
+ case ThisType(_) | NoPrefix | WildcardType | NoType | ErrorType | ConstantType(_) =>
+ true
+ case _ =>
+ typeVarToOriginMap(this) eq this
+ }
+
/** Is this type completed (i.e. not a lazy type)?
*/
def isComplete: Boolean = true
@@ -623,14 +640,23 @@ trait Types {
}
/**
- * @param name ...
- * @param excludedFlags ...
- * @param requiredFlags ...
- * @param stableOnly ...
- * @return ...
+ * Find member(s) in this type. If several members matching criteria are found, they are
+ * returned in an OverloadedSymbol
+ *
+ * @param name The member's name, where nme.ANYNAME means `unspecified'
+ * @param excludedFlags Returned members do not have these flags
+ * @param requiredFlags Returned members do have these flags
+ * @param stableOnly If set, return only members that are types or stable values
+ * @param from ??
*/
//TODO: use narrow only for modules? (correct? efficiency gain?)
def findMember(name: Name, excludedFlags: Int, requiredFlags: Long, stableOnly: Boolean)(from:Symbol): Symbol = {
+ // if this type contains type variables, get rid of them;
+ // without this, the matchesType call would lead to type variables on both sides
+ // of a subtyping/equality judgement, which can lead to recursive types being constructed.
+ // See (t0851) for a situation where this happens.
+ if (!this.isGround)
+ return typeVarToOriginMap(this).findMember(name, excludedFlags, requiredFlags, stableOnly)(from)
if (inIDE) trackTypeIDE(typeSymbol)
if (util.Statistics.enabled) findMemberCount += 1
val startTime = if (util.Statistics.enabled) currentTime else 0l
@@ -762,8 +788,24 @@ trait Types {
/** The kind of this type; used for debugging */
def kind: String = "unknown type of class "+getClass()
+
+ override def toString: String =
+ if (tostringRecursions >= maxTostringRecursions)
+ "..."
+ else
+ try {
+ tostringRecursions += 1
+ safeToString
+ } finally {
+ tostringRecursions -= 1
+ }
+
+ def safeToString: String = super.toString
}
+ private final val maxTostringRecursions = 50
+ private var tostringRecursions = 0
+
// Subclasses ------------------------------------------------------------
trait UniqueType {
@@ -794,7 +836,7 @@ trait Types {
override def isNotNull: Boolean = true
override def notNull = this
override def deconst: Type = underlying //todo: needed?
- override def toString: String = underlying.toString + " with NotNull"
+ override def safeToString: String = underlying.toString + " with NotNull"
override def kind = "NotNullType"
}
@@ -810,7 +852,7 @@ trait Types {
if (util.Statistics.enabled) singletonClosureCount += 1
addClosure(this, underlying.closure)
}
- override def toString: String = prefixString + "type"
+ override def safeToString: String = prefixString + "type"
/*
override def typeOfThis: Type = typeSymbol.typeOfThis
override def bounds: TypeBounds = mkTypeBounds(this, this)
@@ -835,7 +877,7 @@ trait Types {
sym
}
override def baseType(clazz: Symbol): Type = this
- override def toString: String = "<error>"
+ override def safeToString: String = "<error>"
override def narrow: Type = this
// override def isNullable: Boolean = true
override def kind = "ErrorType"
@@ -843,20 +885,20 @@ trait Types {
/** An object representing an unknown type */
case object WildcardType extends Type {
- override def toString: String = "?"
+ override def safeToString: String = "?"
// override def isNullable: Boolean = true
override def kind = "WildcardType"
}
case class BoundedWildcardType(override val bounds: TypeBounds) extends Type {
- override def toString: String = "?" + bounds
+ override def safeToString: String = "?" + bounds
override def kind = "BoundedWildcardType"
}
/** An object representing a non-existing type */
case object NoType extends Type {
override def isTrivial: Boolean = true
- override def toString: String = "<notype>"
+ override def safeToString: String = "<notype>"
// override def isNullable: Boolean = true
override def kind = "NoType"
}
@@ -866,7 +908,7 @@ trait Types {
override def isTrivial: Boolean = true
override def isStable: Boolean = true
override def prefixString = ""
- override def toString: String = "<noprefix>"
+ override def safeToString: String = "<noprefix>"
// override def isNullable: Boolean = true
override def kind = "NoPrefixType"
}
@@ -885,7 +927,7 @@ trait Types {
else if (sym.isAnonymousClass || sym.isRefinementClass) "this."
else if (sym.isModuleClass) sym.fullNameString + "."
else sym.nameString + ".this."
- override def toString: String =
+ override def safeToString: String =
if (sym.isRoot) "<root>"
else if (sym.isEmptyPackageClass) "<empty>"
else super.toString
@@ -896,7 +938,7 @@ trait Types {
case class DeBruijnIndex(level: Int, paramId: Int) extends Type {
override def isTrivial = true
override def isStable = true
- override def toString = "<param "+level+"."+paramId+">"
+ override def safeToString = "<param "+level+"."+paramId+">"
override def kind = "DeBruijnIndex"
}
@@ -966,9 +1008,12 @@ trait Types {
def supertype = hi
override val isTrivial: Boolean = lo.isTrivial && hi.isTrivial
override def bounds: TypeBounds = this
- def containsType(that: Type) = that <:< this || lo <:< that && that <:< hi;
+ def containsType(that: Type) = that match {
+ case TypeBounds(_, _) => that <:< this
+ case _ => lo <:< that && that <:< hi
+ }
// override def isNullable: Boolean = AllRefClass.tpe <:< lo;
- override def toString = ">: " + lo + " <: " + hi
+ override def safeToString = ">: " + lo + " <: " + hi
override def kind = "TypeBoundsType"
}
@@ -1138,7 +1183,7 @@ trait Types {
// override def isNullable: Boolean =
// parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
- override def toString: String =
+ override def safeToString: String =
parents.mkString("", " with ", "") +
(if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
decls.mkString("{", "; ", "}") else "")
@@ -1307,7 +1352,7 @@ trait Types {
override def isTrivial: Boolean = true
override def isNotNull = value.value != null
override def deconst: Type = underlying
- override def toString: String =
+ override def safeToString: String =
underlying.toString + "(" + value.escapedStringValue + ")"
// override def isNullable: Boolean = value.value eq null
// override def isNonNull: Boolean = value.value ne null
@@ -1516,7 +1561,7 @@ A type's typeSymbol should never be inspected directly.
// override def isNullable: Boolean = sym.info.isNullable
- override def toString: String = {
+ override def safeToString: String = {
if (!settings.debug.value) {
if (sym == RepeatedParamClass && !args.isEmpty)
return args(0).toString + "*"
@@ -1595,9 +1640,10 @@ A type's typeSymbol should never be inspected directly.
params.mkString(paramPrefix, ",", ")")+res
}
- override def toString: String =
+ override def safeToString: String =
if (resultType.isDependent) dependentToString(0)
else paramTypes.mkString(paramPrefix, ",", ")") + resultType
+
override def kind = "MethodType"
}
@@ -1649,7 +1695,7 @@ A type's typeSymbol should never be inspected directly.
override def isHigherKinded = !typeParams.isEmpty
- override def toString: String =
+ override def safeToString: String =
(if (typeParams.isEmpty) "=> "
else (typeParams map (_.defString) mkString ("[", ",", "]")))+resultType
@@ -1702,7 +1748,7 @@ A type's typeSymbol should never be inspected directly.
underlying.substSym(quantified, skolems)
}
- override def toString: String = {
+ override def safeToString: String = {
val str =
underlying+(quantified map (_.existentialToString) mkString(" forSome { ", "; ", " }"))
if (settings.explaintypes.value) "("+str+")" else str
@@ -1730,7 +1776,7 @@ A type's typeSymbol should never be inspected directly.
*/
case class OverloadedType(pre: Type, alternatives: List[Symbol]) extends Type {
override def prefix: Type = pre
- override def toString =
+ override def safeToString =
(alternatives map pre.memberType).mkString("", " <and> ", "")
override def kind = "OverloadedType"
}
@@ -1740,7 +1786,7 @@ A type's typeSymbol should never be inspected directly.
* Not used after phase `typer'.
*/
case class AntiPolyType(pre: Type, targs: List[Type]) extends Type {
- override def toString =
+ override def safeToString =
pre.toString + targs.mkString("(with type arguments ", ",", ")");
override def memberType(sym: Symbol) = pre.memberType(sym) match {
case PolyType(tparams, restp) => restp.subst(tparams, targs)
@@ -1749,23 +1795,40 @@ A type's typeSymbol should never be inspected directly.
override def kind = "AntiPolyType"
}
+ //private var tidCount = 0 //DEBUG
+
/** A class representing a type variable
* Not used after phase `typer'.
*/
case class TypeVar(origin: Type, constr0: TypeConstraint) extends Type {
+ // var tid = { tidCount += 1; tidCount } //DEBUG
+
/** The constraint associated with the variable */
var constr = constr0
/** The variable's skolemizatuon level */
val level = skolemizationLevel
+ def setInst(tp: Type) {
+ assert(!(tp containsTp this), this)
+ constr.inst = tp
+ }
+
+ def tryInstantiate(tp: Type): Boolean =
+ if (constr.lobounds.forall(_ <:< tp) && constr.hibounds.forall(tp <:< _)) {
+ setInst(tp)
+ true
+ } else false
+
override def typeSymbol = origin.typeSymbol
- override def toString: String =
+ override def safeToString: String = {
+ def varString = "?"+(if (settings.explaintypes.value) level else "")+origin// +"#"+tid //DEBUG
if (constr.inst eq null) "<null " + origin + ">"
- else if (constr.inst eq NoType)
- "?"+(if (settings.explaintypes.value) level else "")+origin
- else constr.inst.toString;
+ else if (settings.debug.value) varString+constr.toString
+ else if (constr.inst eq NoType) varString
+ else constr.inst.toString
+ }
override def isStable = origin.isStable
override def kind = "TypeVar"
}
@@ -1791,7 +1854,7 @@ A type's typeSymbol should never be inspected directly.
override protected def rewrap(tp: Type) = AnnotatedType(attributes, tp, selfsym)
- override def toString: String = {
+ override def safeToString: String = {
val attString =
if (attributes.isEmpty)
""
@@ -1840,7 +1903,7 @@ A type's typeSymbol should never be inspected directly.
abstract class LazyType extends Type {
override def isComplete: Boolean = false
override def complete(sym: Symbol)
- override def toString = "<?>"
+ override def safeToString = "<?>"
override def kind = "LazyType"
}
@@ -2204,11 +2267,6 @@ A type's typeSymbol should never be inspected directly.
tc
}
- def instantiate(tp: Type): Boolean =
- if (lobounds.forall(_ <:< tp) && hibounds.forall(tp <:< _)) {
- inst = tp; true
- } else false
-
override def toString =
lobounds.mkString("[ _>:(", ",", ") ") +
hibounds.mkString("| _<:(", ",", ") ] _= ") + inst
@@ -2943,6 +3001,15 @@ A type's typeSymbol should never be inspected directly.
}
}
+ /** A map to convert every occurrence of a type variable to a
+ wildcard type */
+ object typeVarToOriginMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeVar(origin, _) => origin
+ case _ => mapOver(tp)
+ }
+ }
+
/** A map to implement the `contains' method */
class ContainsTraverser(sym: Symbol) extends TypeTraverser {
var result = false
@@ -3438,10 +3505,10 @@ A type's typeSymbol should never be inspected directly.
bounds containsType tp1
case (tv1 @ TypeVar(_, constr1), _) =>
if (constr1.inst != NoType) constr1.inst =:= tp2
- else isRelatable(tv1, tp2) && (constr1 instantiate wildcardToTypeVarMap(tp2))
+ else isRelatable(tv1, tp2) && (tv1 tryInstantiate wildcardToTypeVarMap(tp2))
case (_, tv2 @ TypeVar(_, constr2)) =>
if (constr2.inst != NoType) tp1 =:= constr2.inst
- else isRelatable(tv2, tp1) && (constr2 instantiate wildcardToTypeVarMap(tp1))
+ else isRelatable(tv2, tp1) && (tv2 tryInstantiate wildcardToTypeVarMap(tp1))
case (AnnotatedType(_,_,_), _) =>
annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAttributes =:= tp2.withoutAttributes
case (_, AnnotatedType(_,_,_)) =>
@@ -3805,7 +3872,7 @@ A type's typeSymbol should never be inspected directly.
}
}
tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar
- tvar.constr.inst = if (up) glb(tvar.constr.hibounds) else lub(tvar.constr.lobounds)
+ tvar setInst (if (up) glb(tvar.constr.hibounds) else lub(tvar.constr.lobounds))
//Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hibounds) else tvar.constr.lobounds)+((if (up) (tvar.constr.hibounds) else tvar.constr.lobounds) map (_.widen))+" = "+tvar.constr.inst)//DEBUG"
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index d0e90a2fe2..71641e2c3a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -636,6 +636,7 @@ trait Contexts { self: Analyzer =>
case _ => false
}
override def hashCode = if (inIDE) expr.hashCodeStructure else expr.hashCode
+ override def safeToString = "ImportType("+expr+")"
}
protected def intern(txt : Context) = txt
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index a936353546..458ef8f52e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -477,16 +477,16 @@ trait Infer {
if (tvar.constr.inst != NoType) {
instantiate(tvar.constr.inst)
} else if ((variance & COVARIANT) != 0 && !tvar.constr.hibounds.isEmpty) {
- tvar.constr.inst = glb(tvar.constr.hibounds)
+ tvar setInst glb(tvar.constr.hibounds)
assertNonCyclic(tvar)//debug
instantiate(tvar.constr.inst)
} else if ((variance & CONTRAVARIANT) != 0 && !tvar.constr.lobounds.isEmpty) {
- tvar.constr.inst = lub(tvar.constr.lobounds)
+ tvar setInst lub(tvar.constr.lobounds)
assertNonCyclic(tvar)//debug
instantiate(tvar.constr.inst)
} else if (!tvar.constr.hibounds.isEmpty && !tvar.constr.lobounds.isEmpty &&
glb(tvar.constr.hibounds) <:< lub(tvar.constr.lobounds)) {
- tvar.constr.inst = glb(tvar.constr.hibounds)
+ tvar setInst glb(tvar.constr.hibounds)
assertNonCyclic(tvar)//debug
instantiate(tvar.constr.inst)
} else {
diff --git a/test/files/neg/bug1279a.check b/test/files/neg/bug1279a.check
index a2259f6cda..edfd1fe871 100644
--- a/test/files/neg/bug1279a.check
+++ b/test/files/neg/bug1279a.check
@@ -1,8 +1,6 @@
-bug1279a.scala:34: error: no type parameters for method all4Impl: (M{type T <: U})Stream[M{type T <: U}] exist so that it can be applied to arguments (first.selfType)
- --- because ---
-argument expression's type is not compatible with formal parameter type;
+bug1279a.scala:34: error: type mismatch;
found : first.selfType
required: M{type T <: this.T}
def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl(first.next))
- ^
+ ^
one error found
diff --git a/test/files/neg/lazy-override.check b/test/files/neg/lazy-override.check
new file mode 100644
index 0000000000..d1c9d305f0
--- /dev/null
+++ b/test/files/neg/lazy-override.check
@@ -0,0 +1,9 @@
+lazy-override.scala:11: error: error overriding value x in class A of type Int;
+ lazy value x cannot override a concrete non-lazy value
+ override lazy val x: Int = { print("/*B.x*/"); 3 }
+ ^
+lazy-override.scala:13: error: error overriding lazy value y in class A of type Int;
+ value y must be declared lazy to override a concrete lazy value
+ override val y: Int = { print("/*B.y*/"); 3 }
+ ^
+two errors found
diff --git a/test/files/neg/lazy-override.scala b/test/files/neg/lazy-override.scala
new file mode 100644
index 0000000000..f41d7f038b
--- /dev/null
+++ b/test/files/neg/lazy-override.scala
@@ -0,0 +1,19 @@
+
+/** Test which should fail compilation */
+ class A {
+ val x: Int = { print("/*A.x*/"); 2 }
+ lazy val y: Int = { print("/*A.y*/"); 2 }
+ }
+
+
+ class B extends A {
+ // lazy overrides strict val
+ override lazy val x: Int = { print("/*B.x*/"); 3 }
+ // strict val overrides lazy
+ override val y: Int = { print("/*B.y*/"); 3 }
+ }
+
+
+
+
+
diff --git a/test/files/pos/t0851.scala b/test/files/pos/t0851.scala
new file mode 100755
index 0000000000..fc7109dcd4
--- /dev/null
+++ b/test/files/pos/t0851.scala
@@ -0,0 +1,14 @@
+package test
+
+object test1 {
+ case class Foo[T,T2](f : (T,T2) => String) extends (((T,T2)) => String){
+ def apply(t : T) = (s:T2) => f(t,s)
+ def apply(p : (T,T2)) = f(p._1,p._2)
+ }
+ implicit def g[T](f : (T,String) => String) = Foo(f)
+ def main(args : Array[String]) : Unit = {
+ val f = (x:Int,s:String) => s + x
+ println(f(1))
+ ()
+ }
+}