summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala12
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala58
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala24
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Variances.scala2
-rw-r--r--test/files/neg/bug783.check4
-rw-r--r--test/files/neg/bug783.scala29
-rw-r--r--test/files/pos/bug397.scala16
7 files changed, 132 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index e9fdb5c91d..1292be6794 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -30,9 +30,15 @@ abstract class TreeBuilder {
def caseClassConstr: Tree =
scalaDot(nme.CaseClass.toTypeName)
- def productConstr(typeArgs: List[Tree]) =
- AppliedTypeTree(scalaDot(newTypeName("Product"+typeArgs.length)), typeArgs)
-
+ def productConstr(typeArgs: List[Tree]) = {
+ def repeatedToSeq(tpt: Tree) = tpt match {
+ case AppliedTypeTree(Select(qual, name), args) if (name == nme.REPEATED_PARAM_CLASS_NAME.toTypeName) =>
+ AppliedTypeTree(Select(qual, nme.Seq.toTypeName), args)
+ case _ =>
+ tpt
+ }
+ AppliedTypeTree(scalaDot(newTypeName("Product"+typeArgs.length)), typeArgs map repeatedToSeq)
+ }
/** Convert all occurrences of (lower-case) variables in a pattern as follows:
* x becomes x @ _
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 9791caeaa4..ef8796b3f8 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -225,7 +225,7 @@ trait Types requires SymbolTable {
}
*/
case _ =>
- //System.out.println("" + this.widen + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain);//debug
+ //System.out.println("" + this.widen + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain);//DEBUG
sym.tpe.asSeenFrom(this, sym.owner)
}
}
@@ -1131,13 +1131,16 @@ trait Types requires SymbolTable {
def TypeBounds(lo: Type, hi: Type): TypeBounds =
unique(new TypeBounds(lo, hi) with UniqueType)
+ def refinementOfClass(clazz: Symbol, parents: List[Type], decls: Scope) =
+ new RefinedType(parents, decls) { override def symbol: Symbol = clazz }
+
/** the canonical creator for a refined type with a given scope */
def refinedType(parents: List[Type], owner: Symbol, decls: Scope): Type = {
if (phase.erasedTypes)
if (parents.isEmpty) ObjectClass.tpe else parents.head
else {
val clazz = owner.newRefinementClass(NoPos)
- val result = new RefinedType(parents, decls) { override def symbol: Symbol = clazz }
+ val result = refinementOfClass(clazz, parents, decls)
clazz.setInfo(result)
result
}
@@ -1301,6 +1304,8 @@ trait Types requires SymbolTable {
abstract class TypeMap extends Function1[Type, Type] {
// deferred inherited: def apply(tp: Type): Type
+ var variance = 1
+
/** Map this function over given type */
def mapOver(tp: Type): Type = tp match {
case ErrorType => tp
@@ -1312,7 +1317,9 @@ trait Types requires SymbolTable {
case SingleType(pre, sym) =>
if (sym.isPackageClass) tp // short path
else {
+ val v = variance; variance = 0
val pre1 = this(pre)
+ variance = v
if (pre1 eq pre) tp
else singleType(pre1, sym)
}
@@ -1323,11 +1330,19 @@ trait Types requires SymbolTable {
else SuperType(thistp1, supertp1)
case TypeRef(pre, sym, args) =>
val pre1 = this(pre)
- val args1 = List.mapConserve(args)(this)
+ //val args1 = List.mapConserve(args)(this)
+ val args1 = if (args.isEmpty) args
+ else {
+ val tparams = sym.typeParams
+ if (tparams.isEmpty) args
+ else mapOverArgs(args, tparams)
+ }
if ((pre1 eq pre) && (args1 eq args)) tp
else typeRef(pre1, sym, args1)
case TypeBounds(lo, hi) =>
+ variance = -variance
val lo1 = this(lo)
+ variance = -variance
val hi1 = this(hi)
if ((lo1 eq lo) && (hi1 eq hi)) tp
else TypeBounds(lo1, hi1)
@@ -1338,6 +1353,8 @@ trait Types requires SymbolTable {
case rtp @ RefinedType(parents, decls) =>
val parents1 = List.mapConserve(parents)(this)
val decls1 = mapOver(decls)
+ //if ((parents1 eq parents) && (decls1 eq decls)) tp
+ //else refinementOfClass(tp.symbol, parents1, decls1)
copyRefinedType(rtp, parents1, decls1)
/*
case ClassInfoType(parents, decls, clazz) =>
@@ -1347,14 +1364,18 @@ trait Types requires SymbolTable {
else cloneDecls(ClassInfoType(parents1, new Scope(), clazz), tp, decls1)
*/
case MethodType(paramtypes, result) =>
+ variance = -variance
val paramtypes1 = List.mapConserve(paramtypes)(this)
+ variance = -variance
val result1 = this(result)
if ((paramtypes1 eq paramtypes) && (result1 eq result)) tp
else if (tp.isInstanceOf[ImplicitMethodType]) ImplicitMethodType(paramtypes1, result1)
else if (tp.isInstanceOf[JavaMethodType]) JavaMethodType(paramtypes1, result1)
else MethodType(paramtypes1, result1)
case PolyType(tparams, result) =>
+ variance = -variance
val tparams1 = mapOver(tparams)
+ variance = -variance
var result1 = this(result)
if ((tparams1 eq tparams) && (result1 eq result)) tp
else PolyType(tparams1, result1.substSym(tparams, tparams1))
@@ -1375,6 +1396,16 @@ trait Types requires SymbolTable {
// throw new Error("mapOver inapplicable for " + tp);
}
+ def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
+ map2Conserve(args, tparams) { (arg, tparam) =>
+ val v = variance
+ if (tparam.isContravariant) variance = -variance
+ else if (!tparam.isCovariant) variance = 0
+ val arg1 = this(arg)
+ variance = v
+ arg1
+ }
+
/** Map this function over given scope */
private def mapOver(scope: Scope): Scope = {
val elems = scope.toList
@@ -1404,6 +1435,11 @@ trait Types requires SymbolTable {
/** A map to compute the asSeenFrom method */
class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap {
+ def base(pre: Type, clazz: Symbol) = {
+ val b = pre.baseType(clazz)
+ if (b == NoType && clazz.isRefinementClass) pre
+ else b
+ }
def apply(tp: Type): Type =
if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
else tp match {
@@ -1416,7 +1452,7 @@ trait Types requires SymbolTable {
case SuperType(thistp, _) => thistp
case _ => pre
}
- else toPrefix(pre.baseType(clazz).prefix, clazz.owner);
+ else toPrefix(base(pre, clazz).prefix, clazz.owner);
toPrefix(pre, clazz)
case TypeRef(prefix, sym, args) if (sym.isTypeParameter) =>
def toInstance(pre: Type, clazz: Symbol): Type =
@@ -1444,7 +1480,7 @@ trait Types requires SymbolTable {
case _ =>
throwError
}
- else toInstance(pre.baseType(clazz).prefix, clazz.owner)
+ else toInstance(base(pre, clazz).prefix, clazz.owner)
}
toInstance(pre, clazz)
case _ =>
@@ -1950,6 +1986,18 @@ trait Types requires SymbolTable {
cl1
}
+ /** like map2, but returns list `xs' itself - instead of a copy - if function
+ * <code>f</code> maps all elements to themselves.
+ */
+ def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] =
+ if (xs.isEmpty) xs
+ else {
+ val x1 = f(xs.head, ys.head)
+ val xs1 = map2Conserve(xs.tail, ys.tail)(f)
+ if ((x1 eq xs.head) && (xs1 eq xs.tail)) xs
+ else x1 :: xs1
+ }
+
// Lubs and Glbs ---------------------------------------------------------
private val recLimit = 10
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ff188d4c23..f8461e52ef 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -289,12 +289,28 @@ trait Typers requires Analyzer {
assert(tree.tpe != null, tree)//debug
apply(tree.tpe)
if (badSymbol == NoSymbol) tree
+ else if (badSymbol.isErroneous) setError(tree)
else {
- if (!badSymbol.isErroneous)
+ val tp1 = heal(tree.tpe)
+ if (tp1 eq tree.tpe) {
error(tree.pos,
- (if (badSymbol.hasFlag(PRIVATE)) "private " else "") + badSymbol +
- " escapes its defining scope as part of type "+tree.tpe)
- setError(tree)
+ (if (badSymbol hasFlag PRIVATE) "private " else "") + badSymbol +
+ " escapes its defining scope as part of type "+tree.tpe)
+ setError(tree)
+ } else
+ check(owner, scope, tree setType tp1)
+ }
+ }
+
+ object heal extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case SingleType(pre, sym) =>
+ if ((variance == 1) && (pre contains badSymbol)) {
+ val tp1 = tp.widen
+ if (tp1 contains badSymbol) tp else tp1
+ } else tp
+ case _ =>
+ mapOver(tp)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
index 2bdb019374..30b89200bb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
@@ -67,7 +67,7 @@ trait Variances {
case ErrorType | WildcardType | NoType | NoPrefix | ThisType(_) | ConstantType(_) =>
VARIANCES
case SingleType(pre, sym) =>
- cut(varianceInType(pre)(tparam))
+ varianceInType(pre)(tparam)
case TypeRef(pre, sym, args) =>
if (sym == tparam) COVARIANT
else varianceInType(pre)(tparam) & varianceInArgs(args, sym.typeParams)(tparam)
diff --git a/test/files/neg/bug783.check b/test/files/neg/bug783.check
new file mode 100644
index 0000000000..9594db14e7
--- /dev/null
+++ b/test/files/neg/bug783.check
@@ -0,0 +1,4 @@
+bug783.scala:12 error: stable identifier required, but Contexts.this.globalInit0 found.
+ globalInit0.Template(10, 20);
+ ^
+one error found
diff --git a/test/files/neg/bug783.scala b/test/files/neg/bug783.scala
new file mode 100644
index 0000000000..0180d3d634
--- /dev/null
+++ b/test/files/neg/bug783.scala
@@ -0,0 +1,29 @@
+package test;
+
+object Main extends Application {
+ class Global {
+ case class Template(x : Int, y : Int) {
+ Console.println("outer: " + Global.this);
+ }
+ }
+ trait Contexts requires Analyzer {
+ val xxx : global.Template = {
+ assert(globalInit0 != null);
+ globalInit0.Template(10, 20);
+ }
+ }
+ abstract class Analyzer extends Contexts {
+ type Global <: Main.Global;
+ final val global : Global = globalInit;
+ def globalInit : Global;
+ final def globalInit0 = globalInit.asInstanceOf[global.type];
+ }
+
+ object global0 extends Global {
+ object analyzer extends Analyzer {
+ type Global = global0.type;
+ override def globalInit = global0;
+ }
+ }
+ Console.println(global0.analyzer.xxx);
+}
diff --git a/test/files/pos/bug397.scala b/test/files/pos/bug397.scala
new file mode 100644
index 0000000000..87be2987ab
--- /dev/null
+++ b/test/files/pos/bug397.scala
@@ -0,0 +1,16 @@
+abstract class Root {
+
+ abstract class Edge {
+ type V;
+ def source: V;
+ }
+
+ abstract class Graph {
+ type W;
+ type E <: Edge{type V = W};
+ def edge: E;
+ }
+
+ val g: Graph{type W = Int};
+ val x: Int = g.edge.source;
+}