diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/TreePrinters.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 67 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Flags.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 40 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 115 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala | 23 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 93 | ||||
-rw-r--r-- | test/files/neg/bug409.check | 2 | ||||
-rw-r--r-- | test/files/neg/bug593.check | 2 | ||||
-rw-r--r-- | test/files/neg/sabin2.check | 5 | ||||
-rw-r--r-- | test/files/neg/sabin2.scala | 23 | ||||
-rw-r--r-- | test/files/run/existentials.check | 3 | ||||
-rwxr-xr-x | test/files/run/existentials.scala | 48 |
17 files changed, 271 insertions, 184 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index f19a0d1092..501339cadf 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -252,12 +252,6 @@ abstract class TreePrinters { case Throw(expr) => print("throw "); print(expr) - case Pack(expr) => - print("pack("); print(expr); print(")") - - case Unpack(expr) => - print("unpack("); print(expr); print(")") - case New(tpe) => print("new "); print(tpe) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 93b74099e7..12e680fb3c 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -109,6 +109,18 @@ trait Trees { ft.hits.toList } + /** Returns optionally first tree (in a preorder traversal) which satisfies predicate `p', + * or None if none exists. + */ + def find(p: Tree => Boolean): Option[Tree] = { + val ft = new FindTraverser(p) + ft.traverse(this) + ft.result + } + + /** Is there part of this tree which satisfies predicate `p'? */ + def exists(p: Tree => Boolean): Boolean = !find(p).isEmpty + override def toString(): String = { val buffer = new StringWriter() val printer = treePrinters.create(new PrintWriter(buffer)) @@ -596,14 +608,6 @@ trait Trees { case class Throw(expr: Tree) extends TermTree - /** Pack skolemized type, yielding existential */ - case class Pack(expr: Tree) - extends TermTree - - /** Unpack existential, yielding skolemized type */ - case class Unpack(expr: Tree) - extends TermTree - /** Object instantiation * One should always use factory method below to build a user level new. * @@ -806,10 +810,6 @@ trait Trees { // try block catch { catches } finally finalizer where catches: List[CaseDef] case Throw(expr) => // throw expr - case Pack(expr) => (eliminated by erasure) - // internal: pack existential type - case Unpack(expr) => (eliminated by erasure) - // internal: unpack existential type case New(tpt) => // new tpt always in the context: new tpt.<init>[targs](args) case Typed(expr, tpt) => (eliminated by erasure) @@ -876,8 +876,6 @@ trait Trees { def Return(tree: Tree, expr: Tree): Return def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try def Throw(tree: Tree, expr: Tree): Throw - def Pack(tree: Tree, expr: Tree): Pack - def Unpack(tree: Tree, expr: Tree): Unpack def New(tree: Tree, tpt: Tree): New def Typed(tree: Tree, expr: Tree, tpt: Tree): Typed def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply @@ -953,10 +951,6 @@ trait Trees { new Try(block, catches, finalizer).copyAttrs(tree) def Throw(tree: Tree, expr: Tree) = new Throw(expr).copyAttrs(tree) - def Pack(tree: Tree, expr: Tree) = - new Pack(expr).copyAttrs(tree) - def Unpack(tree: Tree, expr: Tree) = - new Unpack(expr).copyAttrs(tree) def New(tree: Tree, tpt: Tree) = new New(tpt).copyAttrs(tree) def Typed(tree: Tree, expr: Tree, tpt: Tree) = @@ -1133,16 +1127,6 @@ trait Trees { if expr0 == expr => t case _ => copy.Throw(tree, expr) } - def Pack(tree: Tree, expr: Tree) = tree match { - case t @ Pack(expr0) - if expr0 == expr => t - case _ => copy.Pack(tree, expr) - } - def Unpack(tree: Tree, expr: Tree) = tree match { - case t @ Unpack(expr0) - if expr0 == expr => t - case _ => copy.Unpack(tree, expr) - } def New(tree: Tree, tpt: Tree) = tree match { case t @ New(tpt0) if tpt0 == tpt => t @@ -1314,10 +1298,6 @@ trait Trees { copy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer)) case Throw(expr) => copy.Throw(tree, transform(expr)) - case Pack(expr) => - copy.Pack(tree, transform(expr)) - case Unpack(expr) => - copy.Unpack(tree, transform(expr)) case New(tpt) => copy.New(tree, transform(tpt)) case Typed(expr, tpt) => @@ -1466,10 +1446,6 @@ trait Trees { traverse(block); traverseTrees(catches); traverse(finalizer) case Throw(expr) => traverse(expr) - case Pack(expr) => - traverse(expr) - case Unpack(expr) => - traverse(expr) case New(tpt) => traverse(tpt) case Typed(expr, tpt) => @@ -1592,12 +1568,27 @@ trait Trees { } class ForeachTraverser(f: Tree => Unit) extends Traverser { - override def traverse(t: Tree) = f(t) + override def traverse(t: Tree) = { + f(t) + super.traverse(t) + } } class FilterTraverser(p: Tree => Boolean) extends Traverser { val hits = new ListBuffer[Tree] - override def traverse(t: Tree) = if (p(t)) hits += t + override def traverse(t: Tree) = { + if (p(t)) hits += t + super.traverse(t) + } + } + + class FindTraverser(p: Tree => Boolean) extends Traverser { + var result: Option[Tree] = None + override def traverse(t: Tree) = + if (result.isEmpty) { + if (p(t)) result = Some(t) + super.traverse(t) + } } object resetPos extends Traverser { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index a6fccb50c2..abe2248b3e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -659,7 +659,10 @@ trait Parsers { t } - /** Type ::= Type1 [where `{' {WhereClause} `}'] + /** Type ::= Type1 [for_some `{' WhereClause {semi WhereClause}} `}'] + * WhereClause ::= type TypeDcl + * | val ValDcl + * | */ def typ(): Tree = { val t = typ1() @@ -2211,7 +2214,7 @@ trait Parsers { templateBody() } else { if (inToken == LPAREN) - syntaxError((if (traitParentSeen) "parents of traits" else "traits")+ + syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ " may not have parameters", true) (emptyValDef, List()) } diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index bfee9e8597..a7c3e5b5d7 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -46,6 +46,7 @@ object Flags extends Enumeration { final val SYNTHETIC = 0x00200000 // symbol is compiler-generated final val STABLE = 0x00400000 // functions that are assumed to be stable // (typically, access methods for valdefs) + // or classes that do not contain abstract types. final val STATIC = 0x00800000 // static field, method or class final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor) @@ -158,9 +159,9 @@ object Flags extends Enumeration { if (flag == IS_ERROR) "<is-error>" else if (flag == OVERLOADED ) "<overloaded>" else if (flag == LIFTED ) "<lifted>" - else if (flag == MIXEDIN ) "<mixedin>" + else if (flag == MIXEDIN ) "<mixedin/existential>" else if (flag == EXPANDEDNAME) "<expandedname>" - else if (flag == IMPLCLASS ) "<implclass/presuper>" + else if (flag == IMPLCLASS ) "<presuper/implclass>" else if (flag == TRANS_FLAG ) "<trans-flag>" else if (flag == LOCKED ) "<locked>" else flag.asInstanceOf[Int] match { diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 6c108ca709..3fbd7b8612 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -43,6 +43,7 @@ trait Symbols { var rawflags: Long = 0 private var rawpos = initPos val id = { ids += 1; ids } +// assert(id != 6935, initName) var validTo: Period = NoPeriod @@ -176,7 +177,8 @@ trait Symbols { def isClass = false //to be overridden def isTypeMember = false //to be overridden def isAliasType = false //to be overridden - def isAbstractType = false //to be overridden + def isAbstractType = false //to be overridden + def isSkolem = false //to be overridden final def isValue = isTerm && !(isModule && hasFlag(PACKAGE | JAVA)) final def isVariable = isTerm && hasFlag(MUTABLE) && !isMethod @@ -202,14 +204,13 @@ trait Symbols { final def isError = hasFlag(IS_ERROR) final def isErroneous = isError || isInitialized && tpe.isErroneous final def isTrait = isClass & hasFlag(TRAIT) - final def isSkolem = deSkolemize != this final def isTypeParameterOrSkolem = isType && hasFlag(PARAM) + final def isTypeSkolem = isSkolem && hasFlag(PARAM) final def isTypeParameter = isTypeParameterOrSkolem && !isSkolem - final def isTypeSkolem = isTypeParameterOrSkolem && isSkolem final def isExistential = isType && hasFlag(EXISTENTIAL) + final def isExistentialSkolem = isSkolem && hasFlag(EXISTENTIAL) final def isExistentialQuantified = isExistential && !isSkolem - final def isExistentialSkolem = isExistential && isSkolem - final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) + final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) final def isAnonymousClass = isClass && (originalName startsWith nme.ANON_CLASS_NAME) // startsWith necessary because name may grow when lifted and also because of anonymous function classes final def isRefinementClass = isClass && name == nme.REFINE_CLASS_NAME.toTypeName; // no lifting for refinement classes @@ -344,6 +345,19 @@ trait Symbols { final def isInitialized: Boolean = validTo != NoPeriod + final def isStableClass: Boolean = { + def hasNoAbstractTypeMember(clazz: Symbol): Boolean = + (clazz hasFlag STABLE) || { + var e = clazz.info.decls.elems + while ((e ne null) && !(e.sym.isAbstractType && info.member(e.sym.name) == e.sym)) + e = e.next + e == null + } + def checkStable() = + (info.baseClasses forall hasNoAbstractTypeMember) && { setFlag(STABLE); true } + isClass && (hasFlag(STABLE) || checkStable()) + } + final def isCovariant: Boolean = isType && hasFlag(COVARIANT) final def isContravariant: Boolean = isType && hasFlag(CONTRAVARIANT) @@ -875,9 +889,14 @@ trait Symbols { initialize.owner.info.decl(facname).suchThat(_.isCaseFactory) } - /** If this symbol is a skolem, its corresponding type parameter, otherwise this */ + /** If this symbol is a type parameter skolem (not an existential skolem!) + * its corresponding type parameter, otherwise this */ def deSkolemize: Symbol = this + /** If this symbol is an existential skolem the location (a Tree or null) + * where it was unpacked. Resulttype is AnyRef because trees are not visible here. */ + def unpackLocation: AnyRef = null + /** Remove private modifier from symbol `sym's definition. If `sym' is a * term symbol rename it by expanding its name to avoid name clashes */ @@ -1218,9 +1237,14 @@ trait Symbols { /** A class for type parameters viewed from inside their scopes */ class TypeSkolem(initOwner: Symbol, initPos: Position, - initName: Name, typeParam: Symbol) + initName: Name, origin: AnyRef) extends TypeSymbol(initOwner, initPos, initName) { - override def deSkolemize = typeParam + override def isSkolem = true + override def deSkolemize = origin match { + case s: Symbol => s + case _ => this + } + override def unpackLocation = origin override def typeParams = info.typeParams //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo override def cloneSymbolImpl(owner: Symbol): Symbol = { throw new Error("should not clone a type skolem") diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 3a15c2e77b..0813bb4794 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -92,7 +92,8 @@ trait Types { trait TypeProxy extends Type { val tp: Type - private def maybeRewrap(newtp: Type) = if (newtp eq tp) this else newtp + protected def maybeRewrap(newtp: Type) = if (newtp eq tp) this else rewrap(newtp) + protected def rewrap(newtp: Type): Type = this // the following are all operations in class Type that are overridden in some subclass // Important to keep this up-to-date when new operations are added! @@ -121,7 +122,8 @@ trait Types { override def notNull = maybeRewrap(tp.notNull) override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = tp.instantiateTypeParams(formals, actuals) - override def skolemizeExistential(owner: Symbol) = tp.skolemizeExistential(owner) + override def skolemizeExistential(owner: Symbol, origin: AnyRef) = + tp.skolemizeExistential(owner, origin) override def normalize = maybeRewrap(tp.normalize) override def decls = tp.decls override def baseType(clazz: Symbol) = tp.baseType(clazz) @@ -241,7 +243,7 @@ trait Types { */ def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = this.subst(formals, actuals) - def skolemizeExistential(owner: Symbol) = this + def skolemizeExistential(owner: Symbol, origin: AnyRef): Type = this /** Reduce to beta eta-long normal form. Expands type aliases and converts higher-kinded TypeRef's to PolyTypes. @M */ def normalize = this // @MAT @@ -317,7 +319,9 @@ trait Types { */ def asSeenFrom(pre: Type, clazz: Symbol): Type = if (!isTrivial && (!phase.erasedTypes || pre.symbol == ArrayClass)) { - new AsSeenFromMap(pre, clazz) apply this + val m = new AsSeenFromMap(pre, clazz) + val tp = m apply this + existentialAbstraction(m.capturedParams, tp) } else this /** The info of `sym', seen as a member of this type. @@ -345,7 +349,7 @@ trait Types { } */ case tp => - //Console.println("" + this + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain);//DEBUG + //Console.println("" + this + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain);//debug tp.asSeenFrom(this, sym.owner) } } @@ -371,21 +375,21 @@ trait Types { def substSuper(from: Type, to: Type): Type = new SubstSuperMap(from, to) apply this - def exskolems: List[Symbol] = - this filter (_.symbol.isExistentialSkolem) map (_.symbol) - /** Returns all parts of this type which satisfy predicate `p' */ def filter(p: Type => Boolean): List[Type] = { new FilterTraverser(p).traverse(this).hits.toList } - /** Returns optionally first type (in a preorder traverser) which satisfies predicate `p', + /** Returns optionally first type (in a preorder traversal) which satisfies predicate `p', * or None if none exists. */ def find(p: Type => Boolean): Option[Type] = { new FindTraverser(p).traverse(this).result } + /** Apply `f' to each part of this type */ + def foreach(f: Type => Unit): Unit = new ForEachTraverser(f).traverse(this) + /** Is there part of this type which satisfies predicate `p'? */ def exists(p: Type => Boolean): Boolean = !find(p).isEmpty @@ -1402,23 +1406,6 @@ A type's symbol should never be inspected directly. class JavaMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt) - /** A class containing the commonalities of existential and universal types */ - abstract class QuantifiedType extends Type { - def quantified: Type - override def paramSectionCount: Int = quantified.paramSectionCount - override def paramTypes: List[Type] = quantified.paramTypes - override def parents: List[Type] = quantified.parents - override def decls: Scope = quantified.decls - override def symbol: Symbol = quantified.symbol - override def prefix: Type = quantified.prefix - override def closure: Array[Type] = quantified.closure - override def closureDepth: Int = quantified.closureDepth - override def baseClasses: List[Symbol] = quantified.baseClasses - override def baseType(clazz: Symbol): Type = quantified.baseType(clazz) - override def narrow: Type = quantified.narrow - // override def isNullable: Boolean = quantified.isNullable; - } - /** A class representing a polymorphic type or, if tparams.length == 0, * a parameterless method type. * (@M: note that polymorphic nullary methods have non-empty tparams, @@ -1427,9 +1414,19 @@ A type's symbol should never be inspected directly. * could use PolyType instead of TypeRef with empty args) */ case class PolyType(override val typeParams: List[Symbol], override val resultType: Type) - extends QuantifiedType { - - def quantified = resultType + extends Type { + + override def paramSectionCount: Int = resultType.paramSectionCount + override def paramTypes: List[Type] = resultType.paramTypes + override def parents: List[Type] = resultType.parents + override def decls: Scope = resultType.decls + override def symbol: Symbol = resultType.symbol + override def prefix: Type = resultType.prefix + override def closure: Array[Type] = resultType.closure + override def closureDepth: Int = resultType.closureDepth + override def baseClasses: List[Symbol] = resultType.baseClasses + override def baseType(clazz: Symbol): Type = resultType.baseType(clazz) + override def narrow: Type = resultType.narrow override def finalResultType: Type = resultType.finalResultType @@ -1454,15 +1451,32 @@ A type's symbol should never be inspected directly. } case class ExistentialType(override val typeParams: List[Symbol], - val quantified: Type) extends QuantifiedType { - override def bounds: TypeBounds = - TypeBounds(ExistentialType(typeParams, quantified.bounds.lo), - ExistentialType(typeParams, quantified.bounds.hi)) - - override def skolemizeExistential(owner: Symbol) = { - val skolems = if (owner == NoSymbol) cloneSymbols(typeParams) - else cloneSymbols(typeParams, owner) - for (skolem <- skolems) skolem resetFlag PARAM setFlag EXISTENTIAL + val quantified: Type) extends TypeProxy + { + val tp = quantified + override protected def rewrap(newtp: Type) = existentialAbstraction(typeParams, newtp) + + override def bounds = TypeBounds(maybeRewrap(tp.bounds.lo), maybeRewrap(tp.bounds.hi)) + override def parents = tp.parents map maybeRewrap + override def prefix = maybeRewrap(tp.prefix) + override def typeArgs = tp.typeArgs map maybeRewrap + override def paramTypes = tp.paramTypes map maybeRewrap + override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = + maybeRewrap(tp.instantiateTypeParams(formals, actuals)) + override def baseType(clazz: Symbol) = maybeRewrap(tp.baseType(clazz)) + override def closure = tp.closure map maybeRewrap + + override def skolemizeExistential(owner: Symbol, origin: AnyRef) = { + def mkSkolem(tparam: Symbol) = + new TypeSkolem( + if (owner == NoSymbol) tparam.owner else owner, + tparam.pos, tparam.name, origin) + .setInfo(tparam.info) + .setFlag(tparam.flags | EXISTENTIAL) + .resetFlag(PARAM) + val skolems = typeParams map mkSkolem + for (skolem <- skolems) + skolem setInfo skolem.info.substSym(typeParams, skolems) quantified.substSym(typeParams, skolems) } @@ -1684,7 +1698,8 @@ A type's symbol should never be inspected directly. if (pre1 ne pre) { if (sym1.isAbstractType) sym1 = rebind(pre1, sym1) typeRef(pre1, sym1, args) - } else if (checkMalformedSwitch && sym1.isAbstractType && !pre.isStable && !pre.isError) { + } else if (checkMalformedSwitch && !pre.isStable && !pre.isError && + (sym1.isAbstractType /* || !pre.widen.symbol.isStableClass*/)) { throw new MalformedType(pre, sym1.nameString) } else if (sym1.isClass && pre.isInstanceOf[CompoundType]) { // sharpen prefix so that it is maximal and still contains the class. @@ -2047,6 +2062,7 @@ A type's symbol should never be inspected directly. /** A map to compute the asSeenFrom method */ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap { + var capturedParams: List[Symbol] = List() /** 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. * The problem is that when forming the closure of an abstract type, @@ -2106,6 +2122,9 @@ A type's symbol should never be inspected directly. basesym.typeParams.map(_.name).mkString("[",",","]")+ " gets applied to arguments "+baseargs.mkString("(",",",")")+", phase = "+phase) instParam(basesym.typeParams, baseargs); + case ExistentialType(tparams, qtpe) => + capturedParams = capturedParams union tparams + toInstance(qtpe, clazz) case _ => throwError } @@ -2163,7 +2182,8 @@ A type's symbol should never be inspected directly. assert(!(tparams exists (from contains))) tp case ExistentialType(tparams, restp) => - assert(!(tparams exists (from contains))) + if (tparams exists (from contains)) + assert(false, "["+from.mkString(",")+":="+to.mkString(",")+"]"+tp) tp case _ => tp @@ -2283,6 +2303,14 @@ A type's symbol should never be inspected directly. } } + class ForEachTraverser(f: Type => Unit) extends TypeTraverser { + def traverse(tp: Type): TypeTraverser = { + f(tp) + mapOver(tp) + this + } + } + /** A map to implement the `filter' method */ class FindTraverser(p: Type => Boolean) extends TypeTraverser { var result: Option[Type] = None @@ -2617,7 +2645,6 @@ A type's symbol should never be inspected directly. } else { isSubType0(tp1, tp2) } - } finally { stc = stc - 1 } @@ -2723,8 +2750,6 @@ A type's symbol should never be inspected directly. (parents2 forall (tp2 => tp1 <:< tp2 || tp2.symbol == NotNullClass && tp1.isNotNull)) && (ref2.toList forall tp1.specializes) && (!parents2.exists(_.symbol.isAbstractType) || tp1.symbol != AllRefClass) - case (RefinedType(parents1, ref1), _) => - parents1 exists (_ <:< tp2) case (_, ExistentialType(tparams2, res2)) => val tvars = tparams2 map (tparam => new TypeVar(tparam.tpe, new TypeConstraint)) val ires2 = res2.instantiateTypeParams(tparams2, tvars) @@ -2732,8 +2757,10 @@ A type's symbol should never be inspected directly. solve(tvars, tparams2, tparams2 map (x => 0), false) isWithinBounds(NoPrefix, NoSymbol, tparams2, tvars map (_.constr.inst)) } + case (RefinedType(parents1, ref1), _) => + parents1 exists (_ <:< tp2) case (ExistentialType(_, _), _) => - tp1.skolemizeExistential(NoSymbol) <:< tp2 + tp1.skolemizeExistential(NoSymbol, null) <:< tp2 /* todo: replace following with case (ThisType(_), _) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 415b2da6d7..1be7a0dc68 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -861,12 +861,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { checkNoDoubleDefs(tree.symbol.owner) copy.Template(tree, parents, emptyValDef, addBridges(body, currentOwner)) - case Pack(expr) => - expr - - case Unpack(expr) => - expr - case _ => tree } diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 317146de97..aba9a20229 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -373,29 +373,6 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter sym setFlag notPROTECTED super.transform(tree) - case Pack(expr) => - super.transform(expr) - - case Unpack(expr) => - super.transform(expr setType tree.tpe) - // Martin to Lex: it seems we need to eliminate unpacks already here, - // rather than in erasure, which would be more logical, because - // otherwise Unpacks survive to later phases when run in the interpreter. - // Why is this? Does the interpreter skip erasure in some circumstances? - // Here's the example that fails when we remove the clause here": - // - // scala - // scala> case class Cell[T](x: T) - // scala> var x: Cell[T] for_some { type T } = new Cell(1) - // scala> x = new Cell("abc") - // (failure in genicode which complains about: - // Exception in thread "main" java.lang.Error: Unexpected tree in genLoad: unpack({ - // line2$object$$iw$$iw.x_=(new line1$object$$iw$$iw$Cell("abc")); - // line2$object$$iw$$iw.x() - // }) - // - // If I run the same with nsc (see existentials.scala), it works. - case Apply(sel @ Select(qual, name), args) if (name == nme.CONSTRUCTOR && isInner(sel.symbol.owner)) => val outerVal = atPos(tree.pos) { diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 79f2b0c734..793b173958 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -21,7 +21,7 @@ import scala.tools.nsc.util.Position * - for every argument to a def parameter `x: => T': * if argument is not a reference to a def parameter: * convert argument `e' to (expansion of) `() => e' - * - for every repated parameter `x: T*' --> x: Seq[T]. + * - for every repeated parameter `x: T*' --> x: Seq[T]. * - for every argument list that corresponds to a repeated parameter * (a_1, ..., a_n) => (Seq(a_1, ..., a_n)) * - for every argument list that is an escaped sequence @@ -52,6 +52,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { def apply(tp0: Type): Type = {val tp=expandAlias(tp0); tp match { case MethodType(formals, MethodType(formals1, restpe)) => apply(MethodType(formals ::: formals1, restpe)) + case MethodType(formals, ExistentialType(tparams, restpe)) => + apply(ExistentialType(tparams, MethodType(formals, restpe))) case mt: ImplicitMethodType => apply(MethodType(mt.paramTypes, mt.resultType)) case PolyType(List(), restpe) => diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index fb32cdcec1..32e2a136d2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -61,10 +61,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT private def checkPackedConforms(tree: Tree, pt: Type): Tree = { if (tree.tpe exists (_.symbol.isExistentialSkolem)) { - val packed = typer.typed(Pack(tree) setPos tree.pos) - println("packed: "+packed+":"+packed.tpe+", pt = "+pt) - if (!(packed.tpe <:< pt)) - typer.infer.typeError(tree.pos, packed.tpe, pt) + val packed = typer.packedType(tree, NoSymbol) + if (!(packed <:< pt)) typer.infer.typeError(tree.pos, packed, pt) } tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 201f53be70..a72afdd642 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -476,6 +476,7 @@ trait Typers { self: Analyzer => } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue) { // (2) errorTree(tree, sym+" is not a value") } else { + skolemizeIfExistential(tree, mode) if (sym.isStable && pre.isStable && tree.tpe.symbol != ByNameParamClass && (isStableContext(tree, mode, pt) || sym.isModule && !sym.isMethod)) tree.setType(singleType(pre, sym)) @@ -483,6 +484,14 @@ trait Typers { self: Analyzer => } } + private def skolemizeIfExistential(tree: Tree, mode: int): Tree = { + if ((mode & (EXPRmode | LHSmode)) == EXPRmode && tree.tpe.isInstanceOf[ExistentialType]) { + tree setType tree.tpe.skolemizeExistential(context.owner, tree) +// Console.println("skolemized "+tree+":"+tree.tpe);//DEBUG + } + tree + } + /** * @param tree ... * @param mode ... @@ -729,7 +738,10 @@ trait Typers { self: Analyzer => } } } - if (settings.debug.value) log("error tree = "+tree) + if (settings.debug.value) { + log("error tree = "+tree) + if (settings.explaintypes.value) explainTypes(tree.tpe, pt) + } typeErrorTree(tree, tree.tpe, pt) } } @@ -1347,9 +1359,9 @@ trait Typers { self: Analyzer => // for (val vparam <- vparams) { // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () // } - var body = pack(typed(fun.body, respt), fun.symbol) + var body = typed(fun.body, respt) val formals = vparamSyms map (_.tpe) - val restpe = body.tpe.deconst + val restpe = packedType(body, fun.symbol).deconst val funtpe = typeRef(clazz.tpe.prefix, clazz, formals ::: List(restpe)) // body = checkNoEscaping.locals(context.scope, restpe, body) val fun1 = copy.Function(fun, vparams, body).setType(funtpe) @@ -1746,34 +1758,35 @@ trait Typers { self: Analyzer => res } - protected def pack(tree: Tree, owner: Symbol): Tree = { + def packedType(tree: Tree, owner: Symbol): Type = { + def defines(tree: Tree, sym: Symbol) = + sym.isExistentialSkolem && sym.unpackLocation == tree || + tree.isDef && tree.symbol == sym def isAnonymousFunction(sym: Symbol) = (sym hasFlag SYNTHETIC) && (sym.name == nme.ANON_FUN_NAME) def isVisibleParameter(sym: Symbol) = (sym hasFlag PARAM) && (sym.owner == owner) && (sym.isType || !isAnonymousFunction(owner)) - object collectLocals extends TypeMap { - var symbols: List[Symbol] = List() - def apply(tp: Type) = { - tp match { - case TypeRef(_, _, _) | SingleType(_, _) => - val sym = tp.symbol - if (sym hasFlag PACKAGE) tp - else { - var o = sym.owner - while (o != owner && !(o hasFlag PACKAGE)) o = o.owner - if (o == owner && !isVisibleParameter(sym) && !(symbols contains sym)) - symbols = sym :: symbols - mapOver(tp) - } - case _ => - mapOver(tp) - } + def containsDef(owner: Symbol, sym: Symbol): Boolean = + (!(sym hasFlag PACKAGE)) && { + var o = sym.owner + while (o != owner && o != NoSymbol && !(o hasFlag PACKAGE)) o = o.owner + o == owner && !isVisibleParameter(sym) + } + def isLocal(sym: Symbol): Boolean = + if (owner == NoSymbol) tree exists (defines(_, sym)) + else containsDef(owner, sym) + var localSyms = collection.immutable.Set[Symbol]() + var boundSyms = collection.immutable.Set[Symbol]() + for (t <- tree.tpe) { + t match { + case ExistentialType(tparams, _) => boundSyms ++= tparams + case _ => } + val sym = t.symbol + if (sym != NoSymbol && !(localSyms contains sym) && !(boundSyms contains sym) && isLocal(sym)) + localSyms += sym } - collectLocals(tree.tpe) - val hidden = collectLocals.symbols.reverse - if (hidden.isEmpty) tree - else Pack(tree) setType packSymbols(hidden, tree.tpe) + packSymbols(localSyms.toList, tree.tpe) } protected def typedExistentialTypeTree(tree: ExistentialTypeTree): Tree = { @@ -1954,7 +1967,7 @@ trait Typers { self: Analyzer => copy.New(tree, tpt1).setType(tpt1.tpe) } - def typedEta(expr1: Tree) = expr1.tpe match { + def typedEta(expr1: Tree): Tree = expr1.tpe match { case TypeRef(_, sym, _) if (sym == ByNameParamClass) => val expr2 = Function(List(), expr1) new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2) @@ -1989,7 +2002,7 @@ trait Typers { self: Analyzer => case ErrorType => expr1 case _ => - errorTree(expr1, "`&' must be applied to method; cannot be applied to " + expr1.tpe) + errorTree(expr1, "_ must follow method; cannot follow " + expr1.tpe) } def typedWildcardStar(expr1: Tree, tpt: Tree) = expr1.tpe.baseType(SeqClass) match { @@ -2596,19 +2609,6 @@ trait Typers { self: Analyzer => val expr1 = typed(expr, ThrowableClass.tpe) copy.Throw(tree, expr1) setType AllClass.tpe - case Pack(expr) => - val expr1 = typed1(expr, mode, pt) - val skolems = new ListBuffer[Symbol] - for (val unpacked @ Unpack(expr) <- expr filter (_.isInstanceOf[Unpack])) { - skolems ++= (unpacked.tpe.exskolems diff expr.tpe.exskolems) - } - val packed = packSymbols(skolems.toList.removeDuplicates, expr.tpe) - copy.Pack(tree, expr1) setType packed - - case Unpack(expr) => - val expr1 = typed1(expr, mode, pt) - copy.Unpack(tree, expr1) setType expr1.tpe.skolemizeExistential(context.owner) - case New(tpt: Tree) => typedNew(tpt) @@ -2625,7 +2625,7 @@ trait Typers { self: Analyzer => if ((mode & PATTERNmode) != 0) inferTypedPattern(tpt1.pos, tpt1.tpe, widen(pt)) else tpt1.tpe //Console.println(typed pattern: "+tree+":"+", tp = "+tpt1.tpe+", pt = "+pt+" ==> "+owntype)//DEBUG - copy.Typed(tree, expr1, tpt1) setType owntype + skolemizeIfExistential(copy.Typed(tree, expr1, tpt1) setType owntype, mode) case TypeApply(fun, args) => // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer) @@ -2661,13 +2661,13 @@ trait Typers { self: Analyzer => } //@M TODO: context.undetparams = undets_fun ? - typedTypeApply(fun1, args1) + skolemizeIfExistential(typedTypeApply(fun1, args1), mode) case Apply(Block(stats, expr), args) => typed1(atPos(tree.pos)(Block(stats, Apply(expr, args))), mode, pt) case Apply(fun, args) => - typedApply(fun, args) + skolemizeIfExistential(typedApply(fun, args), mode) case ApplyDynamic(qual, args) => val qual1 = typed(qual, AnyRefClass.tpe) @@ -2765,9 +2765,6 @@ trait Typers { self: Analyzer => } var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt)) //Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams);//DEBUG - if ((mode & (EXPRmode | LHSmode)) == EXPRmode && tree1.tpe.isInstanceOf[ExistentialType]) - tree1 = Unpack(tree1) setPos tree1.pos setType tree1.tpe.skolemizeExistential(context.owner) - //Console.println("skolemized "+tree1+":"+tree1.tpe);//DEBUG val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt) //Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG // if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) @@ -2850,9 +2847,9 @@ trait Typers { self: Analyzer => } def computeType(tree: Tree, pt: Type): Type = { - val tree1 = pack(typed(tree, pt), context.owner) + val tree1 = typed(tree, pt) transformed(tree) = tree1 - tree1.tpe + packedType(tree1, context.owner) } def transformedOrTyped(tree: Tree, pt: Type): Tree = transformed.get(tree) match { diff --git a/test/files/neg/bug409.check b/test/files/neg/bug409.check index 63ece3b0f0..25e5a41d16 100644 --- a/test/files/neg/bug409.check +++ b/test/files/neg/bug409.check @@ -1,4 +1,4 @@ -bug409.scala:6: error: traits may not have parameters +bug409.scala:6: error: traits or objects may not have parameters class Toto extends Expr with Case1(12); ^ one error found diff --git a/test/files/neg/bug593.check b/test/files/neg/bug593.check index eeb745631b..f71affec5a 100644 --- a/test/files/neg/bug593.check +++ b/test/files/neg/bug593.check @@ -1,4 +1,4 @@ -bug593.scala:1: error: traits may not have parameters +bug593.scala:1: error: traits or objects may not have parameters trait Wrapper[T](x : T) { ^ one error found diff --git a/test/files/neg/sabin2.check b/test/files/neg/sabin2.check new file mode 100644 index 0000000000..e127cc67a2 --- /dev/null +++ b/test/files/neg/sabin2.check @@ -0,0 +1,5 @@ +sabin2.scala:22: error: method set cannot be accessed in Test.this.Base#Inner + because its instance type (Test.this.Base#T)Unit contains a malformed type: Test.this.Base#T + a.set(b.get()) // Error + ^ +one error found diff --git a/test/files/neg/sabin2.scala b/test/files/neg/sabin2.scala new file mode 100644 index 0000000000..308632e990 --- /dev/null +++ b/test/files/neg/sabin2.scala @@ -0,0 +1,23 @@ +object Test extends Application + { + abstract class Base { + type T + var x: T = _ + class Inner { + def set(y: T) = x = y + def get() = x + def print() = println("Hello world") + } + } + + object IntBase extends Base { type T = Int } + object StringBase extends Base { type T = String } + + val a : Base#Inner = new IntBase.Inner + val b : Base#Inner = new StringBase.Inner + + a.print() // OK + b.print() // OK + + a.set(b.get()) // Error + } diff --git a/test/files/run/existentials.check b/test/files/run/existentials.check new file mode 100644 index 0000000000..c1bffda530 --- /dev/null +++ b/test/files/run/existentials.check @@ -0,0 +1,3 @@ +Int 2 +Float 2 +Cell(abc) diff --git a/test/files/run/existentials.scala b/test/files/run/existentials.scala new file mode 100755 index 0000000000..3d51751996 --- /dev/null +++ b/test/files/run/existentials.scala @@ -0,0 +1,48 @@ +class Foo { + class Line { + case class Cell[T](var x: T) + def f[T](x: Any): Cell[t1] for_some { type t1 } = x match { case y: Cell[t] => y } + + var x: Cell[T] for_some { type T } = new Cell(1) + println({ x = new Cell("abc"); x }) + } +} + +trait Counter[T] { + def newCounter: T + def get(i: T): Int + def inc(i: T): T + } + + object Test extends Application { + + def foo(x : Counter[T] { def name : String } for_some { type T }) = x match { + case ctr: Counter[t] => + val c = ctr.newCounter + println(ctr.name+" "+ctr.get(ctr.inc(ctr.inc(c)))) + case _ => + } + + var ex: Counter[T] for_some { type T } = _ + ex = ci + ex = cf + + val ci = new Counter[Int] { + def newCounter = 0 + def get(i: Int) = i + def inc(i: Int) = i+1 + def name = "Int" + } + + val cf = new Counter[Float] { + def newCounter = 0 + def get(i: Float) = i.intValue + def inc(i: Float) = i+1 + def name = "Float" + } + + foo(ci) + foo(cf) + val foo = new Foo + new foo.Line +} |