diff options
author | Martin Odersky <odersky@gmail.com> | 2006-10-20 13:37:17 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2006-10-20 13:37:17 +0000 |
commit | f9e5afd36a8a241abc86c80197d8fbe10488280e (patch) | |
tree | 0210b277aeabea10dc8eca0dc96171dcd5934976 /src | |
parent | f3f8f974bf0ebbe4746fbe83103566e71e8b1e7c (diff) | |
download | scala-f9e5afd36a8a241abc86c80197d8fbe10488280e.tar.gz scala-f9e5afd36a8a241abc86c80197d8fbe10488280e.tar.bz2 scala-f9e5afd36a8a241abc86c80197d8fbe10488280e.zip |
fixed problems in type patterns
made some type error messages more precise
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 101 |
3 files changed, 88 insertions, 22 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 |