summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2007-06-09 13:03:55 +0000
committerMartin Odersky <odersky@gmail.com>2007-06-09 13:03:55 +0000
commit8414ebada9615aac0e8b436e7bdbeee5986ccaa3 (patch)
treef62c23aec3d9f49446aebd76963667be8468f48d /src/compiler/scala/tools/nsc/typechecker
parent6ad83dae6960a78d6014c6fcfee1889a322ad5d7 (diff)
downloadscala-8414ebada9615aac0e8b436e7bdbeee5986ccaa3.tar.gz
scala-8414ebada9615aac0e8b436e7bdbeee5986ccaa3.tar.bz2
scala-8414ebada9615aac0e8b436e7bdbeee5986ccaa3.zip
added existential types
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala159
3 files changed, 147 insertions, 46 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 2ea69a2914..944d271d1d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -26,13 +26,9 @@ trait Namers { self: Analyzer =>
*/
class DeSkolemizeMap(tparams: List[Symbol]) extends TypeMap {
def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) =>
- val tparam = sym.deSkolemize
- mapOver(
- if (tparam == sym || !(tparams contains tparam)) tp
- else rawTypeRef(NoPrefix, tparam, args))
- case SingleType(pre, sym) if (sym.isThisSkolem) =>
- mkThisType(sym.deSkolemize)
+ case TypeRef(pre, sym, args)
+ if (sym.isTypeSkolem && (tparams contains sym.deSkolemize)) =>
+ mapOver(rawTypeRef(NoPrefix, sym.deSkolemize, args))
case PolyType(tparams1, restpe) =>
new DeSkolemizeMap(tparams1 ::: tparams).mapOver(tp)
case ClassInfoType(parents, decls, clazz) =>
@@ -774,6 +770,7 @@ trait Namers { self: Analyzer =>
context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters");
if ((sym.flags & DEFERRED) != 0) {
if (!sym.isValueParameter && !sym.isTypeParameterOrSkolem &&
+ !context.tree.isInstanceOf[ExistentialTypeTree] &&
(!sym.owner.isClass || sym.owner.isModuleClass || sym.owner.isAnonymousClass)) {
context.error(sym.pos,
"only classes can have declared but undefined members" + varNotice(sym))
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 8fc956715b..fb32cdcec1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -38,10 +38,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
class SuperAccTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
private var validCurrentOwner = true
private var accDefs: List[(Symbol, ListBuffer[Tree])] = List()
+ private val typer = analyzer.newTyper(analyzer.rootContext(unit))
private def accDefBuf(clazz: Symbol) =
accDefs.dropWhile(_._1 != clazz).head._2
-
+/*
private def transformArgs(args: List[Tree], formals: List[Type]) = {
if (!formals.isEmpty && formals.last.symbol == definitions.ByNameParamClass)
((args take (formals.length - 1) map transform) :::
@@ -49,6 +50,24 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
else
args map transform
}
+*/
+ private def transformArgs(args: List[Tree], formals: List[Type]) =
+ List.map2(args, formals){ (arg, formal) =>
+ if (formal.symbol == definitions.ByNameParamClass)
+ withInvalidOwner { checkPackedConforms(transform(arg), formal.typeArgs.head) }
+ else transform(arg)
+ } :::
+ (args drop formals.length map transform)
+
+ 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)
+ }
+ tree
+ }
override def transform(tree: Tree): Tree = tree match {
case ClassDef(_, _, _, _) =>
@@ -301,7 +320,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
if (host.thisSym != host) {
if (host.thisSym.tpe.symbol.hasFlag(JAVA) || currentOwner.enclClass.isTrait)
unit.error(pos, "Implementation restriction: " + currentOwner.enclClass + " accesses protected "
- + sym + " from 'required' " + host.thisSym.tpe)
+ + sym + " from self type " + host.thisSym.tpe)
false
} else res
} else res
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 468a2c1924..201f53be70 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -338,21 +338,15 @@ trait Typers { self: Analyzer =>
this.owner = owner
this.scope = scope
hiddenSymbols = List()
- apply(tree.tpe)
- if (hiddenSymbols.isEmpty) tree
+ val tp1 = apply(tree.tpe)
+ if (hiddenSymbols.isEmpty) tree setType tp1
else if (hiddenSymbols exists (_.isErroneous)) setError(tree)
else if (isFullyDefined(pt)) tree setType pt //todo: eliminate
- else if (tree.tpe.symbol.isAnonymousClass) // todo: eliminate
- check(owner, scope, pt, tree setType anonymousClassRefinement(tree.tpe.symbol))
- else if (owner == NoSymbol) { // locals
- val (tparams, tp1) = existentialTransform(hiddenSymbols.reverse, tree.tpe)
-// Console.println("original type: "+tree.tpe)
-// Console.println("exist params : "+tparams)
-// Console.println("replaced type: "+tp1)
- tree setType existentialAbstraction(tparams, tp1)
-// Console.println("abstracted type: "+tree.tpe)
-// tree
- } else { // privates
+ else if (tp1.symbol.isAnonymousClass) // todo: eliminate
+ check(owner, scope, pt, tree setType anonymousClassRefinement(tp1.symbol))
+ else if (owner == NoSymbol)
+ tree setType packSymbols(hiddenSymbols.reverse, tp1)
+ else { // privates
val badSymbol = hiddenSymbols.head
error(tree.pos,
(if (badSymbol hasFlag PRIVATE) "private " else "") + badSymbol +
@@ -386,12 +380,21 @@ trait Typers { self: Analyzer =>
}
}
}
- t match {
- case TypeRef(_, sym, _) => checkNoEscape(sym)
- case SingleType(_, sym) => checkNoEscape(sym)
- case _ =>
- }
- mapOver(t)
+ mapOver(
+ t match {
+ case TypeRef(_, sym, args) =>
+ checkNoEscape(sym)
+ if (!hiddenSymbols.isEmpty && hiddenSymbols.head == sym &&
+ sym.isAliasType && sym.typeParams.length == args.length) {
+ hiddenSymbols = hiddenSymbols.tail
+ t.normalize
+ } else t
+ case SingleType(_, sym) =>
+ checkNoEscape(sym)
+ t
+ case _ =>
+ t
+ })
}
}
@@ -1253,7 +1256,8 @@ trait Typers { self: Analyzer =>
val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt)
val block1 = copy.Block(block, stats1, expr1)
.setType(if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst)
- checkNoEscaping.locals(context.scope, pt, block1)
+ //checkNoEscaping.locals(context.scope, pt, block1)
+ block1
}
/**
@@ -1279,7 +1283,7 @@ trait Typers { self: Analyzer =>
}
}
}
- body1 = checkNoEscaping.locals(context.scope, pt, body1)
+// body1 = checkNoEscaping.locals(context.scope, pt, body1)
copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
}
@@ -1340,15 +1344,15 @@ trait Typers { self: Analyzer =>
if (inIDE) // HACK to process arguments types in IDE.
typedFunctionIDE(fun, context);
val vparams = List.mapConserve(fun.vparams)(typedValDef)
- for (vparam <- vparams) {
- checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
- }
- val body = checkNoEscaping.locals(context.scope, respt, typed(fun.body, respt))
+// for (val vparam <- vparams) {
+// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
+// }
+ var body = pack(typed(fun.body, respt), fun.symbol)
val formals = vparamSyms map (_.tpe)
val restpe = body.tpe.deconst
val funtpe = typeRef(clazz.tpe.prefix, clazz, formals ::: List(restpe))
- val fun1 = copy.Function(fun, vparams, checkNoEscaping.locals(context.scope, restpe, body))
- .setType(funtpe)
+// body = checkNoEscaping.locals(context.scope, restpe, body)
+ val fun1 = copy.Function(fun, vparams, body).setType(funtpe)
if (codeExpected) {
val liftPoint = Apply(Select(Ident(CodeModule), nme.lift_), List(fun1))
typed(atPos(fun.pos)(liftPoint))
@@ -1709,21 +1713,77 @@ trait Typers { self: Analyzer =>
*/
protected def existentialTransform(rawSyms: List[Symbol], tp: Type) = {
val typeParams = rawSyms map { sym =>
- if (sym.isType) sym.cloneSymbol
- else sym.owner.newAbstractType(sym.pos, newTermName(sym.name+".Type"))//todo: change to .type
- .setInfo(mkTypeBounds(AllClass.tpe, sym.tpe))
+ val (name, bound) =
+ if (sym.isClass)
+ (sym.name,
+ mkTypeBounds(AllClass.tpe, anonymousClassRefinement(sym)))
+ else if (sym.isAbstractType)
+ (sym.name,
+ sym.info)
+ else if (sym.isTerm)
+ (newTypeName(sym.name+".type"),
+ mkTypeBounds(AllClass.tpe, intersectionType(List(sym.tpe, SingletonClass.tpe))))
+ else
+ throw new Error("unexpected alias type: "+sym)
+ sym.owner.newAbstractType(sym.pos, name) setFlag EXISTENTIAL setInfo bound
}
val typeParamTypes = typeParams map (_.tpe)
for (tparam <- typeParams) tparam.setInfo(tparam.info.subst(rawSyms, typeParamTypes))
(typeParams, tp.subst(rawSyms, typeParamTypes))
}
+ /** Compute an existential type from raw hidden symbols `syms' and type `tp'
+ */
+ def packSymbols(hidden: List[Symbol], tp: Type) =
+ if (hidden.isEmpty) tp
+ else {
+// Console.println("original type: "+tp)
+// Console.println("hidden symbols: "+hidden)
+ val (tparams, tp1) = existentialTransform(hidden, tp)
+// Console.println("tparams: "+tparams+", result: "+tp1)
+ val res = existentialAbstraction(tparams, tp1)
+// Console.println("final result: "+res)
+ res
+ }
+
+ protected def pack(tree: Tree, owner: Symbol): Tree = {
+ 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)
+ }
+ }
+ }
+ collectLocals(tree.tpe)
+ val hidden = collectLocals.symbols.reverse
+ if (hidden.isEmpty) tree
+ else Pack(tree) setType packSymbols(hidden, tree.tpe)
+ }
+
protected def typedExistentialTypeTree(tree: ExistentialTypeTree): Tree = {
- namer.enterSyms(tree.whereClauses)
- val whereClauses1 = typedStats(tree.whereClauses, NoSymbol)
+ for (val wc <- tree.whereClauses)
+ if (wc.symbol == NoSymbol) { namer.enterSym(wc); wc.symbol setFlag EXISTENTIAL }
+ else context.scope enter wc.symbol
+ val whereClauses1 = typedStats(tree.whereClauses, context.owner)
val tpt1 = typedType(tree.tpt)
val (typeParams, tpe) = existentialTransform(tree.whereClauses map (_.symbol), tpt1.tpe)
- copy.ExistentialTypeTree(tree, tpt1, whereClauses1).setType(ExistentialType(typeParams, tpe))
+ TypeTree(ExistentialType(typeParams, tpe)) setOriginal tree
}
/**
@@ -1838,7 +1898,10 @@ trait Typers { self: Analyzer =>
val rhs1 = typed(rhs, lhs1.tpe)
copy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe
} else {
- if (!lhs1.tpe.isError) error(tree.pos, "assignment to non-variable ")
+ if (!lhs1.tpe.isError) {
+ println(lhs1+" = "+rhs)
+ error(tree.pos, "assignment to non-variable ")
+ }
setError(tree)
}
}
@@ -2533,6 +2596,19 @@ 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)
@@ -2681,11 +2757,20 @@ trait Typers { self: Analyzer =>
if (tree.hasSymbol) tree.symbol = NoSymbol
}
//Console.println("typing "+tree+", "+context.undetparams);//DEBUG
- val tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, pt)
+ def dropExistential(tp: Type) = tp match {
+ case ExistentialType(tparams, tpe) =>
+ if (settings.debug.value) println("drop ex "+tree+" "+tp)
+ tpe.subst(tparams, tparams map (x => WildcardType))
+ case _ => tp
+ }
+ 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)
result
} catch {
case ex: TypeError =>
@@ -2765,7 +2850,7 @@ trait Typers { self: Analyzer =>
}
def computeType(tree: Tree, pt: Type): Type = {
- val tree1 = typed(tree, pt)
+ val tree1 = pack(typed(tree, pt), context.owner)
transformed(tree) = tree1
tree1.tpe
}