From a16dd265fddd7da26564109f4026fb1d12c1071a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 6 Mar 2003 19:14:59 +0000 Subject: *** empty log message *** --- sources/scalac/symtab/Type.java | 57 ++++-- sources/scalac/transformer/LambdaLift.java | 37 ++++ sources/scalac/transformer/UnCurry.java | 4 +- sources/scalac/typechecker/Analyzer.java | 318 ++++++++++++++++------------- sources/scalac/util/Names.java | 1 + test/files/neg/S2.scala | 19 ++ test/files/neg/S4.scala | 11 + test/files/neg/S6.scala | 12 ++ test/files/neg/S7.scala | 7 + test/files/neg/vincent.scala | 21 ++ test/files/neg/vincent1.scala | 17 ++ test/files/pos/S1.scala | 13 ++ test/files/pos/S3.scala | 14 ++ test/files/pos/S5.scala | 30 +++ test/files/pos/S8.scala | 19 ++ test/files/pos/philippe3.scala | 40 ++++ test/files/pos/scall.bat | 50 +++++ test/neg/S2.scala | 19 ++ test/neg/S4.scala | 11 + test/neg/S6.scala | 12 ++ test/neg/S7.scala | 7 + test/neg/vincent.scala | 21 ++ test/neg/vincent1.scala | 17 ++ test/pos/S1.scala | 13 ++ test/pos/S3.scala | 14 ++ test/pos/S5.scala | 30 +++ test/pos/S8.scala | 19 ++ test/pos/philippe3.scala | 40 ++++ test/pos/scall.bat | 50 +++++ 29 files changed, 760 insertions(+), 163 deletions(-) create mode 100644 test/files/neg/S2.scala create mode 100644 test/files/neg/S4.scala create mode 100644 test/files/neg/S6.scala create mode 100644 test/files/neg/S7.scala create mode 100644 test/files/neg/vincent.scala create mode 100644 test/files/neg/vincent1.scala create mode 100644 test/files/pos/S1.scala create mode 100644 test/files/pos/S3.scala create mode 100644 test/files/pos/S5.scala create mode 100644 test/files/pos/S8.scala create mode 100644 test/files/pos/philippe3.scala create mode 100644 test/files/pos/scall.bat create mode 100644 test/neg/S2.scala create mode 100644 test/neg/S4.scala create mode 100644 test/neg/S6.scala create mode 100644 test/neg/S7.scala create mode 100644 test/neg/vincent.scala create mode 100644 test/neg/vincent1.scala create mode 100644 test/pos/S1.scala create mode 100644 test/pos/S3.scala create mode 100644 test/pos/S5.scala create mode 100644 test/pos/S8.scala create mode 100644 test/pos/philippe3.scala create mode 100644 test/pos/scall.bat 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"); diff --git a/test/files/neg/S2.scala b/test/files/neg/S2.scala new file mode 100644 index 0000000000..83cc1829a3 --- /dev/null +++ b/test/files/neg/S2.scala @@ -0,0 +1,19 @@ +/* I was wondering for a long time what types x and y have; +** the compiler claims: z.Inner (see commented out line) +** This is strange because z is not in scope. +** Furthermore, compilation of this class yields the message: (why?) +** +** S2.scala:16: illegal cyclic reference involving value t +** def t = foo(x, y); +** ^ +*/ +module M { + def foo[T](x: T, y: T): T = x; + class S2() { + class Inner() extends S2() {} + def x = { val z = new S2(); new z.Inner(); } + def y = { val z = new S2(); new z.Inner(); } + def t = foo(x, y); + //def testType: Inner = x; + } +} diff --git a/test/files/neg/S4.scala b/test/files/neg/S4.scala new file mode 100644 index 0000000000..4f7941082f --- /dev/null +++ b/test/files/neg/S4.scala @@ -0,0 +1,11 @@ +/* This one compiles, but even if we would have dependent +** constructor types, it would be not sound. +*/ +class S4(a: Other) extends a.Inner() { + def foo(x: a.Inner) = x; + val b = new Other(); + foo(new S4(b)) +} +class Other() { + class Inner() {} +} diff --git a/test/files/neg/S6.scala b/test/files/neg/S6.scala new file mode 100644 index 0000000000..dfe53d22bd --- /dev/null +++ b/test/files/neg/S6.scala @@ -0,0 +1,12 @@ +/* This program puts the compiler into an endless loop +*/ +trait T1 { + type T; +} +trait T2 { + type S; + type T <: S; +} +abstract class S6() extends T1 with T2 { + type S <: T; +} diff --git a/test/files/neg/S7.scala b/test/files/neg/S7.scala new file mode 100644 index 0000000000..ecb801b9dc --- /dev/null +++ b/test/files/neg/S7.scala @@ -0,0 +1,7 @@ +/* Another example for a non-terminating compiler run. +*/ +class S7[T]() { + val a: S7[T] = this; + class A() extends a.C() {} + class C() extends a.A() {} +} diff --git a/test/files/neg/vincent.scala b/test/files/neg/vincent.scala new file mode 100644 index 0000000000..0af526d6aa --- /dev/null +++ b/test/files/neg/vincent.scala @@ -0,0 +1,21 @@ +module test { + + trait A { type T; } + + trait B { type T; } + + /** def functor(x: A): B with { type T = x.T } */ + abstract class functor() { + val arg: A; + val res: B with { type T = arg.T } = + new B with { type T = arg.T; }; + } + + val a = new A with { type T = String }; + /** val b: B with { type T = String } = functor(a) */ + val b: B with { type T = String } = { + val tmp = new functor() with { val arg = a }; + tmp.res + } + +} diff --git a/test/files/neg/vincent1.scala b/test/files/neg/vincent1.scala new file mode 100644 index 0000000000..afcb9a94f4 --- /dev/null +++ b/test/files/neg/vincent1.scala @@ -0,0 +1,17 @@ +module test { + + trait A { type T; } + + trait B { type T; } + + def functor(x: A): B with { type T = x.T } = + new B with { + type T = x.T; + }; + + val a = new A with { type T = String }; + val b = functor(a); + + val s: b.T = "coucou"; + +} diff --git a/test/files/pos/S1.scala b/test/files/pos/S1.scala new file mode 100644 index 0000000000..eba81109b3 --- /dev/null +++ b/test/files/pos/S1.scala @@ -0,0 +1,13 @@ +/* This is probably no bug, I just don't understand why +** type inference does not find the right instantiation of foo. +** Currently it reports: +** +** S1.scala:12: inferred type arguments [S1] do not conform to +** method foo's type parameter bounds [T <: S1.this.type] +** foo(this); +** ^ +*/ +class S1() { + def foo[T <: this.type](x: T) = x; + foo(this); +} diff --git a/test/files/pos/S3.scala b/test/files/pos/S3.scala new file mode 100644 index 0000000000..1e0f0288b1 --- /dev/null +++ b/test/files/pos/S3.scala @@ -0,0 +1,14 @@ +/* Why does this code fail? b has type a.type, so the third +** declaration in S3 should be okay... The compiler writes instead: +** +** found : S3.this.b.type (with underlying type S3) +** required: S3.this.a.type +** val c: a.type = b; +** ^ +** Without declaration 3, everything is fine. +*/ +class S3() { + val a = new S3(); + val b: a.type = a; + val c: a.type = b; +} diff --git a/test/files/pos/S5.scala b/test/files/pos/S5.scala new file mode 100644 index 0000000000..87325b47e4 --- /dev/null +++ b/test/files/pos/S5.scala @@ -0,0 +1,30 @@ +/* Here's a fragment of a Scala encoding for the Keris module system; +** the compiler claims: +** +** S5.scala:28: value n in class N of type N.this._N.n +** cannot override value n in class M of type M.this._N.n +** val system = new M() with N() {} +** ^ +** To me it seems like the code is perfectly fine... +*/ +abstract class M() { + val _N: N; + val n: _N.n; + val _M: M = this; + val m: _M.m = new _M.m(); + class m() { + // module body of M + } +} +abstract class N() { + val _N: N = this; + val n: _N.n = new _N.n(); + val _M: M; + val m: _M.m; + class n() { + // module body of N + } +} +module O { + val system = new M() with N() {} +} diff --git a/test/files/pos/S8.scala b/test/files/pos/S8.scala new file mode 100644 index 0000000000..e4339bb3f1 --- /dev/null +++ b/test/files/pos/S8.scala @@ -0,0 +1,19 @@ +/* I believe this code is correct, but the compiler rejects it: +** +** S8.scala:18: type mismatch; +** found : M.x.A +** required: M.x.a.B +** val y: x.a.B = new x.A(); //correct? +** ^ +** For a given value x of type S8, type x.A should be +** a subtype of x.a.B. +*/ +class S8() { + val a: S8 = this; + class A() extends a.B() {} + class B() {} +} +module M { + val x = new S8(); + val y: x.a.B = new x.A(); //correct? +} diff --git a/test/files/pos/philippe3.scala b/test/files/pos/philippe3.scala new file mode 100644 index 0000000000..d99ec41f52 --- /dev/null +++ b/test/files/pos/philippe3.scala @@ -0,0 +1,40 @@ + +class Foo(x: Int) {} +case class Bar(y: Int) extends Foo(y); + + +trait T {} +trait U {} +class C() {} + + +trait T1; +trait T2 {} +trait T5 extends T; +trait T6 extends T {} +trait T7 extends T with U; +trait T8 extends T with U {} + +class C1(); +class C2() {} +class C5() extends C(); +class C6() extends C() {} +class C7() extends C() with U; +class C8() extends C() with U {} + +case class D1(); +case class D2() {} +case class D5() extends C(); +case class D6() extends C() {} +case class D7() extends C() with U; +case class D8() extends C() with U {} + +module M1; +module M2 {} +module M5 extends C(); +module M6 extends C() {} +module M7 extends C() with U; +module M8 extends C() with U {} + + + diff --git a/test/files/pos/scall.bat b/test/files/pos/scall.bat new file mode 100644 index 0000000000..4e9f31425e --- /dev/null +++ b/test/files/pos/scall.bat @@ -0,0 +1,50 @@ +scalac -prompt A.scala; +scalac -prompt IntSet.scala; +scalac -prompt List1.scala; +scalac -prompt Rational.scala; +scalac -prompt X.scala; +scalac -prompt Y.scala; +scalac -prompt Z.scala; +scalac -prompt abstract.scala; +scalac -prompt cls.scala; +scalac -prompt cls1.scala; +scalac -prompt clsrefine.scala; +scalac -prompt cours1.scala; +scalac -prompt cours2.scala; +scalac -prompt cours2a.scala; +scalac -prompt cours2b.scala; +scalac -prompt cours2c.scala; +scalac -prompt eta.scala; +scalac -prompt exceptions.scala; +scalac -prompt imports.scala; +scalac -prompt lambda.scala; +scalac -prompt lambdalift.scala; +scalac -prompt lambdalift1.scala; +scalac -prompt matthias1.scala; +scalac -prompt maxim1.scala; +scalac -prompt michel1.scala; +scalac -prompt michel2.scala; +scalac -prompt michel3.scala; +scalac -prompt michel4.scala; +scalac -prompt michel5.scala; +scalac -prompt modules.scala; +scalac -prompt modules1.scala; +scalac -prompt moduletrans.scala; +scalac -prompt nested.scala; +scalac -prompt override.scala; +scalac -prompt patterns.scala; +scalac -prompt patterns2.scala; +scalac -prompt philippe1.scala; +scalac -prompt philippe2.scala; +scalac -prompt reftest.scala; +scalac -prompt sort1.scala; +scalac -prompt sqrt.scala; +scalac -prompt stable.scala; +scalac -prompt strings.scala; +scalac -prompt test1.scala; +scalac -prompt test2.scala; +scalac -prompt test4.scala; +scalac -prompt test4a.scala; +scalac -prompt test4refine.scala; +scalac -prompt test5.scala; +scalac -prompt test5refine.scala; diff --git a/test/neg/S2.scala b/test/neg/S2.scala new file mode 100644 index 0000000000..83cc1829a3 --- /dev/null +++ b/test/neg/S2.scala @@ -0,0 +1,19 @@ +/* I was wondering for a long time what types x and y have; +** the compiler claims: z.Inner (see commented out line) +** This is strange because z is not in scope. +** Furthermore, compilation of this class yields the message: (why?) +** +** S2.scala:16: illegal cyclic reference involving value t +** def t = foo(x, y); +** ^ +*/ +module M { + def foo[T](x: T, y: T): T = x; + class S2() { + class Inner() extends S2() {} + def x = { val z = new S2(); new z.Inner(); } + def y = { val z = new S2(); new z.Inner(); } + def t = foo(x, y); + //def testType: Inner = x; + } +} diff --git a/test/neg/S4.scala b/test/neg/S4.scala new file mode 100644 index 0000000000..4f7941082f --- /dev/null +++ b/test/neg/S4.scala @@ -0,0 +1,11 @@ +/* This one compiles, but even if we would have dependent +** constructor types, it would be not sound. +*/ +class S4(a: Other) extends a.Inner() { + def foo(x: a.Inner) = x; + val b = new Other(); + foo(new S4(b)) +} +class Other() { + class Inner() {} +} diff --git a/test/neg/S6.scala b/test/neg/S6.scala new file mode 100644 index 0000000000..dfe53d22bd --- /dev/null +++ b/test/neg/S6.scala @@ -0,0 +1,12 @@ +/* This program puts the compiler into an endless loop +*/ +trait T1 { + type T; +} +trait T2 { + type S; + type T <: S; +} +abstract class S6() extends T1 with T2 { + type S <: T; +} diff --git a/test/neg/S7.scala b/test/neg/S7.scala new file mode 100644 index 0000000000..ecb801b9dc --- /dev/null +++ b/test/neg/S7.scala @@ -0,0 +1,7 @@ +/* Another example for a non-terminating compiler run. +*/ +class S7[T]() { + val a: S7[T] = this; + class A() extends a.C() {} + class C() extends a.A() {} +} diff --git a/test/neg/vincent.scala b/test/neg/vincent.scala new file mode 100644 index 0000000000..0af526d6aa --- /dev/null +++ b/test/neg/vincent.scala @@ -0,0 +1,21 @@ +module test { + + trait A { type T; } + + trait B { type T; } + + /** def functor(x: A): B with { type T = x.T } */ + abstract class functor() { + val arg: A; + val res: B with { type T = arg.T } = + new B with { type T = arg.T; }; + } + + val a = new A with { type T = String }; + /** val b: B with { type T = String } = functor(a) */ + val b: B with { type T = String } = { + val tmp = new functor() with { val arg = a }; + tmp.res + } + +} diff --git a/test/neg/vincent1.scala b/test/neg/vincent1.scala new file mode 100644 index 0000000000..afcb9a94f4 --- /dev/null +++ b/test/neg/vincent1.scala @@ -0,0 +1,17 @@ +module test { + + trait A { type T; } + + trait B { type T; } + + def functor(x: A): B with { type T = x.T } = + new B with { + type T = x.T; + }; + + val a = new A with { type T = String }; + val b = functor(a); + + val s: b.T = "coucou"; + +} diff --git a/test/pos/S1.scala b/test/pos/S1.scala new file mode 100644 index 0000000000..eba81109b3 --- /dev/null +++ b/test/pos/S1.scala @@ -0,0 +1,13 @@ +/* This is probably no bug, I just don't understand why +** type inference does not find the right instantiation of foo. +** Currently it reports: +** +** S1.scala:12: inferred type arguments [S1] do not conform to +** method foo's type parameter bounds [T <: S1.this.type] +** foo(this); +** ^ +*/ +class S1() { + def foo[T <: this.type](x: T) = x; + foo(this); +} diff --git a/test/pos/S3.scala b/test/pos/S3.scala new file mode 100644 index 0000000000..1e0f0288b1 --- /dev/null +++ b/test/pos/S3.scala @@ -0,0 +1,14 @@ +/* Why does this code fail? b has type a.type, so the third +** declaration in S3 should be okay... The compiler writes instead: +** +** found : S3.this.b.type (with underlying type S3) +** required: S3.this.a.type +** val c: a.type = b; +** ^ +** Without declaration 3, everything is fine. +*/ +class S3() { + val a = new S3(); + val b: a.type = a; + val c: a.type = b; +} diff --git a/test/pos/S5.scala b/test/pos/S5.scala new file mode 100644 index 0000000000..87325b47e4 --- /dev/null +++ b/test/pos/S5.scala @@ -0,0 +1,30 @@ +/* Here's a fragment of a Scala encoding for the Keris module system; +** the compiler claims: +** +** S5.scala:28: value n in class N of type N.this._N.n +** cannot override value n in class M of type M.this._N.n +** val system = new M() with N() {} +** ^ +** To me it seems like the code is perfectly fine... +*/ +abstract class M() { + val _N: N; + val n: _N.n; + val _M: M = this; + val m: _M.m = new _M.m(); + class m() { + // module body of M + } +} +abstract class N() { + val _N: N = this; + val n: _N.n = new _N.n(); + val _M: M; + val m: _M.m; + class n() { + // module body of N + } +} +module O { + val system = new M() with N() {} +} diff --git a/test/pos/S8.scala b/test/pos/S8.scala new file mode 100644 index 0000000000..e4339bb3f1 --- /dev/null +++ b/test/pos/S8.scala @@ -0,0 +1,19 @@ +/* I believe this code is correct, but the compiler rejects it: +** +** S8.scala:18: type mismatch; +** found : M.x.A +** required: M.x.a.B +** val y: x.a.B = new x.A(); //correct? +** ^ +** For a given value x of type S8, type x.A should be +** a subtype of x.a.B. +*/ +class S8() { + val a: S8 = this; + class A() extends a.B() {} + class B() {} +} +module M { + val x = new S8(); + val y: x.a.B = new x.A(); //correct? +} diff --git a/test/pos/philippe3.scala b/test/pos/philippe3.scala new file mode 100644 index 0000000000..d99ec41f52 --- /dev/null +++ b/test/pos/philippe3.scala @@ -0,0 +1,40 @@ + +class Foo(x: Int) {} +case class Bar(y: Int) extends Foo(y); + + +trait T {} +trait U {} +class C() {} + + +trait T1; +trait T2 {} +trait T5 extends T; +trait T6 extends T {} +trait T7 extends T with U; +trait T8 extends T with U {} + +class C1(); +class C2() {} +class C5() extends C(); +class C6() extends C() {} +class C7() extends C() with U; +class C8() extends C() with U {} + +case class D1(); +case class D2() {} +case class D5() extends C(); +case class D6() extends C() {} +case class D7() extends C() with U; +case class D8() extends C() with U {} + +module M1; +module M2 {} +module M5 extends C(); +module M6 extends C() {} +module M7 extends C() with U; +module M8 extends C() with U {} + + + diff --git a/test/pos/scall.bat b/test/pos/scall.bat new file mode 100644 index 0000000000..4e9f31425e --- /dev/null +++ b/test/pos/scall.bat @@ -0,0 +1,50 @@ +scalac -prompt A.scala; +scalac -prompt IntSet.scala; +scalac -prompt List1.scala; +scalac -prompt Rational.scala; +scalac -prompt X.scala; +scalac -prompt Y.scala; +scalac -prompt Z.scala; +scalac -prompt abstract.scala; +scalac -prompt cls.scala; +scalac -prompt cls1.scala; +scalac -prompt clsrefine.scala; +scalac -prompt cours1.scala; +scalac -prompt cours2.scala; +scalac -prompt cours2a.scala; +scalac -prompt cours2b.scala; +scalac -prompt cours2c.scala; +scalac -prompt eta.scala; +scalac -prompt exceptions.scala; +scalac -prompt imports.scala; +scalac -prompt lambda.scala; +scalac -prompt lambdalift.scala; +scalac -prompt lambdalift1.scala; +scalac -prompt matthias1.scala; +scalac -prompt maxim1.scala; +scalac -prompt michel1.scala; +scalac -prompt michel2.scala; +scalac -prompt michel3.scala; +scalac -prompt michel4.scala; +scalac -prompt michel5.scala; +scalac -prompt modules.scala; +scalac -prompt modules1.scala; +scalac -prompt moduletrans.scala; +scalac -prompt nested.scala; +scalac -prompt override.scala; +scalac -prompt patterns.scala; +scalac -prompt patterns2.scala; +scalac -prompt philippe1.scala; +scalac -prompt philippe2.scala; +scalac -prompt reftest.scala; +scalac -prompt sort1.scala; +scalac -prompt sqrt.scala; +scalac -prompt stable.scala; +scalac -prompt strings.scala; +scalac -prompt test1.scala; +scalac -prompt test2.scala; +scalac -prompt test4.scala; +scalac -prompt test4a.scala; +scalac -prompt test4refine.scala; +scalac -prompt test5.scala; +scalac -prompt test5refine.scala; -- cgit v1.2.3