summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala135
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala268
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala125
-rwxr-xr-xsrc/library/scala/reflect/generic/Trees.scala1
-rw-r--r--test/files/neg/bug2206.check5
-rw-r--r--test/files/neg/bug2206.scala15
-rw-r--r--test/files/neg/bug278.check5
-rw-r--r--test/files/neg/overload-msg.check13
-rw-r--r--test/files/neg/overload-msg.scala4
-rw-r--r--test/files/neg/typeerror.check2
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