summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2007-06-15 18:00:19 +0000
committerMartin Odersky <odersky@gmail.com>2007-06-15 18:00:19 +0000
commit225fac5af513f7bc7edd7b7e8e262ab151ef823e (patch)
tree06bf7b50cd2486323994fe32999bdc2754c37cac
parentba3b4ba405c66059a3ca7809557d988358fa7162 (diff)
downloadscala-225fac5af513f7bc7edd7b7e8e262ab151ef823e.tar.gz
scala-225fac5af513f7bc7edd7b7e8e262ab151ef823e.tar.bz2
scala-225fac5af513f7bc7edd7b7e8e262ab151ef823e.zip
more existentials
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala67
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Flags.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala40
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala115
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala23
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala93
-rw-r--r--test/files/neg/bug409.check2
-rw-r--r--test/files/neg/bug593.check2
-rw-r--r--test/files/neg/sabin2.check5
-rw-r--r--test/files/neg/sabin2.scala23
-rw-r--r--test/files/run/existentials.check3
-rwxr-xr-xtest/files/run/existentials.scala48
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
+}