diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 103 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 4 | ||||
-rw-r--r-- | test/files/neg/abstract.check | 18 | ||||
-rw-r--r-- | test/files/neg/abstract.scala | 10 |
4 files changed, 87 insertions, 48 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 1441a1e7b5..379a157b44 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -45,7 +45,10 @@ trait Types requires SymbolTable { var subtypeMillis = 0l private var explainSwitch = false - private var checkMalformedSwitch = true + + /** A varaince value that expresses that no type approximations are allowed + */ + private final val NOAPPROX = -2 val emptyTypeArray = new Array[Type](0) @@ -417,8 +420,6 @@ trait Types requires SymbolTable { var excluded = excludedFlags | DEFERRED var self: Type = null var continue = true - var savedCheckMalformedSwitch = checkMalformedSwitch - checkMalformedSwitch = false while (continue) { continue = false var bcs = baseClasses @@ -433,7 +434,6 @@ trait Types requires SymbolTable { val excl = sym.getFlag(excluded) if (excl == 0) { if (name.isTypeName || stableOnly) { - checkMalformedSwitch = savedCheckMalformedSwitch if (util.Statistics.enabled) findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime return sym @@ -471,7 +471,6 @@ trait Types requires SymbolTable { } // while (!bcs.isEmpty) excluded = excludedFlags } // while (continue) - checkMalformedSwitch = savedCheckMalformedSwitch if (util.Statistics.enabled) findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime if (members == null) { @@ -547,7 +546,7 @@ trait Types requires SymbolTable { } case class BoundedWildcardType(override val bounds: TypeBounds) extends Type { - override def toString(): String = "?" + bounds + override def toString(): String = "_" + bounds } /** An object representing a non-existing type */ @@ -854,7 +853,7 @@ trait Types requires SymbolTable { * @param args ... */ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { - assert(!checkMalformedSwitch || !sym.isAbstractType || pre.isStable || pre.isError) + assert(!sym.isAbstractType || pre.isStable || pre.isError) assert(!pre.isInstanceOf[ClassInfoType], this) assert(!sym.isTypeParameterOrSkolem || pre == NoPrefix, this) @@ -1099,21 +1098,33 @@ trait Types requires SymbolTable { def ThisType(sym: Symbol): Type = if (phase.erasedTypes) sym.tpe else unique(new ThisType(sym) with UniqueType) + /** A creator of type approximations, depending on variance + */ + def typeApproximation(variance: int, lo: Type, hi: Type, pre: Type, sym: Symbol) = variance match { + case 0 => BoundedWildcardType(TypeBounds(lo, hi)) + case 1 => hi + case -1 => lo + case NOAPPROX => throw new MalformedType(pre, sym.name.toString) + } + /** The canonical creator for single-types */ - def singleType(pre: Type, sym: Symbol): Type = { + def singleType(pre: Type, sym: Symbol): Type = singleType(pre, sym, NOAPPROX) + + /** The creator for single-types or their approximations */ + def singleType(pre: Type, sym: Symbol, variance: int): Type = if (phase.erasedTypes) sym.tpe.resultType - else if (checkMalformedSwitch && !pre.isStable && !pre.isError) - throw new MalformedType(pre, sym.name.toString()) else if (sym.isRootPackage) ThisType(RootClass) else { var sym1 = rebind(pre, sym) val pre1 = removeSuper(pre, sym1) if (pre1 ne pre) sym1 = rebind(pre1, sym1) - unique(new SingleType(pre1, sym1) with UniqueType) + if (!pre1.isStable && !pre1.isError) + typeApproximation(variance, AllClass.tpe, pre.memberType(sym).resultType, pre, sym) + else + unique(new SingleType(pre1, sym1) with UniqueType) } - } /** The canonical creator for super-types */ def SuperType(thistp: Type, supertp: Type): Type = @@ -1156,10 +1167,11 @@ trait Types requires SymbolTable { * @param args ... * @return ... */ - def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = { + def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = typeRef(pre, sym, args, NOAPPROX) + + /** The creator for typerefs or their approximations */ + def typeRef(pre: Type, sym: Symbol, args: List[Type], variance: int): Type = { var sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym - if (checkMalformedSwitch && sym1.isAbstractType && !pre.isStable && !pre.isError) - throw new MalformedType(pre, sym.nameString) if (sym1.isAliasType && sym1.info.typeParams.length == args.length) { // note: we require that object is initialized, // that's why we use info.typeParams instead of typeParams. @@ -1173,7 +1185,13 @@ trait Types requires SymbolTable { val pre1 = removeSuper(pre, sym1) if (pre1 ne pre) { if (sym1.isAbstractType) sym1 = rebind(pre1, sym1) - typeRef(pre1, sym1, args) + typeRef(pre1, sym1, args, variance) + } else if (sym1.isAbstractType && !pre.isStable && !pre.isError) { + val lo = sym.info.bounds.lo + var hi = sym.info.bounds.hi + if (hi contains sym) hi = AnyClass.tpe // this is crude; we should try to refine this! + def transform(tp: Type): Type = tp.asSeenFrom(pre, sym.owner).subst(sym.typeParams, args) + typeApproximation(variance, transform(lo), transform(hi), pre, sym1) } else { rawTypeRef(pre, sym1, args) } @@ -1280,6 +1298,8 @@ trait Types requires SymbolTable { abstract class TypeMap extends Function1[Type, Type] { // deferred inherited: def apply(tp: Type): Type + var variance = 1 + private def cloneDecls(result: Type, tp: Type, decls: Scope): Type = { val syms1 = decls.toList for (val sym <- syms1) @@ -1302,9 +1322,11 @@ 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) + else singleType(pre1, sym, variance) } case SuperType(thistp, supertp) => val thistp1 = this(thistp) @@ -1315,13 +1337,15 @@ trait Types requires SymbolTable { val pre1 = this(pre) val args1 = List.mapConserve(args)(this) if ((pre1 eq pre) && (args1 eq args)) tp - else typeRef(pre1, sym, args1) + else typeRef(pre1, sym, args1, variance) 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) - case BoundedWildcardType(bounds) => + case BoundedWildcardType(bounds) => //todo: merge WildcardType and BoundedWildcardType? val bounds1 = this(bounds) if (bounds1 eq bounds) tp else BoundedWildcardType(bounds1.asInstanceOf[TypeBounds]) @@ -1338,14 +1362,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)) @@ -1366,6 +1394,19 @@ trait Types requires SymbolTable { // throw new Error("mapOver inapplicable for " + tp); } + def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = args match { + case List() => List() + case arg :: args0 => + val v = variance + if (tparams.head.isContravariant) variance = -variance + else if (!tparams.head.isCovariant) variance = 0 + val arg1 = this(arg) + variance = v + val args1 = mapOverArgs(args0, tparams.tail) + if ((arg1 eq arg) && (args1 eq args0)) args + else arg1 :: args1 + } + /** Map this function over given scope */ private def mapOver(scope: Scope): Scope = { val elems = scope.toList @@ -1476,8 +1517,8 @@ trait Types requires SymbolTable { class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends SubstMap(from, to) { protected def toType(fromtp: Type, sym: Symbol) = fromtp match { - case TypeRef(pre, _, args) => typeRef(pre, sym, args) - case SingleType(pre, _) => singleType(pre, sym) + case TypeRef(pre, _, args) => typeRef(pre, sym, args, variance) + case SingleType(pre, _) => singleType(pre, sym, variance) } override def apply(tp: Type): Type = { def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol = @@ -1486,9 +1527,9 @@ trait Types requires SymbolTable { else subst(sym, from.tail, to.tail) tp match { case TypeRef(pre, sym, args) if !(pre eq NoPrefix) => - mapOver(typeRef(pre, subst(sym, from, to), args)) + mapOver(typeRef(pre, subst(sym, from, to), args, variance)) case SingleType(pre, sym) if !(pre eq NoPrefix) => - mapOver(singleType(pre, subst(sym, from, to))) + mapOver(singleType(pre, subst(sym, from, to), variance)) case _ => super.apply(tp) } @@ -1617,7 +1658,7 @@ trait Types requires SymbolTable { val pre1 = this(pre) val sym1 = adaptToNewRun(pre1, sym) if ((pre1 eq pre) && (sym1 eq sym)) tp - else singleType(pre1, sym1) + else singleType(pre1, sym1, variance) } case TypeRef(pre, sym, args) => if (sym.isPackageClass) tp @@ -1626,7 +1667,7 @@ trait Types requires SymbolTable { val args1 = List.mapConserve(args)(this) val sym1 = adaptToNewRun(pre1, sym) if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) tp - else typeRef(pre1, sym1, args1) + else typeRef(pre1, sym1, args1, variance) } case PolyType(tparams, restp) => val restp1 = this(restp) @@ -2287,7 +2328,7 @@ trait Types requires SymbolTable { else NoType)); try { if (args contains NoType) None - else Some(typeRef(pre, sym, args)) + else Some(typeRef(pre, sym, args, variance)) } catch { case ex: MalformedType => None } @@ -2295,7 +2336,7 @@ trait Types requires SymbolTable { val pres = tps map (.prefix) val pre = if (variance == 1) lub(pres) else glb(pres) try { - Some(singleType(pre, sym)) + Some(singleType(pre, sym, variance)) } catch { case ex: MalformedType => None } @@ -2403,12 +2444,4 @@ trait Types requires SymbolTable { found <:< required explainSwitch = s } - - def withoutMalformedChecks[T](op: => T): T = { - val savedCheckMalformedSwitch = checkMalformedSwitch - checkMalformedSwitch = false - val result = op - checkMalformedSwitch = savedCheckMalformedSwitch - result - } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 98e48286fa..9c4b1d3647 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -297,8 +297,9 @@ 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) @@ -308,6 +309,7 @@ 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 diff --git a/test/files/neg/abstract.check b/test/files/neg/abstract.check index 87fb66f946..86fded0fce 100644 --- a/test/files/neg/abstract.check +++ b/test/files/neg/abstract.check @@ -1,9 +1,11 @@ -abstract.scala:5 error: method bar cannot be accessed in A.this.T - because its instance type ()A.this.T#T contains a malformed type: A.this.T#T - def foo1 = bar().bar(); - ^ -abstract.scala:7 error: method bar cannot be accessed in A - because its instance type ()A#T contains a malformed type: A#T - def foo3 = baz().bar(); - ^ +abstract.scala:6 error: type mismatch; + found : A + required: A.this.T + def foo2: T = bar().baz(); + ^ +abstract.scala:9 error: type mismatch; + found : A + required: A.this.T + def foo5: T = baz().baz(); + ^ two errors found diff --git a/test/files/neg/abstract.scala b/test/files/neg/abstract.scala index 41cfc81309..f8ecae16fa 100644 --- a/test/files/neg/abstract.scala +++ b/test/files/neg/abstract.scala @@ -2,8 +2,10 @@ trait A { type T <: A; def baz(): A; def bar(): T; - def foo1 = bar().bar(); - def foo2 = bar().baz(); - def foo3 = baz().bar(); - def foo4 = baz().baz(); + def foo1: A = bar().bar(); + def foo2: T = bar().baz(); + def foo3 = bar().baz(); + def foo4: A = baz().bar(); + def foo5: T = baz().baz(); + def foo6 = baz().baz(); } |