diff options
Diffstat (limited to 'sources')
-rw-r--r-- | sources/scalac/symtab/Type.java | 57 | ||||
-rw-r--r-- | sources/scalac/transformer/LambdaLift.java | 37 | ||||
-rw-r--r-- | sources/scalac/transformer/UnCurry.java | 4 | ||||
-rw-r--r-- | sources/scalac/typechecker/Analyzer.java | 318 | ||||
-rw-r--r-- | sources/scalac/util/Names.java | 1 |
5 files changed, 254 insertions, 163 deletions
diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index a11f8bea8f..0f5a7ac6d4 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -80,7 +80,11 @@ public class Type implements Modifiers, Kinds, TypeTags { public static final Type[] NO_ARRAY = new Type[0]; public static SingleType singleType(Type pre, Symbol sym) { - return new ExtSingleType(pre, sym); + if (pre.isStable() || pre == ErrorType) + return new ExtSingleType(pre, sym); + else + throw new Type.Error( + "malformed type: " + pre + "." + sym.nameString() + ".type"); } public static TypeRef appliedType(Type tycon, Type[] args) { @@ -116,6 +120,16 @@ public class Type implements Modifiers, Kinds, TypeTags { return res; } + public static Type typeRef(Type pre, Symbol sym, Type[] args) { + if (pre.isStable() || pre == ErrorType) + return TypeRef(pre, sym, args); + else if (sym.kind == ALIAS) + return pre.memberInfo(sym); + else // todo: handle Java-style inner classes + throw new Type.Error( + "malformed type: " + pre + "." + sym.nameString()); + } + static class ExtSingleType extends SingleType { Type tp = null; int definedId = -1; @@ -569,12 +583,12 @@ public class Type implements Modifiers, Kinds, TypeTags { case ThisType(_): return tp; case TypeRef(Type pre, Symbol sym, Type[] args): - Type pre1 = map(pre); + Type pre1 = apply(pre); Type[] args1 = map(args); if (pre1 == pre && args1 == args) return tp; else return TypeRef(pre1, sym, args1); case SingleType(Type pre, Symbol sym): - Type pre1 = map(pre); + Type pre1 = apply(pre); if (pre1 == pre) return tp; else return singleType(pre1, sym); case CompoundType(Type[] parts, Scope members): @@ -720,10 +734,11 @@ public class Type implements Modifiers, Kinds, TypeTags { return pre.memberInfo(sym).baseType(clazz); else if (clazz.isCompoundSym()) return NoType; - else + else { return sym.baseType(clazz) .asSeenFrom(pre, clazz.owner()) .subst(sym.typeParams(), args); + } case CompoundType(Type[] parts, _): for (int i = parts.length - 1; i >= 0; i--) { @@ -764,7 +779,15 @@ public class Type implements Modifiers, Kinds, TypeTags { this.pre = pre; this.clazz = clazz; } + public Type apply0(Type t) { + Type t1 = apply0(t); + System.out.println(t + " as seen from (" + pre + "," + clazz + ") = " + t1);//debug + return t1; + } + public Type apply(Type t) { + if (pre == NoType || clazz.kind != CLASS) + return t; switch (t) { case ThisType(Symbol sym): return t.toPrefix(pre, clazz); @@ -786,7 +809,8 @@ public class Type implements Modifiers, Kinds, TypeTags { } return t1; } else { - Type prefix1 = prefix.toPrefix(pre, clazz); + //Type prefix1 = prefix.toPrefix(pre, clazz); + Type prefix1 = apply(prefix); Symbol sym1 = (prefix1 == prefix || (sym.flags & MODUL) != 0) ? sym : prefix1.rebind(sym); boolean prevTypeArg = typeArg; @@ -799,7 +823,8 @@ public class Type implements Modifiers, Kinds, TypeTags { case SingleType(Type prefix, Symbol sym): try { - Type prefix1 = prefix.toPrefix(pre, clazz); + //Type prefix1 = prefix.toPrefix(pre, clazz); + Type prefix1 = apply(prefix); if (prefix1 == prefix) return t; else return singleType(prefix1, prefix1.rebind(sym)); } catch (Type.Error ex) { @@ -849,17 +874,10 @@ public class Type implements Modifiers, Kinds, TypeTags { Type toPrefix(Type pre, Symbol clazz) { if (pre == NoType || clazz.kind != CLASS) return this; - if (symbol().isSubClass(clazz) && - pre.symbol().isSubClass(symbol())) { - if (!pre.isStable() && pre != ErrorType) { - throw new Type.Error ( - "malformed type: " + pre + "." + symbol().nameString()); - } + else if (symbol().isSubClass(clazz) && pre.symbol().isSubClass(symbol())) return pre; - } else { - return toPrefix( - pre.baseType(clazz).prefix(), clazz.owner()); - } + else + return toPrefix(pre.baseType(clazz).prefix(), clazz.owner()); } /** This type Types as seen from prefix `pre' and class `clazz'. This means: @@ -897,10 +915,9 @@ public class Type implements Modifiers, Kinds, TypeTags { } private Type memberTransform(Symbol sym, Type tp) { - Type tp1 = tp.asSeenFrom(narrow(), sym.owner()); - Type tp2 = tp1.asSeenFrom(this, widen().symbol()); - //if (Global.instance.debug) System.out.println(this + "/" + widen() + ".memberType(" + sym + ":" + tp + ") = " + tp1 + "/" + tp2);//DEBUG - return tp2; + Type tp1 = tp.asSeenFrom(this, sym.owner()); + //if (Global.instance.debug) System.out.println(this + ".memberType(" + sym + ":" + tp + ") = " + tp1);//debug + return tp1; } // Substitutions --------------------------------------------------------------- diff --git a/sources/scalac/transformer/LambdaLift.java b/sources/scalac/transformer/LambdaLift.java index 608db61eae..48f1edf66a 100644 --- a/sources/scalac/transformer/LambdaLift.java +++ b/sources/scalac/transformer/LambdaLift.java @@ -380,6 +380,11 @@ public class LambdaLift extends OwnerTransformer } return copy.ValDef(tree, mods, name1, tpe1, rhs1); + case Tuple(Tree[] args): + Tree tree1 = mkList(tree.pos, tree.type, transform(args)); + //new scalac.ast.printer.TextTreePrinter().print("TUPLE: ").print(tree).print("\n ==> \n").print(tree1).println().end();//DEBUG + return tree1; + case Apply(Tree fn, Tree[] args): Symbol fsym = TreeInfo.methSymbol(fn); Tree fn1 = transform(fn); @@ -535,4 +540,36 @@ public class LambdaLift extends OwnerTransformer return args; } } + + Tree mkList(int pos, Type tpe, Tree[] args) { + return mkList(pos, tpe.typeArgs()[0], args, 0); + } + + Tree mkList(int pos, Type elemtpe, Tree[] args, int start) { + if (start == args.length) return mkNil(pos, elemtpe); + else return mkCons(pos, elemtpe, args[start], + mkList(pos, elemtpe, args, start + 1)); + } + + Tree mkNil(int pos, Type elemtpe) { + return gen.New( + gen.Apply( + gen.TypeApply( + gen.mkRef( + pos, + global.definitions.getClass(Names.scala_Nil).constructor()), + new Tree[]{gen.mkType(pos, elemtpe)}), + new Tree[]{})); + } + + Tree mkCons(int pos, Type elemtpe, Tree hd, Tree tl) { + return gen.New( + gen.Apply( + gen.TypeApply( + gen.mkRef( + pos, + global.definitions.getClass(Names.scala_COLONCOLON).constructor()), + new Tree[]{gen.mkType(pos, elemtpe)}), + new Tree[]{hd, tl})); + } } diff --git a/sources/scalac/transformer/UnCurry.java b/sources/scalac/transformer/UnCurry.java index 9647b43852..427c7a0efd 100644 --- a/sources/scalac/transformer/UnCurry.java +++ b/sources/scalac/transformer/UnCurry.java @@ -146,10 +146,10 @@ public class UnCurry extends OwnerTransformer private Tree[] transformArgs(int pos, Tree[] args, Type methtype) { switch (methtype) { case MethodType(Symbol[] params, _): + Tree[] args0 = args;//debug if (params.length == 1 && (params[0].flags & REPEATED) != 0) { assert (args.length != 1 || !(args[0] instanceof Tree.Tuple)); - args = new Tree[]{ - make.Tuple(pos, args).setType(params[0].type())}; + args = new Tree[]{make.Tuple(pos, args).setType(params[0].type())}; } Tree[] args1 = args; for (int i = 0; i < args.length; i++) { diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index 1a37745586..fe6a0b13d5 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -182,6 +182,24 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { error(pos, infer.typeErrorMsg("type mismatch", found, req) + explanation); } + void reportTypeError(int pos, Type.Error ex) { + if (ex instanceof CyclicReference) { + if (global.debug) ex.printStackTrace();//DEBUG + CyclicReference cyc = (CyclicReference) ex; + if (cyc.info instanceof LazyTreeType) { + switch (((LazyTreeType) cyc.info).tree) { + case ValDef(_, _, _, _): + error(pos, "recursive " + cyc.sym + " needs type"); + break; + case DefDef(_, _, _, _, _, _): + error(pos, "recursive function " + cyc.sym.name + " needs result type"); + } + } + } + //throw ex;//DEBUG + error(pos, ex.msg); + } + // Name resolution ----------------------------------------------------------- String decode(Name name) { @@ -281,6 +299,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * nested within definition of base class, or that occur within same * statement sequence. * - self-type of current class is a subtype of self-type of each parent class. + * - parent types do not refer to value parameters of class. */ void validateParentClasses(Tree[] constrs, Type[] parents, Type selfType) { if (parents.length == 0 || !checkClassType(constrs[0].pos, parents[0])) return; @@ -434,7 +453,28 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } - /** Check that + /** Check that type `tp' is not a subtype of itself. + */ + public void checkNonCyclic(int pos, Type tp) { + switch (tp) { + case TypeRef(Type pre, Symbol sym, Type[] args): + sym.initialize(); + if ((sym.flags & LOCKED) != 0) { + error(pos, "cyclic aliasing or subtyping involving " + sym); + } else if (sym.kind == ALIAS || sym.kind == TYPE) { + assert (sym.flags & LOCKED) == 0; + sym.flags |= LOCKED; + checkNonCyclic( + pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); + sym.flags &= ~LOCKED; + } + break; + case CompoundType(Type[] parents, Scope members): + for (int i = 0; i < parents.length; i++) { + checkNonCyclic(pos, parents[i]); + } + } + } /** Check that type does not refer to components defined in current scope. */ @@ -451,25 +491,23 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { public Type apply(Type t) { switch (t.unalias()) { case TypeRef(ThisType(_), Symbol sym, Type[] args): - Scope.Entry e = context.scope.lookupEntry(sym.name); - if (e.sym == sym && e.owner == context.scope) { - throw new Type.Error( - "type " + t + " escapes its defining scope"); - } else { - map(args); - return t; - } + checkNoEscape(t, sym); + break; case SingleType(ThisType(_), Symbol sym): - Scope.Entry e = context.scope.lookupEntry(sym.name); - if (e.sym == sym && e.owner == context.scope) { - return apply(t.widen()); - } else { - return t; - } - default: - return map(t); + checkNoEscape(t, sym); + break; + } + return map(t); + } + private void checkNoEscape(Type t, Symbol sym) { + Scope.Entry e = context.scope.lookupEntry(sym.name); + if (e.sym == sym && e.owner == context.scope && + !(e.sym.kind == TYPE && (e.sym.flags & PARAM) != 0)) { + throw new Type.Error( + "type " + t + " escapes its defining scope"); } - }}; + } + }; /** Check that tree represents a pure definition. */ @@ -755,122 +793,129 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Type savedPt = this.pt; this.pt = Type.AnyType; - Symbol sym = tree.symbol(); - if (global.debug) System.out.println("defining " + sym);//debug - Type owntype; - switch (tree) { - case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ): - assert (mods & LOCKED) == 0 || sym.isAnonymousClass(): sym; // to catch repeated evaluations - ((ClassDef) tree).mods |= LOCKED; - - pushContext(tree, sym.constructor(), new Scope(context.scope)); - Symbol[] tparamSyms = enterParams(tparams); - Symbol[][] vparamSyms = enterParams(vparams); - - if ((mods & CASE) != 0 && vparams.length > 0) - templ.body = desugarize.addCaseElements(templ.body, vparams[0]); - - for (int i = 0; i < vparamSyms.length; i++) - for (int j = 0; j < vparamSyms[i].length; j++) - context.scope.unlink( - context.scope.lookupEntry(vparamSyms[i][j].name)); - Type constrtype = makeMethodType( - tparamSyms, - vparamSyms, - Type.TypeRef(sym.owner().thisType(), sym, Symbol.type(tparamSyms))); - sym.constructor().setInfo(constrtype); - // necessary so that we can access tparams - sym.constructor().flags |= INITIALIZED; - if (tpe != Tree.Empty) - sym.setTypeOfThis(transform(tpe, TYPEmode).type); - - reenterParams(vparams); - defineTemplate(templ, sym); - owntype = templ.type; - popContext(); - break; + try { + Symbol sym = tree.symbol(); + if (global.debug) System.out.println("defining " + sym);//debug + Type owntype; + switch (tree) { + case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ): + if ((mods & LOCKED) != 0 && !sym.isAnonymousClass()) { + sym.setInfo(Type.ErrorType); + throw new CyclicReference(sym, Type.NoType); + } - case ModuleDef(int mods, Name name, Tree tpe, Tree.Template templ): - Symbol clazz = sym.moduleClass(); - defineTemplate(templ, clazz); - clazz.setInfo(templ.type); - if (tpe == Tree.Empty) owntype = clazz.type(); - else owntype = transform(tpe, TYPEmode).type; - break; + ((ClassDef) tree).mods |= LOCKED; - case ValDef(int mods, Name name, Tree tpe, Tree rhs): - if (tpe == Tree.Empty) { - pushContext(tree, sym, context.scope); - if (rhs == Tree.Empty) { - if ((sym.owner().flags & ACCESSOR) != 0) { - // this is the paremeter of a variable setter method. - ((ValDef) tree).tpe = tpe = - gen.mkType(tree.pos, sym.owner().accessed().type()); - } else { - error(tree.pos, "missing parameter type"); - ((ValDef) tree).tpe = tpe = - gen.mkType(tree.pos, Type.ErrorType); - } - owntype = tpe.type; - } else { - if ((mods & CASE) != 0) { - //rhs was already attributed + pushContext(tree, sym.constructor(), new Scope(context.scope)); + Symbol[] tparamSyms = enterParams(tparams); + Symbol[][] vparamSyms = enterParams(vparams); + + if ((mods & CASE) != 0 && vparams.length > 0) + templ.body = desugarize.addCaseElements(templ.body, vparams[0]); + + Type constrtype = makeMethodType( + tparamSyms, + vparamSyms, + Type.TypeRef(sym.owner().thisType(), sym, Symbol.type(tparamSyms))); + sym.constructor().setInfo(constrtype); + // necessary so that we can access tparams + sym.constructor().flags |= INITIALIZED; + + if (tpe != Tree.Empty) + sym.setTypeOfThis( + checkNoEscape(tpe.pos, transform(tpe, TYPEmode).type)); + + defineTemplate(templ, sym); + owntype = templ.type; + popContext(); + break; + + case ModuleDef(int mods, Name name, Tree tpe, Tree.Template templ): + Symbol clazz = sym.moduleClass(); + defineTemplate(templ, clazz); + clazz.setInfo(templ.type); + if (tpe == Tree.Empty) owntype = clazz.type(); + else owntype = transform(tpe, TYPEmode).type; + break; + + case ValDef(int mods, Name name, Tree tpe, Tree rhs): + if (tpe == Tree.Empty) { + pushContext(tree, sym, context.scope); + if (rhs == Tree.Empty) { + if ((sym.owner().flags & ACCESSOR) != 0) { + // this is the paremeter of a variable setter method. + ((ValDef) tree).tpe = tpe = + gen.mkType(tree.pos, sym.owner().accessed().type()); + } else { + error(tree.pos, "missing parameter type"); + ((ValDef) tree).tpe = tpe = + gen.mkType(tree.pos, Type.ErrorType); + } + owntype = tpe.type; } else { - ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode); + if ((mods & CASE) != 0) { + //rhs was already attributed + } else { + ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode); + } + owntype = rhs.type; } - owntype = rhs.type; + popContext(); + } else { + owntype = transform(tpe, TYPEmode).type; } - popContext(); - } else { - owntype = transform(tpe, TYPEmode).type; - } - break; - - case DefDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree rhs): - pushContext(tree, sym, new Scope(context.scope)); - Symbol[] tparamSyms = enterParams(tparams); - Type restpe = null; - if (tpe != Tree.Empty) { - restpe = transform(tpe, TYPEmode).type; - } - Symbol[][] vparamSyms = enterParams(vparams); - if (tpe == Tree.Empty) { - int rhsmode = name.isConstrName() ? CONSTRmode : EXPRmode; - ((DefDef) tree).rhs = rhs = transform(rhs, rhsmode); - restpe = rhs.type; - } - popContext(); - owntype = makeMethodType(tparamSyms, vparamSyms, restpe); - break; + break; - case TypeDef(int mods, Name name, Tree rhs): - //todo: alwyas have context.owner as owner. - if (sym.kind == TYPE) { - pushContext(rhs, context.owner, context.scope); - context.delayArgs = true; - owntype = transform(rhs, TYPEmode).type; - owntype.symbol().initialize();//to detect cycles - popContext(); - } else { // sym.kind == ALIAS + case DefDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree rhs): pushContext(tree, sym, new Scope(context.scope)); - owntype = transform(rhs, TYPEmode | FUNmode).type; + Symbol[] tparamSyms = enterParams(tparams); + Symbol[][] vparamSyms = enterParams(vparams); + Type restpe; + if (tpe == Tree.Empty) { + int rhsmode = name.isConstrName() ? CONSTRmode : EXPRmode; + ((DefDef) tree).rhs = rhs = transform(rhs, rhsmode); + restpe = checkNoEscape(rhs.pos, rhs.type); + } else { + restpe = checkNoEscape( + tpe.pos, transform(tpe, TYPEmode).type); + } popContext(); - } - break; + owntype = makeMethodType(tparamSyms, vparamSyms, restpe); + break; - case Import(Tree expr, Name[] selectors): - Tree expr1 = transform(expr, EXPRmode | QUALmode); - ((Import) tree).expr = expr1; - checkStable(expr1); - owntype = expr1.type; - break; + case TypeDef(int mods, Name name, Tree rhs): + //todo: alwyas have context.owner as owner. + if (sym.kind == TYPE) { + pushContext(rhs, context.owner, context.scope); + context.delayArgs = true; + owntype = transform(rhs, TYPEmode).type; + owntype.symbol().initialize();//to detect cycles + popContext(); + } else { // sym.kind == ALIAS + pushContext(tree, sym, new Scope(context.scope)); + owntype = transform(rhs, TYPEmode | FUNmode).type; + popContext(); + } + checkNonCyclic(tree.pos, owntype); + break; - default: - throw new ApplicationError(); + case Import(Tree expr, Name[] selectors): + Tree expr1 = transform(expr, EXPRmode | QUALmode); + ((Import) tree).expr = expr1; + checkStable(expr1); + owntype = expr1.type; + break; + + default: + throw new ApplicationError(); + } + sym.setInfo(owntype); + validate(sym); + if (global.debug) System.out.println("defined " + sym);//debug + } catch (Type.Error ex) { + reportTypeError(tree.pos, ex); } - sym.setInfo(owntype); - validate(sym); - if (global.debug) System.out.println("defined " + sym);//debug + this.unit = savedUnit; this.context = savedContext; this.mode = savedMode; @@ -1167,8 +1212,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { pushContext(constrs[i], context.owner, context.scope); context.delayArgs = delayArgs; constrs[i] = transform(constrs[i], CONSTRmode, pt); - if (constrs[i].hasSymbol()) - constrs[i].symbol().initialize();//to detect cycles + Symbol c = TreeInfo.methSymbol(constrs[i]).primaryConstructorClass(); + if (c.kind == CLASS) c.initialize();//to detect cycles popContext(); } return constrs; @@ -1590,10 +1635,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { pushContext(tree, sym.constructor(), new Scope(context.scope)); reenterParams(tparams); Tree.TypeDef[] tparams1 = transform(tparams); - Tree tpe1 = transform(tpe); reenterParams(vparams); Tree.ValDef[][] vparams1 = transform(vparams); + Tree tpe1 = transform(tpe); Tree.Template templ1 = transformTemplate(templ, sym); + for (int i = 0; i < templ1.parents.length; i++) + checkNoEscape(templ1.parents[i].pos, templ1.parents[i].type); + if ((sym.flags & ABSTRACTCLASS) == 0 && !sym.type().isSubType(sym.typeOfThis())) error(sym.pos, sym + @@ -1631,9 +1679,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { pushContext(tree, sym, new Scope(context.scope)); reenterParams(tparams); Tree.TypeDef[] tparams1 = transform(tparams); - Tree tpe1 = transform(tpe, TYPEmode); reenterParams(vparams); Tree.ValDef[][] vparams1 = transform(vparams); + Tree tpe1 = transform(tpe, TYPEmode); Tree rhs1 = rhs; if (tpe1 == Tree.Empty) { tpe1 = gen.mkType(rhs1.pos, rhs1.type); @@ -2018,20 +2066,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { throw new ApplicationError("illegal tree: " + tree); } } catch (Type.Error ex) { - if (ex instanceof CyclicReference) { - if (global.debug) ex.printStackTrace();//DEBUG - CyclicReference cyc = (CyclicReference) ex; - if (cyc.info instanceof LazyTreeType) { - switch (((LazyTreeType) cyc.info).tree) { - case ValDef(_, _, _, _): - return error(tree, "recursive " + cyc.sym + " needs type"); - case DefDef(_, _, _, _, _, _): - return error(tree, "recursive function " + cyc.sym.name + " needs result type"); - } - } - } - throw ex;//debug - //return error(tree, ex.msg); + reportTypeError(tree.pos, ex); + return tree; } } diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index c54f044f06..a70d6beedb 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -75,6 +75,7 @@ public class Names { public static final Name predef = Name.fromString("predef"); public static final Name runtime = Name.fromString("runtime"); public static final Name scala = Name.fromString("scala"); + public static final Name scala_COLONCOLON = Name.fromString("scala." + COLONCOLON); public static final Name scala_Algebraic = Name.fromString("scala.Algebraic"); public static final Name scala_Any = Name.fromString("scala.Any"); public static final Name scala_AnyRef = Name.fromString("scala.AnyRef"); |