From 76993fa93bc39bab65e61b4fa9a3887befd48372 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 11 Oct 2005 20:28:06 +0000 Subject: *** empty log message *** --- sources/scala/reflect/Symbol.scala | 4 +- sources/scala/reflect/Type.scala | 3 +- sources/scala/tools/nsc/ast/parser/Parsers.scala | 10 +- sources/scala/tools/nsc/ast/parser/Scanners.scala | 1 + sources/scala/tools/nsc/ast/parser/Tokens.scala | 1 + sources/scala/tools/nsc/symtab/StdNames.scala | 1 + sources/scala/tools/nsc/symtab/Symbols.scala | 5 + sources/scala/tools/nsc/transform/Erasure.scala | 18 ++- .../scala/tools/nsc/typechecker/Codification.scala | 125 +++++++++++++-------- sources/scala/tools/nsc/typechecker/Typers.scala | 17 +-- test-nsc/files/pos/code.scala | 3 + test-nsc/files/run/bug457.scala | 36 ++++++ 12 files changed, 161 insertions(+), 63 deletions(-) create mode 100755 test-nsc/files/pos/code.scala create mode 100755 test-nsc/files/run/bug457.scala diff --git a/sources/scala/reflect/Symbol.scala b/sources/scala/reflect/Symbol.scala index d0368edd72..14be8e9317 100755 --- a/sources/scala/reflect/Symbol.scala +++ b/sources/scala/reflect/Symbol.scala @@ -25,7 +25,7 @@ abstract class GlobalSymbol(val fullname: String) extends Symbol { abstract class LocalSymbol extends Symbol {} case class Class(override val fullname: String) extends GlobalSymbol(fullname) { - val tpe = TypeIdent(ThisType(owner), this); + val tpe = NamedType(fullname); } case class Method(override val fullname: String, tpe: Type) extends GlobalSymbol(fullname); @@ -47,5 +47,5 @@ case object NoSymbol extends Symbol { case object RootSymbol extends Symbol { val owner = NoSymbol; val name = ""; - val tpe = TypeIdent(NoPrefix, this) + val tpe = NoPrefix } diff --git a/sources/scala/reflect/Type.scala b/sources/scala/reflect/Type.scala index 9b4c4d2e1b..76f1ffd227 100755 --- a/sources/scala/reflect/Type.scala +++ b/sources/scala/reflect/Type.scala @@ -13,7 +13,8 @@ abstract class Type; case object NoPrefix extends Type; case object NoType extends Type; -case class TypeIdent(pre: Type, sym: Symbol) extends Type; +case class NamedType(fullname: String) extends Type; +case class PrefixedType(pre: Type, sym: Symbol) extends Type; case class SingleType(pre: Type, sym: Symbol) extends Type; case class ThisType(clazz: Symbol) extends Type; case class AppliedType(tpe: Type, args: List[Type]) extends Type; diff --git a/sources/scala/tools/nsc/ast/parser/Parsers.scala b/sources/scala/tools/nsc/ast/parser/Parsers.scala index 59eaa4eb47..d8a4f9e49d 100755 --- a/sources/scala/tools/nsc/ast/parser/Parsers.scala +++ b/sources/scala/tools/nsc/ast/parser/Parsers.scala @@ -436,10 +436,10 @@ import Tokens._; if (in.token == COLON) { in.nextToken(); typ() } else TypeTree(); - /** SimpleTypedOpt ::= [`:' SimpleType] + /** RequiresTypedOpt ::= [`:' SimpleType | requires SimpleType] */ - def simpleTypedOpt(): Tree = - if (in.token == COLON) { in.nextToken(); simpleType() } + def requiresTypeOpt(): Tree = + if (in.token == COLON | in.token == REQUIRES) { in.nextToken(); simpleType() } else TypeTree(); /** Types ::= Type {`,' Type} @@ -1484,7 +1484,7 @@ import Tokens._; EmptyTree } - /** ClassDef ::= ClassSig [`:' SimpleType] ClassTemplate + /** ClassDef ::= ClassSig RequiresTypeOpt ClassTemplate * ClassSig ::= Id [TypeParamClause] {ClassParamClause} */ def classDef(mods: int): Tree = @@ -1494,7 +1494,7 @@ import Tokens._; val tparams = typeParamClauseOpt(name, implicitViews); if ((mods & Flags.CASE) != 0 && in.token != LPAREN) accept(LPAREN); val vparamss = paramClauses(name, implicitViews.toList, (mods & Flags.CASE) != 0); - val thistpe = simpleTypedOpt(); + val thistpe = requiresTypeOpt(); val template = classTemplate(mods, name, vparamss); ClassDef(mods, name, tparams, thistpe, template) } diff --git a/sources/scala/tools/nsc/ast/parser/Scanners.scala b/sources/scala/tools/nsc/ast/parser/Scanners.scala index 31508fc1e5..bf55b2ebe9 100755 --- a/sources/scala/tools/nsc/ast/parser/Scanners.scala +++ b/sources/scala/tools/nsc/ast/parser/Scanners.scala @@ -745,6 +745,7 @@ import scala.tools.nsc.util.CharArrayReader; enterKeyword(nme.IMPLICITkw, IMPLICIT); enterKeyword(nme.IMPORTkw, IMPORT); enterKeyword(nme.MATCHkw, MATCH); + enterKeyword(nme.REQUIRESkw, REQUIRES); enterKeyword(nme.NEWkw, NEW); enterKeyword(nme.NULLkw, NULL); enterKeyword(nme.OBJECTkw, OBJECT); diff --git a/sources/scala/tools/nsc/ast/parser/Tokens.scala b/sources/scala/tools/nsc/ast/parser/Tokens.scala index 67c7572aac..85340fa84b 100644 --- a/sources/scala/tools/nsc/ast/parser/Tokens.scala +++ b/sources/scala/tools/nsc/ast/parser/Tokens.scala @@ -66,6 +66,7 @@ object Tokens { final val WHILE = 56; final val RETURN = 57; final val MATCH = 58; + final val REQUIRES = 59; /** special symbols */ final val COMMA = 61; diff --git a/sources/scala/tools/nsc/symtab/StdNames.scala b/sources/scala/tools/nsc/symtab/StdNames.scala index 78d4da8403..022d4ec357 100755 --- a/sources/scala/tools/nsc/symtab/StdNames.scala +++ b/sources/scala/tools/nsc/symtab/StdNames.scala @@ -37,6 +37,7 @@ import scala.tools.nsc.util.NameTransformer; val PRIVATEkw = newTermName("private"); val PROTECTEDkw = newTermName("protected"); val RETURNkw = newTermName("return"); + val REQUIRESkw = newTermName("requires"); val SEALEDkw = newTermName("sealed"); val SUPERkw = newTermName("super"); val THISkw = newTermName("this"); diff --git a/sources/scala/tools/nsc/symtab/Symbols.scala b/sources/scala/tools/nsc/symtab/Symbols.scala index 0bf2c14ec5..2fef116ccd 100755 --- a/sources/scala/tools/nsc/symtab/Symbols.scala +++ b/sources/scala/tools/nsc/symtab/Symbols.scala @@ -840,6 +840,11 @@ import Flags._; override def setInfo(tp: Type): this.type = { tpePhase = null; tyconCache = null; + tp match { //debug + case TypeRef(_, sym, _) => + assert(sym != this, this); + case _ => + } super.setInfo(tp); this } diff --git a/sources/scala/tools/nsc/transform/Erasure.scala b/sources/scala/tools/nsc/transform/Erasure.scala index ac2413c678..b14b939e70 100755 --- a/sources/scala/tools/nsc/transform/Erasure.scala +++ b/sources/scala/tools/nsc/transform/Erasure.scala @@ -278,7 +278,23 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { /** A replacement for the standard typer's `typed1' method */ override protected def typed1(tree: Tree, mode: int, pt: Type): Tree = { - super.typed1(adaptMember(tree), mode, pt) + val tree1 = super.typed1(adaptMember(tree), mode, pt); + tree1 match { + case If(cond, thenp, elsep) => + val thenp1 = adaptToType(thenp, tree1.tpe); + val elsep1 = if (elsep.isEmpty) elsep else adaptToType(elsep, tree1.tpe); + copy.If(tree1, cond, thenp1, elsep1); + case Match(selector, cases) => + val cases1 = cases map { + case cdef @ CaseDef(pat, guard, body) => + val body1 = adaptToType(body, tree1.tpe); + copy.CaseDef(cdef, pat, guard, body1) setType body1.tpe + } + copy.Match(tree1, selector, cases1) + // todo: do same for try + case _ => + tree1 + } } } diff --git a/sources/scala/tools/nsc/typechecker/Codification.scala b/sources/scala/tools/nsc/typechecker/Codification.scala index 9070b001b3..3c1b53b952 100755 --- a/sources/scala/tools/nsc/typechecker/Codification.scala +++ b/sources/scala/tools/nsc/typechecker/Codification.scala @@ -13,10 +13,6 @@ import scala.tools.nsc.util.{ListBuffer, FreshNameCreator}; import global._; - def codify(tree: Tree): Tree = - New(TypeTree(appliedType(definitions.TypedCodeClass.typeConstructor, List(tree.tpe))), - List(List(inject(reify(tree))))); - case class FreeValue(tree: Tree) extends reflect.Code; type ReifyEnvironment = ListMap[Symbol, reflect.Symbol]; @@ -51,19 +47,25 @@ import scala.tools.nsc.util.{ListBuffer, FreshNameCreator}; throw new TypeError("cannot reify tree: " + tree) } + private def mkGlobalSymbol(fullname: String, sym: Symbol): reflect.Symbol = + if (sym.isClass) reflect.Class(fullname) + else if (sym.isType) reflect.TypeField(fullname, reify(sym.info)) + else if (sym.isMethod) reflect.Method(fullname, reify(sym.info)) + else reflect.Field(fullname, reify(sym.info)); + def reify(sym: Symbol): reflect.Symbol = env.get(sym) match { case Some(rsym) => rsym case None => - reify(sym.owner) match { + if (sym.isRoot || sym.isRootPackage || sym.isEmptyPackageClass || sym.isEmptyPackage) + reflect.RootSymbol + else reify(sym.owner) match { case reflect.NoSymbol => reflect.NoSymbol; - case reflect.Class(ownername) => - val fullname = ownername + "." + sym.name; - if (sym.isClass) reflect.Class(fullname) - else if (sym.isType) reflect.TypeField(fullname, reify(sym.info)) - else if (sym.isMethod) reflect.Method(fullname, reify(sym.info)) - else reflect.Field(fullname, reify(sym.info)) + case reflect.RootSymbol => + mkGlobalSymbol(sym.name.toString(), sym) + case reflect.Class(ownername) => + mkGlobalSymbol(ownername + "." + sym.name, sym) case _ => reflect.NoSymbol } @@ -75,8 +77,9 @@ import scala.tools.nsc.util.{ListBuffer, FreshNameCreator}; case NoType => reflect.NoType case TypeRef(pre, sym, args) => - val tp = reflect.TypeIdent(reify(pre), reify(sym)); - if (args.isEmpty) tp else reflect.AppliedType(tp, args map reify) + val tp = if (sym.owner.isPackageClass) reflect.NamedType(sym.fullNameString); + else reflect.PrefixedType(reify(pre), reify(sym)); + if (args.isEmpty) tp else reflect.AppliedType(tp, args map reify) case SingleType(pre, sym) => reflect.SingleType(reify(pre), reify(sym)) case ThisType(clazz) => @@ -99,35 +102,38 @@ import scala.tools.nsc.util.{ListBuffer, FreshNameCreator}; // todo replace className by caseName in CaseClass once we have switched to nsc. def className(value: CaseClass): String = value match { - case reflect.Ident(_) => "Ident" - case reflect.Select(_, _) => "Select" - case reflect.Literal(_) => "Literal" - case reflect.Apply(_, _) => "Apply" - case reflect.TypeApply(_, _) => "TypeApply" - case reflect.Function(_, _) => "Function" - case reflect.Class(_) => "Class" - case reflect.Method(_, _) => "Method" - case reflect.Field(_, _) => "Field" - case reflect.TypeIdent(_, _) => "TypeIdent" - case reflect.SingleType(_, _) => "SingleType" - case reflect.ThisType(_) => "ThisType" - case reflect.AppliedType(_, _) => "AppliedType" - case reflect.TypeBounds(_, _) => "TypeBounds" + case _ :: _ => "scala.$colon$colon" + case reflect.Ident(_) => "scala.reflect.Ident" + case reflect.Select(_, _) => "scala.reflect.Select" + case reflect.Literal(_) => "scala.reflect.Literal" + case reflect.Apply(_, _) => "scala.reflect.Apply" + case reflect.TypeApply(_, _) => "scala.reflect.TypeApply" + case reflect.Function(_, _) => "scala.reflect.Function" + case reflect.Class(_) => "scala.reflect.Class" + case reflect.Method(_, _) => "scala.reflect.Method" + case reflect.Field(_, _) => "scala.reflect.Field" + case reflect.NamedType(_) => "scala.reflect.NamedType" + case reflect.PrefixedType(_, _) => "scala.reflect.PrefixedType" + case reflect.SingleType(_, _) => "scala.reflect.SingleType" + case reflect.ThisType(_) => "scala.reflect.ThisType" + case reflect.AppliedType(_, _) => "scala.reflect.AppliedType" + case reflect.TypeBounds(_, _) => "scala.reflect.TypeBounds" case reflect.MethodType(_, _) => - if (value.isInstanceOf[reflect.ImplicitMethodType]) "ImplicitMethodType" else "MethodType" + if (value.isInstanceOf[reflect.ImplicitMethodType]) "scala.reflect.ImplicitMethodType" else "scala.reflect.MethodType" case _ => "" } def objectName(value: Any): String = value match { - case reflect.NoSymbol => "NoSymbol" - case reflect.RootSymbol => "RootSymbol" - case reflect.NoPrefix => "NoPrefix" - case reflect.NoType => "NoType" + case Nil => "scala.Nil" + case reflect.NoSymbol => "scala.reflect.NoSymbol" + case reflect.RootSymbol => "scala.reflect.RootSymbol" + case reflect.NoPrefix => "scala.reflect.NoPrefix" + case reflect.NoType => "scala.reflect.NoType" case _ => "" } - def injectType(name: String): Tree = TypeTree(definitions.getClass("scala.reflect." + name).tpe); + def injectType(name: String): Tree = TypeTree(definitions.getClass(name).initialize.tpe); def inject(value: Any): Tree = value match { case FreeValue(tree) => @@ -137,26 +143,34 @@ import scala.tools.nsc.util.{ListBuffer, FreshNameCreator}; val vdefs = for (val param <- params) yield { val lname = newTermName(fresh.newName()); env1 = env1.update(param, lname); - ValDef(0, lname, injectType("LocalValue"), - New(injectType("LocalValue"), + ValDef(0, lname, injectType("scala.reflect.LocalValue"), + New(injectType("scala.reflect.LocalValue"), List(List(inject(param.owner), inject(param.name), inject(param.tpe))))) } Block(vdefs, new Injector(env1, fresh).inject(body)) case rsym: reflect.LocalSymbol => Ident(env(rsym)) - case s: String => - Literal(Constant(s)) + case x: String => Literal(Constant(x)) + case x: Boolean => Literal(Constant(x)) + case x: Byte => Literal(Constant(x)) + case x: Short => Literal(Constant(x)) + case x: Char => Literal(Constant(x)) + case x: Int => Literal(Constant(x)) + case x: Long => Literal(Constant(x)) + case x: Float => Literal(Constant(x)) + case x: Double => Literal(Constant(x)) case c: CaseClass => - val name = className(c); - if (name.length == 0) throw new Error("don't know how to inject " + value); - val injectedArgs = new ListBuffer[Tree]; - for (val i <- Iterator.range(0, c.caseArity)) - injectedArgs += inject(c.caseElement(i)); - New(injectType(name), List(injectedArgs.toList)) - case _ => - val name = objectName(value); - if (name.length == 0) throw new Error("don't know how to inject " + value); - gen.mkRef(definitions.getModule("scala.reflect." + name)) + val name = objectName(c); + if (name.length() != 0) gen.mkRef(definitions.getModule(name)) + else { + val name = className(c); + if (name.length() == 0) throw new Error("don't know how to inject " + value); + val injectedArgs = new ListBuffer[Tree]; + for (val i <- Iterator.range(0, c.caseArity)) + injectedArgs += inject(c.caseElement(i)); + New(Ident(definitions.getClass(name)), List(injectedArgs.toList)) + } + case _ => throw new Error("don't know how to inject " + value); } } @@ -165,4 +179,21 @@ import scala.tools.nsc.util.{ListBuffer, FreshNameCreator}; def inject(code: reflect.Code): Tree = new Injector(ListMap.Empty, new FreshNameCreator).inject(code); + + /** returns + * < new TypedCode[T](tree1) > + * where T = tree.tpe + * tree1 = inject(reify(tree)) + */ + def codify(tree: Tree): Tree = { + val reified = reify(tree); + System.out.println("reified = " + reified); + val injected = inject(reified); + System.out.println("injected = " + injected); + New(TypeTree(appliedType(definitions.TypedCodeClass.typeConstructor, List(tree.tpe))), + List(List(injected))); + + } } + + diff --git a/sources/scala/tools/nsc/typechecker/Typers.scala b/sources/scala/tools/nsc/typechecker/Typers.scala index 83ec152b06..0356cd7bd6 100755 --- a/sources/scala/tools/nsc/typechecker/Typers.scala +++ b/sources/scala/tools/nsc/typechecker/Typers.scala @@ -40,7 +40,8 @@ import collection.mutable.HashMap; val infer = new Inferencer(context0) { override def isCoercible(tp: Type, pt: Type): boolean = - context0.reportGeneralErrors && // this condition prevents chains of views + tp.isError || pt.isError || + context0.reportGeneralErrors && // this condition prevents chains of views inferView(Position.NOPOS, tp, pt, false) != EmptyTree } @@ -373,7 +374,8 @@ import collection.mutable.HashMap; return typed(atPos(tree.pos)(Block(List(tree), Literal(()))), mode, pt) case _ => } - if (context.reportGeneralErrors) { // (13); the condition prevents chains of views + if (context.reportGeneralErrors && !tree.tpe.isError && !pt.isError) { + // (13); the condition prevents chains of views val coercion = inferView(tree.pos, tree.tpe, pt, true); if (coercion != EmptyTree) { if (settings.debug.value) log("inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe); @@ -711,7 +713,7 @@ import collection.mutable.HashMap; } def typedFunction(fun: Function, mode: int, pt: Type): Tree = { - def decompose(tp: Type): Triple[Symbol, List[Type], Type] = + def decompose(pt: Type): Triple[Symbol, List[Type], Type] = if (isFunctionType(pt) || pt.symbol == PartialFunctionClass && @@ -882,7 +884,8 @@ import collection.mutable.HashMap; } else { qual.tpe.member(name) } - if (sym == NoSymbol && qual.isTerm && (qual.symbol == null || qual.symbol.isValue) && !phase.erasedTypes) { + if (sym == NoSymbol && qual.isTerm && (qual.symbol == null || qual.symbol.isValue) && + !phase.erasedTypes && !qual.tpe.widen.isError) { val coercion = inferView(qual.pos, qual.tpe, name, true); if (coercion != EmptyTree) return typed( @@ -890,7 +893,7 @@ import collection.mutable.HashMap; } if (sym.info == NoType) { if (settings.debug.value) log("qual = " + qual + ":" + qual.tpe + "\nSymbol=" + qual.tpe.symbol + "\nsymbol-info = " + qual.tpe.symbol.info + "\nscope-id = " + qual.tpe.symbol.info.decls.hashCode() + "\nmembers = " + qual.tpe.members + "\nfound = " + sym); - if (!qual.tpe.isError) + if (!qual.tpe.widen.isError) error(tree.pos, decode(name) + " is not a member of " + qual.tpe.widen + (if (Position.line(tree.pos) > Position.line(qual.pos)) @@ -1295,9 +1298,9 @@ import collection.mutable.HashMap; //System.out.println("typing " + tree);//DEBUG } val tree1 = if (tree.tpe != null) tree else typed1(tree, mode, pt); - //System.out.println("typed " + tree1 + ":" + tree1.tpe);//DEBUG + //System.out.println("typed " + tree1 + ":" + tree1.tpe);//debug val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt); - //System.out.println("adpated " + tree1 + ":" + tree1.tpe + " to " + pt);//DEBUG + //System.out.println("adapted " + tree1 + ":" + tree1.tpe + " to " + pt);//debug result } catch { case ex: TypeError => diff --git a/test-nsc/files/pos/code.scala b/test-nsc/files/pos/code.scala new file mode 100755 index 0000000000..05c6e4a779 --- /dev/null +++ b/test-nsc/files/pos/code.scala @@ -0,0 +1,3 @@ +class Test { + val fun: reflect.TypedCode[int => int] = x => x + 1; +} diff --git a/test-nsc/files/run/bug457.scala b/test-nsc/files/run/bug457.scala new file mode 100755 index 0000000000..5b1462f7e2 --- /dev/null +++ b/test-nsc/files/run/bug457.scala @@ -0,0 +1,36 @@ +object Foo { + +// def method= { +// val x = "Hello, world"; +// val y = 100; + +// y match { +// case _: Int +// if (x match { case t => t.trim().length() == 0 }) => +// false; +// // case _ => true; +// } +// } + + def method2(): scala.Boolean = { + val x: java.lang.String = "Hello, world"; + val y: scala.Int = 100; + { + var temp1: scala.Int = y; + var result: scala.Boolean = false; + if ( + { + var result1: scala.Boolean = false; + if (y == 100) + result1 + else + scala.MatchError.fail("crazybox.scala", 11) + } && (y == 90) + ) + result + else + scala.MatchError.fail("crazybox.scala", 9); + } + } + +} -- cgit v1.2.3