From 8397c7b73c2930229eae509e089550b0c3020ce2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 May 2007 14:17:05 +0000 Subject: fixed bugs 1143, 1136, 1102 --- src/compiler/scala/tools/nsc/CompilerCommand.scala | 1 + src/compiler/scala/tools/nsc/Global.scala | 4 +- src/compiler/scala/tools/nsc/Settings.scala | 1 + .../scala/tools/nsc/ast/NodePrinters.scala | 41 ++++++++- .../scala/tools/nsc/ast/parser/Parsers.scala | 6 ++ .../scala/tools/nsc/symtab/AnnotationInfos.scala | 2 +- src/compiler/scala/tools/nsc/symtab/Flags.scala | 2 +- src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 + src/compiler/scala/tools/nsc/symtab/Symbols.scala | 1 - .../scala/tools/nsc/typechecker/Infer.scala | 22 ++--- .../tools/nsc/typechecker/SyntheticMethods.scala | 96 +++++++++++++++------- .../scala/tools/nsc/typechecker/Typers.scala | 6 +- 12 files changed, 134 insertions(+), 49 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index 89302b0749..d246e05959 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -24,6 +24,7 @@ class CompilerCommand(arguments: List[String], val settings: Settings, /** A message explaining usage and options */ def usageMsg: String = { + // todo: print -X and -javadoc options only on demand val helpSyntaxColumnWidth: int = Iterable.max(settings.allSettings map (. helpSyntax.length())) def format(s: String): String = { diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 31e4f162a3..9d76ab531c 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -497,8 +497,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable phase = globalPhase globalPhase.run if (settings.print contains globalPhase.name) - if (globalPhase.id >= icodePhase.id) writeICode() + if (globalPhase.id >= icodePhase.id) writeICode() + else if (settings.Xshowtrees.value) nodePrinters.printAll() else treePrinter.printAll() + if (settings.browse contains globalPhase.name) treeBrowser.browse(units) informTime(globalPhase.description, startTime) globalPhase = globalPhase.next diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index 848fc8a8f1..626c41cfd9 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -125,6 +125,7 @@ class Settings(error: String => unit) { val Xdetach = BooleanSetting("-Xdetach", "Perform detaching of remote closures") val Xshowcls = StringSetting ("-Xshowcls", "class", "Show class info", "") val Xshowobj = StringSetting ("-Xshowobj", "object", "Show object info", "") + val Xshowtrees = BooleanSetting ("-Xshowtrees", "Show detailed trees when used in connection with -print:phase") val Xlinearizer = ChoiceSetting ("-Xlinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") val Xgenerics = BooleanSetting("-Xgenerics", "Use generic Java types") val Xprintpos = BooleanSetting("-Xprintpos", "Print tree positions (as offsets)") diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 31cc368ec8..24fd0971cd 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -232,8 +232,34 @@ abstract class NodePrinters { traverse(tpt, level + 1, true) traverse(rhs, level + 1, false) printcln(")") + case PackageDef(name, stats) => + println("PackageDef("+name+", ") + for (stat <- stats) + traverse(stat, level + 1, false) + printcln(")") case _ => - printcln("***" + tree.getClass) + tree match { + case p: Product => + if (p.productArity != 0) { + println(p.productPrefix+"(") + for (elem <- (0 until p.productArity) map p.productElement) { + def printElem(elem: Any, level: int): unit = elem match { + case t: Tree => + traverse(t, level, false) + case xs: List[_] => + print("List(") + for (x <- xs) printElem(x, level+1) + printcln(")") + case _ => + println(elem.toString) + } + printElem(elem, level+1) + } + printcln(")") + } else printcln(p.productPrefix) + case _ => + printcln("***" + tree.getClass) + } } } buf setLength 0 @@ -241,4 +267,17 @@ abstract class NodePrinters { buf.toString } } + def printUnit(unit: CompilationUnit) { + print("// Scala source: " + unit.source + "\n") + if (unit.body ne null) { + print(nodeToString(unit.body)); println() + } else { + print("") + } + println() + } + def printAll() { + print("[[syntax trees at end of " + phase + "]]") + for (unit <- global.currentRun.units) printUnit(unit) + } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index c938abb4bf..66168724b0 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2239,6 +2239,8 @@ trait Parsers { * | */ def templateStatSeq() = { + val savedImplicitParams = implicitParams + implicitParams = List() var self: ValDef = emptyValDef val stats = new ListBuffer[Tree] if (isExprIntro) { @@ -2266,6 +2268,7 @@ trait Parsers { if (inToken != RBRACE && inToken != EOF) acceptStatSep() } checkNoImplicitParams() + implicitParams = savedImplicitParams (self, stats.toList) } @@ -2305,6 +2308,8 @@ trait Parsers { if (inToken == RBRACE || inToken == CASE) stats += Literal(()).setPos(inCurrentPos) } + val savedImplicitParams = implicitParams + implicitParams = List() var last = false while ((inToken != RBRACE) && (inToken != EOF) && (inToken != CASE) && !last) { if (inToken == IMPORT) { @@ -2324,6 +2329,7 @@ trait Parsers { } } checkNoImplicitParams() + implicitParams = savedImplicitParams stats.toList } diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala index 8b36ad819f..e1d72105ca 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala @@ -41,7 +41,7 @@ trait AnnotationInfos { None } - private object symbolReifier extends SymbolReifier { + private val symbolReifier = new SymbolReifier { val symbols: AnnotationInfos.this.type = AnnotationInfos.this } diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index 4c5f227a21..83b538ee9d 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -65,7 +65,7 @@ object Flags extends Enumeration { final val LIFTED = 0x400000000L // class has been lifted out to package level // local value has been lifted out to class level // todo: make LIFTED = latePRIVATE? - final val MIXEDIN = 0x800000000L // member has been mixed in + final val MIXEDIN = 0x800000000L // term member has been mixed in final val EXPANDEDNAME = 0x1000000000L // name has been expanded with class suffix final val IMPLCLASS = 0x2000000000L // symbol is an implementation class diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index fd1893054c..d6efdb32cb 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -302,6 +302,7 @@ trait StdNames { val receive = newTermName("receive") val report = newTermName("report") val runtime = newTermName("runtime") + val sameElements = newTermName("sameElements") val scala_ = newTermName("scala") val send = newTermName("send") val synchronized_ = newTermName("synchronized") diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index c1d2d222ea..81ba6b5b9e 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -677,7 +677,6 @@ trait Symbols { def thisType: Type = NoPrefix /** Return every accessor of a primary constructor parameter in this case class - * todo: limit to accessors for first constructor parameter section. */ final def caseFieldAccessors: List[Symbol] = info.decls.toList filter (sym => !(sym hasFlag PRIVATE) && sym.hasFlag(CASEACCESSOR)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index ac009e4c3e..80ba2c1df1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -630,18 +630,19 @@ trait Infer { false } - /** Is type `tpe1' a strictly better alternative than type `ftpe2'? - * - * @param tpe1 ... - * @param tpe2 ... - * @return ... + /** Is type `tpe1' a strictly better expression alternative than type `tpe2'? */ - def isStrictlyBetter(tpe1: Type, tpe2: Type) = { + def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = { def isNullary(tpe: Type) = tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty isNullary(tpe1) && !isNullary(tpe2) || - specializes(tpe1, tpe2) && !specializes(tpe2, tpe1) + isStrictlyBetter(tpe1, tpe2) } + /** Is type `tpe1' a strictly better alternative than type `tpe2'? + */ + def isStrictlyBetter(tpe1: Type, tpe2: Type) = + specializes(tpe1, tpe2) && !specializes(tpe2, tpe1) + /** error if arguments not within bounds. */ def checkBounds(pos: Position, pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type], prefix: String) = { @@ -1132,7 +1133,7 @@ trait Infer { val tp2 = pre.memberType(sym2) (tp2 == ErrorType || !global.typer.infer.isCompatible(tp2, pt) && global.typer.infer.isCompatible(tp1, pt) || - isStrictlyBetter(tp1, tp2)) } + isStrictlyBetterExpr(tp1, tp2)) } val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => if (improves(alt, best)) alt else best) val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)) @@ -1176,10 +1177,9 @@ trait Infer { tryTwice { if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt) val applicable = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt)) - def improves(sym1: Symbol, sym2: Symbol) = ( + def improves(sym1: Symbol, sym2: Symbol) = sym2 == NoSymbol || sym2.isError || - specializes(pre.memberType(sym1), pre.memberType(sym2)) - ) + isStrictlyBetter(pre.memberType(sym1), pre.memberType(sym2)) val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) => if (improves(alt, best)) alt else best) val competing = applicable dropWhile (alt => best == alt || improves(best, alt)) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 1872642459..d91426867d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -37,7 +37,9 @@ trait SyntheticMethods requires Analyzer { * @param unit ... * @return ... */ - def addSyntheticMethods(templ: Template, clazz: Symbol, unit: CompilationUnit): Template = { + def addSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = { + + val localTyper = newTyper(context) def hasImplementation(name: Name): boolean = { val sym = clazz.info.nonPrivateMember(name) @@ -111,32 +113,66 @@ trait SyntheticMethods requires Analyzer { Apply(gen.mkAttributedRef(target), This(clazz) :: (vparamss.head map Ident)))) } + /** The equality method for case classes and modules: + * def equals(that: Any) = + * (this eq that) || + * (that match { + * case this.C(this.arg_1, ..., this.arg_n) => true + * case _ => false + * }) + */ def equalsMethod: Tree = { - val constrParamTypes = clazz.primaryConstructor.tpe.paramTypes - val hasVarArgs = !constrParamTypes.isEmpty && constrParamTypes.last.symbol == RepeatedParamClass - val target = getMember(ScalaRunTimeModule, if (hasVarArgs) nme._equalsWithVarArgs else nme._equals) - val paramtypes = - if (target.tpe.paramTypes.isEmpty) List() - else target.tpe.paramTypes.tail val method = syntheticMethod( - nme.equals_, 0, MethodType(paramtypes, target.tpe.resultType)) - typed(DefDef(method, vparamss => - Apply( - Select( - Apply( - Select(Ident(vparamss.head.head), Object_eq), - List(This(clazz))), - Boolean_or), - List( - Apply( - Select( - TypeApply( - Select(Ident(vparamss.head.head), Any_isInstanceOf), - List(TypeTree(clazz.tpe))), - Boolean_and), - List( - Apply(gen.mkAttributedRef(target), - This(clazz) :: (vparamss.head map Ident)))))))); + nme.equals_, 0, MethodType(List(AnyClass.tpe), BooleanClass.tpe)) + localTyper.typed { + DefDef( + method, + { vparamss => + val that = Ident(vparamss.head.head) + val constrParamTypes = clazz.primaryConstructor.tpe.paramTypes + val hasVarArgs = !constrParamTypes.isEmpty && constrParamTypes.last.symbol == RepeatedParamClass + if (clazz.isStatic) { + val target = getMember(ScalaRunTimeModule, if (hasVarArgs) nme._equalsWithVarArgs else nme._equals) + Apply( + Select( + TypeApply( + Select(that, Any_isInstanceOf), + List(TypeTree(clazz.tpe))), + Boolean_and), + List( + Apply(gen.mkAttributedRef(target), + This(clazz) :: (vparamss.head map Ident)))) + } else { + val (pat, guard) = { + val guards = new ListBuffer[Tree] + val params = for ((acc, cpt) <- clazz.caseFieldAccessors zip constrParamTypes) yield { + val name = context.unit.fresh.newName(acc.name+"$") + val isVarArg = cpt.symbol == RepeatedParamClass + guards += Apply( + Select( + Ident(name), + if (isVarArg) nme.sameElements else nme.equals_), + List(Ident(acc))) + Bind(name, + if (isVarArg) Star(Ident(nme.WILDCARD)) + else Ident(nme.WILDCARD)) + } + ( Apply(Ident(clazz.name.toTermName), params), + if (guards.isEmpty) EmptyTree + else guards reduceLeft { (g1: Tree, g2: Tree) => + Apply(Select(g1, nme.AMPAMP), List(g2)) + } + ) + } + Match( + that, + List( + CaseDef(pat, guard, Literal(Constant(true))), + CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))))) + } + } + ) + } } def isSerializable(clazz: Symbol): Boolean = @@ -153,8 +189,8 @@ trait SyntheticMethods requires Analyzer { def newAccessorMethod(tree: Tree): Tree = tree match { case DefDef(_, _, _, _, _, rhs) => val newAcc = tree.symbol.cloneSymbol - newAcc.name = unit.fresh.newName("" + tree.symbol.name + "$") - newAcc.setFlag(SYNTHETIC).resetFlag(ACCESSOR | PARAMACCESSOR) + newAcc.name = context.unit.fresh.newName(tree.symbol.name + "$") + newAcc.setFlag(SYNTHETIC).resetFlag(ACCESSOR | PARAMACCESSOR | PRIVATE) newAcc.owner.info.decls enter newAcc val result = typed(DefDef(newAcc, vparamss => rhs.duplicate)) log("new accessor method " + result) @@ -163,7 +199,7 @@ trait SyntheticMethods requires Analyzer { def beanSetterOrGetter(sym: Symbol): Symbol = if (!sym.name(0).isLetter) { - unit.error(sym.pos, "attribute `BeanProperty' can be applied only to fields that start with a letter") + context.unit.error(sym.pos, "attribute `BeanProperty' can be applied only to fields that start with a letter") NoSymbol } else { var name0 = sym.name @@ -174,7 +210,7 @@ trait SyntheticMethods requires Analyzer { val name1 = prefix + name0(0).toUpperCase + name0.subName(1, name0.length) val sym1 = clazz.info.decl(name1) if (sym1 != NoSymbol && sym1.tpe.paramTypes.length == arity) { - unit.error(sym.pos, "a definition of `"+name1+"' already exists in " + clazz) + context.unit.error(sym.pos, "a definition of `"+name1+"' already exists in " + clazz) NoSymbol } else { clazz.newMethod(sym.pos, name1) @@ -251,7 +287,7 @@ trait SyntheticMethods requires Analyzer { else if (sym.isSetter) addBeanSetterMethod(sym) else if (sym.isMethod || sym.isType) - unit.error(sym.pos, "attribute `BeanProperty' is not applicable to " + sym) + context.unit.error(sym.pos, "attribute `BeanProperty' is not applicable to " + sym) } val synthetics = ts.toList copy.Template( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 30f693155d..7b6d84acb8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -939,7 +939,7 @@ trait Typers requires Analyzer { val tparams1 = List.mapConserve(cdef.tparams)(typedAbsTypeDef) val impl1 = newTyper(context.make(cdef.impl, clazz, newTemplateScope(cdef.impl, clazz))) .typedTemplate(cdef.impl, parentTypes(cdef.impl)) - val impl2 = addSyntheticMethods(impl1, clazz, context.unit) + val impl2 = addSyntheticMethods(impl1, clazz, context) copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, impl2) .setType(NoType) } @@ -954,7 +954,7 @@ trait Typers requires Analyzer { val clazz = mdef.symbol.moduleClass val impl1 = newTyper(context.make(mdef.impl, clazz, newTemplateScope(mdef.impl, clazz))) .typedTemplate(mdef.impl, parentTypes(mdef.impl)) - val impl2 = addSyntheticMethods(impl1, clazz, context.unit) + val impl2 = addSyntheticMethods(impl1, clazz, context) copy.ModuleDef(mdef, mdef.mods, mdef.name, impl2) setType NoType } @@ -2854,7 +2854,7 @@ trait Typers requires Analyzer { def improves(info1: ImplicitInfo, info2: ImplicitInfo) = (info2 == NoImplicitInfo) || (info1 != NoImplicitInfo) && - isStrictlyBetter(info1.tpe, info2.tpe) + isStrictlyBetterExpr(info1.tpe, info2.tpe) val shadowed = new HashSet[Name](8) def isApplicable(info: ImplicitInfo): boolean = !containsError(info.tpe) && -- cgit v1.2.3