From 28d40d21d0d29ff4c2f002090eeafd2c53817c64 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 10 Apr 2007 17:51:34 +0000 Subject: more changes to support early inits. --- src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 52 ++++----- .../scala/tools/nsc/ast/parser/Parsers.scala | 3 +- .../scala/tools/nsc/typechecker/Typers.scala | 121 +++++++++++++-------- 3 files changed, 100 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index e47183f146..66dc60fe45 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -117,28 +117,22 @@ abstract class TreeInfo { /** Is tree a self constructor call? */ - def isSelfConstrCall(tree: Tree): boolean = tree match { - case Ident(nme.CONSTRUCTOR) => - true - case Select(This(_), nme.CONSTRUCTOR) => - true - case TypeApply(constr, _) => - isSelfConstrCall(constr) - case Apply(constr, _) => - isSelfConstrCall(constr) - case _ => - false + def isSelfConstrCall(tree: Tree): boolean = methPart(tree) match { + case Ident(nme.CONSTRUCTOR) + | Select(This(_), nme.CONSTRUCTOR) => true + case _ => false } - def isSuperConstrCall(tree: Tree): boolean = tree match { - case Select(Super(_, _), nme.CONSTRUCTOR) => - true - case TypeApply(constr, _) => - isSuperConstrCall(constr) - case Apply(constr, _) => - isSuperConstrCall(constr) - case _ => - false + def isSuperConstrCall(tree: Tree): boolean = methPart(tree) match { + case Select(Super(_, _), nme.CONSTRUCTOR) => true + case _ => false + } + + def isSelfOrSuperConstrCall(tree: Tree): boolean = methPart(tree) match { + case Ident(nme.CONSTRUCTOR) + | Select(This(_), nme.CONSTRUCTOR) + | Select(Super(_, _), nme.CONSTRUCTOR) => true + case _ => false } /** Is tree a variable pattern */ @@ -155,15 +149,9 @@ abstract class TreeInfo { case _ :: stats1 => firstConstructor(stats1) } - /** The reference to super in the body of a primary constructor */ - def superRef(tree: Tree): Tree = tree match { - case Block(stats, _) if !stats.isEmpty => superRef(stats.last) - case Apply(sr, _) => sr - case _ => EmptyTree - } - /** The value definitions marked PRESUPER in this statement sequence */ - def preSuperFields(stats: List[Tree]) = stats filter isPreSuper + def preSuperFields(stats: List[Tree]): List[ValDef] = + for (val vdef @ ValDef(mods, _, _, _) <- stats; mods hasFlag PRESUPER) yield vdef def isPreSuper(tree: Tree) = tree match { case ValDef(mods, _, _, _) => mods hasFlag PRESUPER @@ -273,6 +261,14 @@ abstract class TreeInfo { case _ => tree } + def firstArgument(tree: Tree): Tree = tree match { + case Apply(fn, args) => + val f = firstArgument(fn) + if (f == EmptyTree && !args.isEmpty) args.head else f + case _ => + EmptyTree + } + /** Top-level definition sequence contains a leading import of Predef or scala.Predef */ def containsLeadingPredefImport(defs: List[Tree]): boolean = defs match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 061aab47a9..1868ab2108 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1170,7 +1170,8 @@ trait Parsers requires SyntaxAnalyzer { /** Generator ::= val Pattern1 `<-' Expr */ def generator(eqOK: boolean): Enumerator = { - val pos = accept(VAL) + val pos = in.currentPos; + if (in.token == VAL) in.nextToken() val pat = pattern1(false) val tok = in.token if (tok == EQUALS && eqOK) in.nextToken() diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 60cfcac73f..326597fe99 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -125,8 +125,7 @@ trait Typers requires Analyzer { private def funMode(mode: int) = mode & (stickyModes | SCCmode) | FUNmode | POLYmode private def argMode(fun: Tree, mode: int) = - if (treeInfo.isSelfConstrCall(fun) || treeInfo.isSuperConstrCall(fun)) mode | SCCmode - else mode + if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode private var xxx = 10; class Typer(context0: Context) { @@ -566,7 +565,7 @@ trait Typers requires Analyzer { inferExprInstance(tree, tparams, pt) adapt(tree, mode, pt) } else { - val typer1 = constrTyperIf(treeInfo.isSelfConstrCall(tree) || treeInfo.isSuperConstrCall(tree)) + val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree)) typer1.typed(typer1.applyImplicitArgs(tree), mode, pt) } case mt: MethodType @@ -738,19 +737,18 @@ trait Typers requires Analyzer { if (member(qual, name) != NoSymbol) qual else adaptToMember(qual, name, WildcardType) - private def completeParentType(tpt: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]], superargs: List[Tree]): Type = { + private def typePrimaryConstrBody(cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { enclTparams foreach context.scope.enter namer.enterValueParams(context.owner, vparamss) - val newTree = New(tpt) - .setType(PolyType(tparams, appliedType(tpt.tpe, tparams map (.tpe)))) - val tree = typed(atPos(tpt.pos)(Apply(Select(newTree, nme.CONSTRUCTOR), superargs))) - if (settings.debug.value) log("superconstr "+tree+" co = "+context.owner);//debug - tree.tpe + typed(cbody) } - def parentTypes(templ: Template): List[Tree] = try { + def parentTypes(templ: Template): List[Tree] = if (templ.parents.isEmpty) List() - else { + else try { + val clazz = context.owner + + // Normalize supertype and mixins so that supertype is always a class, not a trait. var supertpt = typedTypeConstructor(templ.parents.head) val firstParent = supertpt.tpe.symbol var mixins = templ.parents.tail map typedType @@ -762,43 +760,71 @@ trait Typers requires Analyzer { supertpt = TypeTree(supertpt1.tpe.parents.head) setOriginal supertpt /* setPos supertpt.pos */ } } - val constr = treeInfo.firstConstructor(templ.body) - if (supertpt.tpe.symbol != firstParent) { - constr match { - case DefDef(_, _, _, _, _, Block(List(Apply(_, superargs)), _)) => - if (!superargs.isEmpty) - error(superargs.head.pos, firstParent+" is a trait; does not take constructor arguments") - case _ => - } + + // Determine + // - supertparams: Missing type parameters from supertype + // - supertpe: Given supertype, polymorphic in supertparams + val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else List() + var supertpe = supertpt.tpe + if (!supertparams.isEmpty) + supertpe = PolyType(supertparams, appliedType(supertpe, supertparams map (.tpe))) + + // A method to replace a super reference by a New in a supercall + def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { + case Apply(fn, args) => + copy.Apply(scall, transformSuperCall(fn), args) + case Select(Super(_, _), nme.CONSTRUCTOR) => + copy.Select( + scall, + New(TypeTree(supertpe) setOriginal supertpt) setType supertpe setPos supertpt.pos, + nme.CONSTRUCTOR) } - if (supertpt.hasSymbol) { - val tparams = supertpt.symbol.typeParams - if (!tparams.isEmpty) { - constr match { - case EmptyTree => - error(supertpt.pos, "missing type arguments") - case DefDef(_, _, _, vparamss, _, Block(List(Apply(_, superargs)), _)) => - val outercontext = context.outer - supertpt = TypeTree( - newTyper(makeNewScope(outercontext, constr, outercontext.owner)) - .completeParentType( - supertpt, - tparams, - context.owner.unsafeTypeParams, - vparamss map (.map(.duplicate)), - superargs map (.duplicate))) setOriginal supertpt /* setPos supertpt.pos */ + + treeInfo.firstConstructor(templ.body) match { + case constr @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => + // Convert constructor body to block in environment and typecheck it + val cstats1: List[Tree] = cstats map (.duplicate) + val scall = if (cstats.isEmpty) EmptyTree else cstats.last + val cbody1 = scall match { + case Apply(_, _) => + copy.Block(cbody, cstats1.init, + if (supertparams.isEmpty) cunit.duplicate + else transformSuperCall(scall)) + case _ => + copy.Block(cbody, cstats1, cunit.duplicate) } - } + + val outercontext = context.outer + val cbody2 = + newTyper(makeNewScope(outercontext, constr, outercontext.owner)) + .typePrimaryConstrBody( + cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (.map(.duplicate))) + + scall match { + case Apply(_, _) => + val sarg = treeInfo.firstArgument(scall) + if (sarg != EmptyTree && supertpe.symbol != firstParent) + error(sarg.pos, firstParent+" is a trait; does not take constructor arguments") + if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos + case _ => + if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") + } + + List.map2(cstats1, treeInfo.preSuperFields(templ.body)) { + (ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe + } + case _ => + if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") } - //Console.println("parents("+context.owner+") = "+supertpt :: mixins);//DEBUG - List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(context.owner, tpt)) + + //Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG + List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(clazz, tpt)) + } catch { + case ex: TypeError => + templ.tpe = null + reportTypeError(templ.pos, ex) + List(TypeTree(AnyRefClass.tpe)) } - } catch { - case ex: TypeError => - templ.tpe = null - reportTypeError(templ.pos, ex) - List(TypeTree(AnyRefClass.tpe)) - } /**

Check that

*