diff options
-rw-r--r-- | doc/reference/ReferencePart.tex | 9 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Analyzer.scala | 65 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Context.scala | 6 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Infer.scala | 51 | ||||
-rw-r--r-- | sources/scalac/symtab/Scope.java | 2 | ||||
-rw-r--r-- | sources/scalac/symtab/Symbol.java | 2 |
6 files changed, 91 insertions, 44 deletions
diff --git a/doc/reference/ReferencePart.tex b/doc/reference/ReferencePart.tex index ce9fdd298a..811fbe90a8 100644 --- a/doc/reference/ReferencePart.tex +++ b/doc/reference/ReferencePart.tex @@ -3485,7 +3485,8 @@ value (or sequence of values). The same variable name may not be bound more than once in a pattern. Pattern matching is always done in a context which supplies an -expected type of the pattern. We distinguish the following kinds of patterns. +expected type of the pattern. We distinguish the following kinds of +patterns. A {\em variable pattern} $x$ is a simple identifier which starts with a lower case letter. It matches any value, and binds the variable @@ -3756,6 +3757,12 @@ def length [a] (xs: List[a]) = xs match { } \end{lstlisting} +In an application of \code{match} such as the one above, the expected +type of all patterns is the type of the qualifier of \code{match}. +In the example above, the expected type of the patterns \code{Nil} and +\code{x :: xs1} would be \code{List[a]}, the type of \code{xs}. + + \chapter{Top-Level Definitions} \label{sec:topdefs} diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala index 4cc4a2be31..b66373e5f8 100644 --- a/sources/scala/tools/scalac/typechecker/Analyzer.scala +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -622,6 +622,24 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( } else vapp } + private def checkLegalView(pos: int, tparams: Array[Symbol], vparam: Symbol, restype: Type): boolean = { + var i = 0; + while (i < tparams.length && tparams(i) != vparam.getType().symbol()) + i = i + 1; + if (i < tparams.length) { + val vb = tparams(i).vuBound(); + if (vb != Global.instance.definitions.ANY_TYPE()) { + val vb1 = vb.subst(tparams, infer.freshVars(tparams)); + if (restype.isSubType(vb1)) { + error(pos, "view is potentially self-referential since its result type " + restype + + " is a subtype of its type parameter view bound " + vb1); + return false; + } + } + } + true + } + // Contexts ------------------------------------------------------------------- /** Push new context associated with given tree, owner, and scope on stack. @@ -823,18 +841,21 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( context.scope.unlink(e); context.scope.enter(sym); } - } else if (context.owner.kind == CLASS && sym.kind == VAL && other.kind == VAL && ((sym.flags & ACCESSOR) == 0 || (other.flags & ACCESSOR) == 0)) { - e.setSymbol(other.overloadWith(sym)); - } else { - if (context.owner.kind == CLASS) - error(sym.pos, - sym.nameString() + " is already defined as " + - other + other.locationString()); - else - error(sym.pos, - sym.nameString() + - " is already defined in local scope"); - } + } else if (context.owner.kind == CLASS && + sym.kind == VAL && other.kind == VAL && + ((sym.flags & ACCESSOR) == 0 || (other.flags & ACCESSOR) == 0) + || + (sym.name == Names.view && + (sym.flags & (PARAM | SYNTHETIC)) == (PARAM | SYNTHETIC))) { + e.setSymbol(other.overloadWith(sym)); + } else if (context.owner.kind == CLASS) + error(sym.pos, + sym.nameString() + " is already defined as " + + other + other.locationString()); + else + error(sym.pos, + sym.nameString() + + " is already defined in local scope"); } else { context.scope.enter(sym); } @@ -1051,7 +1072,8 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( vsyms(i).name = vparams(i).name; //necessary since vsyms might have been unpickled vparams(i).setSymbol(vsyms(i)); - context.scope.enter(vsyms(i)); + //potential overload in case this is a view parameter + context.scope.enterOrOverload(vsyms(i)); i = i + 1 } rest = restp; @@ -1155,6 +1177,12 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( owntype = makeMethodType(tparamSyms, vparamSyms, restype); //System.out.println("methtype " + name + ":" + owntype);//DEBUG + if (name == Names.view && + infer.isViewBounded(tparamSyms) && + vparamSyms.length == 2 && vparamSyms(1).length == 1 && + !checkLegalView(tree.pos, tparamSyms, vparamSyms(1)(0), restype)) + owntype = makeMethodType(tparamSyms, vparamSyms, Type.ErrorType); + case Tree$ValDef(mods, name, _tpe, _rhs) => var tpe = _tpe; var rhs = _rhs; @@ -1576,6 +1604,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( } } if ((mode & CONSTRmode) == 0) { + System.out.println(tree); typeError(tree.pos, owntype, pt); Type.explainTypes(owntype, pt); setError(tree); @@ -1642,7 +1671,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( c = c.outer } if (lastc != Context.NONE) { - //System.out.println("revising stop to [" + lastc.tree + "]; symbol = " + sym + ", context = " + nextcontext);//debug + //System.out.println("revising stop to [" + lastc.tree + "]; symbol = " + sym + ", context = " + nextcontext);//DEBUG stopPos = lastc.tree.pos; } } @@ -1727,10 +1756,10 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( var sym: Symbol = qual.getType().lookup(name); if (sym.kind == NONE) { if (name != Names.view) { - val v = infer.bestView(qual.getType(), Type.AnyType, name); + val qtype = qual.getType().singleDeref(); + val v = infer.bestView(qtype, Type.AnyType, name); if (v != null) { - qual = applyView( - v, qual.setType(qual.getType().singleDeref()), EXPRmode, Type.AnyType); + qual = applyView(v, qual.setType(qtype), EXPRmode, Type.AnyType); sym = qual.getType().lookup(name); assert(sym.kind != NONE); } else { @@ -2114,7 +2143,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( */ override def transform(tree: Tree): Tree = { - //System.out.println("transforming " + tree);//DEBUG + //System.out.println("transforming " + tree + ":" + pt);//DEBUG if (tree.getType() != null) { checkDefined.all = tree; checkDefined.traverse(tree);//debug return tree; diff --git a/sources/scala/tools/scalac/typechecker/Context.scala b/sources/scala/tools/scalac/typechecker/Context.scala index 58eb148ba7..9bea4b495a 100644 --- a/sources/scala/tools/scalac/typechecker/Context.scala +++ b/sources/scala/tools/scalac/typechecker/Context.scala @@ -82,9 +82,10 @@ class Context { def isUnShadowed(view: View) = view.context == this || !infer.specializes(view.symtype, symtype); */ - if (viewCache.forall(v => v.sym != sym)) { + if (viewCache.forall(v => v.sym != sym) && + symtype.resultType() != Type.ErrorType) { val v = View(sym, symtype, qual, this); - //System.out.println("VIEW " + sym + ":" + symtype + " " + qual);// + //System.out.println("VIEW " + sym + ":" + symtype + " " + qual);//DEBUG viewCache = v :: viewCache;//.filter(isUnShadowed); } } @@ -94,6 +95,7 @@ class Context { val e = scope.lookupEntry(Names.view); if (e.owner == scope && e.sym.kind == VAL) addView(e.sym, e.sym.getType(), Tree.Empty); + var imp = imports; while (imp != outer.imports) { val sym = imp.importedSymbol(Names.view); diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala index 1d4484d85d..6825aae1e6 100644 --- a/sources/scala/tools/scalac/typechecker/Infer.scala +++ b/sources/scala/tools/scalac/typechecker/Infer.scala @@ -304,12 +304,15 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal var i = alttypes.length - 1; var vs: List[View] = List(); while (i >= 0) { - vs = View(alts(i), alttypes(i), qual, Context.NONE) :: vs; + if (alttypes(i).resultType() != Type.ErrorType) + vs = View(alts(i), alttypes(i), qual, Context.NONE) :: vs; i = i - 1 } vs case viewtype => - List(View(viewsym, viewtype, qual, Context.NONE)) + if (viewtype.resultType() != Type.ErrorType) + List(View(viewsym, viewtype, qual, Context.NONE)) + else List() } } else List() } else List() @@ -648,7 +651,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal /** Generate an array of fresh type variables corresponding to parameters * `tparams' */ - private def freshVars(tparams: Array[Symbol]): Array[Type] = { + def freshVars(tparams: Array[Symbol]): Array[Type] = { val tvars: Array[Type] = new Array[Type](tparams.length); { var i = 0; while (i < tvars.length) { tvars(i) = new Type$TypeVar(tparams(i).getType(), new Type$Constraint()); @@ -1119,24 +1122,30 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal isCompatible(restpe, pt, regularValue) && (fieldName == Names.EMPTY || restpe.lookup(fieldName).kind != NONE) case Type$PolyType(tparams, Type$MethodType(params, restpe)) => - try { - val targs: Array[Type] = methTypeArgsSkipViews( - tparams, params, argtypes, restpe, pt, false, regularValue); - if (targs != null) { - val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams, restpe); - val restpe1 = skipViewParams(tparams, restpe); - isWithinBounds(tparams, targs) && - exprTypeArgs(uninstantiated, - restpe1.subst(tparams, targs), pt, - regularValue) != null && - (fieldName == Names.EMPTY || - restpe1.subst(tparams, targs).lookup(fieldName).kind != NONE) - } else { - false + var i = 0; + while (i < argtypes.length && !argtypes(i).containsSome(tparams)) + i = i + 1; + if (i < argtypes.length) + isApplicable(freshInstance(ftpe), argtypes, pt, fieldName, regularValue); + else + try { + val targs: Array[Type] = methTypeArgsSkipViews( + tparams, params, argtypes, restpe, pt, false, regularValue); + if (targs != null) { + val uninstantiated: Array[Symbol] = normalizeArgs(targs, tparams, restpe); + val restpe1 = skipViewParams(tparams, restpe); + isWithinBounds(tparams, targs) && + exprTypeArgs(uninstantiated, + restpe1.subst(tparams, targs), pt, + regularValue) != null && + (fieldName == Names.EMPTY || + restpe1.subst(tparams, targs).lookup(fieldName).kind != NONE) + } else { + false + } + } catch { + case ex: NoInstance => false } - } catch { - case ex: NoInstance => false - } case _ => if (!regularValue) { val ftpe1 = applyType(ftpe); @@ -1293,7 +1302,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal def bestView(tp: Type, pt: Type, name: Name): View = { var best: View = null; var viewMeths = getViews(tp); - //System.out.println("best view for " + tp + "/" + pt + " in " + viewMeths);//DEBUG + //System.out.println("best view for " + tp + "/" + pt + "/" + name + " in " + viewMeths);//DEBUG val argtypes = NewArray.Type(tp); while (!viewMeths.isEmpty) { if (isApplicable(viewMeths.head.symtype, argtypes, pt, name, false) && diff --git a/sources/scalac/symtab/Scope.java b/sources/scalac/symtab/Scope.java index e91789d107..cc76b5ab1d 100644 --- a/sources/scalac/symtab/Scope.java +++ b/sources/scalac/symtab/Scope.java @@ -69,7 +69,7 @@ public class Scope { /** the next entry in the hash bucket */ - private Entry tail; + public Entry tail; /** the next entry in this scope */ diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index 46c436a901..0e052b424f 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -1505,7 +1505,7 @@ public abstract class Symbol implements Modifiers, Kinds { assert this.name == that.name : Debug.show(this) + " <> " + Debug.show(that); assert this.owner == that.owner : Debug.show(this) + " != " + Debug.show(that); assert this.isConstructor() == that.isConstructor(); - int overflags = (this.flags & that.flags & (JAVA | ACCESSFLAGS | DEFERRED)) | + int overflags = (this.flags & that.flags & (JAVA | ACCESSFLAGS | DEFERRED | PARAM | SYNTHETIC)) | ((this.flags | that.flags) & ACCESSOR); Symbol overloaded = (this.isConstructor()) ? this.constructorClass().newConstructor(this.constructorClass().pos, overflags) |