summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/reference/ReferencePart.tex9
-rw-r--r--sources/scala/tools/scalac/typechecker/Analyzer.scala65
-rw-r--r--sources/scala/tools/scalac/typechecker/Context.scala6
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala51
-rw-r--r--sources/scalac/symtab/Scope.java2
-rw-r--r--sources/scalac/symtab/Symbol.java2
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)