diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 93 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 28 | ||||
-rw-r--r-- | test/files/jvm/protectedacc.scala | 3 | ||||
-rw-r--r-- | test/files/neg/abstract.check | 10 | ||||
-rw-r--r-- | test/files/neg/bug1010.check | 6 | ||||
-rw-r--r-- | test/files/neg/bug1010.scala (renamed from test/files/pos/bug1010.scala) | 0 | ||||
-rw-r--r-- | test/files/neg/bug415.check | 5 | ||||
-rw-r--r-- | test/files/neg/bug836.check | 9 | ||||
-rw-r--r-- | test/files/neg/bug839.check | 5 | ||||
-rw-r--r-- | test/files/neg/sabin2.check | 7 | ||||
-rw-r--r-- | test/files/pos/bug415.scala (renamed from test/files/neg/bug415.scala) | 0 | ||||
-rw-r--r-- | test/files/pos/bug839.scala (renamed from test/files/neg/bug839.scala) | 0 |
13 files changed, 99 insertions, 76 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 8014881cf2..cf89332ae9 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -1154,6 +1154,15 @@ trait Symbols { /** Concatenate strings separated by spaces */ private def compose(ss: List[String]): String = ss.filter("" !=).mkString("", " ", "") + + /** String representation of existentially bound variable */ + def existentialToString = { + val tname = name.toString + if ((tname endsWith ".type") && (info.bounds.hi.typeSymbol isSubClass SingletonClass) && + !settings.debug.value) + "val "+tname.substring(0, tname.length - 5)+": "+dropSingletonType(info.bounds.hi) + else defString + } } /** A class for term symbols */ diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 95903f985b..32aef9e36b 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -72,7 +72,7 @@ trait Types { var subtypeMillis = 0l private var explainSwitch = false - private var checkMalformedSwitch = true + private var checkMalformedSwitch = false // todo: it's now always false. Remove all code that depends on this switch. private final val LubGlbMargin = 0 private final val LogPendingSubTypesThreshold = 50 @@ -699,6 +699,23 @@ trait Types { } } + /** The existential skolems and existentially quantifed variables which are free in this type */ + def existentialSkolems: List[Symbol] = { + var boundSyms: List[Symbol] = List() + var skolems: List[Symbol] = List() + for (t <- this) { + t match { + case ExistentialType(tparams, qtpe) => + boundSyms = boundSyms ::: tparams + case TypeRef(_, sym, _) => + if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym)) + skolems = sym :: skolems + case _ => + } + } + skolems + } + /** Return the attributes on this type */ val attributes: List[AnnotationInfo] = Nil @@ -1641,18 +1658,10 @@ A type's typeSymbol should never be inspected directly. override def toString: String = { val str = - underlying+(quantified map tparamToString mkString(" forSome { ", "; ", " }")) + underlying+(quantified map (_.existentialToString) mkString(" forSome { ", "; ", " }")) if (settings.explaintypes.value) "("+str+")" else str } - private def tparamToString(tparam: Symbol) = { - val tname = tparam.name.toString - if ((tname endsWith ".type") && (tparam.info.bounds.hi.typeSymbol isSubClass SingletonClass) && - !settings.debug.value) - "val "+tname.substring(0, tname.length - 5)+": "+dropSingletonType(tparam.info.bounds.hi) - else tparam.defString - } - override def cloneInfo(owner: Symbol) = { val tparams = cloneSymbols(quantified, owner) ExistentialType(tparams, underlying.substSym(quantified, tparams)) @@ -1735,7 +1744,6 @@ A type's typeSymbol should never be inspected directly. attString + underlying } - /** Add a number of attributes to this type */ override def withAttributes(attribs: List[AnnotationInfo]): Type = AnnotatedType(attribs:::this.attributes, this) @@ -2012,13 +2020,13 @@ A type's typeSymbol should never be inspected directly. else { val extrapolate = new TypeMap { variance = 1 - stableNeeded = false def apply(tp: Type): Type = { val tp1 = mapOver(tp) tp1 match { case TypeRef(pre, sym, args) if (tparams contains sym) && (variance != 0) => val repl = if (variance == 1) dropSingletonType(tp1.bounds.hi) else tp1.bounds.lo - if ((!stableNeeded || repl.isStable) && !(tparams exists (repl.contains))) repl + if (repl.typeSymbol != AllClass && repl.typeSymbol != AllRefClass && + !(tparams exists (repl.contains))) repl else tp1 case _ => tp1 @@ -2042,7 +2050,7 @@ A type's typeSymbol should never be inspected directly. } /** Remove any occurrence of type <singleton> from this type and its parents */ - private object dropSingletonType extends TypeMap { + object dropSingletonType extends TypeMap { def apply(tp: Type): Type = { tp match { case TypeRef(_, sym, _) if (sym == SingletonClass) => @@ -2116,10 +2124,6 @@ A type's typeSymbol should never be inspected directly. */ var variance = 0 - /** Is a stable type needed here? - */ - var stableNeeded = false - /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { case ErrorType => tp @@ -2132,11 +2136,7 @@ A type's typeSymbol should never be inspected directly. case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { - val v = variance; variance = 0 - val s = stableNeeded; stableNeeded = true val pre1 = this(pre) - variance = v - stableNeeded = s if (pre1 eq pre) tp else singleType(pre1, sym) } @@ -2146,9 +2146,7 @@ A type's typeSymbol should never be inspected directly. if ((thistp1 eq thistp) && (supertp1 eq supertp)) tp else mkSuperType(thistp1, supertp1) case TypeRef(pre, sym, args) => - val s = stableNeeded; stableNeeded = true val pre1 = this(pre) - stableNeeded = s //val args1 = List.mapConserve(args)(this) val args1 = if (args.isEmpty) args else { @@ -2272,30 +2270,30 @@ A type's typeSymbol should never be inspected directly. def apply(tp: Type): Type = { traverse(tp); tp } } - private val emptySymTypeMap = scala.collection.immutable.Map[Symbol, Type]() + private val emptySymMap = scala.collection.immutable.Map[Symbol, Symbol]() - private def makeExistential(owner: Symbol, lo: Type, hi: Type) = + private def makeExistential(suffix: String, owner: Symbol, lo: Type, hi: Type) = recycle( - owner.newAbstractType(owner.pos, freshTypeName()).setFlag(EXISTENTIAL) + owner.newAbstractType(owner.pos, newTypeName(freshTypeName()+suffix)).setFlag(EXISTENTIAL) ).setInfo(TypeBounds(lo, hi)) /** A map to compute the asSeenFrom method */ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap { var capturedParams: List[Symbol] = List() - var capturedPre = emptySymTypeMap + var capturedPre = emptySymMap + variance = 1 - // not yet used - def stabilize(pre: Type, clazz: Symbol) = - if (true || pre.isStable || pre.typeSymbol.isPackageClass) pre - else capturedPre get clazz match { - case Some(tp) => tp + def stabilize(pre: Type, clazz: Symbol): Type = { + capturedPre get clazz match { case None => - println("skolemizing "+pre) - val qvar = makeExistential(clazz, AllClass.tpe, pre) + val qvar = makeExistential(".type", clazz, AllClass.tpe, intersectionType(List(pre, SingletonClass.tpe))) + capturedPre += (clazz -> qvar) capturedParams = qvar :: capturedParams - capturedPre += (clazz -> qvar.tpe) - qvar.tpe + qvar + case Some(qvar) => + qvar } + }.tpe /** Return pre.baseType(clazz), or if that's NoType and clazz is a refinement, pre itself. * See bug397.scala for an example where the second alternative is needed. @@ -2315,19 +2313,26 @@ A type's typeSymbol should never be inspected directly. def toPrefix(pre: Type, clazz: Symbol): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else if ((sym isNonBottomSubClass clazz) && - (pre.widen.typeSymbol isNonBottomSubClass sym)) - pre match { + (pre.widen.typeSymbol isNonBottomSubClass sym)) { + val pre1 = pre match { case SuperType(thistp, _) => thistp case _ => pre } - else toPrefix(base(pre, clazz).prefix, clazz.owner); + if (!(variance == 1 || + pre1.isStable || + pre1.typeSymbol.isPackageClass || + pre1.typeSymbol.isModuleClass && pre1.typeSymbol.isStatic)) { +// throw new MalformedType("non-stable type "+pre1+" replacing a stable reference "+tp) + stabilize(pre1, sym) + } else { + pre1 + } + } else toPrefix(base(pre, clazz).prefix, clazz.owner); toPrefix(pre, clazz) 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 if (pre1.isStable) singleType(pre1, sym) else pre1.memberType(sym).resultType //todo: this should be rolled into existential abstraction @@ -2343,7 +2348,7 @@ A type's typeSymbol should never be inspected directly. // the node is re-typed. if (inIDE) throw new TypeError("internal error: " + tp + " in " + sym.owner + " cannot be instantiated from " + pre.widen) - else throw new Error("" + tp + sym.locationString + + else throw new Error("" + tp + sym.locationString + " cannot be instantiated from " + pre.widen) def instParam(ps: List[Symbol], as: List[Type]): Type = if (ps.isEmpty) throwError @@ -3720,7 +3725,7 @@ A type's typeSymbol should never be inspected directly. if (l <:< g) l else { val owner = commonOwner(as) - val qvar = makeExistential(commonOwner(as), g, l) + val qvar = makeExistential("", commonOwner(as), g, l) capturedParams += qvar qvar.tpe } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index c939ab9979..61de540d03 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -160,6 +160,8 @@ trait Infer { case PolyType(List(), restpe) => if (util.Statistics.enabled) normP = normP + 1 normalize(restpe) + case ExistentialType(tparams, qtpe) => + ExistentialType(tparams, normalize(qtpe)) case tp1 => if (util.Statistics.enabled) normO = normO + 1 tp1 // @MAT aliases already handled by subtyping @@ -201,14 +203,20 @@ trait Infer { else " of type "+tree.tpe) + (if (tree.symbol.name == nme.apply) tree.symbol.locationString else "") - def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = ( + def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = treeSymTypeMsg(tree) + msg + argtpes.mkString("(", ",", ")") + (if (pt == WildcardType) "" else " with expected result type " + pt) - ) + + // todo: use also for other error messages + def existentialContext(tp: Type) = tp.existentialSkolems match { + case List() => "" + case skolems => " where "+(skolems map (_.existentialToString) mkString ", ") + } def foundReqMsg(found: Type, req: Type): String = withDisambiguation(found, req) { - ";\n found : " + found.toLongString + "\n required: " + req + ";\n found : " + found.toLongString + existentialContext(found) + + "\n required: " + req + existentialContext(req) } def typeErrorMsg(found: Type, req: Type) = @@ -331,6 +339,8 @@ trait Infer { isPlausiblyCompatible(restpe, pt) case mt: ImplicitMethodType => isPlausiblyCompatible(mt.resultType, pt) + case ExistentialType(tparams, qtpe) => + isPlausiblyCompatible(qtpe, pt) case MethodType(formals, _) => pt.normalize match { case TypeRef(pre, sym, args) => @@ -519,6 +529,8 @@ trait Infer { def isApplicable(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = ftpe match { + case ExistentialType(tparams, qtpe) => + isApplicable(undetparams, qtpe, argtpes0, pt) case MethodType(formals0, _) => val formals = formalTypes(formals0, argtpes0.length) val argtpes = actualTypes(argtpes0, formals.length) @@ -567,6 +579,8 @@ trait Infer { * @return ... */ def specializes(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { + case et: ExistentialType => + et.withTypeVars(specializes(_, ftpe2)) case MethodType(formals, _) => isApplicable(List(), ftpe2, formals, WildcardType) case PolyType(tparams, MethodType(formals, _)) => @@ -580,8 +594,12 @@ trait Infer { /** Is type `tpe1' a strictly better expression alternative than type `tpe2'? */ def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = { - def isNullary(tpe: Type) = tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty - def isMethod(tpe: Type) = tpe match { + def isNullary(tpe: Type): Boolean = tpe match { + case tp: RewrappingTypeProxy => isNullary(tp.underlying) + case _ => tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty + } + def isMethod(tpe: Type): Boolean = tpe match { + case tp: RewrappingTypeProxy => isMethod(tp.underlying) case MethodType(_, _) | PolyType(_, _) => true case _ => false } diff --git a/test/files/jvm/protectedacc.scala b/test/files/jvm/protectedacc.scala index 50fd66c0b5..fc6d5336d4 100644 --- a/test/files/jvm/protectedacc.scala +++ b/test/files/jvm/protectedacc.scala @@ -136,7 +136,8 @@ package p { m(self) trait InnerInner { - getB.tie(self2) + val g = getB + g.tie(self2.asInstanceOf[g.Node]) } } } diff --git a/test/files/neg/abstract.check b/test/files/neg/abstract.check index c33011bb55..b73539112a 100644 --- a/test/files/neg/abstract.check +++ b/test/files/neg/abstract.check @@ -1,19 +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: A = bar().bar(); - ^ abstract.scala:6: error: type mismatch; found : A required: A.this.T def foo2: T = bar().baz(); ^ -abstract.scala:8: error: method bar cannot be accessed in A - because its instance type ()A#T contains a malformed type: A#T - def foo4: A = baz().bar(); - ^ abstract.scala:9: error: type mismatch; found : A required: A.this.T def foo5: T = baz().baz(); ^ -four errors found +two errors found diff --git a/test/files/neg/bug1010.check b/test/files/neg/bug1010.check new file mode 100644 index 0000000000..a0a97e940c --- /dev/null +++ b/test/files/neg/bug1010.check @@ -0,0 +1,6 @@ +bug1010.scala:14: error: type mismatch; + found : MailBox#Message + required: _1.in.Message where val _1: Actor + unstable.send(msg) // in.Message becomes unstable.Message, but that's ok since Message is a concrete type member + ^ +one error found diff --git a/test/files/pos/bug1010.scala b/test/files/neg/bug1010.scala index 7a1e6615e5..7a1e6615e5 100644 --- a/test/files/pos/bug1010.scala +++ b/test/files/neg/bug1010.scala diff --git a/test/files/neg/bug415.check b/test/files/neg/bug415.check deleted file mode 100644 index a1c68954cb..0000000000 --- a/test/files/neg/bug415.check +++ /dev/null @@ -1,5 +0,0 @@ -bug415.scala:8: error: method x cannot be accessed in A - because its instance type => A#T contains a malformed type: A#T - val y: String = a.x; - ^ -one error found diff --git a/test/files/neg/bug836.check b/test/files/neg/bug836.check index 1fcae2ecb3..4949e2cd66 100644 --- a/test/files/neg/bug836.check +++ b/test/files/neg/bug836.check @@ -1,5 +1,6 @@ -bug836.scala:6: error: type S cannot be accessed in A.this.MyObj - because its instance type A.this.MyObj#S is malformed - type S = MyObj#S - ^ +bug836.scala:9: error: type mismatch; + found : Any + required: A.this.S + val some: S = any // compiles => type X is set to scala.Any + ^ one error found diff --git a/test/files/neg/bug839.check b/test/files/neg/bug839.check deleted file mode 100644 index 2f22e26d44..0000000000 --- a/test/files/neg/bug839.check +++ /dev/null @@ -1,5 +0,0 @@ -bug839.scala:25: error: method set cannot be accessed in object Test.this.FileImpl#treeBuilder - because its instance type (Test.this.Global#Tree)Unit contains a malformed type: Test.this.Global#Tree - file.treeBuilder.set(nsc.get); - ^ -one error found diff --git a/test/files/neg/sabin2.check b/test/files/neg/sabin2.check index 682c08bc62..0e148fa038 100644 --- a/test/files/neg/sabin2.check +++ b/test/files/neg/sabin2.check @@ -1,5 +1,6 @@ -sabin2.scala:22: error: method set cannot be accessed in Test.Base#Inner - because its instance type (Test.Base#T)Unit contains a malformed type: Test.Base#T +sabin2.scala:22: error: type mismatch; + found : Test.Base#T + required: _1.T where val _1: Test.Base a.set(b.get()) // Error - ^ + ^ one error found diff --git a/test/files/neg/bug415.scala b/test/files/pos/bug415.scala index 355b6136d1..355b6136d1 100644 --- a/test/files/neg/bug415.scala +++ b/test/files/pos/bug415.scala diff --git a/test/files/neg/bug839.scala b/test/files/pos/bug839.scala index d845ed3aae..d845ed3aae 100644 --- a/test/files/neg/bug839.scala +++ b/test/files/pos/bug839.scala |