diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Analyzer.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 135 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 21 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala | 268 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 125 | ||||
-rwxr-xr-x | src/library/scala/reflect/generic/Trees.scala | 1 | ||||
-rw-r--r-- | test/files/neg/bug2206.check | 5 | ||||
-rw-r--r-- | test/files/neg/bug2206.scala | 15 | ||||
-rw-r--r-- | test/files/neg/bug278.check | 5 | ||||
-rw-r--r-- | test/files/neg/overload-msg.check | 13 | ||||
-rw-r--r-- | test/files/neg/overload-msg.scala | 4 | ||||
-rw-r--r-- | test/files/neg/typeerror.check | 2 |
13 files changed, 392 insertions, 207 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 635608520d..70bf55e661 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -22,6 +22,7 @@ trait Analyzer extends AnyRef with SyntheticMethods with Unapplies with NamesDefaults + with TypeDiagnostics { val global : Global import global._ diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 2858f4298c..9a6c4cc401 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -639,9 +639,9 @@ self: Analyzer => val applicable = applicableInfos(implicitInfoss, isLocal, invalidImplicits) if (applicable.isEmpty && !invalidImplicits.isEmpty) { - infer.setAddendum(tree.pos, () => + setAddendum(tree.pos, () => "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+ - "\n because it comes after the application point and it lacks an explicit result type") + " because it comes after the application point and it lacks an explicit result type") } val start = startCounter(subtypeImprovCount) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 4557f7bde1..1ee1604319 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -120,7 +120,7 @@ trait Infer { case NoPrefix | ThisType(_) | ConstantType(_) => true case TypeRef(pre, sym, args) => - isFullyDefined(pre) && (args.isEmpty || (args forall isFullyDefined)) + isFullyDefined(pre) && (args forall isFullyDefined) case SingleType(pre, sym) => isFullyDefined(pre) case RefinedType(ts, decls) => @@ -197,72 +197,17 @@ trait Infer { /** The context-dependent inferencer part */ class Inferencer(context: Context) { - /* -- Error Messages --------------------------------------------------- */ - - private var addendumPos: Position = NoPosition - private var addendum: () => String = _ - - def setAddendum(pos: Position, msg: () => String) = { - addendumPos = pos - addendum = msg - } - def setError[T <: Tree](tree: T): T = { - if (tree.hasSymbol) - if (context.reportGeneralErrors) { - val name = newTermName("<error: " + tree.symbol + ">") - tree.setSymbol( - if (tree.isType) context.owner.newErrorClass(name.toTypeName) - else context.owner.newErrorValue(name)) - } else { - tree.setSymbol(if (tree.isType) stdErrorClass else stdErrorValue) - } - tree.setType(ErrorType) - } - - def decode(name: Name): String = - (if (name.isTypeName) "type " else "value ") + name.decode + def name = newTermName("<error: " + tree.symbol + ">") + def errorClass = if (context.reportGeneralErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass + def errorValue = if (context.reportGeneralErrors) context.owner.newErrorValue(name) else stdErrorValue + def errorSym = if (tree.isType) errorClass else errorValue - def treeSymTypeMsg(tree: Tree): String = - if (tree.symbol eq null) - "expression of type " + tree.tpe - else if (tree.symbol.hasFlag(OVERLOADED)) - "overloaded method " + tree.symbol + " with alternatives " + tree.tpe - else - tree.symbol.toString() + - (if (tree.symbol.isModule) "" - else if (tree.tpe.paramSectionCount > 0) ": "+tree.tpe - else " of type "+tree.tpe) + - (if (tree.symbol.name == nme.apply) tree.symbol.locationString else "") - - def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = - treeSymTypeMsg(tree) + msg + argtpes.mkString("(", ",", ")") + - (if (isWildcard(pt)) "" else " with expected result type " + pt) - - // todo: use also for other error messages - private def existentialContext(tp: Type) = tp.existentialSkolems match { - case List() => "" - case skolems => - def disambiguate(ss: List[String]) = ss match { - case List() => ss - case s :: ss1 => s :: (ss1 map (s1 => if (s1 == s) "(some other)"+s1 else s1)) - } - " where "+(disambiguate(skolems map (_.existentialToString)) mkString ", ") - } - - def foundReqMsg(found: Type, req: Type): String = - withDisambiguation(found, req) { - ";\n found : " + found.toLongString + existentialContext(found) + - "\n required: " + req + existentialContext(req) - } + if (tree.hasSymbol) + tree setSymbol errorSym - def typeErrorMsg(found: Type, req: Type) = { - //println(found.baseTypeSeq) - "type mismatch" + foundReqMsg(found, req) + - (if ((found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req)) - "\n possible cause: missing arguments for method or constructor" - else "") + tree setType ErrorType } def error(pos: Position, msg: String) { @@ -276,67 +221,27 @@ trait Infer { def typeError(pos: Position, found: Type, req: Type) { if (!found.isErroneous && !req.isErroneous) { - error(pos, - typeErrorMsg(found, req)+ - (if (pos != NoPosition && pos == addendumPos) addendum() - else "")) - if (settings.explaintypes.value) explainTypes(found, req) + error(pos, withAddendum(pos)(typeErrorMsg(found, req))) + + if (settings.explaintypes.value) + explainTypes(found, req) } } + def typeErrorMsg(found: Type, req: Type) = { + def isPossiblyMissingArgs = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req) + def missingArgsMsg = if (isPossiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else "" + + "type mismatch" + foundReqMsg(found, req) + missingArgsMsg + } + def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = { typeError(tree.pos, found, req) setError(tree) } def explainTypes(tp1: Type, tp2: Type) = - withDisambiguation(tp1, tp2) { global.explainTypes(tp1, tp2) } - - /** If types `tp1' `tp2' contain different type variables with same name - * differentiate the names by including owner information. Also, if the - * type error is because of a conflict between two identically named - * classes and one is in package scala, fully qualify the name so one - * need not deduce why "java.util.Iterator" and "Iterator" don't match. - */ - private def withDisambiguation[T](tp1: Type, tp2: Type)(op: => T): T = { - - def explainName(sym: Symbol) = { - if (!sym.name.toString.endsWith(")")) { - sym.name = newTypeName(sym.name.toString+"(in "+sym.owner+")") - } - } - - val patches = new ListBuffer[(Symbol, Symbol, Name)] - for { - t1 @ TypeRef(_, sym1, _) <- tp1 - t2 @ TypeRef(_, sym2, _) <- tp2 - if sym1 != sym2 - } { - if (t1.toString == t2.toString) { // type variable collisions - val name = sym1.name - explainName(sym1) - explainName(sym2) - if (sym1.owner == sym2.owner) sym2.name = newTypeName("(some other)"+sym2.name) - patches += ((sym1, sym2, name)) - } - else if (sym1.name == sym2.name) { // symbol name collisions where one is in scala._ - val name = sym1.name - def scalaQualify(s: Symbol) = - if (s.owner.isScalaPackageClass) s.name = newTypeName("scala." + s.name) - List(sym1, sym2) foreach scalaQualify - patches += ((sym1, sym2, name)) - } - } - - val result = op - - for ((sym1, sym2, name) <- patches) { - sym1.name = name - sym2.name = name - } - - result - } + withDisambiguation(tp1, tp2)(global.explainTypes(tp1, tp2)) /* -- Tests & Checks---------------------------------------------------- */ diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 003a173892..bd8482cd67 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -971,17 +971,20 @@ abstract class RefChecks extends InfoTransform { private def checkAnnotations(tpes: List[Type], pos: Position) = tpes foreach (tp => checkTypeRef(tp, pos)) private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f - private def applyRefchecksToAnnotations(tree: Tree) = tree match { - case m: MemberDef => - checkAnnotations(m.symbol.annotations map (_.atp), tree.pos) - transformTrees(m.symbol.annotations.flatMap(_.args)) - case TypeTree() => doTypeTraversal(tree) { - case AnnotatedType(annots, _, _) => - checkAnnotations(annots map (_.atp), tree.pos) - transformTrees(annots.flatMap(_.args)) + private def applyRefchecksToAnnotations(tree: Tree) = { + def applyChecks(annots: List[AnnotationInfo]) = { + checkAnnotations(annots map (_.atp), tree.pos) + transformTrees(annots flatMap (_.args)) + } + + tree match { + case m: MemberDef => applyChecks(m.symbol.annotations) + case TypeTree() => doTypeTraversal(tree) { + case AnnotatedType(annots, _, _) => applyChecks(annots) + case _ => + } case _ => } - case _ => } private def transformCaseApply(tree: Tree, ifNot: => Unit) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala new file mode 100644 index 0000000000..1166f62ddb --- /dev/null +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -0,0 +1,268 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package typechecker + +import scala.collection.mutable +import scala.collection.mutable.ListBuffer +import scala.util.control.ControlThrowable +import scala.util.control.Exception.ultimately +import symtab.Flags._ +import PartialFunction._ + +/** An interface to enable higher configurability of diagnostic messages + * regarding type errors. This is barely a beginning as error messages are + * distributed far and wide across the codebase. The plan is to partition + * error messages into some broad groups and provide some mechanism for + * being more or less verbose on a selective basis. Possible groups include + * such examples as + * + * arity errors + * kind errors + * variance errors + * ambiguity errors + * volatility/stability errors + * implementation restrictions + * + * And more, and there is plenty of overlap, so it'll be a process. + * + * @author Paul Phillips + * @version 1.0 + */ +trait TypeDiagnostics { + self: Analyzer => + + import global._ + import definitions._ + import global.typer.infer + + /** It can be quite difficult to know which of the many functions called "error" + * is being called at any given point in the compiler. To alleviate this I am + * renaming such functions inside this trait based on where it originated. + */ + def inferError(pos: Position, msg: String) = infer.error(pos, msg) + + /** The common situation of making sure nothing is erroneous could be + * nicer if Symbols, Types, and Trees all implemented some common interface + * in which isErroneous and similar would be placed. + */ + def noErroneousTypes(tps: Type*) = tps forall (x => !x.isErroneous) + def noErroneousSyms(syms: Symbol*) = syms forall (x => !x.isErroneous) + def noErroneousTrees(trees: Tree*) = trees forall (x => !x.isErroneous) + + /** A map of Positions to addendums - if an error involves a position in + * the map, the addendum should also be printed. + */ + private var addendums = mutable.Map[Position, () => String]() + + def setAddendum(pos: Position, msg: () => String) = + if (pos != NoPosition) + addendums(pos) = msg + + def withAddendum(pos: Position) = (_: String) + addendums.getOrElse(pos, () => "")() + + def decodeWithNamespace(name: Name): String = { + val prefix = if (name.isTypeName) "type " else "value " + prefix + name.decode + } + + /** Does the positioned line assigned to t1 precede that of t2? + */ + def linePrecedes(t1: Tree, t2: Tree) = t1.pos.isDefined && t1.pos.isDefined && t1.pos.line < t2.pos.line + + def notAMember(sel: Tree, qual: Tree, name: Name) = { + def decoded = decodeWithNamespace(name) + + def msg: String = name match { + case nme.CONSTRUCTOR => qual.tpe.widen+" does not have a constructor" + case _ => + def memberOf = if (qual.tpe.typeSymbol.isTypeParameterOrSkolem) "type parameter " else "" + def possibleCause = + if (linePrecedes(qual, sel)) + "\npossible cause: maybe a semicolon is missing before `"+decoded+"'?" + else + "" + + decoded+" is not a member of "+ memberOf + qual.tpe.widen + possibleCause + } + inferError(sel.pos, withAddendum(qual.pos)(msg)) + } + + /** Only prints the parameter names if they're not synthetic, + * since "x$1: Int" does not offer any more information than "Int". + */ + private def methodTypeErrorString(tp: Type) = tp match { + case mt @ MethodType(params, resultType) => + def forString = + if (params exists (_.isSynthetic)) params map (_.tpe) + else params map (_.defString) + + forString.mkString("(", ",", ")") + resultType + case x => x.toString + } + + def alternatives(tree: Tree): List[Type] = tree.tpe match { + case OverloadedType(pre, alternatives) => alternatives map pre.memberType + case _ => Nil + } + def alternativesString(tree: Tree) = + alternatives(tree) map (x => " " + methodTypeErrorString(x)) mkString ("", " <and>\n", "\n") + + def missingParameterTypeError(fun: Tree, vparam: ValDef) = { + val suffix = if (vparam.mods.isSynthetic) " for expanded function "+fun else "" + + inferError(vparam.pos, "missing parameter type" + suffix) + ErrorType + } + + def treeSymTypeMsg(tree: Tree): String = { + val sym = tree.symbol + def hasParams = tree.tpe.paramSectionCount > 0 + def preResultString = if (hasParams) ": " else " of type " + + def nullMessage = "expression of type " + tree.tpe + def overloadedMessage = "overloaded method " + sym + " with alternatives:\n" + alternativesString(tree) + def moduleMessage = "" + sym + def defaultMessage = moduleMessage + preResultString + tree.tpe + def applyMessage = defaultMessage + tree.symbol.locationString + + if (sym == null) nullMessage + else if (sym.isOverloaded) overloadedMessage + else if (sym.isModule) moduleMessage + else if (sym.name == nme.apply) applyMessage + else defaultMessage + } + + def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = { + def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")") + + def resType = if (isWildcard(pt)) "" else " with expected result type " + pt + def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt + + withDisambiguation(allTypes: _*) { + treeSymTypeMsg(tree) + msg + asParams(argtpes) + resType + } + } + + def disambiguate(ss: List[String]) = ss match { + case Nil => Nil + case s :: ss => s :: (ss map { case `s` => "(some other)"+s ; case x => x }) + } + + // todo: use also for other error messages + def existentialContext(tp: Type) = tp.existentialSkolems match { + case Nil => "" + case xs => " where " + (disambiguate(xs map (_.existentialToString)) mkString ", ") + } + + def foundReqMsg(found: Type, req: Type): String = + withDisambiguation(found, req) { + ";\n found : " + found.toLongString + existentialContext(found) + + "\n required: " + req + existentialContext(req) + } + + /** If two given types contain different type variables with the same name + * differentiate the names by including owner information. Also, if the + * type error is because of a conflict between two identically named + * classes and one is in package scala, fully qualify the name so one + * need not deduce why "java.util.Iterator" and "Iterator" don't match. + * Another disambiguation performed is to address the confusion present + * in the following snippet: + * def f[Int](x: Int) = x + 5. + */ + def withDisambiguation[T](types: Type*)(op: => T): T = { + object SymExtractor { + def unapply(x: Any) = x match { + case t @ TypeRef(_, sym, _) => Some(t -> sym) + case t @ ConstantType(value) => Some(t -> t.underlying.typeSymbol) + case _ => None + } + } + val typerefs = + for (tp <- types.toList ; SymExtractor(t, sym) <- tp) yield + t -> sym + + val savedNames = typerefs map { case (_, sym) => sym -> sym.name } toMap + def restoreNames = savedNames foreach { case (sym, name) => sym.name = name } + + def isAlreadyAltered(sym: Symbol) = sym.name != savedNames(sym) + + def modifyName(sym: Symbol)(f: String => String): Unit = + sym.name = newTypeName(f(sym.name.toString)) + + def scalaQualify(sym: Symbol) = + if (sym.owner.isScalaPackageClass) + modifyName(sym)("scala." + _) + + def explainName(sym: Symbol) = { + scalaQualify(sym) + + if (!isAlreadyAltered(sym)) + modifyName(sym)(_ + "(in " + sym.owner + ")") + } + + ultimately(restoreNames) { + for ((t1, sym1) <- typerefs ; (t2, sym2) <- typerefs ; if sym1 != sym2 && (sym1 isLess sym2)) { + + if (t1.toString == t2.toString) { // type variable collisions + List(sym1, sym2) foreach explainName + if (sym1.owner == sym2.owner) + sym2.name = newTypeName("(some other)"+sym2.name) + } + else if (sym1.name == sym2.name) { // symbol name collisions + List(sym1, sym2) foreach { x => + if (x.owner.isScalaPackageClass) + modifyName(x)("scala." + _) + else if (x.isTypeParameterOrSkolem) + explainName(x) + } + } + } + + // performing the actual operation + op + } + } + + trait TyperDiagnostics { + self: Typer => + + private def contextError(pos: Position, msg: String) = context.error(pos, msg) + private def contextError(pos: Position, err: Throwable) = context.error(pos, err) + + def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded + def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive" + + /** Returns Some(msg) if the given tree is untyped apparently due + * to a cyclic reference, and None otherwise. + */ + def cyclicReferenceMessage(sym: Symbol, tree: Tree) = condOpt(tree) { + case ValDef(_, _, tpt, _) if tpt.tpe == null => "recursive "+sym+" needs type" + case DefDef(_, _, _, _, tpt, _) if tpt.tpe == null => List(cyclicAdjective(sym), sym, "needs result type") mkString " " + } + + /** Report a type error. + * + * @param pos0 The position where to report the error + * @param ex The exception that caused the error + */ + def reportTypeError(pos: Position, ex: TypeError) { + if (ex.pos == NoPosition) ex.pos = pos + if (!context.reportGeneralErrors) throw ex + if (settings.debug.value) ex.printStackTrace() + + ex match { + case CyclicReference(sym, info: TypeCompleter) => + contextError(ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) + + if (sym == ObjectClass) + throw new FatalError("cannot redefine root "+sym) + case _ => + contextError(ex.pos, ex) + } + } + } +} diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ed7c1dec15..b6271b8ef1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -161,7 +161,7 @@ trait Typers { self: Analyzer => else mode } - abstract class Typer(context0: Context) { + abstract class Typer(context0: Context) extends TyperDiagnostics { import context0.unit val infer = new Inferencer(context0) { @@ -252,35 +252,6 @@ trait Typers { self: Analyzer => private[typechecker] var context = context0 def context1 = context - /** Report a type error. - * - * @param pos0 The position where to report the error - * @param ex The exception that caused the error - */ - def reportTypeError(pos: Position, ex: TypeError) { - if (ex.pos == NoPosition) ex.pos = pos - if (!context.reportGeneralErrors) throw ex - if (settings.debug.value) ex.printStackTrace() - ex match { - case CyclicReference(sym, info: TypeCompleter) => - val msg = - info.tree match { - case ValDef(_, _, tpt, _) if (tpt.tpe eq null) => - "recursive "+sym+" needs type" - case DefDef(_, _, _, _, tpt, _) if (tpt.tpe eq null) => - (if (sym.owner.isClass && sym.owner.info.member(sym.name).hasFlag(OVERLOADED)) "overloaded " - else "recursive ")+sym+" needs result type" - case _ => - ex.getMessage() - } - context.error(ex.pos, msg) - if (sym == ObjectClass) - throw new FatalError("cannot redefine root "+sym) - case _ => - context.error(ex.pos, ex) - } - } - /** Check that <code>tree</code> is a stable expression. * * @param tree ... @@ -2936,6 +2907,8 @@ trait Typers { self: Analyzer => * @return ... */ protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = { + def isPatternMode = (mode & PATTERNmode) != 0 + //Console.println("typed1("+tree.getClass()+","+Integer.toHexString(mode)+","+pt+")") def ptOrLub(tps: List[Type]) = if (isFullyDefined(pt)) (pt, false) else weakLub(tps map (_.deconst)) @@ -3056,32 +3029,36 @@ trait Typers { self: Analyzer => } def typedAssign(lhs: Tree, rhs: Tree): Tree = { - val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType) - val varsym = lhs1.symbol - if ((varsym ne null) && treeInfo.mayBeVarGetter(varsym)) + val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType) + val varsym = lhs1.symbol + def failMsg = + if (varsym != null && varsym.isValue) "reassignment to val" + else "assignment to non variable" + + def fail = { + if (!lhs1.tpe.isError) + error(tree.pos, failMsg) + + setError(tree) + } + if (varsym == null) + return fail + + if (treeInfo.mayBeVarGetter(varsym)) { lhs1 match { case Select(qual, name) => - return typed( - Apply( - Select(qual, nme.getterToSetter(name)) setPos lhs.pos, - List(rhs)) setPos tree.pos, - mode, pt) + val sel = Select(qual, nme.getterToSetter(name)) setPos lhs.pos + val app = Apply(sel, List(rhs)) setPos tree.pos + return typed(app, mode, pt) case _ => - } - if ((varsym ne null) && (varsym.isVariable || varsym.isValue && phase.erasedTypes)) { + } + if (varsym.isVariable || varsym.isValue && phase.erasedTypes) { val rhs1 = typed(rhs, EXPRmode | BYVALmode, lhs1.tpe) treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe - } else { - if (!lhs1.tpe.isError) { - //println(lhs1+" = "+rhs+" "+varsym+" "+mayBeVarGetter(varsym)+" "+varsym.ownerChain+" "+varsym.info)// DEBUG - error(tree.pos, - if ((varsym ne null) && varsym.isValue) "reassignment to val" - else "assignment to non variable") - } - setError(tree) } + else fail } def typedIf(cond: Tree, thenp: Tree, elsep: Tree) = { @@ -3227,19 +3204,19 @@ trait Typers { self: Analyzer => t case ex: TypeError => stopTimer(failedApplyNanos, start) - def errorInResult(tree: Tree): Boolean = tree.pos == ex.pos || { - tree match { - case Block(_, r) => errorInResult(r) - case Match(_, cases) => cases exists errorInResult - case CaseDef(_, _, r) => errorInResult(r) - case Annotated(_, r) => errorInResult(r) - case If(_, t, e) => errorInResult(t) || errorInResult(e) - case Try(b, catches, _) => errorInResult(b) || (catches exists errorInResult) - case Typed(r, Function(List(), EmptyTree)) => errorInResult(r) - case _ => false - } - } - if (errorInResult(fun) || (args exists errorInResult) || errorInResult(tree)) { + def treesInResult(tree: Tree): List[Tree] = tree :: (tree match { + case Block(_, r) => treesInResult(r) + case Match(_, cases) => cases + case CaseDef(_, _, r) => treesInResult(r) + case Annotated(_, r) => treesInResult(r) + case If(_, t, e) => treesInResult(t) ++ treesInResult(e) + case Try(b, catches, _) => treesInResult(b) ++ catches + case Typed(r, Function(Nil, EmptyTree)) => treesInResult(r) + case _ => Nil + }) + def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ex.pos) + + if (fun :: tree :: args exists errorInResult) { if (printTypings) println("second try for: "+fun+" and "+args) val Select(qual, name) = fun val args1 = tryTypedArgs(args, argMode(fun, mode), ex) @@ -3260,11 +3237,11 @@ trait Typers { self: Analyzer => def typedApply(fun: Tree, args: List[Tree]) = { val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable - if (stableApplication && (mode & PATTERNmode) != 0) { + if (stableApplication && isPatternMode) { // treat stable function applications f() as expressions. typed1(tree, mode & ~PATTERNmode | EXPRmode, pt) } else { - val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType + val funpt = if (isPatternMode) pt else WildcardType val appStart = startTimer(failedApplyNanos) val opeqStart = startTimer(failedOpEqNanos) silent(_.typed(fun, funMode(mode), funpt)) match { @@ -3305,7 +3282,7 @@ trait Typers { self: Analyzer => case ex: TypeError => fun match { case Select(qual, name) - if (mode & PATTERNmode) == 0 && nme.isOpAssignmentName(name.decode) => + if !isPatternMode && nme.isOpAssignmentName(name.decode) => val qual1 = typedQualifier(qual) if (treeInfo.isVariableOrGetter(qual1)) { stopTimer(failedOpEqNanos, opeqStart) @@ -3482,19 +3459,9 @@ trait Typers { self: Analyzer => if (name == nme.ERROR && onlyPresentation) return makeErrorTree - if (!qual.tpe.widen.isErroneous) { - error(tree.pos, - if (name == nme.CONSTRUCTOR) - qual.tpe.widen+" does not have a constructor" - else - decode(name)+" is not a member of "+ - (if (qual.tpe.typeSymbol.isTypeParameterOrSkolem) "type parameter " else "") + - qual.tpe.widen + - (if ((context.unit ne null) && // Martin: why is this condition needed? - qual.pos.isDefined && tree.pos.isDefined && qual.pos.line < tree.pos.line) - "\npossible cause: maybe a semicolon is missing before `"+decode(name)+"'?" - else "")) - } + if (!qual.tpe.widen.isErroneous) + notAMember(tree, qual, name) + if (onlyPresentation) makeErrorTree else setError(tree) } else { val tree1 = tree match { @@ -3634,7 +3601,7 @@ trait Typers { self: Analyzer => if (settings.debug.value) { log(context.imports)//debug } - error(tree.pos, "not found: "+decode(name)) + error(tree.pos, "not found: "+decodeWithNamespace(name)) defSym = context.owner.newErrorSymbol(name) } } @@ -3871,7 +3838,7 @@ trait Typers { self: Analyzer => val tpt1 = typedType(tpt, mode) val expr1 = typed(expr, mode & stickyModes, tpt1.tpe.deconst) val owntype = - if ((mode & PATTERNmode) != 0) inferTypedPattern(tpt1.pos, tpt1.tpe, pt) + if (isPatternMode) inferTypedPattern(tpt1.pos, tpt1.tpe, pt) else tpt1.tpe //Console.println(typed pattern: "+tree+":"+", tp = "+tpt1.tpe+", pt = "+pt+" ==> "+owntype)//DEBUG treeCopy.Typed(tree, expr1, tpt1) setType owntype diff --git a/src/library/scala/reflect/generic/Trees.scala b/src/library/scala/reflect/generic/Trees.scala index df93d157e3..c880a335de 100755 --- a/src/library/scala/reflect/generic/Trees.scala +++ b/src/library/scala/reflect/generic/Trees.scala @@ -37,6 +37,7 @@ trait Trees { self: Universe => def isProtected = hasFlag(PROTECTED) def isPublic = !isPrivate && !isProtected def isSealed = hasFlag(SEALED ) + def isSynthetic = hasFlag(SYNTHETIC) def isTrait = hasFlag(TRAIT ) def isVariable = hasFlag(MUTABLE ) diff --git a/test/files/neg/bug2206.check b/test/files/neg/bug2206.check new file mode 100644 index 0000000000..3deb4d99ef --- /dev/null +++ b/test/files/neg/bug2206.check @@ -0,0 +1,5 @@ +bug2206.scala:10: error: value f is not a member of o.A + Note: implicit method ax is not applicable here because it comes after the application point and it lacks an explicit result type + a.f() + ^ +one error found diff --git a/test/files/neg/bug2206.scala b/test/files/neg/bug2206.scala new file mode 100644 index 0000000000..cd2ec225e9 --- /dev/null +++ b/test/files/neg/bug2206.scala @@ -0,0 +1,15 @@ +object o { + class A + + class AX { + def f() { } + } + + import Implicits._ + val a = new A + a.f() + + object Implicits { + implicit def ax(a: A) = new AX + } +}
\ No newline at end of file diff --git a/test/files/neg/bug278.check b/test/files/neg/bug278.check index a3d44f6508..ad0a97371e 100644 --- a/test/files/neg/bug278.check +++ b/test/files/neg/bug278.check @@ -1,4 +1,7 @@ -bug278.scala:5: error: overloaded method value a with alternatives => (C.this.A) => Unit <and> => () => Unit does not take type parameters +bug278.scala:5: error: overloaded method value a with alternatives: + => (C.this.A) => Unit <and> + => () => Unit + does not take type parameters a[A] ^ bug278.scala:4: error: method a is defined twice diff --git a/test/files/neg/overload-msg.check b/test/files/neg/overload-msg.check new file mode 100644 index 0000000000..780830bff9 --- /dev/null +++ b/test/files/neg/overload-msg.check @@ -0,0 +1,13 @@ +overload-msg.scala:3: error: overloaded method value + with alternatives: + (Double)Double <and> + (Float)Float <and> + (Long)Long <and> + (scala.Int)scala.Int <and> + (Char)scala.Int <and> + (Short)scala.Int <and> + (Byte)scala.Int <and> + (java.lang.String)java.lang.String + cannot be applied to (Int(in method f)) + def f[Int](y: Int) = x + y + ^ +one error found diff --git a/test/files/neg/overload-msg.scala b/test/files/neg/overload-msg.scala new file mode 100644 index 0000000000..8715c156a2 --- /dev/null +++ b/test/files/neg/overload-msg.scala @@ -0,0 +1,4 @@ +// type parameter shadows actual type, massive overload error confuses. +class A(x: Int) { + def f[Int](y: Int) = x + y +} diff --git a/test/files/neg/typeerror.check b/test/files/neg/typeerror.check index 3e21a79ad5..3ce11dad8a 100644 --- a/test/files/neg/typeerror.check +++ b/test/files/neg/typeerror.check @@ -1,6 +1,6 @@ typeerror.scala:6: error: type mismatch; found : Long(in method add) - required: Long(in package scala) + required: scala.Long else add2(x.head, y.head) :: add(x.tail, y.tail) ^ one error found |