diff options
author | Martin Odersky <odersky@gmail.com> | 2007-06-09 13:03:55 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2007-06-09 13:03:55 +0000 |
commit | 8414ebada9615aac0e8b436e7bdbeee5986ccaa3 (patch) | |
tree | f62c23aec3d9f49446aebd76963667be8468f48d /src/compiler/scala/tools/nsc/typechecker | |
parent | 6ad83dae6960a78d6014c6fcfee1889a322ad5d7 (diff) | |
download | scala-8414ebada9615aac0e8b436e7bdbeee5986ccaa3.tar.gz scala-8414ebada9615aac0e8b436e7bdbeee5986ccaa3.tar.bz2 scala-8414ebada9615aac0e8b436e7bdbeee5986ccaa3.zip |
added existential types
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
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 } |