summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-10-20 13:37:17 +0000
committerMartin Odersky <odersky@gmail.com>2006-10-20 13:37:17 +0000
commitf9e5afd36a8a241abc86c80197d8fbe10488280e (patch)
tree0210b277aeabea10dc8eca0dc96171dcd5934976
parentf3f8f974bf0ebbe4746fbe83103566e71e8b1e7c (diff)
downloadscala-f9e5afd36a8a241abc86c80197d8fbe10488280e.tar.gz
scala-f9e5afd36a8a241abc86c80197d8fbe10488280e.tar.bz2
scala-f9e5afd36a8a241abc86c80197d8fbe10488280e.zip
fixed problems in type patterns
made some type error messages more precise
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala101
-rw-r--r--test/files/neg/bug126.check4
-rw-r--r--test/files/neg/bug126.scala8
-rw-r--r--test/files/neg/escapes.check5
-rwxr-xr-xtest/files/neg/escapes.scala6
-rw-r--r--test/files/neg/gadts1.check7
-rw-r--r--test/files/neg/viewtest.check7
-rwxr-xr-xtest/files/pos/escapes2.scala5
-rw-r--r--test/files/pos/viewtest2.scala2
-rw-r--r--test/files/run/lisp.scala2
12 files changed, 113 insertions, 43 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index c586253333..233b67aaf2 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -160,7 +160,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
* try {
* body
* } catch {
- * case ex: NonLocalReturnException =>
+ * case ex: NonLocalReturnException[_] =>
* if (ex.key().eq(key)) ex.value()
* else throw ex
* }
@@ -170,7 +170,11 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
localTyper.typed {
val extpe = nonLocalReturnExceptionType(meth)
val ex = meth.newValue(body.pos, nme.ex) setInfo extpe
- val pat = Bind(ex, Typed(Ident(nme.WILDCARD), TypeTree(extpe)))
+ val pat = Bind(ex,
+ Typed(Ident(nme.WILDCARD),
+ AppliedTypeTree(Ident(NonLocalReturnExceptionClass),
+ List(Bind(nme.WILDCARD.toTypeName,
+ EmptyTree)))))
val rhs =
If(
Apply(
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 6d2806c6ce..1f3743c310 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -336,7 +336,6 @@ trait Contexts requires Analyzer {
if (settings.debug.value) log("resetting " + sym + " to " + info);
sym.info match {
case TypeBounds(lo, hi) if (hi <:< lo && lo <:< hi) =>
- Console.println("subst "+sym+" to "+lo)
current = current.subst(List(sym), List(lo))
case _ =>
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 793cceb256..95a0fd4028 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -234,7 +234,9 @@ trait Infer requires Analyzer {
)
def foundReqMsg(found: Type, req: Type): String =
- ";\n found : " + found.toLongString + "\n required: " + req
+ withDisambiguation(found, req) {
+ ";\n found : " + found.toLongString + "\n required: " + req
+ }
def error(pos: PositionType, msg: String): unit =
context.error(pos, msg)
@@ -251,8 +253,7 @@ trait Infer requires Analyzer {
(if (!(found.resultType eq found) && isWeaklyCompatible(found.resultType, req))
"\n possible cause: missing arguments for method or constructor"
else ""))
- if (settings.explaintypes.value)
- explainTypes(found, req)
+ if (settings.explaintypes.value) explainTypes(found, req)
}
def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = {
@@ -260,6 +261,42 @@ trait Infer requires Analyzer {
setError(tree)
}
+ def explainTypes(tp1: Type, tp2: Type) =
+ withDisambiguation(tp1, tp2) { global.explainTypes(tp1, tp2) }
+
+ /** If types `tp1' `tp2' contain different type variables with same name
+ * differentiate the names by including owner information
+ */
+ private def withDisambiguation[T](tp1: Type, tp2: Type)(op: => T): T = {
+
+ def explainName(sym: Symbol) = { sym.name = newTypeName("<"+sym+" in "+sym.owner+">") }
+
+ val patches = {
+ val tparams1 = freeTypeParams.collect(tp1)
+ val tparams2 = freeTypeParams.collect(tp2)
+ for {
+ val tparam1 <- tparams1
+ val tparam2 <- tparams2
+ tparam1 != tparam2 && tparam1.name == tparam2.name
+ } yield {
+ val name = tparam1.name
+ explainName(tparam1)
+ explainName(tparam2)
+ if (tparam1.owner == tparam2.owner) tparam2.name = newTypeName("some other "+tparam2.name)
+ Triple(tparam1, tparam2, tparam1.name)
+ }
+ }
+
+ val result = op
+
+ for (val Triple(tparam1, tparam2, name) <- patches) {
+ tparam1.name = name
+ tparam2.name = name
+ }
+
+ result
+ }
+
/* -- Tests & Checks---------------------------------------------------- */
/** Check that <code>sym</code> is defined and accessible as a member of
@@ -297,9 +334,8 @@ trait Infer requires Analyzer {
accessError("")
} else {
//System.out.println("check acc " + sym1 + ":" + sym1.tpe + " from " + pre);//DEBUG
- var owntype = /* try{ */
+ var owntype = try{
pre.memberType(sym1)
-/*
} catch {
case ex: MalformedType =>
val sym2 = underlying(sym1)
@@ -309,7 +345,6 @@ trait Infer requires Analyzer {
else " contains a "+ex.msg))
ErrorType
}
-*/
if (pre.isInstanceOf[SuperType])
owntype = owntype.substSuper(pre, site.symbol.thisType)
tree setSymbol sym1 setType owntype
@@ -696,7 +731,7 @@ trait Infer requires Analyzer {
computeArgs
} else if (isFullyDefined(pt)) {
if (settings.debug.value) log("infer constr " + tree + ":" + restpe + ", pt = " + pt)
- var ptparams = freeTypeParams.collect(pt)
+ var ptparams = freeTypeParamsOfTerms.collect(pt)
if (settings.debug.value) log("free type params = " + ptparams)
val ptWithWildcards = pt.subst(ptparams, ptparams map (ptparam => WildcardType))
tvars = undetparams map freshVar
@@ -777,17 +812,35 @@ trait Infer requires Analyzer {
}
}
+ /** Type intersection of simple type `tp1' with general type `tp2'
+ * The result eliminates some redundancies
+ */
+ def intersect(tp1: Type, tp2: Type): Type = {
+ if (tp1 <:< tp2) tp1
+ else if (tp2 <:< tp1) tp2
+ else {
+ val reduced2 = tp2 match {
+ case rtp @ RefinedType(parents2, decls2) =>
+ copyRefinedType(rtp, parents2 filter (p2 => !(tp1 <:< p2)), decls2)
+ case _ =>
+ tp2
+ }
+ intersectionType(List(tp1, reduced2))
+ }
+ }
+
def inferTypedPattern(tpt: Tree, pt: Type): Type = {
+ //Console.println("infer typed pattern: "+tpt)//DEBUG
checkCheckable(tpt.pos, tpt.tpe)
if (!(tpt.tpe <:< pt)) {
- val tpparams = freeTypeParams.collect(tpt.tpe)
+ val tpparams = freeTypeParamsOfTerms.collect(tpt.tpe)
if (settings.debug.value) log("free type params (1) = " + tpparams)
var tvars = tpparams map freshVar
var tp = tpt.tpe.subst(tpparams, tvars)
if (!(tp <:< pt)) {
tvars = tpparams map freshVar
tp = tpt.tpe.subst(tpparams, tvars)
- val ptparams = freeTypeParams.collect(pt)
+ val ptparams = freeTypeParamsOfTerms.collect(pt)
if (settings.debug.value) log("free type params (2) = " + ptparams)
val ptvars = ptparams map freshVar
val pt1 = pt.subst(ptparams, ptvars)
@@ -799,7 +852,7 @@ trait Infer requires Analyzer {
}
tvars foreach instantiateTypeVar(true)
}
- intersectionType(List(tpt.tpe, pt))
+ intersect(tpt.tpe, pt)
}
object toOrigin extends TypeMap {
@@ -809,25 +862,24 @@ trait Infer requires Analyzer {
}
}
- /** A traverser to collect type parameters referred to in a type
- */
- object freeTypeParams extends TypeTraverser {
+ abstract class FreeSymCollector extends TypeTraverser {
private var result: List[Symbol] = _
- private def includeIfTypeParam(sym: Symbol): unit = {
- if (sym.isAbstractType && sym.owner.isTerm && !result.contains(sym))
- result = sym :: result
- }
+ protected def includeCondition(sym: Symbol): boolean
+ private def include(sym: Symbol): unit =
+ if (includeCondition(sym) && !result.contains(sym)) result = sym :: result
+
override def traverse(tp: Type): TypeTraverser = {
tp match {
case TypeRef(NoPrefix, sym, _) =>
- includeIfTypeParam(sym)
+ include(sym)
case TypeRef(ThisType(_), sym, _) =>
- includeIfTypeParam(sym)
+ include(sym)
case _ =>
}
mapOver(tp)
this
}
+
/** Collect all abstract type symbols referred to by type <code>tp</code>.
*
* @param tp ...
@@ -840,6 +892,17 @@ trait Infer requires Analyzer {
}
}
+ /** A traverser to collect type parameters referred to in a type
+ */
+ object freeTypeParamsOfTerms extends FreeSymCollector {
+ protected def includeCondition(sym: Symbol): boolean = sym.isAbstractType && sym.owner.isTerm
+ }
+
+ object freeTypeParams extends FreeSymCollector {
+ protected def includeCondition(sym: Symbol): boolean =
+ sym.isAbstractType && (sym.owner.isTerm || (sym hasFlag PARAM))
+ }
+
/* -- Overload Resolution ---------------------------------------------- */
/** Assign <code>tree</code> the symbol and type of the alternative which
diff --git a/test/files/neg/bug126.check b/test/files/neg/bug126.check
deleted file mode 100644
index 84a50aa821..0000000000
--- a/test/files/neg/bug126.check
+++ /dev/null
@@ -1,4 +0,0 @@
-bug126.scala:5 error: forward reference extends over definition of value foo2
- val Tuple1(foo2:(Any => Any)) = Tuple1((x:Any) => foo2(x));
- ^
-one error found
diff --git a/test/files/neg/bug126.scala b/test/files/neg/bug126.scala
deleted file mode 100644
index 75c10e608a..0000000000
--- a/test/files/neg/bug126.scala
+++ /dev/null
@@ -1,8 +0,0 @@
-class O {
- val Bar:Any => Any = ((x:Any) => Bar(x));
- val Tuple2(foo:(Any => Any), bar) = Tuple2((x:Any) => foo(x), 1);
- {
- val Tuple1(foo2:(Any => Any)) = Tuple1((x:Any) => foo2(x));
- Console.println(foo2)
- }
-}
diff --git a/test/files/neg/escapes.check b/test/files/neg/escapes.check
new file mode 100644
index 0000000000..95299a4c75
--- /dev/null
+++ b/test/files/neg/escapes.check
@@ -0,0 +1,5 @@
+escapes.scala:2 error: type t escapes its defining scope as part of type t
+ def f(x: Any) = x match { case y: Cell[t] => y.elem }
+ ^
+subst type t to T
+one error found
diff --git a/test/files/neg/escapes.scala b/test/files/neg/escapes.scala
new file mode 100755
index 0000000000..3a280e8d0a
--- /dev/null
+++ b/test/files/neg/escapes.scala
@@ -0,0 +1,6 @@
+object Test {
+ def f(x: Any) = x match { case y: Cell[t] => y.elem }
+ class C3[T](val elem: T)
+ class D3[T](val elemD: T) extends C3[T](elemD)
+ def f[T](x: C3[T]) = x match { case d: D3[t] => d.elemD }
+}
diff --git a/test/files/neg/gadts1.check b/test/files/neg/gadts1.check
index 8b3d6605ed..a761b79cb8 100644
--- a/test/files/neg/gadts1.check
+++ b/test/files/neg/gadts1.check
@@ -1,11 +1,6 @@
gadts1.scala:15 error: type mismatch;
- found : Test.this.NumTerm
- required: Test.this.Term[a]
- case NumTerm(n) => c.x = Double(1.0)
- ^
-gadts1.scala:15 error: type mismatch;
found : Test.this.Double
required: a
case NumTerm(n) => c.x = Double(1.0)
^
-two errors found
+one error found
diff --git a/test/files/neg/viewtest.check b/test/files/neg/viewtest.check
index b98b56bce5..044c3b7d91 100644
--- a/test/files/neg/viewtest.check
+++ b/test/files/neg/viewtest.check
@@ -1,7 +1,12 @@
+viewtest.scala:43 error: type mismatch;
+ found : scala.List[<type a in method compareTo>]
+ required: scala.List[<type a in method view3>]
+ case y1: List[a] => compareLists(x, y1)
+ ^
viewtest.scala:104 error: ambiguous implicit value:
both method view4 in object O of type [a](a)a
and method identity in object Predef of type [a](a)a
match expected type (test.Str) => test.Ordered[test.Str]
t = t insert Str(s)
^
-one error found
+two errors found
diff --git a/test/files/pos/escapes2.scala b/test/files/pos/escapes2.scala
new file mode 100755
index 0000000000..b94066936a
--- /dev/null
+++ b/test/files/pos/escapes2.scala
@@ -0,0 +1,5 @@
+object Test {
+ class C3[T](val elem: T)
+ class D3[T](val elemD: T) extends C3[T](elemD)
+ def f[T](x: C3[T]) = x match { case d: D3[t] => d.elemD }
+}
diff --git a/test/files/pos/viewtest2.scala b/test/files/pos/viewtest2.scala
index 66cd1aa1bd..6a6ed96df7 100644
--- a/test/files/pos/viewtest2.scala
+++ b/test/files/pos/viewtest2.scala
@@ -40,7 +40,7 @@ object O {
implicit def view3[a <% Ordered[a]](x: List[a]): Ordered[List[a]] =
new Ordered[List[a]] {
def compareTo [b >: List[a] <% Ordered[b]](y: b): int = y match {
- case y1: List[a] => compareLists(x, y1)
+ case y1: List[a1] => compareLists(x, y1.asInstanceOf[List[a]])
case _ => -(y compareTo x)
}
private def compareLists(xs: List[a], ys: List[a]): int = {
diff --git a/test/files/run/lisp.scala b/test/files/run/lisp.scala
index f12196ca50..bf895f2349 100644
--- a/test/files/run/lisp.scala
+++ b/test/files/run/lisp.scala
@@ -287,7 +287,7 @@ object LispAny extends Lisp {
}
def asList(x: Data): List[Data] = x match {
- case y: List[Data] => y
+ case y: List[_] => y
case _ => lispError("malformed list: " + x)
}