summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2007-04-06 09:23:03 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2007-04-06 09:23:03 +0000
commite1c732db445d1ab0172bc25073ce865acc7d280b (patch)
tree4e1445535167194e09815e95563e4d2a9ef927f3 /src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
parent289fd3d7307ca117a419e71e3a20b0b811a0d33f (diff)
downloadscala-e1c732db445d1ab0172bc25073ce865acc7d280b.tar.gz
scala-e1c732db445d1ab0172bc25073ce865acc7d280b.tar.bz2
scala-e1c732db445d1ab0172bc25073ce865acc7d280b.zip
merged in tcpoly branch (at r10641)
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/RefChecks.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala521
1 files changed, 277 insertions, 244 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 00e015956c..39ff15d671 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -72,11 +72,13 @@ abstract class RefChecks extends InfoTransform {
* 1.2. O must not be final.
* 1.3. O is deferred, or M has `override' modifier.
* 1.4. If O is an immutable value, then so is M.
- * 1.5. Neither M nor O are a parameterized type alias
+ * // @M: LIFTED 1.5. Neither M nor O are a parameterized type alias
* 1.6. If O is a type alias, then M is an alias of O.
* 1.7. If O is an abstract type then
- * either M is an abstract type, and M's bounds are sharper than O's bounds.
- * or M is an unparameterized type alias or class which conforms to O's bounds.
+ * 1.7.1 either M is an abstract type, and M's bounds are sharper than O's bounds.
+ * or M is a type alias or class which conforms to O's bounds.
+ * 1.7.2 higher-order type arguments must respect bounds on higher-order type parameters -- @M
+ * (explicit bounds and those implied by variance annotations) -- @see checkKindBounds
* 1.8. If O and M are values, then
* 1.8.1 M's type is a subtype of O's type, or
* 1.8.2 M is of type []S, O is of type ()T and S <: T, or
@@ -100,7 +102,7 @@ abstract class RefChecks extends InfoTransform {
else "")))
}
- def overridesType(tp1: Type, tp2: Type): boolean = (tp1, tp2) match {
+ def overridesType(tp1: Type, tp2: Type): boolean = (tp1.normalize, tp2.normalize) match {
case (MethodType(List(), rtp1), PolyType(List(), rtp2)) =>
rtp1 <:< rtp2
case (PolyType(List(), rtp1), MethodType(List(), rtp2)) =>
@@ -115,52 +117,52 @@ abstract class RefChecks extends InfoTransform {
* <code>member</code> are met.
*/
def checkOverride(clazz: Symbol, member: Symbol, other: Symbol): unit = {
- val pos = if (member.owner == clazz) member.pos else clazz.pos
+ val pos = if (member.owner == clazz) member.pos else clazz.pos
- def overrideError(msg: String): unit =
- if (other.tpe != ErrorType && member.tpe != ErrorType)
- unit.error(pos, "error overriding " + infoString(other) +
- ";\n " + infoString(member) + " " + msg);
+ def overrideError(msg: String): unit =
+ if (other.tpe != ErrorType && member.tpe != ErrorType)
+ unit.error(pos, "error overriding " + infoString(other) +
+ ";\n " + infoString(member) + " " + msg);
- def overrideTypeError(): unit = {
- if (other.tpe != ErrorType && member.tpe != ErrorType) {
- overrideError("has incompatible type "+analyzer.underlying(member).tpe);
- explainTypes(member.tpe, other.tpe);
- }
- }
+ def overrideTypeError(): unit = {
+ if (other.tpe != ErrorType && member.tpe != ErrorType) {
+ overrideError("has incompatible type "+analyzer.underlying(member).tpe.normalize);
+ explainTypes(member.tpe, other.tpe);
+ }
+ }
def overrideAccessError(): unit = {
val pwString = if (other.privateWithin == NoSymbol) ""
else other.privateWithin.name.toString
val otherAccess = flagsToString(other getFlag (PRIVATE | PROTECTED), pwString)
- overrideError("has weaker access privileges; it should be "+
+ overrideError("has weaker access privileges; it should be "+
(if (otherAccess == "") "public" else "at least "+otherAccess))
}
- //Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
-
- // return if we already checked this combination elsewhere
- if (member.owner != clazz) {
- if ((member.owner isSubClass other.owner) &&
- ((member hasFlag DEFERRED) || !(other hasFlag DEFERRED))) {
- //Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG
- return;
- }
- if (clazz.info.parents exists (parent =>
- (parent.symbol isSubClass other.owner) && (parent.symbol isSubClass member.owner) &&
- ((member hasFlag DEFERRED) || !(other hasFlag DEFERRED)))) {
- //Console.println(infoString(member) + " shadows2 " + infoString(other) + " in " + clazz);//DEBUG
- return;
- }
- if (clazz.info.parents forall (parent =>
- (parent.symbol isSubClass other.owner) == (parent.symbol isSubClass member.owner))) {
- //Console.println(infoString(member) + " shadows " + infoString(other) + " in " + clazz);//DEBUG
- return;
- }
- }
-
- if (member hasFlag PRIVATE) { // (1.1)
- overrideError("has weaker access privileges; it should not be private")
+ //Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
+
+ // return if we already checked this combination elsewhere
+ if (member.owner != clazz) {
+ if ((member.owner isSubClass other.owner) &&
+ ((member hasFlag DEFERRED) || !(other hasFlag DEFERRED))) {
+ //Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG
+ return;
+ }
+ if (clazz.info.parents exists (parent =>
+ (parent.symbol isSubClass other.owner) && (parent.symbol isSubClass member.owner) &&
+ ((member hasFlag DEFERRED) || !(other hasFlag DEFERRED)))) {
+ //Console.println(infoString(member) + " shadows2 " + infoString(other) + " in " + clazz);//DEBUG
+ return;
+ }
+ if (clazz.info.parents forall (parent =>
+ (parent.symbol isSubClass other.owner) == (parent.symbol isSubClass member.owner))) {
+ //Console.println(infoString(member) + " shadows " + infoString(other) + " in " + clazz);//DEBUG
+ return;
+ }
+ }
+
+ if (member hasFlag PRIVATE) { // (1.1)
+ overrideError("has weaker access privileges; it should not be private")
}
val mb = member.accessBoundary(member.owner)
val ob = other.accessBoundary(member.owner)
@@ -170,81 +172,106 @@ abstract class RefChecks extends InfoTransform {
(other hasFlag PROTECTED) && !(member hasFlag PROTECTED))) {
overrideAccessError()
} else if (other hasFlag FINAL) { // (1.2)
- overrideError("cannot override final member");
- } else if (!(other hasFlag DEFERRED) && !(member hasFlag (OVERRIDE | ABSOVERRIDE))) { // (1.3)
- overrideError("needs `override' modifier");
- } else if ((other hasFlag ABSOVERRIDE) && other.isIncompleteIn(clazz) && !(member hasFlag ABSOVERRIDE)) {
- overrideError("needs `abstract override' modifiers")
+ overrideError("cannot override final member");
+ } else if (!(other hasFlag DEFERRED) && !(member hasFlag (OVERRIDE | ABSOVERRIDE))) { // (1.3)
+ overrideError("needs `override' modifier");
+ } else if ((other hasFlag ABSOVERRIDE) && other.isIncompleteIn(clazz) && !(member hasFlag ABSOVERRIDE)) {
+ overrideError("needs `abstract override' modifiers")
} else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) &&
(other hasFlag ACCESSOR) && other.accessed.isVariable) {
overrideError("cannot override a mutable variable")
- } else if (other.isStable && !member.isStable) { // (1.4)
- overrideError("needs to be an immutable value")
+ } else if (other.isStable && !member.isStable) { // (1.4)
+ overrideError("needs to be an immutable value")
} else if (other.isStable && !(other hasFlag DEFERRED) && other.owner.isTrait && (member hasFlag OVERRIDE)) {
overrideError("cannot override a value or variable definition in a trait " +
"\n (this is an implementation restriction)")
- } else {
- if (other.isAliasType) {
- if (!member.typeParams.isEmpty) // (1.5)
- overrideError("may not be parameterized");
- if (!other.typeParams.isEmpty) // (1.5)
- overrideError("may not override parameterized type");
- if (!(self.memberType(member) =:= self.memberType(other))) // (1.6)
- overrideTypeError();
- } else if (other.isAbstractType) {
- if (!member.typeParams.isEmpty) // (1.7)
- overrideError("may not be parameterized");
- if (!(self.memberInfo(other).bounds containsType self.memberType(member))) { // (1.7) {
- overrideTypeError(); // todo: do an explaintypes with bounds here
+ } else {
+ if (other.isAliasType) {
+ //if (!member.typeParams.isEmpty) // (1.5) @MAT
+ // overrideError("may not be parameterized");
+ //if (!other.typeParams.isEmpty) // (1.5) @MAT
+ // overrideError("may not override parameterized type");
+ // @M: substSym
+ if (!(self.memberType(member).substSym(member.typeParams, other.typeParams) =:= self.memberType(other))) // (1.6)
+ overrideTypeError();
+ } else if (other.isAbstractType) {
+ //if (!member.typeParams.isEmpty) // (1.7) @MAT
+ // overrideError("may not be parameterized");
+ var memberTp = self.memberType(member)
+
+ if (!(self.memberInfo(other).bounds containsType memberTp)) { // (1.7.1) {
+ overrideTypeError(); // todo: do an explaintypes with bounds here
}
- } else if (other.isTerm) {
- if (!overridesType(self.memberInfo(member), self.memberInfo(other))) { // 8
- overrideTypeError();
+
+ // check overriding (abstract type --> abstract type or abstract type --> concrete type member (a type alias))
+ // making an abstract type member concrete is like passing a type argument
+ val kindErrors = typer.infer.checkKindBounds(List(other), List(memberTp)) // (1.7.2)
+
+ if(!kindErrors.isEmpty)
+ unit.error(member.pos,
+ "The kind of "+member.keyString+" "+member.varianceString + member.nameString+
+ " does not conform to the expected kind of " + other.defString + other.locationString + "." +
+ kindErrors.toList.mkString("\n", ", ", ""))
+
+ // check a type alias's RHS corresponds to its declaration
+ // this overlaps somewhat with validateVariance
+ if(member.isAliasType) {
+ val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.normalize))
+
+ if(!kindErrors.isEmpty)
+ unit.error(member.pos,
+ "The kind of the right-hand side "+memberTp.normalize+" of "+member.keyString+" "+
+ member.varianceString + member.nameString+ " does not conform to its expected kind."+
+ kindErrors.toList.mkString("\n", ", ", ""))
+ }
+ } else if (other.isTerm) {
+ if (!overridesType(self.memberInfo(member), self.memberInfo(other))) { // 8
+ overrideTypeError();
}
- }
- }
+ }
+ }
}
val opc = new overridingPairs.Cursor(clazz)
while (opc.hasNext) {
- //Console.println("overrides " + opc.overriding/* + ":" + opc.overriding.tpe*/ + opc.overriding.locationString + " " + opc.overridden/* + ":" + opc.overridden.tpe*/ + opc.overridden.locationString + opc.overridden.hasFlag(DEFERRED));//DEBUG
- if (!opc.overridden.isClass) checkOverride(clazz, opc.overriding, opc.overridden);
+ //Console.println("overrides " + opc.overriding/* + ":" + opc.overriding.tpe*/ + opc.overriding.locationString + " " + opc.overridden/* + ":" + opc.overridden.tpe*/ + opc.overridden.locationString + opc.overridden.hasFlag(DEFERRED));//DEBUG
+ if (!opc.overridden.isClass) checkOverride(clazz, opc.overriding, opc.overridden);
- opc.next
+ opc.next
}
// 2. Check that only abstract classes have deferred members
if (clazz.isClass && !clazz.isTrait) {
- def abstractClassError(mustBeMixin: boolean, msg: String): unit = {
- unit.error(clazz.pos,
- (if (clazz.isAnonymousClass || clazz.isModuleClass) "object creation impossible"
- else if (mustBeMixin) clazz.toString() + " needs to be a mixin"
- else clazz.toString() + " needs to be abstract") + ", since " + msg);
- clazz.setFlag(ABSTRACT)
- }
- for (val member <- clazz.tpe.nonPrivateMembers)
- if ((member hasFlag DEFERRED) && !(clazz hasFlag ABSTRACT)) {
- abstractClassError(
+ def abstractClassError(mustBeMixin: boolean, msg: String): unit = {
+ unit.error(clazz.pos,
+ (if (clazz.isAnonymousClass || clazz.isModuleClass) "object creation impossible"
+ else if (mustBeMixin) clazz.toString() + " needs to be a mixin"
+ else clazz.toString() + " needs to be abstract") + ", since " + msg);
+ clazz.setFlag(ABSTRACT)
+ }
+ for (val member <- clazz.tpe.nonPrivateMembers)
+ if ((member hasFlag DEFERRED) && !(clazz hasFlag ABSTRACT)) {
+ abstractClassError(
false, infoString(member) + " is not defined" + analyzer.varNotice(member))
- } else if ((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)) {
- val other = member.superSymbol(clazz);
- abstractClassError(true,
- infoString(member) + " is marked `abstract' and `override'" +
- (if (other != NoSymbol)
- " and overrides incomplete superclass member " + infoString(other)
- else ""))
- }
+ } else if ((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)) {
+ val other = member.superSymbol(clazz);
+ abstractClassError(true,
+ infoString(member) + " is marked `abstract' and `override'" +
+ (if (other != NoSymbol)
+ " and overrides incomplete superclass member " + infoString(other)
+ else ""))
+ }
}
// 3. Check that every defined member with an `override' modifier overrides some other member.
for (val member <- clazz.info.decls.toList)
- if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) &&
- (clazz.info.baseClasses.tail forall {
+ if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) &&
+ (clazz.info.baseClasses.tail forall {
bc => member.matchingSymbol(bc, clazz.thisType) == NoSymbol
})) {
// for (val bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG
- unit.error(member.pos, member.toString() + " overrides nothing");
- member resetFlag OVERRIDE
- }
+ unit.error(member.pos, member.toString() + " overrides nothing");
+ member resetFlag OVERRIDE
+ }
}
// Basetype Checking --------------------------------------------------------
@@ -270,37 +297,37 @@ abstract class RefChecks extends InfoTransform {
var seenCaseClass = if (clazz hasFlag CASE) clazz else NoSymbol
def validateTypes(tps: List[Type], includeSuper: boolean): unit = {
- if (!tps.isEmpty) {
- for (val tp <- tps.tail.reverse) validateType(tp, false);
- if (includeSuper) validateType(tps.head, true);
- }
+ if (!tps.isEmpty) {
+ for (val tp <- tps.tail.reverse) validateType(tp, false);
+ if (includeSuper) validateType(tps.head, true);
+ }
}
def validateType(tp: Type, includeSuper: boolean): unit = {
- val baseClass = tp.symbol
- if (baseClass.isClass) {
- val index = clazz.info.closurePos(baseClass)
- if (index >= 0) {
- if ((seenTypes(index) ne null) && !(seenTypes(index) <:< tp))
- unit.error(clazz.pos, "illegal inheritance;\n " + clazz +
- " inherits different type instances of " + baseClass +
- ":\n" + tp + " and " + seenTypes(index));
- seenTypes(index) = tp;
- // check that case classes do not inherit from case classes
- if (baseClass hasFlag CASE) {
- if (seenCaseClass != NoSymbol && seenCaseClass != baseClass)
- unit.error(clazz.pos, "implementation restriction: case " +
- seenCaseClass + " and case " + baseClass +
+ val baseClass = tp.symbol
+ if (baseClass.isClass) {
+ val index = clazz.info.closurePos(baseClass)
+ if (index >= 0) {
+ if ((seenTypes(index) ne null) && !(seenTypes(index) <:< tp))
+ unit.error(clazz.pos, "illegal inheritance;\n " + clazz +
+ " inherits different type instances of " + baseClass +
+ ":\n" + tp + " and " + seenTypes(index));
+ seenTypes(index) = tp;
+ // check that case classes do not inherit from case classes
+ if (baseClass hasFlag CASE) {
+ if (seenCaseClass != NoSymbol && seenCaseClass != baseClass)
+ unit.error(clazz.pos, "implementation restriction: case " +
+ seenCaseClass + " and case " + baseClass +
" cannot be combined in one object");
- seenCaseClass = baseClass
- }
- // check that inner classes do not inherit from Annotation
+ seenCaseClass = baseClass
+ }
+ // check that inner classes do not inherit from Annotation
if (baseClass == ClassfileAnnotationClass)
if (!clazz.owner.isPackageClass)
unit.error(clazz.pos, "inner classes cannot be classfile annotations")
- }
- validateTypes(tp.parents, includeSuper)
- }
+ }
+ validateTypes(tp.parents, includeSuper)
+ }
}
validateTypes(clazz.info.parents, true)
@@ -322,68 +349,70 @@ abstract class RefChecks extends InfoTransform {
private def validateVariance(base: Symbol, all: Type, variance: int): unit = {
def varianceString(variance: int): String =
- if (variance == 1) "covariant"
- else if (variance == -1) "contravariant"
- else "invariant";
+ if (variance == 1) "covariant"
+ else if (variance == -1) "contravariant"
+ else "invariant";
def relativeVariance(tvar: Symbol): int = {
- val clazz = tvar.owner
- var sym = base
- var state = CoVariance
- while (sym != clazz && state != AnyVariance) {
- //Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG
- if ((sym hasFlag PARAM) && !sym.owner.isConstructor) state = -state;
- else if (!sym.owner.isClass || sym.isPrivateLocal) state = AnyVariance;
- else if (sym.isAliasType) state = NoVariance;
- sym = sym.owner
- }
- state
+ val clazz = tvar.owner
+ var sym = base
+ var state = CoVariance
+ while (sym != clazz && state != AnyVariance) {
+ //Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG
+ if ((sym hasFlag PARAM) && !sym.owner.isConstructor) state = -state;
+ else if (!sym.owner.isClass || sym.isPrivateLocal) state = AnyVariance;
+ else if (sym.isAliasType) state = NoVariance;
+ sym = sym.owner
+ }
+ state
}
def validateVariance(tp: Type, variance: int): unit = tp match {
- case ErrorType => ;
- case WildcardType => ;
- case NoType => ;
- case NoPrefix => ;
- case ThisType(_) => ;
- case ConstantType(_) => ;
- case SingleType(pre, sym) =>
- validateVariance(pre, variance)
- case TypeRef(pre, sym, args) =>
- if (sym.variance != NoVariance) {
- val v = relativeVariance(sym);
- if (v != AnyVariance && sym.variance != v * variance) {
- //Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG
- unit.error(base.pos,
- varianceString(sym.variance) + " " + sym +
- " occurs in " + varianceString(v * variance) +
- " position in type " + all + " of " + base);
- }
- }
- validateVariance(pre, variance)
- validateVarianceArgs(args, variance, sym.typeParams)
- case ClassInfoType(parents, decls, symbol) =>
- validateVariances(parents, variance)
- case RefinedType(parents, decls) =>
- validateVariances(parents, variance)
- case TypeBounds(lo, hi) =>
- validateVariance(lo, -variance)
- validateVariance(hi, variance)
- case MethodType(formals, result) =>
- validateVariance(result, variance)
- case PolyType(tparams, result) =>
- validateVariance(result, variance)
+ case ErrorType => ;
+ case WildcardType => ;
+ case NoType => ;
+ case NoPrefix => ;
+ case ThisType(_) => ;
+ case ConstantType(_) => ;
+ case SingleType(pre, sym) =>
+ validateVariance(pre, variance)
+ case TypeRef(pre, sym, args) =>
+ if (sym.variance != NoVariance) {
+ val v = relativeVariance(sym);
+ if (v != AnyVariance && sym.variance != v * variance) {
+ //Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG
+ unit.error(base.pos,
+ varianceString(sym.variance) + " " + sym +
+ " occurs in " + varianceString(v * variance) +
+ " position in type " + all + " of " + base);
+ }
+ }
+ validateVariance(pre, variance)
+ validateVarianceArgs(args, variance, sym.typeParams) //@M for higher-kinded typeref, args.isEmpty
+ // However, these args respect variances by construction anyway
+ // -- the interesting case is in type application, see checkKindBounds in Infer
+ case ClassInfoType(parents, decls, symbol) =>
+ validateVariances(parents, variance)
+ case RefinedType(parents, decls) =>
+ validateVariances(parents, variance)
+ case TypeBounds(lo, hi) =>
+ validateVariance(lo, -variance)
+ validateVariance(hi, variance)
+ case MethodType(formals, result) =>
+ validateVariance(result, variance)
+ case PolyType(tparams, result) =>
+ validateVariance(result, variance)
case AnnotatedType(attribs, tp) =>
validateVariance(tp, variance)
}
def validateVariances(tps: List[Type], variance: int): unit =
- tps foreach (tp => validateVariance(tp, variance))
+ tps foreach (tp => validateVariance(tp, variance))
def validateVarianceArgs(tps: List[Type], variance: int, tparams: List[Symbol]): unit =
- (tps zip tparams) foreach {
- case (tp, tparam) => validateVariance(tp, variance * tparam.variance)
- }
+ (tps zip tparams) foreach {
+ case (tp, tparam) => validateVariance(tp, variance * tparam.variance)
+ }
validateVariance(all, variance)
}
@@ -409,35 +438,38 @@ abstract class RefChecks extends InfoTransform {
private def enterSyms(stats: List[Tree]): unit = {
var index = -1
for (val stat <- stats) {
- index = index + 1;
- stat match {
+ index = index + 1;
+ stat match {
case ClassDef(_, _, _, _, _) | DefDef(_, _, _, _, _, _) | ModuleDef(_, _, _) | ValDef(_, _, _, _) =>
assert(stat.symbol != NoSymbol, stat);//debug
if (stat.symbol.isLocal) {
- currentLevel.scope.enter(newScopeEntry(stat.symbol, currentLevel.scope));
- symIndex(stat.symbol) = index;
+ currentLevel.scope.enter(newScopeEntry(stat.symbol, currentLevel.scope));
+ symIndex(stat.symbol) = index;
}
case _ =>
- }
+ }
}
}
private def enterReference(pos: int, sym: Symbol): unit =
if (sym.isLocal) {
- val e = currentLevel.scope.lookupEntry(sym.name)
- if ((e ne null) && sym == e.sym) {
+ val e = currentLevel.scope.lookupEntry(sym.name)
+ if ((e ne null) && sym == e.sym) {
var l = currentLevel
while (l.scope != e.owner) l = l.outer;
- val symindex = symIndex(sym)
- if (l.maxindex < symindex) {
- l.refpos = pos
- l.refsym = sym
- l.maxindex = symindex
- }
- }
+ val symindex = symIndex(sym)
+ if (l.maxindex < symindex) {
+ l.refpos = pos
+ l.refsym = sym
+ l.maxindex = symindex
+ }
+ }
}
// Comparison checking -------------------------------------------------------
+ object normalizeAll extends TypeMap {
+ def apply(tp: Type) = mapOver(tp).normalize
+ }
def checkSensible(pos: int, fn: Tree, args: List[Tree]) = fn match {
case Select(qual, name) if (args.length == 1) =>
@@ -461,8 +493,8 @@ abstract class RefChecks extends InfoTransform {
unit.warning(pos, "comparing "+what+" using `"+name.decode+"' will always yield "+
(alwaysEqual == (name == nme.EQ || name == nme.LE || name == nme.GE)))
def nonSensible(pre: String, alwaysEqual: boolean) =
- nonSensibleWarning(pre+"values of types "+qual.tpe.widen+" and "+args.head.tpe.widen,
- alwaysEqual)
+ nonSensibleWarning(pre+"values of types "+normalizeAll(qual.tpe.widen)+" and "+normalizeAll(args.head.tpe.widen),
+ alwaysEqual) // @MAT normalize for consistency in error message, otherwise part is normalized due to use of `symbol', but the rest isn't
def hasObjectEquals = receiver.info.member(nme.equals_) == Object_equals
if (formal == UnitClass && actual == UnitClass)
nonSensible("", true)
@@ -511,13 +543,13 @@ abstract class RefChecks extends InfoTransform {
def transformStat(tree: Tree, index: int): List[Tree] = tree match {
case ModuleDef(mods, name, impl) =>
- val sym = tree.symbol
- val cdef = ClassDef(mods | MODULE, name, List(), emptyValDef, impl)
- .setPos(tree.pos)
+ val sym = tree.symbol
+ val cdef = ClassDef(mods | MODULE, name, List(), emptyValDef, impl)
+ .setPos(tree.pos)
.setSymbol(sym.moduleClass)
.setType(NoType);
- if (sym.isStatic) List(transform(cdef))
- else {
+ if (sym.isStatic) List(transform(cdef))
+ else {
val vdef =
localTyper.typed {
atPos(tree.pos) {
@@ -526,8 +558,8 @@ abstract class RefChecks extends InfoTransform {
}
val ddef =
- atPhase(phase.next) {
- localTyper.typed {
+ atPhase(phase.next) {
+ localTyper.typed {
if (sym.owner.isTrait) gen.mkModuleAccessDcl(sym)
else gen.mkModuleAccessDef(sym, vdef.symbol)
}
@@ -535,7 +567,7 @@ abstract class RefChecks extends InfoTransform {
if (sym.owner.isTrait) transformTrees(List(cdef, ddef))
else transformTrees(List(cdef, vdef, ddef))
- }
+ }
case ClassDef(_, _, _, _, _) if isConcreteLocalCaseFactory(tree.symbol) =>
val clazz = tree.symbol
@@ -564,27 +596,27 @@ abstract class RefChecks extends InfoTransform {
}
case ValDef(_, _, _, _) =>
- val tree1 = transform(tree); // important to do before forward reference check
- if (tree.symbol.isLocal && index <= currentLevel.maxindex) {
- if (settings.debug.value) Console.println(currentLevel.refsym);
- unit.error(currentLevel.refpos, "forward reference extends over definition of " + tree.symbol);
- }
- List(tree1)
+ val tree1 = transform(tree); // important to do before forward reference check
+ if (tree.symbol.isLocal && index <= currentLevel.maxindex) {
+ if (settings.debug.value) Console.println(currentLevel.refsym);
+ unit.error(currentLevel.refpos, "forward reference extends over definition of " + tree.symbol);
+ }
+ List(tree1)
case Import(_, _) =>
- List()
+ List()
case _ =>
- List(transform(tree))
+ List(transform(tree))
}
override def transform(tree: Tree): Tree = try {
/* Check whether argument types conform to bounds of type parameters */
def checkBounds(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type]): unit = try {
- typer.infer.checkBounds(tree.pos, pre, owner, tparams, argtps, "");
+ typer.infer.checkBounds(tree.pos, pre, owner, tparams, argtps, "");
} catch {
- case ex: TypeError => unit.error(tree.pos, ex.getMessage());
+ case ex: TypeError => unit.error(tree.pos, ex.getMessage());
}
def isIrrefutable(pat: Tree, seltpe: Type): boolean = {
@@ -631,40 +663,41 @@ abstract class RefChecks extends InfoTransform {
val sym = tree.symbol
var result = tree
tree match {
- case ClassDef(mods, name, tparams, _, impl) =>
- validateVariance(sym, sym.info, CoVariance)
- validateVariance(sym, sym.typeOfThis, CoVariance)
+ case ClassDef(mods, name, tparams, _, impl) =>
+ validateVariance(sym, sym.info, CoVariance)
+ validateVariance(sym, sym.typeOfThis, CoVariance)
- case DefDef(_, _, _, _, _, _) =>
- validateVariance(sym, sym.tpe, CoVariance)
+ case DefDef(_, _, _, _, _, _) =>
+ validateVariance(sym, sym.tpe, CoVariance) //@M TODO: might be affected by change in tpe --> can't use tree.tpe though
checkDeprecatedOvers()
- case ValDef(_, _, _, _) =>
- validateVariance(sym, sym.tpe, if (sym.isVariable) NoVariance else CoVariance)
+ case ValDef(_, _, _, _) =>
+ validateVariance(sym, sym.tpe, if (sym.isVariable) NoVariance else CoVariance) //@M TODO: might be affected by change in tpe --> can't use tree.tpe though
checkDeprecatedOvers()
- case AbsTypeDef(_, _, _, _) =>
- validateVariance(sym, sym.info, CoVariance)
+ case AbsTypeDef(_, _, _, _, _) =>
+ validateVariance(sym, sym.info, CoVariance)
- case AliasTypeDef(_, _, _, _) =>
- validateVariance(sym, sym.info, CoVariance)
+ case AliasTypeDef(_, _, _, _) =>
+ validateVariance(sym, sym.info, CoVariance)
- case Template(_, _) =>
- localTyper = localTyper.atOwner(tree, currentOwner)
- validateBaseTypes(currentOwner)
- checkAllOverrides(currentOwner)
+ case Template(_, _) =>
+ localTyper = localTyper.atOwner(tree, currentOwner)
+ validateBaseTypes(currentOwner)
+ checkAllOverrides(currentOwner)
- case TypeTree() =>
- new TypeTraverser {
- def traverse(tp: Type): TypeTraverser = tp match {
- case TypeRef(pre, sym, args) => checkBounds(pre, sym.owner, sym.typeParams, args); this
- case _ => this
- }
- } traverse tree.tpe
+ case TypeTree() =>
+ new TypeTraverser {
+ def traverse(tp: Type): TypeTraverser = tp match {
+ case tr@TypeRef(pre, sym, _) if tr.isHigherKinded => this //@M a higher-kinded typeref doesn't have any args to check
+ case TypeRef(pre, sym, args) => checkBounds(pre, sym.owner, sym.typeParams, args); this
+ case _ => this
+ }
+ } traverse tree.tpe
- case TypeApply(fn, args) =>
- checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (.tpe))
- if (sym.isSourceMethod && sym.hasFlag(CASE)) result = toConstructor(tree.pos, tree.tpe)
+ case TypeApply(fn, args) =>
+ checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (.tpe))
+ if (sym.isSourceMethod && sym.hasFlag(CASE)) result = toConstructor(tree.pos, tree.tpe)
case Apply(
Select(qual, nme.filter),
@@ -686,37 +719,37 @@ abstract class RefChecks extends InfoTransform {
case _ =>
}
- case New(tpt) =>
- enterReference(tree.pos, tpt.tpe.symbol)
-
- case Ident(name) =>
- if (sym.isSourceMethod && sym.hasFlag(CASE))
- result = toConstructor(tree.pos, tree.tpe)
- else if (name != nme.WILDCARD && name != nme.WILDCARD_STAR.toTypeName) {
- assert(sym != NoSymbol, tree)//debug
- enterReference(tree.pos, sym)
- }
-
- case Select(qual, name) =>
- if (sym.isSourceMethod && sym.hasFlag(CASE))
- result = toConstructor(tree.pos, tree.tpe)
- else qual match {
- case Super(qualifier, mix) =>
+ case New(tpt) =>
+ enterReference(tree.pos, tpt.tpe.symbol)
+
+ case Ident(name) =>
+ if (sym.isSourceMethod && sym.hasFlag(CASE))
+ result = toConstructor(tree.pos, tree.tpe)
+ else if (name != nme.WILDCARD && name != nme.WILDCARD_STAR.toTypeName) {
+ assert(sym != NoSymbol, tree)//debug
+ enterReference(tree.pos, sym)
+ }
+
+ case Select(qual, name) =>
+ if (sym.isSourceMethod && sym.hasFlag(CASE))
+ result = toConstructor(tree.pos, tree.tpe)
+ else qual match {
+ case Super(qualifier, mix) =>
val base = qual.symbol;
//Console.println("super: " + tree + " in " + base);//DEBUG
assert(!(base.isTrait && sym.isTerm && mix == nme.EMPTY.toTypeName)) // term should have been eliminated by super accessors
case _ =>
}
- case _ =>
+ case _ =>
}
result = super.transform(result)
localTyper = savedLocalTyper
result
} catch {
case ex: TypeError =>
- if (settings.debug.value) ex.printStackTrace();
- unit.error(tree.pos, ex.getMessage())
- tree
+ if (settings.debug.value) ex.printStackTrace();
+ unit.error(tree.pos, ex.getMessage())
+ tree
}
}
}