From 1111b27d0eb95d69d7507291d242817a2dbe7e64 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 23 Sep 2011 14:22:13 +0000 Subject: Back to square one. Current design of error trees complicates the design of reflection library, and introduces sometimes unnecessary boilerplate and since I do not want to stall that work I am reverting all the changes related to error trees. A different design is currently under consideration but work will be done on separate branch on github. Revisions that got reverted: r25705, r25704 (partially), r25673, r25669, r25649, r25644, r25621, r25620, r25619 Review by odersky and extempore. --- .../scala/tools/nsc/typechecker/Analyzer.scala | 1 - .../scala/tools/nsc/typechecker/Contexts.scala | 8 +- .../scala/tools/nsc/typechecker/ErrorTrees.scala | 930 ------------- .../scala/tools/nsc/typechecker/Implicits.scala | 23 +- .../scala/tools/nsc/typechecker/Infer.scala | 303 ++-- .../scala/tools/nsc/typechecker/Namers.scala | 55 +- .../tools/nsc/typechecker/NamesDefaults.scala | 72 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 26 +- .../tools/nsc/typechecker/SuperAccessors.scala | 5 +- .../tools/nsc/typechecker/SyntheticMethods.scala | 2 +- .../tools/nsc/typechecker/TypeDiagnostics.scala | 73 +- .../scala/tools/nsc/typechecker/Typers.scala | 1462 ++++++++------------ 12 files changed, 830 insertions(+), 2130 deletions(-) delete mode 100644 src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala (limited to 'src/compiler/scala/tools/nsc/typechecker') diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 60e1a6c747..e3786c154f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -22,7 +22,6 @@ trait Analyzer extends AnyRef with Unapplies with NamesDefaults with TypeDiagnostics - with ErrorTrees { val global : Global import global._ diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 1764161866..c5304ca103 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -193,7 +193,7 @@ trait Contexts { self: Analyzer => c.retyping = this.retyping c.openImplicits = this.openImplicits registerContext(c.asInstanceOf[analyzer.Context]) - // debuglog("Created context: " + this + " ==> " + c) + debuglog("Created context: " + this + " ==> " + c) c } @@ -283,12 +283,6 @@ trait Contexts { self: Analyzer => else throw new TypeError(pos, msg1) } -/*!!! def errorTree(pos: Position, msg: String): ErrorTree = { - error(pos, msg) - ErrorTree(msg) setPos pos - } - */ - def warning(pos: Position, msg: String) = { if (reportGeneralErrors) unit.warning(pos, msg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala b/src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala deleted file mode 100644 index 39d9d6b2ae..0000000000 --- a/src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala +++ /dev/null @@ -1,930 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package typechecker - -/** - * @author Hubert Plociniczak - * @version 1.0 - */ - -import scala.collection.{ mutable, immutable } -import scala.tools.util.StringOps.{ countElementsAsString, countAsString } - -trait ErrorTrees { - self: Analyzer => - - import global._ - - trait ErrorTree extends AbsErrorTree { - override def containsError() = true - def emit(context: Context): Unit - def emit(): Unit = emit(typer.context.asInstanceOf[Context]) - def exception: TypeError = null // Once we get rid of all thrown type errors (apart from cyclic), remove - var reported = false - override def tpe = ErrorType - - // Debugging option - if (settings.errortrees.value) - println("[ErrorTree instance] " + this.getClass) - } - - trait ErrorPosAndMsg { - def errMsg: String - def errPos: Position - def shouldEmit: Boolean - def emit(context: Context): Unit - } - protected trait ContextError extends ErrorPosAndMsg { } - - trait ErrorTreeWithContext extends ErrorTree with ContextError { - def shouldEmit = true - def emit(context: Context) = if (shouldEmit) context.error(errPos, errMsg) - } - - /** Traverses a tree, collecting subtrees for which the first argument is - * defined. A given tree's children are traversed only if the keepTraversing - * predicate returns true for that tree. - */ - def pruningCollect[T](pf: PartialFunction[Tree, T])(keepTraversing: Tree => Boolean): Tree => List[T] = { - class Collector extends Traverser { - val trees = mutable.ListBuffer[T]() - override def traverse(t: Tree) { - if (pf.isDefinedAt(t)) - trees += pf(t) - if (keepTraversing(t)) - super.traverse(t) - } - } - tree => { - val c = new Collector - c traverse tree - c.trees.toList - } - } - - def errorTreesFinder(tree: Tree): List[ErrorTree] = - pruningCollect({ case e: ErrorTree if !e.reported => e })(!_.isInstanceOf[ErrorTree])(tree) - - def quickErrorTreeFinder(tree: Tree): ErrorTree = tree find (_.isInstanceOf[ErrorTree]) match { - case Some(x: ErrorTree) => x - case _ => NullErrorTree - } - - protected abstract class TreeForwarder(forwardTo: Tree) extends Tree { - override def pos = forwardTo.pos - override def hasSymbol = forwardTo.hasSymbol - override def symbol = forwardTo.symbol - override def symbol_=(x: Symbol) = forwardTo.symbol = x - } - abstract class PositionedErrorTree(tree: Tree) extends ErrorTree with ErrorPosAndMsg { - def errPos = tree.pos - def shouldEmit = !tree.isErroneous - def emit(context: Context) = if (shouldEmit) context.error(errPos, errMsg) - } - abstract class ContextErrorTree(tree: Tree) extends PositionedErrorTree(tree) with ContextError { } - abstract class ErrorTreeForwarder(tree: Tree) extends TreeForwarder(tree) with ErrorTree with ErrorPosAndMsg { - def errPos = tree.pos - def shouldEmit = !tree.isErroneous - def emit(context: Context) = if (shouldEmit) context.error(errPos, errMsg) - } - abstract class ContextErrorTreeForwarder(tree: Tree) extends ErrorTreeForwarder(tree) with ContextError { } - - // create trees for specific error trees - - trait TyperErrorTrees { - self: Typer => - - trait TypeErrorTrait extends ErrorTree with ErrorPosAndMsg { - def errMsg = "type error" // not used - def emit(context: Context) { - reportTypeError(context, errPos, exception) - } - } - abstract class TypeErrorTreeForwarder(tree: Tree) extends ErrorTreeForwarder(tree) with TypeErrorTrait { - override def emit(context: Context) { - super[TypeErrorTrait].emit(context) - } - } - - import infer.setError - - case class UnstableTreeError(tree: Tree) extends ErrorTreeForwarder(tree) { - private def addendum = { - // !!! unused - // val tpe = tree.symbol.tpe match { - // case PolyType(_, rtpe) => rtpe - // case t => t - // } - "\n Note that "+tree.symbol+" is not stable because its type, "+tree.tpe+", is volatile." - } - def errMsg = ( - "stable identifier required, but "+tree+" found." + ( - if (isStableExceptVolatile(tree)) addendum else "" - ) - ) - } - - case class NoImplicitFoundError(tree: Tree, param: Symbol) extends ContextErrorTreeForwarder(tree) { - def errMsg = { - val paramName = param.name - val paramTp = param.tpe - paramTp.typeSymbol match { - case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp) - case _ => - "could not find implicit value for "+ - (if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type " - else "parameter "+paramName+": ")+paramTp - } - } - } - - case class TypeErrorTree(tree: Tree, pt: Type, override val exception: TypeError) extends TypeErrorTreeForwarder(tree) { } - - case class AdaptToMemberWithArgsError(tree: Tree, override val exception: TypeError) extends TypeErrorTreeForwarder(tree) { } - - case class WithFilterError(tree: Tree, override val exception: TypeError) extends TypeErrorTreeForwarder(tree) { - override def emit(context: Context) { - super.emit(context) - setError(tree) - } - } - - case class ParentTypesError(templ: Template, override val exception: TypeError) extends TypeErrorTrait { - def errPos = templ.pos - def shouldEmit = !templ.isErroneous - override def emit(context: Context) { - templ.tpe = null - super.emit(context) - } - } - - // additional parentTypes errors - case class ConstrArgsInTraitParentTpeError(arg: Tree, parent: Symbol) extends ContextErrorTree(arg) { - def errMsg = parent + " is a trait; does not take constructor arguments" - } - - case class MissingTypeArgumentsParentTpeError(supertpt: Tree) extends ContextErrorTree(supertpt) { - def errMsg = "missing type arguments" - } - - case class SilentTypeError(tree: Tree, override val exception: TypeError) extends TypeErrorTrait { - def shouldEmit = false // !!! correct? - def errPos = tree.pos - } - - case class TypedApplyError(tree: Tree, override val exception: TypeError) extends TypeErrorTreeForwarder(tree) { - override def pos = exception.pos - } - - case class AssignmentTypedApplyError(tree: Tree) extends ContextErrorTreeForwarder(tree) { - def errMsg = "reassignment to val" - } - - // typedIdent - case class AmbiguousIdentError(tree: Tree, name: Name, msg: String) extends ContextErrorTreeForwarder(tree) { - def errMsg = "reference to " + name + " is ambiguous;\n" + msg - } - - case class SymbolNotFound(tree: Tree, name: Name, owner: Symbol) extends ContextErrorTreeForwarder(tree) { - def errMsg = "not found: "+decodeWithKind(name, owner) - } - - // typedAppliedTypeTree - case class AppliedTypeNoParametersError(tree: Tree, errTpe: Type) extends ErrorTreeForwarder(tree) { - def errMsg = errTpe + " does not take type parameters" - } - - case class AppliedTypeWrongNumberOfArgsError(tree: Tree, errMsg: String) extends ErrorTreeForwarder(tree) { } - - // packagedef - case class RefTreeError(tree: Tree, name: Name) extends ErrorTree with RefTree { - // Error was already reported - def emit(context: Context) { } - } - - // typedTypeDef - case class LowerBoundError(tree: TypeDef, lowB: Type, highB: Type) extends ContextErrorTree(tree) { - def errMsg = "lower bound "+lowB+" does not conform to upper bound "+highB - } - - // check privates - case class HiddenSymbolWithError(tree: Tree) extends ErrorTree { - def emit(context: Context) { } - } - - case class SymbolEscapesScopeError(tree: Tree, badSymbol: Symbol) extends ErrorTreeWithContext { - private val treeTpe = tree.tpe - def errPos = tree.pos - def errMsg = modifierString + badSymbol + " escapes its defining scope as part of type "+treeTpe - private def modifierString = if (badSymbol.isPrivate) "private " else "" - } - - // typedDefDef - case class StarParamNotLastError(param: Tree) extends ContextErrorTree(param) { - def errMsg = "*-parameter must come last" - } - - case class StarWithDefaultError(meth: Symbol) extends ErrorTreeWithContext { - def errMsg = "a parameter section with a `*'-parameter is not allowed to have default arguments" - def errPos = meth.pos - } - - case class InvalidConstructorDefError(ddef: Tree) extends ContextErrorTree(ddef) { - def errMsg = "constructor definition not allowed here" - } - - case class DeprecatedParamNameError(param: Symbol, name: Name) extends ErrorTreeWithContext { - def errMsg = "deprecated parameter name "+ name +" has to be distinct from any other parameter name (deprecated or not)." - def errPos = param.pos - } - - // computeParamAliases - case class SuperConstrReferenceError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "super constructor cannot be passed a self reference unless parameter is declared by-name" - } - - case class SuperConstrArgsThisReferenceError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "super constructor arguments cannot reference unconstructed `this`" - } - - // typedValDef - case class VolatileValueError(vdef: Tree) extends ContextErrorTree(vdef) { - def errMsg = "values cannot be volatile" - } - - case class FinalVolatileVarError(vdef: Tree) extends ContextErrorTree(vdef) { - def errMsg = "final vars cannot be volatile" - } - - case class LocalVarUninitializedError(vdef: Tree) extends ContextErrorTree(vdef) { - def errMsg = "local variables must be initialized" - } - - //typedAssign - case class AssignmentError(tree: Tree, varSym: Symbol) extends ContextErrorTreeForwarder(tree) { - def errMsg = - if (varSym != null && varSym.isValue) "reassignment to val" - else "assignment to non variable" - } - - case class UnexpectedTreeAssignmentConversionError(tree: Tree) extends ContextErrorTreeForwarder(tree) { - def errMsg = "Unexpected tree during assignment conversion." - } - - case class MultiDimensionalArrayError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "cannot create a generic multi-dimensional array of more than "+ definitions.MaxArrayDims+" dimensions" - } - - //typedSuper - case class MixinMissingParentClassNameError(tree: Tree, mix: Name, clazz: Symbol) extends ContextErrorTree(tree) { - def errMsg = mix+" does not name a parent class of "+clazz - } - - case class AmbiguousParentClassError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "ambiguous parent class qualifier" - } - - //typedSelect - case class NotAMemberErroneous(tree: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "" - override def emit(context: Context) { } - } - - case class NotAMemberError(sel: Tree, qual: Tree, name: Name) extends ContextErrorTreeForwarder(sel) { - def errMsg = { - val owner = qual.tpe.typeSymbol - val target = qual.tpe.widen - def targetKindString = if (owner.isTypeParameterOrSkolem) "type parameter " else "" - def nameString = decodeWithKind(name, owner) - /** Illuminating some common situations and errors a bit further. */ - def addendum = { - val companion = { - if (name.isTermName && owner.isPackageClass) { - target.member(name.toTypeName) match { - case NoSymbol => "" - case sym => "\nNote: %s exists, but it has no companion object.".format(sym) - } - } - else "" - } - val semicolon = ( - if (linePrecedes(qual, sel)) - "\npossible cause: maybe a semicolon is missing before `"+nameString+"'?" - else - "" - ) - companion + semicolon - } - withAddendum(qual.pos)( - if (name == nme.CONSTRUCTOR) target + " does not have a constructor" - else nameString + " is not a member of " + targetKindString + target + addendum - ) - } - } - - //typedNew - case class IsAbstractError(tree: Tree, sym: Symbol) extends ContextErrorTree(tree) { - def errMsg = sym + " is abstract; cannot be instantiated" - } - - case class DoesNotConformToSelfTypeError(tree: Tree, sym: Symbol, tpe0: Type) extends ContextErrorTree(tree) { - def errMsg = sym + " cannot be instantiated because it does not conform to its self-type " + tpe0 - } - - //typedEta - case class UnderscoreEtaError(tree: Tree) extends PositionedErrorTree(tree) { - def errMsg = "_ must follow method; cannot follow " + tree.tpe - } - - //typedReturn - case class ReturnOutsideOfDefError(tree: Tree) extends PositionedErrorTree(tree) { - def errMsg = "return outside method definition" - } - - case class ReturnWithoutTypeError(tree: Tree, owner: Symbol) extends PositionedErrorTree(tree) { - def errMsg = owner + " has return statement; needs result type" - } - - //typedBind - case class VariableInPatternAlternativeError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "illegal variable in pattern alternative" - } - - //typedCase - case class StarPositionInPatternError(errPos: Position) extends ErrorTreeWithContext { - def errMsg = "_* may only come last" - } - - //typedFunction - case class MaxFunctionArityError(fun: Tree) extends ErrorTreeForwarder(fun) { - def errMsg = "implementation restricts functions to " + definitions.MaxFunctionArity + " parameters" - } - - case class WrongNumberOfParametersError(tree: Tree, argpts: List[Type]) extends ErrorTreeForwarder(tree) { - def errMsg = "wrong number of parameters; expected = " + argpts.length - } - - case class MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) extends ContextErrorTree(vparam) { - def anonMessage = ( - "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" + - "\nExpected type was: " + pt.toLongString - ) - - private val suffix = - if (!vparam.mods.isSynthetic) "" - else " for expanded function" + (fun match { - case Function(_, Match(_, _)) => anonMessage - case _ => " " + fun - }) - - def errMsg = "missing parameter type" + suffix - } - - case class ConstructorsOrderError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "called constructor's definition must precede calling constructor's definition" - } - - case class OnlyDeclarationsError(tree: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "only declarations allowed here" - } - - // typedAnnotation - case class AnnotationNotAConstantError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "annotation argument needs to be a constant; found: " + tree - } - - case class AnnotationArgNullError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "annotation argument cannot be null" - } - - case class ArrayConstantsError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "Array constants have to be specified using the `Array(...)' factory method" - } - - case class ArrayConstantsTypeMismatchError(tree: Tree, pt: Type) extends ContextErrorTree(tree) { - def errMsg = "found array constant, expected argument of type " + pt - } - - case class UnexpectedTreeAnnotation(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "unexpected tree in annotation: "+ tree - } - - case class AnnotationTypeMismatchError(tree: Tree, expected: Type, found: Type) extends ContextErrorTree(tree) { - def errMsg = "expected annotation of type " + expected + ", found " + found - } - - case class MultipleArgumentListForAnnotationError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "multiple argument lists on classfile annotation" - } - - case class UnknownAnnotationNameError(tree: Tree, name: Name) extends ContextErrorTree(tree) { - def errMsg = "unknown annotation argument name: " + name - } - - case class DuplicateValueAnnotationError(tree: Tree, name: Name) extends ContextErrorTree(tree) { - def errMsg = "duplicate value for annotation argument " + name - } - - case class ClassfileAnnotationsAsNamedArgsError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "classfile annotation arguments have to be supplied as named arguments" - } - - case class AnnotationMissingArgError(tree: Tree, annType: Type, name: Symbol) extends ContextErrorTree(tree) { - def errMsg = "annotation " + annType.typeSymbol.fullName + " is missing argument " + name.name - } - - case class NestedAnnotationError(tree: Tree, annType: Type) extends ContextErrorTree(tree) { - def errMsg = "nested classfile annotations must be defined in java; found: "+ annType - } - - case class UnexpectedTreeAnnotationError(tree: Tree, unexpected: Tree) extends ContextErrorTree(tree) { - def errMsg = "unexpected tree after typing annotation: "+ unexpected - } - - // TODO no test case - //typedExistentialTypeTree - case class AbstractionFromVolatileTypeError(vd: ValDef) extends ContextErrorTree(vd) { - def errMsg = "illegal abstraction from value with volatile type "+vd.symbol.tpe - } - - case class TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "wrong number of type parameters for "+treeSymTypeMsg(fun) - } - - case class TypedApplyDoesNotTakeTpeParametersError(tree: Tree, fun: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = treeSymTypeMsg(fun)+" does not take type parameters." - } - - // doTypeApply - //tryNamesDefaults - case class WrongNumberOfArgsError(tree: Tree, fun: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "wrong number of arguments for "+ treeSymTypeMsg(fun) - } - - case class TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "too many arguments for "+treeSymTypeMsg(fun) - } - - case class MultipleVarargError(tree: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "when using named arguments, the vararg parameter has to be specified exactly once" - } - - case class ModuleUsingCompanionClassDefaultArgsErrror(tree: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "module extending its companion class cannot use default constructor arguments" - } - - case class NotEnoughArgsError(tree: Tree, fun0: Tree, missing0: List[Symbol]) extends ErrorTreeForwarder(tree) { - def errMsg = notEnoughArgumentsMsg(fun0, missing0) - def notEnoughArgumentsMsg(fun: Tree, missing: List[Symbol]) = { - val suffix = { - if (missing.isEmpty) "" - else { - val keep = missing take 3 map (_.name) - ".\nUnspecified value parameter%s %s".format( - if (missing.tail.isEmpty) "" else "s", - if (missing drop 3 nonEmpty) (keep :+ "...").mkString(", ") - else keep.mkString("", ", ", ".") - ) - } - } - - "not enough arguments for " + treeSymTypeMsg(fun) + suffix - } - } - - //doTypedApply - ErrorType - case class ErroneousFunInTypeApplyError(fun: Tree, args: List[Tree]) extends TreeForwarder(fun) with ErrorTree { - private lazy val errorCache = errorTreesFinder(fun) ++ (args flatMap errorTreesFinder) - - def emit(context: Context) { - errorCache foreach (_ emit context) - } - } - - //doTypedApply - patternMode - // TODO: missing test case - case class TooManyArgsPatternError(fun: Tree) extends ContextErrorTreeForwarder(fun) { - def errMsg = "too many arguments for unapply pattern, maximum = "+definitions.MaxTupleArity - } - - case class WrongNumberArgsPatternError(tree: Tree, fun: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = "wrong number of arguments for "+treeSymTypeMsg(fun) - } - - // Extends ErrorTreeWithPrettyPrinter to pass presentation/ping-pong test case - case class ApplyWithoutArgsError(tree: Tree, fun: Tree) extends ErrorTreeForwarder(tree) with ErrorTreeWithPrettyPrinter { - def errMsg = fun.tpe+" does not take parameters" - override def toString = "" + tree - } - - //checkClassType - // When validating parents we sometimes should continue to - // type the body of the template and sometimes not. - // trait BlockingError allows us to distinguish it - trait BlockingError - - case class TypeNotAStablePrefixError(pre: Type, errPos: Position) extends ErrorTreeWithContext with BlockingError { - def errMsg = "type "+pre+" is not a stable prefix" - } - - case class ClassTypeRequiredError(tree: Tree, found: AnyRef) extends ContextErrorTree(tree) with BlockingError { - def errMsg = "class type required but "+found+" found" - } - - // validateParentClasses - case class ParentSuperSubclassError(errPos: Position, superclazz: Symbol, - parentSym: Symbol, mixin: Symbol) - extends ErrorTreeWithContext { - - def errMsg = "illegal inheritance; super"+superclazz+ - "\n is not a subclass of the super"+parentSym+ - "\n of the mixin " + mixin - } - - case class ParentNotATraitMixinError(errPos: Position, mixin: Symbol) extends ErrorTreeWithContext with BlockingError { - def errMsg = mixin+" needs to be a trait to be mixed in" - } - - case class ParentFinalInheritanceError(errPos: Position, mixin: Symbol) extends ErrorTreeWithContext with BlockingError { - def errMsg = "illegal inheritance from final "+mixin - } - - case class ParentSealedInheritanceError(errPos: Position, mixin: Symbol) extends ErrorTreeWithContext with BlockingError { - def errMsg = "illegal inheritance from sealed "+mixin - } - - case class ParentSelfTypeConformanceError(errPos: Position, selfType: Type, parent: Tree) extends ErrorTreeWithContext { - def errMsg = ( - "illegal inheritance;\n self-type "+selfType+" does not conform to "+ - parent +"'s selftype "+parent.tpe.typeOfThis - ) - } - - case class ParentInheritedTwiceError(errPos: Position, parent: Symbol) extends ErrorTreeWithContext with BlockingError { - def errMsg = parent+" is inherited twice" - } - - //adapt - case class MissingArgsForMethodTpeError(tree: Tree, meth: Symbol) extends PositionedErrorTree(tree) { - def errMsg = ( - "missing arguments for " + meth.fullLocationString + ( - if (meth.isConstructor) "" - else ";\nfollow this method with `_' if you want to treat it as a partially applied function" - ) - ) - } - - // This is really a workaround for a compiler bug - case class Bug4425Error(tree: Tree) extends ContextErrorTreeForwarder(tree) { - def errMsg = "erroneous or inaccessible type" - } - - case class MissingTypeParametersError(tree: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = tree.symbol+" takes type parameters" - - // !!! Necessary? - // override def emit(context: Context) { - // super.emit(context) - // setError(tree) - // } - } - - case class KindArityMismatchError(tree: Tree, pt: Type) extends ErrorTreeForwarder(tree) { - def errMsg = ( - tree.tpe+" takes "+countElementsAsString(tree.tpe.typeParams.length, "type parameter")+ - ", expected: "+countAsString(pt.typeParams.length) - ) - } - //case class ParamsNotConvertible - - case class CaseClassConstructorError(tree: Tree) extends ErrorTreeForwarder(tree) { - def errMsg = tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method" - } - - //TODO Needs test case - case class ConstructorPrefixError(tree: Tree, restpe: Type) extends ContextErrorTree(tree) { - def errMsg = restpe.prefix+" is not a legal prefix for a constructor" - } - - // SelectFromTypeTree - case class TypeSelectionFromVolatileTypeError(tree: Tree, qual: Tree) extends ContextErrorTree(tree) { - def errMsg = "illegal type selection from volatile type "+qual.tpe - } - - // packedType - case class InferTypeWithVolatileTypeSelectionError(tree: Tree, pre: Type) extends ContextErrorTree(tree) { - def errMsg = "Inferred type "+tree.tpe+" contains type selection from volatile type "+pre - } - - case class AbstractExistentiallyOverParamerizedTpeError(tree: Tree, tp: Type) extends ContextErrorTree(tree) { - def errMsg = "can't existentially abstract over parameterized type " + tp - } - - //manifestTreee - case class MissingManifestError(errPos: Position, full: Boolean, tp: Type) extends ErrorTreeWithContext { - def errMsg = "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp - } - - // TODO needs test case - // cases where we do not necessairly return trees - case class DependentMethodTpeConversionToFunctionError(errPos: Position, tp: Type) extends ErrorTreeWithContext { - def errMsg = "method with dependent type "+tpe+" cannot be converted to function value" - override def pos = errPos - } - - //checkStarPatOK - case class StarPatternWithVarargParametersError(errPos: Position) extends ErrorTreeWithContext { - def errMsg = "star patterns must correspond with varargs parameters" - } - - case class GetterDefinedTwiceError(getter: Symbol) extends ErrorTreeWithContext { - def errMsg = getter+" is defined twice" - def errPos = getter.pos - } - - case class BeanPropertyAnnotationLimitationError(tree: Tree) extends ContextErrorTree(tree) { - def errMsg = "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import" - } - - // TODO missing test case - case class FinitaryError(tparam: Symbol) extends ErrorTreeWithContext { - def errMsg = "class graph is not finitary because type parameter "+tparam.name+" is expansively recursive" - def errPos = tparam.pos - } - - // TODO missing test case for a second case - case class QualifyingClassError(tree: Tree, qual: Name) extends ContextErrorTree(tree) { - def errMsg = - if (qual.isEmpty) tree + " can be used only in a class, object, or template" - else qual + " is not an enclosing class" - } - - // def stabilize - case class NotAValueError(tree: Tree, sym: Symbol) extends ErrorTreeForwarder(tree) { - def errMsg = sym.kindString + " " + sym.fullName + " is not a value" - } - - // checkNoDoubleDefs... - case class DefDefinedTwiceError(sym0: Symbol, sym1: Symbol) extends ErrorTreeWithContext { - def errMsg = sym1+" is defined twice"+{if(!settings.debug.value) "" else " in "+context.unit} - def errPos = sym0.pos - override def pos = sym0.pos - } - - // cyclic errors - case class CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) extends ErrorTreeWithContext { - def errMsg = "cyclic aliasing or subtyping involving "+sym0 - override def pos = errPos - } - - case class CyclicReferenceError(errPos: Position, lockedSym: Symbol) extends ErrorTreeWithContext { - def errMsg = "illegal cyclic reference involving " + lockedSym - override def pos = errPos - } - } - - trait InferencerErrorTrees { - self: Inferencer => - - private def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = { - def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")") - - def resType = if (pt isWildcard) "" else " with expected result type " + pt - def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt - def locals = alternatives(tree) flatMap (_.typeParams) - - withDisambiguation(locals, allTypes: _*) { - treeSymTypeMsg(tree) + msg + asParams(argtpes) + resType - } - } - - case class AccessError(tree: Tree, sym: Symbol, pre: Type, owner0: Symbol, explanation: String) extends ContextErrorTreeForwarder(tree) { - def errMsg = { - val realsym = underlying(sym) - val location = if (sym.isClassConstructor) owner0 else pre.widen - - realsym.fullLocationString + " cannot be accessed in " + - location + explanation - } - } - - case class NoMethodInstanceError(fn: Tree, args: List[Tree], msg: String) extends ErrorTreeForwarder(fn) { - def errMsg = ( - "no type parameters for " + - applyErrorMsg(fn, " exist so that it can be applied to arguments ", args map (_.tpe.widen), WildcardType) + - "\n --- because ---\n" + msg - ) - } - - // TODO: no test case - case class NoConstructorInstanceError(tree: Tree, restpe: Type, pt: Type, msg: String) extends ErrorTreeForwarder(tree) { - def errMsg = ( - "constructor of type " + restpe + - " cannot be uniquely instantiated to expected type " + pt + - "\n --- because ---\n" + msg - ) - } - - case class ConstrInstantiationError(tree: Tree, restpe: Type, pt: Type) extends ErrorTreeForwarder(tree) { - def errMsg = "constructor cannot be instantiated to expected type" + foundReqMsg(restpe, pt) - } - - case class NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) extends ErrorTreeForwarder(tree) { - def errMsg = applyErrorMsg(tree, " cannot be applied to ", argtpes, pt) - } - - case class AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, - firstCompeting: Symbol, argtpes: List[Type], pt: Type) - extends ErrorTreeForwarder(tree) { - - def errMsg = ( - "argument types " + argtpes.mkString("(", ",", ")") + - (if (pt == WildcardType) "" else " and expected result type " + pt) - ) - override def emit(context: Context) { - context.ambiguousError(tree.pos, pre, best, firstCompeting, errMsg) - } - } - - case class NoBestExprAlternativeError(tree: Tree, pt: Type) extends ContextErrorTreeForwarder(tree) { - def errMsg = withAddendum(tree.pos)(typeErrorMsg(tree.symbol.tpe, pt)) - } - - case class AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type) - extends ErrorTreeForwarder(tree) { - - def errMsg = "expected type " + pt - override def emit(context: Context) { - context.ambiguousError(tree.pos, pre, best, firstCompeting, errMsg) - } - } - - // checkBounds - case class KindBoundErrors(errPos: Position, prefix: String, targs: List[Type], - tparams: List[Symbol], kindErrors: List[String]) - extends ErrorTreeWithContext { - - def errMsg = ( - prefix + "kinds of the type arguments " + targs.mkString("(", ",", ")") + - " do not conform to the expected kinds of the type parameters "+ - tparams.mkString("(", ",", ")") + tparams.head.locationString+ "." + - kindErrors.toList.mkString("\n", ", ", "") - ) - override def pos = errPos - } - - case class NotWithinBounds(pos0: Position, prefix: String, targs: List[Type], - tparams: List[Symbol], kindErrors: List[String]) - extends ErrorTree { - - val savedContext = getContext - def emit(context: Context) { - val validContext = if (context.unit == NoCompilationUnit) savedContext else context - validContext.error(pos0, - prefix + "type arguments " + targs.mkString("[", ",", "]") + - " do not conform to " + tparams.head.owner + "'s type parameter bounds " + - (tparams map (_.defString)).mkString("[", ",", "]")) - if (settings.explaintypes.value) { - val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds) - (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ)) - (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi)) - () - } - } - - override def pos = pos0 - } - - //substExpr - case class PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) extends ContextErrorTreeForwarder(tree) { - def errMsg = ( - "polymorphic expression cannot be instantiated to expected type" + - foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt) - ) - } - - //checkCheckable - case class TypePatternOrIsInstanceTestError(errPos: Position, tp: Type) extends ErrorTreeWithContext { - def errMsg = "type "+tp+" cannot be used in a type pattern or isInstanceOf test" - override def pos = errPos - } - - case class IncompletePatternTypeError(errPos: Position, pattp: Type, pt: Type) extends ErrorTreeWithContext { - def errMsg = "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt) - override def pos = errPos - } - - case class IncompatibleScrutineeTypeError(errPos: Position, pattp: Type, pt: Type) extends ErrorTreeWithContext { - def errMsg = "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt) - override def pos = errPos - } - - case class PatternTypeIncompatibleWithPtError(pat: Tree, pt1: Type, pt: Type) extends ContextErrorTreeForwarder(pat) { - def errMsg = { - val sym = pat.tpe.typeSymbol - val clazz = sym.companionClass - val addendum = ( - if (sym.isModuleClass && clazz.isCaseClass && (clazz isSubClass pt1.typeSymbol)) { - // TODO: move these somewhere reusable. - val typeString = clazz.typeParams match { - case Nil => "" + clazz.name - case xs => xs map (_ => "_") mkString (clazz.name + "[", ",", "]") - } - val caseString = ( - clazz.caseFieldAccessors - map (_ => "_") // could use the actual param names here - mkString (clazz.name + "(", ",", ")") - ) - ( - "\nNote: if you intended to match against the class, try `case _: " + - typeString + "` or `case " + caseString + "`" - ) - } - else "" - ) - "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt) + addendum - } - } - - case class PolyAlternativeError(tree: Tree, errMsg: String) extends ContextErrorTreeForwarder(tree) { } - } - - trait NamerErrorTrees { - self: Namer => - - // Currently too general - case class TypeSigError(tree: Tree, override val exception: TypeError) extends ErrorTree { - def emit(context: Context) { - typer.reportTypeError(context, tree.pos, exception) - } - } - } - - // General errors - case class PendingErrors(pending0: List[ErrorTree]) - extends ErrorTree { - assert(pending0.nonEmpty, "pending exceptions cannot be empty") - - def emit(context: Context) { - // Try to report each, here we dont' care - // if any of those throws TypeError - // this is handled in the actual application code - pending0.foreach(_.emit(context)) - } - - override def pos = pending0.head.pos - override def exception: TypeError = pending0.head.exception - } - - case object NullErrorTree extends ErrorTree { - def emit(context: Context) {} - } - - case class SetErrorTree(tree: Tree) extends ErrorTree { - def emit(context: Context) { - typer.infer.setError(tree) - } - } - - //NamesDefaults errors, refactor to their own trait - case class NameClashError(sym: Symbol, arg: Tree) extends ErrorTreeWithContext { - def errMsg = - "%s definition needs %s because '%s' is used as a named argument in its body.".format( - "variable", // "method" - "type", // "result type" - sym.name) - - override def emit(context: Context) = { - super.emit(context) - // This is ugly hack to avoid reporting double errors - // when dealing with AmbiguousReferences problem (error tree below) in names defaults. - typer.infer.setError(arg) - } - - def errPos = sym.pos - override def pos = sym.pos - } - - case class AmbiguousReferenceInNamesDefaultError(arg: Tree, name: Name) extends ErrorTreeForwarder(arg) { - def errMsg = ( - "reference to "+ name +" is ambiguous; it is both, a parameter\n"+ - "name of the method and the name of a variable currently in scope." - ) - } - - case class UnknownParameterNameNamesDefaultError(arg: Tree, name: Name) extends ErrorTreeForwarder(arg) { - def errMsg = "unknown parameter name: " + name - } - - case class DoubleParamNamesDefaultError(arg: Tree, name: Name) extends ErrorTreeForwarder(arg) { - def errMsg = "parameter specified twice: "+ name - } - - case class PositionalAfterNamedNamesDefaultError(arg: Tree) extends ErrorTreeForwarder(arg) { - def errMsg = "positional after named argument." - } -} diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 0ab619e875..169295e5c9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -522,9 +522,6 @@ trait Implicits { else typed1(itree, EXPRmode, wildPt) - if (itree1.containsError()) - return SearchFailure - incCounter(typedImplicits) printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt)) @@ -544,7 +541,7 @@ trait Implicits { } } - if (itree2.containsErrorOrIsErrorTyped()) + if (itree2.tpe.isError) SearchFailure else if (!hasMatchingSymbol(itree1)) fail("candidate implicit %s is shadowed by other implicit %s".format( @@ -568,11 +565,7 @@ trait Implicits { false, lubDepth(List(itree2.tpe, pt))) // #2421: check that we correctly instantiated type parameters outside of the implicit tree: - // TODO: refactoring needed, shouldn't emit it here - checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") match { - case Some(err) => err.emit(context) - case _ => - } + checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") // filter out failures from type inference, don't want to remove them from undetParams! // we must be conservative in leaving type params in undetparams @@ -597,18 +590,12 @@ trait Implicits { // re-typecheck) // TODO: the return tree is ignored. This seems to make // no difference, but it's bad practice regardless. - - // we call typedTypeApply which can return an error tree, - // so we cannot ignore the tree - // TODO check if that is enough - val checked = itree2 match { + itree2 match { case TypeApply(fun, args) => typedTypeApply(itree2, EXPRmode, fun, args) case Apply(TypeApply(fun, args), _) => typedTypeApply(itree2, EXPRmode, fun, args) // t2421c case t => t } - if (checked.containsError()) - return SearchFailure - val result = new SearchResult(checked, subst) + val result = new SearchResult(itree2, subst) incCounter(foundImplicits) printInference("[typedImplicit1] SearchResult: " + result) result @@ -618,8 +605,6 @@ trait Implicits { } } catch { - // TODO: once refactoring of type errors is done we should only - // catch here cyclic references. case ex: TypeError => fail(ex.getMessage()) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 26e4da5d79..354eb52913 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -189,7 +189,7 @@ trait Infer { private val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR) /** The context-dependent inferencer part */ - class Inferencer(context: Context) extends InferencerErrorTrees { + class Inferencer(context: Context) { /* -- Error Messages --------------------------------------------------- */ def setError[T <: Tree](tree: T): T = { def name = newTermName("") @@ -203,20 +203,19 @@ trait Infer { tree setType ErrorType } - protected def getContext = context - def error(pos: Position, msg: String) { context.error(pos, msg) } -/* def makeErrorTree(tree: Tree, msg: String): Tree = { + def errorTree(tree: Tree, msg: String): Tree = { if (!tree.isErroneous) error(tree.pos, msg) setError(tree) - }*/ + } def typeError(pos: Position, found: Type, req: Type) { if (!found.isErroneous && !req.isErroneous) { error(pos, withAddendum(pos)(typeErrorMsg(found, req))) + if (settings.explaintypes.value) explainTypes(found, req) } @@ -229,8 +228,6 @@ trait Infer { "type mismatch" + foundReqMsg(found, req) + missingArgsMsg } - // TODO: replace with standard Error tree - // currently only used in adapt in Typers def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = { // If the expected type is a refinement type, and the found type is a refinement or an anon // class, we can greatly improve the error message by retyping the tree to recover the actual @@ -290,7 +287,7 @@ trait Infer { Console.println(tree) Console.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType)) } - AccessError(tree, sym, pre, context.enclClass.owner, + new AccessError(tree, sym, pre, if (settings.check.isDefault) analyzer.lastAccessCheckDetails else @@ -317,17 +314,11 @@ trait Infer { if (settings.debug.value) ex.printStackTrace val sym2 = underlying(sym1) val itype = pre.memberType(sym2) - return AccessError(tree, sym, pre, context.enclClass.owner, + new AccessError(tree, sym, pre, "\n because its instance type "+itype+ (if ("malformed type: "+itype.toString==ex.msg) " is malformed" - else " contains a "+ex.msg)) - -// enabling the following TypeError case -// crashes a few examples because there are situations (like in NamesDefaults) -// where CyclicReference is expected -// case ex: TypeError => -// return TypeErrorTree(tree, ex)(context) - + else " contains a "+ex.msg)).emit() + ErrorType } if (pre.isInstanceOf[SuperType]) owntype = owntype.substSuper(pre, site.symbol.thisType) @@ -920,9 +911,7 @@ trait Infer { false } - /** - * Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors). - * The chance of TypeErrors should be reduced through error trees + /** Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors). */ private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = { @@ -1103,20 +1092,37 @@ trait Infer { */ /** error if arguments not within bounds. */ def checkBounds(pos: Position, pre: Type, owner: Symbol, - tparams: List[Symbol], targs: List[Type], prefix: String): Option[ErrorTree] = { + tparams: List[Symbol], targs: List[Type], prefix: String) = { //@M validate variances & bounds of targs wrt variances & bounds of tparams //@M TODO: better place to check this? //@M TODO: errors for getters & setters are reported separately val kindErrors = checkKindBounds(tparams, targs, pre, owner) - if(!kindErrors.isEmpty) { - if (targs contains WildcardType) None - else Some(KindBoundErrors(pos, prefix, targs, tparams, kindErrors)) - } else if (!isWithinBounds(pre, owner, tparams, targs)) { - if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) - Some(NotWithinBounds(pos, prefix, targs, tparams, kindErrors)) - else None - } else None + if (!kindErrors.isEmpty) { + if (targs contains WildcardType) () + else error(pos, + prefix + "kinds of the type arguments " + targs.mkString("(", ",", ")") + + " do not conform to the expected kinds of the type parameters "+ + tparams.mkString("(", ",", ")") + tparams.head.locationString+ "." + + kindErrors.toList.mkString("\n", ", ", "")) + } + else if (!isWithinBounds(pre, owner, tparams, targs)) { + if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) { + //val bounds = instantiatedBounds(pre, owner, tparams, targs)//DEBUG + //println("bounds = "+bounds+", targs = "+targs+", targclasses = "+(targs map (_.getClass))+", parents = "+(targs map (_.parents))) + //println(List.map2(bounds, targs)((bound, targ) => bound containsType targ)) + error(pos, + prefix + "type arguments " + targs.mkString("[", ",", "]") + + " do not conform to " + tparams.head.owner + "'s type parameter bounds " + + (tparams map (_.defString)).mkString("[", ",", "]")) + if (settings.explaintypes.value) { + val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds) + (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ)) + (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi)) + () + } + } + } } @@ -1160,7 +1166,7 @@ trait Infer { * first to `strictPt` and then, if this fails, to `lenientPt`. If both * attempts fail, an error is produced. */ - def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type) = { + def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type) { printInference( ptBlock("inferArgumentInstance", "tree" -> tree, @@ -1174,8 +1180,8 @@ trait Infer { if ((targs eq null) || !(tree.tpe.subst(undetparams, targs) <:< strictPt)) { targs = exprTypeArgs(undetparams, tree.tpe, lenientPt) } - printInference("[inferArgumentInstance] finished, targs = " + targs) substExpr(tree, undetparams, targs, lenientPt) + printInference("[inferArgumentInstance] finished, targs = " + targs) } /** Infer type arguments `targs` for `tparams` of polymorphic expression in `tree`, given prototype `pt`. @@ -1183,7 +1189,7 @@ trait Infer { * Substitute `tparams` to `targs` in `tree`, after adjustment by `adjustTypeArgs`, returning the type parameters that were not determined * If passed, infers against specified type `treeTp` instead of `tree.tp`. */ - def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): (Option[ErrorTree], List[Symbol]) = { + def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): List[Symbol] = { val treeTp = if(treeTp0 eq null) tree.tpe else treeTp0 // can't refer to tree in default for treeTp0 printInference( ptBlock("inferExprInstance", @@ -1196,7 +1202,8 @@ trait Infer { val targs = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible) if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226 - (substExpr(tree, tparams, targs, pt), List()) + substExpr(tree, tparams, targs, pt) + List() } else { val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, targs) printInference( @@ -1206,7 +1213,8 @@ trait Infer { "leftUndet" -> leftUndet ) ) - (substExpr(tree, okParams, okArgs, pt), leftUndet) + substExpr(tree, okParams, okArgs, pt) + leftUndet } } @@ -1219,15 +1227,13 @@ trait Infer { * @param pt ... */ private def substExpr(tree: Tree, undetparams: List[Symbol], - targs: List[Type], pt: Type): Option[ErrorTree] = { + targs: List[Type], pt: Type) { if (targs eq null) { if (!tree.tpe.isErroneous && !pt.isErroneous) - Some(PolymorphicExpressionInstantiationError(tree, undetparams, pt)) - else - None + error(tree.pos, "polymorphic expression cannot be instantiated to expected type" + + foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt)) } else { new TreeTypeSubstituter(undetparams, targs).traverse(tree) - None } } @@ -1242,7 +1248,7 @@ trait Infer { * and that thus have not been substituted. */ def inferMethodInstance(fn: Tree, undetparams: List[Symbol], - args: List[Tree], pt0: Type): Either[ErrorTree, List[Symbol]] = fn.tpe match { + args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match { case MethodType(params0, _) => printInference( ptBlock("inferMethodInstance", @@ -1262,32 +1268,31 @@ trait Infer { val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt) - checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") match { - case Some(err) => - Left(err) - case _ => - // bounds are ok - val treeSubst = new TreeTypeSubstituter(okparams, okargs) - treeSubst traverseTrees fn :: args - - val result = leftUndet match { - case Nil => Nil - case xs => - // #3890 - val xs1 = treeSubst.typeSubst mapOver xs - if (xs ne xs1) - new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args - - xs1 - } - if (result.nonEmpty) - printInference("inferMethodInstance, still undetermined: " + result) + checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") + val treeSubst = new TreeTypeSubstituter(okparams, okargs) + treeSubst traverseTrees fn :: args - Right(result) + val result = leftUndet match { + case Nil => Nil + case xs => + // #3890 + val xs1 = treeSubst.typeSubst mapOver xs + if (xs ne xs1) + new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args + + xs1 } + if (result.nonEmpty) + printInference("inferMethodInstance, still undetermined: " + result) + + result } catch ifNoInstance { msg => - Left(NoMethodInstanceError(fn, args, msg)) + errorTree(fn, "no type parameters for " + + applyErrorMsg(fn, " exist so that it can be applied to arguments ", args map (_.tpe.widen), WildcardType) + + "\n --- because ---\n" + msg + ) + Nil } } @@ -1312,7 +1317,7 @@ trait Infer { * @param undetparams the undetermined type parameters * @param pt the expected result type of the instance */ - def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type): Option[ErrorTree] = { + def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type) { val pt = widen(pt0) //println("infer constr inst "+tree+"/"+undetparams+"/"+pt0) var restpe = tree.tpe.finalResultType @@ -1327,14 +1332,17 @@ trait Infer { // checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") // no checkBounds here. If we enable it, test bug602 fails. new TreeTypeSubstituter(undetparams, targs).traverse(tree) - None - } catch ifNoInstance{ msg => - Some(NoConstructorInstanceError(tree, restpe, pt, msg)) + } catch { + case ex: NoInstance => + errorTree(tree, "constructor of type " + restpe + + " cannot be uniquely instantiated to expected type " + pt + + "\n --- because ---\n" + ex.getMessage()) } def instError = { if (settings.debug.value) Console.println("ici " + tree + " " + undetparams + " " + pt) if (settings.explaintypes.value) explainTypes(restpe.instantiateTypeParams(undetparams, tvars), pt) - Some(ConstrInstantiationError(tree, restpe, pt)) + errorTree(tree, "constructor cannot be instantiated to expected type" + + foundReqMsg(restpe, pt)) } if (restpe.instantiateTypeParams(undetparams, tvars) <:< pt) { computeArgs @@ -1352,7 +1360,6 @@ trait Infer { val pt1 = pt.instantiateTypeParams(ptparams, ptvars) if (isPopulated(restpe, pt1)) { ptvars foreach instantiateTypeVar - None } else { if (settings.debug.value) Console.println("no instance: "); instError } } else { if (settings.debug.value) Console.println("not a subtype " + restpe.instantiateTypeParams(undetparams, tvars) + " of " + ptWithWildcards); instError } } else { if (settings.debug.value) Console.println("not fully defined: " + pt); instError } @@ -1405,12 +1412,11 @@ trait Infer { } } - def checkCheckable(pos: Position, tp: Type, kind: String): Option[ErrorTree] = { + def checkCheckable(pos: Position, tp: Type, kind: String) { def patternWarning(tp0: Type, prefix: String) = { context.unit.uncheckedWarning(pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure") } - def check(tp: Type, bound: List[Symbol]): Option[ErrorTree] = { - implicit def listErrorsToPending(l: List[ErrorTree]): Option[ErrorTree] = if (l.isEmpty) None else Some(PendingErrors(l)) + def check(tp: Type, bound: List[Symbol]) { def isLocalBinding(sym: Symbol) = sym.isAbstractType && ((bound contains sym) || @@ -1422,38 +1428,36 @@ trait Infer { case SingleType(pre, _) => check(pre, bound) case TypeRef(pre, sym, args) => - val checkForSymAndArgs: Option[ErrorTree] = if (sym.isAbstractType) { + if (sym.isAbstractType) { if (!isLocalBinding(sym)) patternWarning(tp, "abstract type ") - None } else if (sym.isAliasType) { check(tp.normalize, bound) } else if (sym == NothingClass || sym == NullClass || sym == AnyValClass) { - Some(TypePatternOrIsInstanceTestError(pos, tp)) + error(pos, "type "+tp+" cannot be used in a type pattern or isInstanceOf test") } else { - args.map( arg => { + for (arg <- args) { if (sym == ArrayClass) check(arg, bound) - else if (arg.typeArgs.nonEmpty) None // avoid spurious warnings with higher-kinded types - else {arg match { + else if (arg.typeArgs.nonEmpty) () // avoid spurious warnings with higher-kinded types + else arg match { case TypeRef(_, sym, _) if isLocalBinding(sym) => - + ; case _ => patternWarning(arg, "non variable type-argument ") - }; None} - }).flatten + } + } } - List(checkForSymAndArgs, check(pre, bound)).flatten + check(pre, bound) case RefinedType(parents, decls) => - if (decls.isEmpty) parents.map(p => check(p, bound)).flatten - else { patternWarning(tp, "refinement "); None } + if (decls.isEmpty) for (p <- parents) check(p, bound) + else patternWarning(tp, "refinement ") case ExistentialType(quantified, tp1) => check(tp1, bound ::: quantified) case ThisType(_) => - None + ; case NoPrefix => - None + ; case _ => patternWarning(tp, "type ") - None } } check(tp, List()) @@ -1476,7 +1480,7 @@ trait Infer { } } - def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Either[ErrorTree, Type] = { + def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = { val pt = widen(pt0) val ptparams = freeTypeParamsOfTerms.collect(pt) val tpparams = freeTypeParamsOfTerms.collect(pattp) @@ -1489,13 +1493,9 @@ trait Infer { * and is a "final type", meaning final + invariant in all type parameters. */ if (pt.isFinalType && ptparams.isEmpty && !ptMatchesPattp) - return Left(IncompatibleScrutineeTypeError(pos, pattp, pt)) + error(pos, "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt)) - checkCheckable(pos, pattp, "pattern ") match { - case Some(err) => - return Left(err) - case _ => () - } + checkCheckable(pos, pattp, "pattern ") if (pattp <:< pt) () else { debuglog("free type params (1) = " + tpparams) @@ -1517,8 +1517,10 @@ trait Infer { // fail if we didn't allow for pattpMatchesPt. if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars) || pattpMatchesPt) ptvars foreach instantiateTypeVar - else - return Left(IncompletePatternTypeError(pos, pattp, pt)) + else { + error(pos, "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt)) + return pattp + } } tvars foreach instantiateTypeVar } @@ -1526,22 +1528,43 @@ trait Infer { * we have to flip the arguments so the expected type is treated as more * general when calculating the intersection. See run/bug2755.scala. */ - if (tpparams.isEmpty && ptparams.nonEmpty) Right(intersect(pattp, pt)) - else Right(intersect(pt, pattp)) + if (tpparams.isEmpty && ptparams.nonEmpty) intersect(pattp, pt) + else intersect(pt, pattp) } - def inferModulePattern(pat: Tree, pt: Type): Option[ErrorTree] = + def inferModulePattern(pat: Tree, pt: Type) = if (!(pat.tpe <:< pt)) { val ptparams = freeTypeParamsOfTerms.collect(pt) debuglog("free type params (2) = " + ptparams) val ptvars = ptparams map freshVar val pt1 = pt.instantiateTypeParams(ptparams, ptvars) - if (pat.tpe <:< pt1) { + if (pat.tpe <:< pt1) ptvars foreach instantiateTypeVar - None - } else - Some(PatternTypeIncompatibleWithPtError(pat, pt1, pt)) - } else None + else { + val sym = pat.tpe.typeSymbol + val clazz = sym.companionClass + val addendum = ( + if (sym.isModuleClass && clazz.isCaseClass && (clazz isSubClass pt1.typeSymbol)) { + // TODO: move these somewhere reusable. + val typeString = clazz.typeParams match { + case Nil => "" + clazz.name + case xs => xs map (_ => "_") mkString (clazz.name + "[", ",", "]") + } + val caseString = ( + clazz.caseFieldAccessors + map (_ => "_") // could use the actual param names here + mkString (clazz.name + "(", ",", ")") + ) + ( + "\nNote: if you intended to match against the class, try `case _: " + + typeString + "` or `case " + caseString + "`" + ) + } + else "" + ) + error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt) + addendum) + } + } object toOrigin extends TypeMap { def apply(tp: Type): Type = tp match { @@ -1608,7 +1631,7 @@ trait Infer { * If several alternatives match `pt`, take parameterless one. * If no alternative matches `pt`, take the parameterless one anyway. */ - def inferExprAlternative(tree: Tree, pt: Type): Option[ErrorTree] = tree.tpe match { + def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) val secondTry = alts0.isEmpty @@ -1639,27 +1662,24 @@ trait Infer { case _ => } } - Some(NoBestExprAlternativeError(tree, pt)) + typeErrorTree(tree, tree.symbol.tpe, pt) } else if (!competing.isEmpty) { if (secondTry) { - Some(NoBestExprAlternativeError(tree, pt)) + typeErrorTree(tree, tree.symbol.tpe, pt) } else { if (!pt.isErroneous) - Some(AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt)) - else - Some(NullErrorTree) // already reported + context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt) + setError(tree) } } else { // val applicable = alts1 filter (alt => // global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) // checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) - None } } } - // TODO: remove once error tree refactoring is done @inline private def wrapTypeError(expr: => Boolean): Boolean = try expr catch { case _: TypeError => false } @@ -1723,7 +1743,7 @@ trait Infer { * assignment expression. */ def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], - argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Option[ErrorTree] = tree.tpe match { + argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match { case OverloadedType(pre, alts) => val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 tryTwice { @@ -1750,22 +1770,24 @@ trait Infer { if (improves(alt, best)) alt else best) val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { - if (pt == WildcardType) - Some(NoBestMethodAlternativeError(tree, argtpes, pt)) - else + if (pt == WildcardType) { + errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) + } else { inferMethodAlternative(tree, undetparams, argtpes, WildcardType) + } } else if (!competing.isEmpty) { if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) - Some(AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt)) - else - Some(NullErrorTree) + context.ambiguousError(tree.pos, pre, best, competing.head, + "argument types " + argtpes.mkString("(", ",", ")") + + (if (pt == WildcardType) "" else " and expected result type " + pt)) + setError(tree) + () } else { // checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) - None } } - case _ => None + case _ => } /** Try inference twice, once without views and once with views, @@ -1773,25 +1795,18 @@ trait Infer { * * @param infer ... */ - def tryTwice(infer: => Option[ErrorTree]): Option[ErrorTree] = { + def tryTwice(infer: => Unit) { if (context.implicitsEnabled) { val reportGeneralErrors = context.reportGeneralErrors context.reportGeneralErrors = false - val res = try { - context.withImplicitsDisabled(infer) match { - case Some(err) => - context.reportGeneralErrors = reportGeneralErrors - infer - case ok => ok - } - } catch { + try context.withImplicitsDisabled(infer) + catch { case ex: CyclicReference => throw ex case ex: TypeError => context.reportGeneralErrors = reportGeneralErrors infer } context.reportGeneralErrors = reportGeneralErrors - res } else infer } @@ -1803,10 +1818,10 @@ trait Infer { * @param tree ... * @param nparams ... */ - def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Option[ErrorTree] = { + def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = { val OverloadedType(pre, alts) = tree.tpe val sym0 = tree.symbol filter (alt => sameLength(alt.typeParams, argtypes)) - def fail(msg: String) = Some(PolyAlternativeError(tree, msg)) + def fail(msg: String): Unit = error(tree.pos, msg) if (sym0 == NoSymbol) return fail( if (alts exists (_.typeParams.nonEmpty)) @@ -1820,13 +1835,12 @@ trait Infer { else { val sym = sym0 filter (alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes)) if (sym == NoSymbol) { - if (argtypes forall (x => !x.isErroneous)) - return fail( + if (argtypes forall (x => !x.isErroneous)) fail( "type arguments " + argtypes.mkString("[", ",", "]") + " conform to the bounds of none of the overloaded alternatives of\n "+sym0+ ": "+sym0.info ) - return None + return } else if (sym.isOverloaded) { val xs = sym.alternatives @@ -1841,7 +1855,24 @@ trait Infer { } // Side effects tree with symbol and type tree setSymbol resSym setType resTpe - None + } + + abstract class TreeForwarder(forwardTo: Tree) extends Tree { + override def pos = forwardTo.pos + override def hasSymbol = forwardTo.hasSymbol + override def symbol = forwardTo.symbol + override def symbol_=(x: Symbol) = forwardTo.symbol = x + } + + case class AccessError(tree: Tree, sym: Symbol, pre: Type, explanation: String) extends TreeForwarder(tree) { + setError(this) + + // @PP: It is improbable this logic shouldn't be in use elsewhere as well. + private def location = if (sym.isClassConstructor) context.enclClass.owner else pre.widen + def emit(): Tree = { + val realsym = underlying(sym) + errorTree(tree, realsym.fullLocationString + " cannot be accessed in " + location + explanation) + } } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index e41bb737f2..d0f1722b1c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -65,26 +65,13 @@ trait Namers { self: Analyzer => classAndNamerOfModule.clear } - abstract class Namer(val context: Context) extends NamerErrorTrees { + abstract class Namer(val context: Context) { val typer = newTyper(context) def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = { - if (mods.hasAccessBoundary) { - val symOrError = typer.qualifyingClass(tree, mods.privateWithin, true) match { - case Left(err) => - try { - err.emit(context) - } catch { - case _: TypeError => - assert(false, "qualifying class info can fail but cannot throw type errors") - } - NoSymbol - case Right(sym) => - sym - } - sym.privateWithin = symOrError - } + if (mods.hasAccessBoundary) + sym.privateWithin = typer.qualifyingClass(tree, mods.privateWithin, true) sym } @@ -161,7 +148,6 @@ trait Namers { self: Analyzer => private def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe) - // TODO: make it into error trees private def doubleDefError(pos: Position, sym: Symbol) { val s1 = if (sym.isModule) "case class companion " else "" val s2 = if (sym.isSynthetic) "(compiler-generated) " + s1 else "" @@ -674,18 +660,10 @@ trait Namers { self: Analyzer => case _ => } sym.setInfo(if (sym.isJavaDefined) RestrictJavaArraysMap(tp) else tp) - if ((sym.isAliasType || sym.isAbstractType) && !sym.isParameter) { - val check = typer.checkNonCyclic(tree.pos, tp) - if (check.isDefined) { - sym.setInfo(ErrorType) // this early test is there to avoid infinite baseTypes when - // adding setters and getters --> bug798 - try { - check.get.emit(context) - } catch { - case _: TypeError => assert(false, "Type errors cannot be thrown in type completers") - } - } - } + if ((sym.isAliasType || sym.isAbstractType) && !sym.isParameter && + !typer.checkNonCyclic(tree.pos, tp)) + sym.setInfo(ErrorType) // this early test is there to avoid infinite baseTypes when + // adding setters and getters --> bug798 debuglog("defined " + sym); validate(sym) } @@ -851,14 +829,7 @@ trait Namers { self: Analyzer => } */ - var parents0 = typer.parentTypes(templ) - try { - parents0.foreach(p => if (p.containsError()) typer.emitAllErrorTrees(p, context)) - } catch { - case _: TypeError => - assert(false, "parent types cannot throw type errors") - } - val parents = parents0 map checkParent + var parents = typer.parentTypes(templ) map checkParent enterSelf(templ.self) val decls = new Scope // for (etdef <- earlyTypes) decls enter etdef.symbol @@ -1342,10 +1313,7 @@ trait Namers { self: Analyzer => case Import(expr, selectors) => val expr1 = typer.typedQualifier(expr) - val stable = typer.checkStable(expr1) - if (stable.containsError()) - typer.emitAllErrorTrees(stable, context) - + typer checkStable expr1 if (expr1.symbol != null && expr1.symbol.isRootPackage) context.error(tree.pos, "_root_ cannot be imported") @@ -1361,10 +1329,7 @@ trait Namers { self: Analyzer => } catch { case ex: TypeError => //Console.println("caught " + ex + " in typeSig") - // TODO: once ErrorTrees are implemented we should be able - // to get rid of this catch and simply report the error - // (maybe apart from cyclic errors) - TypeSigError(tree, ex).emit(context) + typer.reportTypeError(tree.pos, ex) ErrorType } result match { diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 729bbf4557..bf7cc72fab 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -304,9 +304,7 @@ trait NamesDefaults { self: Analyzer => // `fun` is typed. `namelessArgs` might be typed or not, if they are types are kept. case Apply(fun, namelessArgs) => val transformedFun = transformNamedApplication(typer, mode, pt)(fun, x => x) - // Is it safe to replace containsError() with containsErrorOrIsErrorTyped()? - if (transformedFun.containsError()) transformedFun - else if (transformedFun.isErroneous) NullErrorTree + if (transformedFun.isErroneous) setError(tree) else { assert(isNamedApplyBlock(transformedFun), transformedFun) val NamedApplyInfo(qual, targs, vargss, blockTyper) = @@ -315,7 +313,8 @@ trait NamesDefaults { self: Analyzer => // type the application without names; put the arguments in definition-site order val typedApp = doTypedApply(tree, funOnly, reorderArgs(namelessArgs, argPos), mode, pt) - if (typedApp.containsErrorOrIsErrorTyped()) typedApp + + if (typedApp.tpe.isError) setError(tree) else typedApp match { // Extract the typed arguments, restore the call-site evaluation order (using // ValDef's in the block), change the arguments to these local values. @@ -440,6 +439,7 @@ trait NamesDefaults { self: Analyzer => * after named ones. */ def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = { + import typer.infer.errorTree // maps indicies from (order written by user) to (order of definition) val argPos = (new Array[Int](args.length)) map (x => -1) @@ -457,10 +457,10 @@ trait NamesDefaults { self: Analyzer => // treat the arg as an assignment of type Unit Assign(a.lhs, rhs).setPos(arg.pos) } else { - UnknownParameterNameNamesDefaultError(arg, name) + errorTree(arg, "unknown parameter name: "+ name) } } else if (argPos contains pos) { - DoubleParamNamesDefaultError(arg, name) + errorTree(arg, "parameter specified twice: "+ name) } else { // for named arguments, check whether the assignment expression would // typecheck. if it does, report an ambiguous error. @@ -481,20 +481,26 @@ trait NamesDefaults { self: Analyzer => val reportAmbiguousErrors = typer.context.reportAmbiguousErrors typer.context.reportAmbiguousErrors = false + var variableNameClash = false val typedAssign = try { typer.silent(_.typed(arg, subst(paramtpe))) } catch { // `silent` only catches and returns TypeErrors which are not // CyclicReferences. Fix for #3685 - - // Returning CyclicReference error trees is problematic - // so we stay with throwing exceptions case cr @ CyclicReference(sym, info) if sym.name == param.name => if (sym.isVariable || sym.isGetter && sym.accessed.isVariable) { // named arg not allowed - NameClashError(sym, arg) + variableNameClash = true + typer.context.error(sym.pos, + "%s definition needs %s because '%s' is used as a named argument in its body.".format( + "variable", // "method" + "type", // "result type" + sym.name + ) + ) + typer.infer.setError(arg) } - else NullErrorTree + else cr } def applyNamedArg = { @@ -507,27 +513,28 @@ trait NamesDefaults { self: Analyzer => } val res = typedAssign match { - case err: NameClashError => - err - case _: TypeError => - // TODO: is should be safe to remove this case after error trees are fully implemented - applyNamedArg - case t: Tree if t.containsErrorOrIsErrorTyped() => - // containsErrorOrIsErrorTyped() needed because of for instance #4041 - applyNamedArg + case _: TypeError => applyNamedArg + case t: Tree => - // This throws an exception which is caught in `tryTypedApply` (as it - // uses `silent`) - unfortunately, tryTypedApply recovers from the - // exception if you use errorTree(arg, ...) and conforms is allowed as - // a view (see tryImplicit in Implicits) because it tries to produce a - // new qualifier (if the old one was P, the new one will be - // conforms.apply(P)), and if that works, it pretends nothing happened. - // - // To make sure tryTypedApply fails, we would like to pass EmptyTree - // instead of arg, but can't do that because eventually setType(ErrorType) - // is called, and EmptyTree can only be typed NoType. Thus we need to - // disable conforms as a view... - AmbiguousReferenceInNamesDefaultError(arg, name) + if (t.isErroneous && !variableNameClash) { + applyNamedArg + } else if (t.isErroneous) { + t // name clash with variable. error was already reported above. + } else { + // This throws an exception which is caught in `tryTypedApply` (as it + // uses `silent`) - unfortunately, tryTypedApply recovers from the + // exception if you use errorTree(arg, ...) and conforms is allowed as + // a view (see tryImplicit in Implicits) because it tries to produce a + // new qualifier (if the old one was P, the new one will be + // conforms.apply(P)), and if that works, it pretends nothing happened. + // + // To make sure tryTypedApply fails, we would like to pass EmptyTree + // instead of arg, but can't do that because eventually setType(ErrorType) + // is called, and EmptyTree can only be typed NoType. Thus we need to + // disable conforms as a view... + errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+ + "name of the method and the name of a variable currently in scope.") + } } typer.context.reportAmbiguousErrors = reportAmbiguousErrors @@ -539,9 +546,8 @@ trait NamesDefaults { self: Analyzer => case _ => argPos(index) = index if (positionalAllowed) arg - else PositionalAfterNamedNamesDefaultError(arg) + else errorTree(arg, "positional after named argument.") } - (namelessArgs, argPos) } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index fda6a6f12e..d4565c8e0c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1190,15 +1190,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R /* Check whether argument types conform to bounds of type parameters */ private def checkBounds(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type], pos: Position): Unit = - try typer.infer.checkBounds(pos, pre, owner, tparams, argtps, "") match { - case Some(err) => err.emit(typer.context) - case _ => () - } + try typer.infer.checkBounds(pos, pre, owner, tparams, argtps, "") catch { case ex: TypeError => - // checkBounds no longer throws errors (apart from Cyclic ones) - // so maybe it is safe to remove/simplify this catch? - unit.error(pos, ex.getMessage()) + unit.error(pos, ex.getMessage()); if (settings.explaintypes.value) { val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, argtps).bounds) (argtps, bounds).zipped map ((targ, bound) => explainTypes(bound.lo, targ)) @@ -1356,13 +1351,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case tpt@TypeTree() => if(tpt.original != null) { tpt.original foreach { - case dc@TypeTreeWithDeferredRefCheck() => - dc.check() match { - case Left(err) => - err.emit() - case Right(t) => - applyRefchecksToAnnotations(t) // #2416 - } + case dc@TypeTreeWithDeferredRefCheck() => applyRefchecksToAnnotations(dc.check()) // #2416 case _ => } } @@ -1526,11 +1515,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if(tpt.original != null) { tpt.original foreach { case dc@TypeTreeWithDeferredRefCheck() => - dc.check() match { - case Left(err) => err.emit() - case Right(tree) => transform(tree) // #2416 -- only call transform to do refchecks, but discard results - // tpt has the right type if the deferred checks are ok - } + transform(dc.check()) // #2416 -- only call transform to do refchecks, but discard results + // tpt has the right type if the deferred checks are ok case _ => } } @@ -1606,7 +1592,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R result } catch { case ex: TypeError => - if (settings.debug.value) ex.printStackTrace() + if (settings.debug.value) ex.printStackTrace(); unit.error(tree.pos, ex.getMessage()) tree } finally { diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index db6d1445a9..8c06dbe0bf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -52,11 +52,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT private def checkPackedConforms(tree: Tree, pt: Type): Tree = { if (tree.tpe exists (_.typeSymbol.isExistentialSkolem)) { val packed = localTyper.packedType(tree, NoSymbol) - packed._2.foreach(_.emit()) - if (!(packed._1 <:< pt)) { + if (!(packed <:< pt)) { val errorContext = localTyper.context.make(localTyper.context.tree) errorContext.reportGeneralErrors = true - analyzer.newTyper(errorContext).infer.typeError(tree.pos, packed._1, pt) + analyzer.newTyper(errorContext).infer.typeError(tree.pos, packed, pt) } } tree diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 6eaa65ce9b..9a8bcca2ba 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -41,7 +41,7 @@ trait SyntheticMethods extends ast.TreeDSL { import CODE._ val localTyper = newTyper( - if (reporter.hasErrors || templ.containsError()) context makeSilent false else context + if (reporter.hasErrors) context makeSilent false else context ) def accessorTypes = clazz.caseFieldAccessors map (_.tpe.finalResultType) def accessorLub = global.weakLub(accessorTypes)._1 diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 0b84e67447..6e0e78e8e2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -135,6 +135,21 @@ trait TypeDiagnostics { def alternativesString(tree: Tree) = alternatives(tree) map (x => " " + methodTypeErrorString(x)) mkString ("", " \n", "\n") + def missingParameterTypeMsg(fun: Tree, vparam: ValDef, pt: Type) = { + def anonMessage = ( + "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" + + "\nExpected type was: " + pt.toLongString + ) + val suffix = + if (!vparam.mods.isSynthetic) "" + else " for expanded function" + (fun match { + case Function(_, Match(_, _)) => anonMessage + case _ => " " + fun + }) + + "missing parameter type" + suffix + } + def treeSymTypeMsg(tree: Tree): String = { val sym = tree.symbol def hasParams = tree.tpe.paramSectionCount > 0 @@ -153,6 +168,34 @@ trait TypeDiagnostics { else defaultMessage } + def notEnoughArgumentsMsg(fun: Tree, missing: List[Symbol]): String = { + val suffix = { + if (missing.isEmpty) "" + else { + val keep = missing take 3 map (_.name) + ".\nUnspecified value parameter%s %s".format( + if (missing.tail.isEmpty) "" else "s", + if (missing drop 3 nonEmpty) (keep :+ "...").mkString(", ") + else keep.mkString("", ", ", ".") + ) + } + } + + "not enough arguments for " + treeSymTypeMsg(fun) + suffix + } + + def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = { + def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")") + + def resType = if (pt isWildcard) "" else " with expected result type " + pt + def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt + def locals = alternatives(tree) flatMap (_.typeParams) + + withDisambiguation(locals, 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 }) @@ -362,10 +405,8 @@ trait TypeDiagnostics { trait TyperDiagnostics { self: Typer => - private def contextError(pos: Position, msg: String) { contextError(context, pos, msg) } - private def contextError(context0: Analyzer#Context, pos: Position, msg: String) { context0.error(pos, msg) } - private def contextError(pos: Position, err: Throwable) { contextError(context, pos, err) } - private def contextError(context0: Analyzer#Context, pos: Position, err: Throwable) { context0.error(pos, err) } + private def contextError(pos: Position, msg: String) = context.error(pos, msg) + private def contextError(pos: Position, err: Throwable) = context.error(pos, err) object checkDead { private var expr: Symbol = NoSymbol @@ -399,46 +440,36 @@ trait TypeDiagnostics { } } - private def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded - private def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive" + 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. */ - private def cyclicReferenceMessage(sym: Symbol, tree: Tree) = condOpt(tree) { + 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 " " } - def reportTypeError(pos: Position, ex: TypeError) { - reportTypeError(context, pos, ex) - } - /** Report a type error. * * @param pos0 The position where to report the error * @param ex The exception that caused the error */ - def reportTypeError(context0: Analyzer#Context, pos: Position, ex: TypeError) { + def reportTypeError(pos: Position, ex: TypeError) { if (ex.pos == NoPosition) ex.pos = pos - if (!context0.reportGeneralErrors) throw ex + if (!context.reportGeneralErrors) throw ex if (settings.debug.value) ex.printStackTrace() ex match { case CyclicReference(sym, info: TypeCompleter) => - contextError(context0, ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) + contextError(ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) if (sym == ObjectClass) throw new FatalError("cannot redefine root "+sym) case _ => - contextError(context0, ex.pos, ex) + contextError(ex.pos, ex) } } - - def emitAllErrorTrees(tree: Tree, context: Context) = - errorTreesFinder(tree).foreach(_.emit(context)) - - def findAllNestedErrors(trees: List[Tree]): List[ErrorTree] = - trees.map(errorTreesFinder(_)).flatten } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 893384ece3..a1343fb7d7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -12,13 +12,13 @@ package scala.tools.nsc package typechecker -import scala.collection.mutable -import mutable.ListBuffer - +import scala.collection.{ mutable, immutable } import scala.tools.nsc.util.BatchSourceFile +import mutable.ListBuffer import symtab.Flags._ -import util.Statistics._ import util.Statistics +import util.Statistics._ +import scala.tools.util.StringOps.{ countAsString, countElementsAsString } // Suggestion check whether we can do without priming scopes with symbols of outer scopes, // like the IDE does. @@ -59,7 +59,7 @@ trait Typers extends Modes with Adaptations { super.traverse(tree) } } -/* needed for experimental version where early types can be type arguments +/* needed for experimental version where eraly types can be type arguments class EarlyMap(clazz: Symbol) extends TypeMap { def apply(tp: Type): Type = tp match { case TypeRef(NoPrefix, sym, List()) if (sym hasFlag PRESUPER) => @@ -77,7 +77,7 @@ trait Typers extends Modes with Adaptations { // that are turned private by typedBlock private final val SYNTHETIC_PRIVATE = TRANS_FLAG - abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with TyperErrorTrees { + abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation { import context0.unit import typeDebug.{ ptTree, ptBlock, ptLine } @@ -99,6 +99,15 @@ trait Typers extends Modes with Adaptations { def mkNamedArg(argTree: Tree, paramName: Name) = atPos(argTree.pos)(new AssignOrNamedArg(Ident(paramName), (argTree))) var mkArg: (Tree, Name) => Tree = mkPositionalArg + def errorMessage(paramName: Name, paramTp: Type) = + paramTp.typeSymbol match { + case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp) + case _ => + "could not find implicit value for "+ + (if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type " + else "parameter "+paramName+": ")+paramTp + } + // DEPMETTODO: instantiate type vars that depend on earlier implicit args (see adapt (4.1)) // // apply the substitutions (undet type param -> type) that were determined @@ -115,9 +124,8 @@ trait Typers extends Modes with Adaptations { argBuff += mkArg(res.tree, param.name) } else { mkArg = mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args - if (!param.hasDefault) { - argBuff += NoImplicitFoundError(fun, param) - } + if (!param.hasDefault) + context.error(fun.pos, errorMessage(param.name, param.tpe)) /* else { TODO: alternative (to expose implicit search failure more) --> resolve argument, do type inference, keep emitting positional args, infer type params based on default value for arg @@ -178,10 +186,6 @@ trait Typers extends Modes with Adaptations { var context = context0 def context1 = context - @inline - private def wrapInBlock(errTree: Tree, original: Tree): Tree = Block(errTree, original) setType ErrorType - - def dropExistential(tp: Type): Type = tp match { case ExistentialType(tparams, tpe) => new SubstWildcardMap(tparams).apply(tp) @@ -198,12 +202,22 @@ trait Typers extends Modes with Adaptations { * @return ... */ def checkStable(tree: Tree): Tree = - if (treeInfo.isPureExpr(tree)) tree else UnstableTreeError(tree) + if (treeInfo.isPureExpr(tree)) tree + else errorTree( + tree, + "stable identifier required, but "+tree+" found."+ + (if (isStableExceptVolatile(tree)) { + val tpe = tree.symbol.tpe match { + case PolyType(_, rtpe) => rtpe + case t => t + } + "\n Note that "+tree.symbol+" is not stable because its type, "+tree.tpe+", is volatile." + } else "")) /** Would tree be a stable (i.e. a pure expression) if the type * of its symbol was not volatile? */ - protected def isStableExceptVolatile(tree: Tree) = { + private def isStableExceptVolatile(tree: Tree) = { tree.hasSymbol && tree.symbol != NoSymbol && tree.tpe.isVolatile && { val savedTpe = tree.symbol.info val savedSTABLE = tree.symbol getFlag STABLE @@ -217,21 +231,21 @@ trait Typers extends Modes with Adaptations { } /** Check that `tpt` refers to a non-refinement class type */ - def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean) = { - def errorNotClass(found: AnyRef) = Some(ClassTypeRequiredError(tpt, found)) - def check(tpe: Type): Option[ErrorTree] = tpe.normalize match { + def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean) { + def errorNotClass(found: AnyRef) = error(tpt.pos, "class type required but "+found+" found") + def check(tpe: Type): Unit = tpe.normalize match { case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass => - if (stablePrefix && phase.id <= currentRun.typerPhase.id) + if (stablePrefix && phase.id <= currentRun.typerPhase.id) { if (!pre.isStable) - Some(TypeNotAStablePrefixError(pre, tpt.pos)) - else - tpt match { + error(tpt.pos, "type "+pre+" is not a stable prefix") + // A type projection like X#Y can get by the stable check if the + // prefix is singleton-bounded, so peek at the tree too. + else tpt match { case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt) - case _ => None - } - else - None - case ErrorType => None + case _ => ; + } + } + case ErrorType => ; case PolyType(_, restpe) => check(restpe) case ExistentialType(_, restpe) if existentialOK => check(restpe) case AnnotatedType(_, underlying, _) => check(underlying) @@ -246,19 +260,18 @@ trait Typers extends Modes with Adaptations { * @param tp ... * @return true if tp is not a subtype of itself. */ - def checkNonCyclic(pos: Position, tp: Type): Option[ErrorTree] = { - def checkNotLocked(sym: Symbol): Option[ErrorTree] = { + def checkNonCyclic(pos: Position, tp: Type): Boolean = { + def checkNotLocked(sym: Symbol): Boolean = { sym.initialize - if (sym.lockOK) None - else Some(CyclicAliasingOrSubtypingError(pos, sym)) + sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false} } tp match { case TypeRef(pre, sym, args) => - val check = checkNotLocked(sym) - if (check.isDefined) check - else if (!sym.isNonClassType) None - else checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym) - + (checkNotLocked(sym)) && ( + !sym.isNonClassType || + checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym) // @M! info for a type ref to a type parameter now returns a polytype + // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym) + ) case SingleType(pre, sym) => checkNotLocked(sym) /* @@ -270,70 +283,51 @@ trait Typers extends Modes with Adaptations { case st: SubType => checkNonCyclic(pos, st.supertype) case ct: CompoundType => - val checkRes = ct.parents map (x => checkNonCyclic(pos, x)) flatten - - if (checkRes.isEmpty) None - else Some(PendingErrors(checkRes)) + ct.parents forall (x => checkNonCyclic(pos, x)) case _ => - None + true } } - // TODO in order to return CyclicReferenceError we need to change the signature of lock - // let's leave it for now - def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Option[ErrorTree] = try { + def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = try { lockedSym.lock { throw new TypeError("illegal cyclic reference involving " + lockedSym) } checkNonCyclic(pos, tp) - } catch { - case _ :TypeError => - Some(CyclicReferenceError(pos, lockedSym)) } finally { lockedSym.unlock() } - def checkNonCyclic(sym: Symbol): Option[ErrorTree] = { - val check = checkNonCyclic(sym.pos, sym.tpe) - if (check.isDefined) - sym.setInfo(ErrorType) - check + def checkNonCyclic(sym: Symbol) { + if (!checkNonCyclic(sym.pos, sym.tpe)) sym.setInfo(ErrorType) } - def checkNonCyclic(defn: Tree, tpt: Tree): Option[ErrorTree] = { - val check = checkNonCyclic(defn.pos, tpt.tpe, defn.symbol) - if (check.isDefined) { + def checkNonCyclic(defn: Tree, tpt: Tree) { + if (!checkNonCyclic(defn.pos, tpt.tpe, defn.symbol)) { tpt.tpe = ErrorType defn.symbol.setInfo(ErrorType) } - check } - def checkParamsConvertible(pos: Position, tpe0: Type): List[ErrorTree] = { - var pending: List[ErrorTree] = List() - def checkParamsConvertible0(tpe: Type) = - tpe match { - case MethodType(formals, restpe) => - /* - if (formals.exists(_.typeSymbol == ByNameParamClass) && formals.length != 1) - error(pos, "methods with `=>`-parameter can be converted to function values only if they take no other parameters") - if (formals exists (isRepeatedParamType(_))) - error(pos, "methods with `*`-parameters cannot be converted to function values"); - */ - if (restpe.isDependent) - pending = DependentMethodTpeConversionToFunctionError(pos, tpe)::pending - checkParamsConvertible(pos, restpe) - case _ => - } - checkParamsConvertible0(tpe0) - pending + def checkParamsConvertible(pos: Position, tpe: Type) { + tpe match { + case MethodType(formals, restpe) => + /* + if (formals.exists(_.typeSymbol == ByNameParamClass) && formals.length != 1) + error(pos, "methods with `=>`-parameter can be converted to function values only if they take no other parameters") + if (formals exists (isRepeatedParamType(_))) + error(pos, "methods with `*`-parameters cannot be converted to function values"); + */ + if (restpe.isDependent) + error(pos, "method with dependent type "+tpe+" cannot be converted to function value") + checkParamsConvertible(pos, restpe) + case _ => + } } - @inline - private def checkStarPatOK(pos: Position, mode: Int):Option[ErrorTree] = + def checkStarPatOK(pos: Position, mode: Int) = if ((mode & STARmode) == 0 && phase.id <= currentRun.typerPhase.id) - Some(StarPatternWithVarargParametersError(pos)) - else None + error(pos, "star patterns must correspond with varargs parameters") /** Check that type of given tree does not contain local or private * components. @@ -351,7 +345,7 @@ trait Typers extends Modes with Adaptations { * @param tree ... * @return ... */ - def privates(owner: Symbol, tree: Tree): Tree = + def privates[T <: Tree](owner: Symbol, tree: T): T = check(owner, EmptyScope, WildcardType, tree) /** Check that type tree does not refer to entities @@ -362,16 +356,16 @@ trait Typers extends Modes with Adaptations { * @param tree ... * @return ... */ - def locals(scope: Scope, pt: Type, tree: Tree): Tree = + def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T = check(NoSymbol, scope, pt, tree) - private def check(owner: Symbol, scope: Scope, pt: Type, tree: Tree): Tree = { + def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = { this.owner = owner this.scope = scope hiddenSymbols = List() val tp1 = apply(tree.tpe) if (hiddenSymbols.isEmpty) tree setType tp1 - else if (hiddenSymbols exists (_.isErroneous)) HiddenSymbolWithError(tree) + else if (hiddenSymbols exists (_.isErroneous)) setError(tree) else if (isFullyDefined(pt)) tree setType pt //todo: eliminate else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate check(owner, scope, pt, tree setType tp1.typeSymbol.classBound) @@ -379,7 +373,10 @@ trait Typers extends Modes with Adaptations { tree setType packSymbols(hiddenSymbols.reverse, tp1) else if (!phase.erasedTypes) { // privates val badSymbol = hiddenSymbols.head - SymbolEscapesScopeError(tree, badSymbol) + error(tree.pos, + (if (badSymbol.isPrivate) "private " else "") + badSymbol + + " escapes its defining scope as part of type "+tree.tpe) + setError(tree) } else tree } @@ -442,12 +439,16 @@ trait Typers extends Modes with Adaptations { /** The qualifying class * of a this or super with prefix qual. */ - def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean): Either[ErrorTree, Symbol] = + def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean): Symbol = context.enclClass.owner.ownerChain.find(o => qual.isEmpty || o.isClass && o.name == qual) match { case Some(c) if packageOK || !c.isPackageClass => - Right(c) + c case _ => - Left(QualifyingClassError(tree, qual)) + error( + tree.pos, + if (qual.isEmpty) tree+" can be used only in a class, object, or template" + else qual+" is not an enclosing class") + NoSymbol } /** The typer for an expression, depending on where we are. If we are before a superclass @@ -564,19 +565,14 @@ trait Typers extends Modes with Adaptations { * 2. Check that packages and static modules are not used as values * 3. Turn tree type into stable type if possible and required by context. */ - private def stabilize(tree0: Tree, pre: Type, mode: Int, pt: Type): Tree = { - val tree = - if (tree0.symbol.isOverloaded && !inFunMode(mode)) - inferExprAlternative(tree0, pt) match { - case Some(err) => err - case _ => tree0 - } - else tree0 + private def stabilize(tree: Tree, pre: Type, mode: Int, pt: Type): Tree = { + if (tree.symbol.isOverloaded && !inFunMode(mode)) + inferExprAlternative(tree, pt) val sym = tree.symbol - def fail() = NotAValueError(tree, sym) + def fail() = errorTree(tree, sym.kindString + " " + sym.fullName + " is not a value") - if (tree.containsErrorOrIsErrorTyped()) tree + if (tree.tpe.isError) tree else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1) if (sym.isValue) checkStable(tree) else fail() @@ -656,8 +652,6 @@ trait Typers extends Modes with Adaptations { } catch { case ex: CyclicReference => throw ex case ex: TypeError => - // TODO: when move to error trees is complete we should - // be able to just drop this case stopCounter(rawTypeFailed, rawTypeStart) stopCounter(findMemberFailed, findMemberStart) stopCounter(subtypeFailed, subtypeStart) @@ -666,6 +660,23 @@ trait Typers extends Modes with Adaptations { } } + /** Utility method: Try op1 on tree. If that gives an error try op2 instead. + */ + def tryBoth(tree: Tree)(op1: (Typer, Tree) => Tree)(op2: (Typer, Tree) => Tree): Tree = + silent(op1(_, tree)) match { + case result1: Tree => + result1 + case ex1: TypeError => + silent(op2(_, resetAllAttrs(tree))) match { + case result2: Tree => +// println("snd succeeded: "+result2) + result2 + case ex2: TypeError => + reportTypeError(tree.pos, ex1) + setError(tree) + } + } + def isCodeType(tpe: Type) = tpe.typeSymbol isNonBottomSubClass CodeClass /** Perform the following adaptations of expression, pattern or type `tree` wrt to @@ -711,6 +722,7 @@ trait Typers extends Modes with Adaptations { if (context.undetparams nonEmpty) { // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition? + context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, // approximate types that depend on arguments since dependency on implicit argument is like dependency on type parameter if (settings.YdepMethTpes.value) mt.approximate else mt, @@ -719,21 +731,14 @@ trait Typers extends Modes with Adaptations { // Looking for a manifest of Nil: This has many potential types, // so we need to instantiate to minimal type List[Nothing]. keepNothings = false, // retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType - useWeaklyCompatible = true) match {// #3808 - case (Some(err), undetparams1) => - context.undetparams = undetparams1 - return err - case (_, undetparams1) => - context.undetparams = undetparams1 - } + useWeaklyCompatible = true) // #3808 } val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree)) if (original != EmptyTree && pt != WildcardType) typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match { - case result: Tree if !result.containsError() => - result - case _ => + case result: Tree => result + case ex: TypeError => debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original)) val tree1 = typed(resetAllAttrs(original), mode, WildcardType) tree1.tpe = addAnnotations(tree1, tree1.tpe) @@ -751,10 +756,7 @@ trait Typers extends Modes with Adaptations { } if (!meth.isConstructor && isFunctionType(pt)) { // (4.2) debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt) - val errs = checkParamsConvertible(tree.pos, tree.tpe) - if (!errs.isEmpty) { - return PendingErrors(errs.reverse) - } + checkParamsConvertible(tree.pos, tree.tpe) val tree0 = etaExpand(context.unit, tree) // println("eta "+tree+" ---> "+tree0+":"+tree0.tpe+" undet: "+context.undetparams+ " mode: "+Integer.toHexString(mode)) @@ -771,10 +773,11 @@ trait Typers extends Modes with Adaptations { } else if (!meth.isConstructor && mt.params.isEmpty) { // (4.3) adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt, original) } else if (context.implicitsEnabled) { - MissingArgsForMethodTpeError(tree, meth) + errorTree(tree, "missing arguments for " + meth + meth.locationString + + (if (meth.isConstructor) "" + else ";\nfollow this method with `_' if you want to treat it as a partially applied function")) } else { - // Relevant only for #4425 ? - Bug4425Error(tree) + setError(tree) } } @@ -787,7 +790,8 @@ trait Typers extends Modes with Adaptations { // or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *, // and thus parameterized types must be applied to their type arguments // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? - MissingTypeParametersError(tree) + errorTree(tree, tree.symbol + " takes type parameters") + tree setType tree.tpe } else if ( // (7.1) @M: check kind-arity // @M: removed check for tree.hasSymbol and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) (inHKMode(mode)) && @@ -802,7 +806,9 @@ trait Typers extends Modes with Adaptations { // Note that we treat Any and Nothing as kind-polymorphic. // We can't perform this check when typing type arguments to an overloaded method before the overload is resolved // (or in the case of an error type) -- this is indicated by pt == WildcardType (see case TypeApply in typed1). - KindArityMismatchError(tree, pt) + errorTree(tree, tree.tpe + " takes " + countElementsAsString(tree.tpe.typeParams.length, "type parameter") + + ", expected: " + countAsString(pt.typeParams.length)) + tree setType tree.tpe } else tree match { // (6) case TypeTree() => tree case _ => TypeTree(tree.tpe) setOriginal (tree) @@ -822,18 +828,13 @@ trait Typers extends Modes with Adaptations { val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) .setOriginal(tree) - inferConstructorInstance(tree1, clazz.typeParams, pt) match { - case Some(err) => - if (tree1.containsError()) - Block(List(err), tree1) - else err - case _ => tree1 - } + inferConstructorInstance(tree1, clazz.typeParams, pt) + tree1 } else { tree } } else { - CaseClassConstructorError(tree) + errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method") } } @@ -851,8 +852,7 @@ trait Typers extends Modes with Adaptations { case other => other } - if (qual.containsError()) qual // Fail quickly - else typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt) + typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt) } // begin adapt @@ -867,10 +867,8 @@ trait Typers extends Modes with Adaptations { } treeCopy.Literal(tree, value) case OverloadedType(pre, alts) if !inFunMode(mode) => // (1) - inferExprAlternative(tree, pt) match { - case Some(err) => err - case _ => adapt(tree, mode, pt, original) - } + inferExprAlternative(tree, pt) + adapt(tree, mode, pt, original) case NullaryMethodType(restpe) => // (2) adapt(tree setType restpe, mode, pt, original) case TypeRef(_, ByNameParamClass, List(arg)) if ((mode & EXPRmode) != 0) => // (2) @@ -929,10 +927,7 @@ trait Typers extends Modes with Adaptations { } else { if (inPatternMode(mode)) { if ((tree.symbol ne null) && tree.symbol.isModule) - inferModulePattern(tree, pt) match { - case Some(err) => return err - case _ => - } + inferModulePattern(tree, pt) if (isPopulated(tree.tpe, approximateAbstracts(pt))) return tree } @@ -960,8 +955,7 @@ trait Typers extends Modes with Adaptations { if (!context.undetparams.isEmpty) { return instantiate(tree, mode, pt) } - val validTree = !tree.containsErrorOrIsErrorTyped() - if (context.implicitsEnabled && !pt.isError && validTree) { + if (context.implicitsEnabled && !tree.tpe.isError && !pt.isError) { // (14); the condition prevents chains of views debuglog("inferring view from " + tree.tpe + " to " + pt) val coercion = inferView(tree, tree.tpe, pt, true) @@ -978,7 +972,7 @@ trait Typers extends Modes with Adaptations { new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt) } } - if (isCodeType(pt) && !isCodeType(tree.tpe) && validTree) + if (isCodeType(pt) && !isCodeType(tree.tpe) && !tree.tpe.isError) return adapt(lifted(tree), mode, pt, original) } if (settings.debug.value) { @@ -1009,7 +1003,7 @@ trait Typers extends Modes with Adaptations { context.unit.warning(tree.pos, "recovering from existential Skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree) adapt(tree, mode, pt.subst(pt.existentialSkolems, pt.existentialSkolems map (_ => WildcardType))) } else - TypeErrorTree(tree, pt, ex) + throw ex } } } @@ -1017,10 +1011,8 @@ trait Typers extends Modes with Adaptations { } def instantiate(tree: Tree, mode: Int, pt: Type): Tree = { - inferExprInstance(tree, context.extractUndetparams(), pt) match { - case (Some(err), _) => err - case _ => adapt(tree, mode, pt) - } + inferExprInstance(tree, context.extractUndetparams(), pt) + adapt(tree, mode, pt) } /** If the expected type is Unit: try instantiating type arguments * with expected type Unit, but if that fails, try again with pt = WildcardType @@ -1028,8 +1020,8 @@ trait Typers extends Modes with Adaptations { */ def instantiateExpectingUnit(tree: Tree, mode: Int): Tree = { val savedUndetparams = context.undetparams - instantiate(tree, mode, UnitClass.tpe) match { - case t: Tree if !t.containsError() => t + silent(_.instantiate(tree, mode, UnitClass.tpe)) match { + case t: Tree => t case _ => context.undetparams = savedUndetparams val valueDiscard = atPos(tree.pos)(Block(List(instantiate(tree, mode, WildcardType)), Literal(Constant()))) @@ -1077,48 +1069,40 @@ trait Typers extends Modes with Adaptations { adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe)) if (pt != WildcardType) { silent(_ => doAdapt(pt)) match { - case result: Tree if result != qual && !result.containsError() => + case result: Tree if result != qual => result case _ => debuglog("fallback on implicits in adaptToArguments: "+qual+" . "+name) doAdapt(WildcardType) } - } else { + } else doAdapt(pt) - } } - /** Try to apply an implicit conversion to `qual` so that it contains - * a method `name`. If that's ambiguous try taking arguments into - * account using `adaptToArguments`. + /** Try o apply an implicit conversion to `qual` to that it contains + * a method `name`. If that's ambiguous try taking arguments into account using `adaptToArguments`. */ def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Int): Tree = { - def onError(reportError: => Tree): Tree = { - // last ditch effort + try { + adaptToMember(qual, HasMember(name)) + } catch { + case ex: TypeError => + // this happens if implicits are ambiguous; try again with more context info. + // println("last ditch effort: "+qual+" . "+name) context.tree match { case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => // try handling the arguments // println("typing args: "+args) silent(_.typedArgs(args, mode)) match { - case xs: List[_] => - val args = xs.asInstanceOf[List[Tree]] - if (args exists (_.containsError())) - reportError - else - adaptToArguments(qual, name, args, WildcardType) - case _ => - reportError + case args: List[_] => + adaptToArguments(qual, name, args.asInstanceOf[List[Tree]], WildcardType) + case _ => + throw ex } case _ => - reportError + // println("not in an apply: "+context.tree+"/"+tree) + throw ex } } - try { - val res = adaptToMember(qual, HasMember(name)) - if (res.containsError()) onError(res) else res - } catch { - case ex: TypeError => - onError(AdaptToMemberWithArgsError(tree, ex)) - } } /** Try to apply an implicit conversion to `qual` to that it contains a @@ -1151,7 +1135,6 @@ trait Typers extends Modes with Adaptations { if (templ.parents.isEmpty) List() else try { val clazz = context.owner - var pending: List[ErrorTree] = List() // Normalize supertype and mixins so that supertype is always a class, not a trait. var supertpt = typedTypeConstructor(templ.parents.head) @@ -1160,13 +1143,7 @@ trait Typers extends Modes with Adaptations { // If first parent is a trait, make it first mixin and add its superclass as first parent while ((supertpt.tpe.typeSymbol ne null) && supertpt.tpe.typeSymbol.initialize.isTrait) { val supertpt1 = typedType(supertpt) - if (supertpt1.containsError()) { - // we assume here that all errors in supertpt1 have already been reported - supertpt setType ErrorType - } else if (supertpt1.tpe.isError) { - // Should not happen with ErrorTree - assert(false, "Erroneous SuperType contains Error tree") - } else { + if (!supertpt1.tpe.isError) { mixins = supertpt1 :: mixins supertpt = TypeTree(supertpt1.tpe.parents.head) setPos supertpt.pos.focus } @@ -1210,20 +1187,14 @@ trait Typers extends Modes with Adaptations { val cbody2 = newTyper(cscope) // called both during completion AND typing. .typePrimaryConstrBody(clazz, cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) - - if (cbody2.containsError()) - pending = errorTreesFinder(cbody2).toList ::: pending - superCall match { case Apply(_, _) => val sarg = treeInfo.firstArgument(superCall) if (sarg != EmptyTree && supertpe.typeSymbol != firstParent) - pending ::= ConstrArgsInTraitParentTpeError(sarg, firstParent) - if (!supertparams.isEmpty) - supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus + error(sarg.pos, firstParent+" is a trait; does not take constructor arguments") + if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus case _ => - if (!supertparams.isEmpty) - pending ::= MissingTypeArgumentsParentTpeError(supertpt) + if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") } val preSuperVals = treeInfo.preSuperFields(templ.body) @@ -1233,8 +1204,7 @@ trait Typers extends Modes with Adaptations { (preSuperStats, preSuperVals).zipped map { case (ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe } case _ => - if (!supertparams.isEmpty) - pending ::= MissingTypeArgumentsParentTpeError(supertpt) + if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") } /* experimental: early types as type arguments val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef) @@ -1246,11 +1216,12 @@ trait Typers extends Modes with Adaptations { */ //Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG - supertpt :: pending ::: mixins mapConserve (tpt => checkNoEscaping.privates(clazz, tpt)) + supertpt :: mixins mapConserve (tpt => checkNoEscaping.privates(clazz, tpt)) } catch { case ex: TypeError => - // TODO: remove once error trees refactoring is done - List(ParentTypesError(templ, ex)) + templ.tpe = null + reportTypeError(templ.pos, ex) + List(TypeTree(AnyRefClass.tpe)) } /**

Check that

@@ -1267,35 +1238,32 @@ trait Typers extends Modes with Adaptations { *
  • no two parents define same symbol.
  • * */ - def validateParentClasses(parents: List[Tree], selfType: Type): Option[PendingErrors] = { - var pending: List[ErrorTree] = List() + def validateParentClasses(parents: List[Tree], selfType: Type) { def validateParentClass(parent: Tree, superclazz: Symbol) { - if (!parent.containsErrorOrIsErrorTyped()) { + if (!parent.tpe.isError) { val psym = parent.tpe.typeSymbol.initialize - checkClassType(parent, false, true) match { - case t@Some(err) => - pending = err::pending - case _ => - } + checkClassType(parent, false, true) if (psym != superclazz) { if (psym.isTrait) { val ps = psym.info.parents if (!ps.isEmpty && !superclazz.isSubClass(ps.head.typeSymbol)) - pending = ParentSuperSubclassError(parent.pos, superclazz, ps.head.typeSymbol, psym)::pending + error(parent.pos, "illegal inheritance; super"+superclazz+ + "\n is not a subclass of the super"+ps.head.typeSymbol+ + "\n of the mixin " + psym) } else { - pending = ParentNotATraitMixinError(parent.pos, psym)::pending + error(parent.pos, psym+" needs to be a trait to be mixed in") } } - if (psym.isFinal) - pending = ParentFinalInheritanceError(parent.pos, psym)::pending - + if (psym.isFinal) { + error(parent.pos, "illegal inheritance from final "+psym) + } if (psym.isSealed && !phase.erasedTypes) { // AnyVal is sealed, but we have to let the value classes through manually if (context.unit.source.file == psym.sourceFile || isValueClass(context.owner)) psym addChild context.owner else - pending = ParentSealedInheritanceError(parent.pos, psym)::pending + error(parent.pos, "illegal inheritance from sealed "+psym) } if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes && @@ -1307,19 +1275,18 @@ trait Typers extends Modes with Adaptations { //Console.println(context.owner);//DEBUG //Console.println(context.owner.unsafeTypeParams);//DEBUG //Console.println(List.fromArray(context.owner.info.closure));//DEBUG - pending = ParentSelfTypeConformanceError(parent.pos, selfType, parent)::pending + error(parent.pos, "illegal inheritance;\n self-type "+ + selfType+" does not conform to "+parent + + "'s selftype "+parent.tpe.typeOfThis) if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis) } if (parents exists (p => p != parent && p.tpe.typeSymbol == psym && !psym.isError)) - pending = ParentInheritedTwiceError(parent.pos, psym)::pending + error(parent.pos, psym+" is inherited twice") } } - if (parents.forall(!_.containsError())) { - // proceed as normal, we know that head.tpe is not error? - if (!parents.isEmpty && !parents.head.tpe.isError) - for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol) - } - if (pending.isEmpty) None else Some(PendingErrors(pending.reverse)) + + if (!parents.isEmpty && !parents.head.tpe.isError) + for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol) /* if (settings.Xshowcls.value != "" && @@ -1330,11 +1297,11 @@ trait Typers extends Modes with Adaptations { */ } - def checkFinitary(classinfo: ClassInfoType): List[ErrorTree] = { + def checkFinitary(classinfo: ClassInfoType) { val clazz = classinfo.typeSymbol - - clazz.typeParams.map(tparam => + for (tparam <- clazz.typeParams) { if (classinfo.expansiveRefs(tparam) contains tparam) { + error(tparam.pos, "class graph is not finitary because type parameter "+tparam.name+" is expansively recursive") val newinfo = ClassInfoType( classinfo.parents map (_.instantiateTypeParams(List(tparam), List(AnyRefClass.tpe))), classinfo.decls, @@ -1345,9 +1312,8 @@ trait Typers extends Modes with Adaptations { case _ => newinfo } } - Some(FinitaryError(tparam)) - } else None - ).flatten + } + } } /** @@ -1434,16 +1400,15 @@ trait Typers extends Modes with Adaptations { val getter = if (isDeferred) value else value.getter(value.owner) assert(getter != NoSymbol, stat) - val gs = new ListBuffer[Tree] if (getter.isOverloaded) - gs.append(GetterDefinedTwiceError(getter)) + error(getter.pos, getter+" is defined twice") getter.setAnnotations(memberAnnots(allAnnots, GetterTargetClass)) if (value.isLazy) List(stat) else { - val vdef = treeCopy.ValDef(stat, mods | PrivateLocal, nme.getterToLocal(name), tpt, rhs) - val getterDef = atPos(vdef.pos.focus) { + val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) + val getterDef: DefDef = atPos(vdef.pos.focus) { if (isDeferred) { val r = DefDef(getter, EmptyTree) r.tpt.asInstanceOf[TypeTree].setOriginal(tpt) // keep type tree of original abstract field @@ -1459,21 +1424,18 @@ trait Typers extends Modes with Adaptations { r } } - - def setterDef(setter: Symbol, isBean: Boolean = false): Tree = { + checkNoEscaping.privates(getter, getterDef.tpt) + def setterDef(setter: Symbol, isBean: Boolean = false): DefDef = { setter setAnnotations memberAnnots(allAnnots, if (isBean) BeanSetterTargetClass else SetterTargetClass) val defTree = if ((mods hasFlag DEFERRED) || (setter hasFlag OVERLOADED)) EmptyTree else Assign(Select(This(value.owner), value), Ident(setter.paramss.head.head)) - typedPos(vdef.pos.focus)(DefDef(setter, defTree)) + typedPos(vdef.pos.focus)(DefDef(setter, defTree)).asInstanceOf[DefDef] } - val privateErrors = checkNoEscaping.privates(getter, getterDef.tpt) - if (privateErrors.containsError()) - privateErrors.foreach(err => gs.append(err)) - + val gs = new ListBuffer[DefDef] gs.append(getterDef) if (mods.isMutable) { val setter = getter.setter(value.owner) @@ -1489,7 +1451,7 @@ trait Typers extends Modes with Adaptations { if (beanGetter == NoSymbol) { // the namer decides wether to generate these symbols or not. at that point, we don't // have symbolic information yet, so we only look for annotations named "BeanProperty". - gs.append(BeanPropertyAnnotationLimitationError(stat)) + unit.error(stat.pos, "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import") } beanGetter.setAnnotations(memberAnnots(allAnnots, BeanGetterTargetClass)) if (mods.isMutable && beanGetter != NoSymbol) { @@ -1588,32 +1550,20 @@ trait Typers extends Modes with Adaptations { // the following is necessary for templates generated later assert(clazz.info.decls != EmptyScope) enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body) - - var doNotTypeBody = false - val parents2 = validateParentClasses(parents1, selfType) match { - case Some(err) => - doNotTypeBody = err.pending0.exists(_.isInstanceOf[BlockingError]) - List(err) - case _ => parents1 - } + validateParentClasses(parents1, selfType) if (clazz.isCase) validateNoCaseAncestor(clazz) if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.owner.isPackageClass) unit.error(clazz.pos, "inner classes cannot be classfile annotations") - - val finitiaryErrs = - if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members - checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) - else List() + if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members + checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) val body = - if (phase.id <= currentRun.typerPhase.id && !reporter.hasErrors && !doNotTypeBody) + if (phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) templ.body flatMap addGetterSetter else templ.body - - val body1 = if (doNotTypeBody) body else typedStats(body, templ.symbol) - val body2 = finitiaryErrs ++ body1 - treeCopy.Template(templ, parents2, self1, body2) setType clazz.tpe + val body1 = typedStats(body, templ.symbol) + treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe } /** Remove definition annotations from modifiers (they have been saved @@ -1631,29 +1581,22 @@ trait Typers extends Modes with Adaptations { val sym = vdef.symbol val typer1 = constrTyperIf(sym.isParameter && sym.owner.isConstructor) val typedMods = removeAnnotations(vdef.mods) - var pending: List[ErrorTree] = List() // complete lazy annotations val annots = sym.annotations var tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) - checkNonCyclic(vdef, tpt1) match { - case Some(cyclic) => - pending = cyclic::pending - case _ => - } + checkNonCyclic(vdef, tpt1) if (sym.hasAnnotation(definitions.VolatileAttr)) { if (!sym.isMutable) - pending = VolatileValueError(vdef)::pending + error(vdef.pos, "values cannot be volatile") else if (sym.isFinal) - pending = FinalVolatileVarError(vdef)::pending + error(vdef.pos, "final vars cannot be volatile") } val rhs1 = - if (tpt1.containsError()) { - vdef.rhs - } else if (vdef.rhs.isEmpty) { + if (vdef.rhs.isEmpty) { if (sym.isVariable && sym.owner.isTerm && phase.id <= currentRun.typerPhase.id) - pending = LocalVarUninitializedError(vdef)::pending + error(vdef.pos, "local variables must be initialized") vdef.rhs } else { val tpt2 = if (sym.hasDefault) { @@ -1676,10 +1619,7 @@ trait Typers extends Modes with Adaptations { } else tpt1.tpe newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, EXPRmode | BYVALmode, tpt2) } - val rhs2 = if (pending.nonEmpty) { - PendingErrors(pending.reverse) - } else rhs1 - treeCopy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs2)) setType NoType + treeCopy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs1)) setType NoType } /** Enter all aliases of local parameter accessors. @@ -1688,7 +1628,7 @@ trait Typers extends Modes with Adaptations { * @param vparamss ... * @param rhs ... */ - def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree): List[ErrorTree] = { + def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { debuglog("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => @@ -1706,17 +1646,16 @@ trait Typers extends Modes with Adaptations { val (superConstr, superArgs) = decompose(rhs) assert(superConstr.symbol ne null)//debug - var pending: List[ErrorTree] = List() // an object cannot be allowed to pass a reference to itself to a superconstructor // because of initialization issues; bug #473 for (arg <- superArgs ; tree <- arg) { val sym = tree.symbol if (sym != null && (sym.info.baseClasses contains clazz)) { if (sym.isModule) - pending = SuperConstrReferenceError(tree)::pending + error(tree.pos, "super constructor cannot be passed a self reference unless parameter is declared by-name") tree match { case This(qual) => - pending = SuperConstrArgsThisReferenceError(tree)::pending + error(tree.pos, "super constructor arguments cannot reference unconstructed `this`") case _ => () } } @@ -1754,8 +1693,6 @@ trait Typers extends Modes with Adaptations { } } } - - pending } /** Check if a structurally defined method violates implementation restrictions. @@ -1804,7 +1741,7 @@ trait Typers extends Modes with Adaptations { lookupVariable(name.toString.substring(1), enclClass) match { case Some(repl) => silent(_.typedTypeConstructor(stringParser(repl).typ())) match { - case tpt: Tree if !tpt.containsError()=> + case tpt: Tree => val alias = enclClass.newAliasType(useCase.pos, name.toTypeName) val tparams = cloneSymbols(tpt.tpe.typeSymbol.typeParams, alias) alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe))) @@ -1832,14 +1769,7 @@ trait Typers extends Modes with Adaptations { * @return ... */ def typedDefDef(ddef: DefDef): DefDef = { - def logErrorTree(t: Tree, errs: List[ErrorTree]) = - t match { - case errTree: ErrorTree => errTree::errs - case _ => errs - } - val meth = ddef.symbol - var pending: List[ErrorTree] = List() reenterTypeParams(ddef.tparams) reenterValueParams(ddef.vparamss) @@ -1861,22 +1791,17 @@ trait Typers extends Modes with Adaptations { val annots = meth.annotations for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1) - if (isRepeatedParamType(vparam1.symbol.tpe)) { - pending = StarParamNotLastError(vparam1)::pending - } + if (isRepeatedParamType(vparam1.symbol.tpe)) + error(vparam1.pos, "*-parameter must come last") var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt)) if (!settings.YdepMethTpes.value) { for (vparams <- vparamss1; vparam <- vparams) { - pending = logErrorTree(checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt), pending) + checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () } - pending = logErrorTree(checkNoEscaping.locals(context.scope, WildcardType, tpt1), pending) - } - checkNonCyclic(ddef, tpt1) match { - case Some(cylic) => - pending = cylic::pending - case _ => + checkNoEscaping.locals(context.scope, WildcardType, tpt1) } + checkNonCyclic(ddef, tpt1) ddef.tpt.setType(tpt1.tpe) val typedMods = removeAnnotations(ddef.mods) var rhs1 = @@ -1885,41 +1810,35 @@ trait Typers extends Modes with Adaptations { (!meth.owner.isClass || meth.owner.isModuleClass || meth.owner.isAnonOrRefinementClass)) - pending = InvalidConstructorDefError(ddef)::pending + error(ddef.pos, "constructor definition not allowed here") typed(ddef.rhs) } else { transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe) } if (meth.isPrimaryConstructor && meth.isClassConstructor && - phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) { - computeParamAliases(meth.owner, vparamss1, rhs1) match { - case Nil => () - case pending0 => - pending = pending0 ::: pending - } - } + phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) + computeParamAliases(meth.owner, vparamss1, rhs1) if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass) rhs1 = checkDead(rhs1) if (phase.id <= currentRun.typerPhase.id && meth.owner.isClass && meth.paramss.exists(ps => ps.exists(_.hasDefaultFlag) && isRepeatedParamType(ps.last.tpe))) - pending = StarWithDefaultError(meth)::pending + error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments") if (phase.id <= currentRun.typerPhase.id) { val allParams = meth.paramss.flatten for (p <- allParams) { for (n <- p.deprecatedParamName) { if (allParams.exists(p1 => p1.name == n || (p != p1 && p1.deprecatedParamName.exists(_ == n)))) - pending = DeprecatedParamNameError(p, n)::pending + error(p.pos, "deprecated parameter name "+ n +" has to be distinct from any other parameter name (deprecated or not).") } } } if (meth.isStructuralRefinementMember) checkMethodStructuralCompatible(meth) - if (pending.nonEmpty) - rhs1 = wrapInBlock(PendingErrors(pending.reverse), rhs1) + treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType } @@ -1948,22 +1867,15 @@ trait Typers extends Modes with Adaptations { } val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs)) - val rhs2 = checkNonCyclic(tdef.symbol) match { - case Some(cyclic) => - wrapInBlock(cyclic, rhs1) - case None => - if (tdef.symbol.owner.isType) - rhs1.tpe match { - case TypeBounds(lo1, hi1) if (!(lo1 <:< hi1)) => - wrapInBlock( - LowerBoundError(tdef, lo1, hi1), - rhs1) - case _ => - rhs1 - } - else rhs1 - } - treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs2) setType NoType + checkNonCyclic(tdef.symbol) + if (tdef.symbol.owner.isType) + rhs1.tpe match { + case TypeBounds(lo1, hi1) => + if (!(lo1 <:< hi1)) + error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1) + case _ => + } + treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType } private def enterLabelDef(stat: Tree) { @@ -2080,17 +1992,10 @@ trait Typers extends Modes with Adaptations { */ def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = { // verify no _* except in last position - var pending: List[ErrorTree] = List() for (Apply(_, xs) <- cdef.pat ; x <- xs dropRight 1 ; if treeInfo isStar x) - pending = StarPositionInPatternError(x.pos)::pending + error(x.pos, "_* may only come last") - val pat0 = typedPattern(cdef.pat, pattpe) - val pat1: Tree = pending match { - case List() => - pat0 - case _ => - wrapInBlock(PendingErrors(pending.reverse), pat0) - } + val pat1: Tree = typedPattern(cdef.pat, pattpe) // When case classes have more than two parameter lists, the pattern ends // up typed as a method. We only pattern match on the first parameter // list, so substitute the final result type of the method, i.e. the type @@ -2106,17 +2011,16 @@ trait Typers extends Modes with Adaptations { val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree else typed(cdef.guard, BooleanClass.tpe) - var body1: Tree = typed(cdef.body, pt) if (!context.savedTypeBounds.isEmpty) { body1.tpe = context.restoreTypeBounds(body1.tpe) if (isFullyDefined(pt) && !(body1.tpe <:< pt)) { - body1 = typed { - atPos(body1.pos) { - // @M no need for pt.normalize here, is done in erasure - TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) + body1 = + typed { + atPos(body1.pos) { + TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) // @M no need for pt.normalize here, is done in erasure + } } - } } } // body1 = checkNoEscaping.locals(context.scope, pt, body1) @@ -2139,7 +2043,7 @@ trait Typers extends Modes with Adaptations { val codeExpected = !forMSIL && (pt.typeSymbol isNonBottomSubClass CodeClass) if (numVparams > definitions.MaxFunctionArity) - return MaxFunctionArityError(fun) + return errorTree(fun, "implementation restricts functions to " + definitions.MaxFunctionArity + " parameters") def decompose(pt: Type): (Symbol, List[Type], Type) = if ((isFunctionType(pt) @@ -2155,10 +2059,9 @@ trait Typers extends Modes with Adaptations { (FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType) val (clazz, argpts, respt) = decompose(if (codeExpected) pt.normalize.typeArgs.head else pt) - val vparamErrors = new mutable.HashMap[ValDef, ErrorTree]() if (argpts.lengthCompare(numVparams) != 0) - WrongNumberOfParametersError(fun, argpts) + errorTree(fun, "wrong number of parameters; expected = " + argpts.length) else { val vparamSyms = (fun.vparams, argpts).zipped map { (vparam, argpt) => if (vparam.tpt.isEmpty) { @@ -2168,7 +2071,7 @@ trait Typers extends Modes with Adaptations { fun match { case etaExpansion(vparams, fn, args) if !codeExpected => silent(_.typed(fn, forFunMode(mode), pt)) match { - case fn1: Tree if context.undetparams.isEmpty && !fn1.containsError() => + case fn1: Tree if context.undetparams.isEmpty => // if context,undetparams is not empty, the function was polymorphic, // so we need the missing arguments to infer its type. See #871 //println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams) @@ -2179,7 +2082,7 @@ trait Typers extends Modes with Adaptations { } case _ => } - vparamErrors += ((vparam, MissingParameterTypeError(fun, vparam, pt))) + error(vparam.pos, missingParameterTypeMsg(fun, vparam, pt)) ErrorType } if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus @@ -2189,21 +2092,14 @@ trait Typers extends Modes with Adaptations { vparam.symbol } - val vparams = fun.vparams mapConserve (p => - { val p0 = typedValDef(p) - if (vparamErrors.contains(p)) { - treeCopy.ValDef(p0, p0.mods, p0.name, vparamErrors(p), p0.rhs) - } - else p0 - }) + val vparams = fun.vparams mapConserve (typedValDef) // for (vparam <- vparams) { // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () // } - val body0 = typed(fun.body, respt) + var body = typed(fun.body, respt) val formals = vparamSyms map (_.tpe) - val (restpe0, errs) = packedType(body0, fun.symbol)//.deconst - val body = if (errs.isEmpty) body0 else Block(errs, body0) - val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe0.deconst) + val restpe = packedType(body, fun.symbol).deconst + val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe) // body = checkNoEscaping.locals(context.scope, restpe, body) val fun1 = treeCopy.Function(fun, vparams, body).setType(funtpe) if (codeExpected) lifted(fun1) else fun1 @@ -2236,10 +2132,11 @@ trait Typers extends Modes with Adaptations { case Some(imp1: Import) => imp1 case None => log("unhandled import: "+imp+" in "+unit); imp } + private def isWarnablePureExpression(tree: Tree) = tree match { case EmptyTree | Literal(Constant(())) => false case _ => - !tree.containsErrorOrIsErrorTyped() && (treeInfo isPureExpr tree) && { + (treeInfo isPureExpr tree) && { val sym = tree.symbol (sym == null) || !(sym.isModule || sym.isLazy) || { debuglog("'Pure' but side-effecting expression in statement position: " + tree) @@ -2255,7 +2152,7 @@ trait Typers extends Modes with Adaptations { val localTarget = stats exists includesTargetPos def typedStat(stat: Tree): Tree = { if (context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(stat)) - OnlyDeclarationsError(stat) + errorTree(stat, "only declarations allowed here") else stat match { case imp @ Import(_, _) => @@ -2273,19 +2170,16 @@ trait Typers extends Modes with Adaptations { // XXX this creates a spurious dead code warning if an exception is thrown // in a constructor, even if it is the only thing in the constructor. val result = checkDead(localTyper.typed(stat, EXPRmode | BYVALmode, WildcardType)) - - val result1 = if (treeInfo.isSelfOrSuperConstrCall(result)) { - context.inConstructorSuffix = true - if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0)) - wrapInBlock(ConstructorsOrderError(stat), result) - else result - } else result - - if (isWarnablePureExpression(result1)) context.warning(stat.pos, + if (treeInfo.isSelfOrSuperConstrCall(result)) { + context.inConstructorSuffix = true + if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0)) + error(stat.pos, "called constructor's definition must precede calling constructor's definition") + } + if (isWarnablePureExpression(result)) context.warning(stat.pos, "a pure expression does nothing in statement position; " + "you may be omitting necessary parentheses" ) - result1 + result } } } @@ -2317,7 +2211,8 @@ trait Typers extends Modes with Adaptations { // error for this is issued in RefChecks.checkDefaultsInOverloaded if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasDefaultFlag && !e.sym.hasAnnotation(BridgeClass) && !e1.sym.hasAnnotation(BridgeClass)) { - newStats += DefDefinedTwiceError(e.sym, e1.sym) + error(e.sym.pos, e1.sym+" is defined twice"+ + {if(!settings.debug.value) "" else " in "+unit.toString}) scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779 } e1 = scope.lookupNextEntry(e1) @@ -2484,15 +2379,8 @@ trait Typers extends Modes with Adaptations { arg1 } context.undetparams = undetparams - - inferMethodAlternative(fun, undetparams, argtpes.toList, pt, - varArgsOnly = treeInfo.isWildcardStarArgList(args)) match { - case Some(err) => - err - case _ => - doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt) - } - + inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args)) + doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt) case mt @ MethodType(params, _) => val paramTypes = mt.paramTypes @@ -2512,7 +2400,7 @@ trait Typers extends Modes with Adaptations { // the inner "doTypedApply" does "extractUndetparams" => restore when it fails val savedUndetparams = context.undetparams silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) match { - case t: Tree if !t.containsError() => + case t: Tree => // Depending on user options, may warn or error here if // a Unit or tuple was inserted. Some(t) filter (tupledTree => @@ -2520,7 +2408,7 @@ trait Typers extends Modes with Adaptations { || tupledTree.symbol == null || checkValidAdaptation(tupledTree, args) ) - case _ => + case ex => context.undetparams = savedUndetparams None } @@ -2538,24 +2426,19 @@ trait Typers extends Modes with Adaptations { if (mt.isErroneous) setError(tree) else if (inPatternMode(mode)) // #2064 - WrongNumberOfArgsError(tree, fun) + errorTree(tree, "wrong number of arguments for "+ treeSymTypeMsg(fun)) else if (lencmp > 0) { - tryTupleApply getOrElse TooManyArgsNamesDefaultsError(tree, fun) + tryTupleApply getOrElse errorTree(tree, "too many arguments for "+treeSymTypeMsg(fun)) } else if (lencmp == 0) { // we don't need defaults. names were used, so this application is transformed // into a block (@see transformNamedApplication in NamesDefaults) - val (namelessArgs, argPos) = removeNames(Typer.this)(args, params) - if (namelessArgs exists (_.containsError())) { - // This should maybe be special handled - val tree1 = treeCopy.Apply(tree, fun, namelessArgs) - setError(tree1) - } else if (namelessArgs exists (_.isErroneous)) { - assert(false, "removeNames for NamesDefaults returns only ErrorTrees in case of error. We got " + namelessArgs) + if (namelessArgs exists (_.isErroneous)) { setError(tree) } else if (!isIdentity(argPos) && !sameLength(formals, params)) // !isIdentity indicates that named arguments are used to re-order arguments - MultipleVarargError(tree) + errorTree(tree, "when using named arguments, the vararg parameter "+ + "has to be specified exactly once") else if (isIdentity(argPos) && !isNamedApplyBlock(fun)) { // if there's no re-ordering, and fun is not transformed, no need to transform // more than an optimization, e.g. important in "synchronized { x = update-x }" @@ -2569,8 +2452,7 @@ trait Typers extends Modes with Adaptations { // calls to the default getters. Example: // foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a)) val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x) - if (fun1.containsError()) fun1 - else if (fun1.isErroneous) setError(tree) + if (fun1.isErroneous) setError(tree) else { assert(isNamedApplyBlock(fun1), fun1) val NamedApplyInfo(qual, targs, previousArgss, _) = context.namedApplyBlockInfo.get._2 @@ -2587,20 +2469,17 @@ trait Typers extends Modes with Adaptations { val lencmp2 = compareLengths(allArgs, formals) if (!sameLength(allArgs, args) && callToCompanionConstr(context, funSym)) { - ModuleUsingCompanionClassDefaultArgsErrror(tree) + errorTree(tree, "module extending its companion class cannot use default constructor arguments") } else if (lencmp2 > 0) { - val errors = removeNames(Typer.this)(allArgs, params)._1.filter(_.containsError()) // #3818 - if (!errors.isEmpty) - wrapInBlock(PendingErrors(findAllNestedErrors(errors)), tree) - else - setError(tree) + removeNames(Typer.this)(allArgs, params) // #3818 + setError(tree) } else if (lencmp2 == 0) { // useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]() val note = "Error occurred in an application involving default arguments." if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt) } else { - tryTupleApply getOrElse NotEnoughArgsError(tree, fun, missing) + tryTupleApply getOrElse errorTree(tree, notEnoughArgumentsMsg(fun, missing)) } } } @@ -2624,7 +2503,6 @@ trait Typers extends Modes with Adaptations { // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case: // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo) // precise(foo) : foo.type => foo.type - val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe)) def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if (inPatternMode(mode)) => rtp @@ -2660,12 +2538,11 @@ trait Typers extends Modes with Adaptations { atPos(tree.pos)(gen.mkNil setType restpe) else constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe)) + } else if (needsInstantiation(tparams, formals, args)) { //println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info))) - inferExprInstance(fun, tparams) match { - case (Some(err), _) => err - case _ => doTypedApply(tree, fun, args, mode, pt) - } + inferExprInstance(fun, tparams) + doTypedApply(tree, fun, args, mode, pt) } else { assert(!inPatternMode(mode)) // this case cannot arise for patterns val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt) @@ -2682,31 +2559,20 @@ trait Typers extends Modes with Adaptations { val argtparams = context.extractUndetparams() if (!argtparams.isEmpty) { val strictPt = formal.instantiateTypeParams(tparams, strictTargs) - inferArgumentInstance(arg1, argtparams, strictPt, lenientPt) match { - case Some(err) => - err - case _ => - arg1 - } - } else arg1 + inferArgumentInstance(arg1, argtparams, strictPt, lenientPt) + } + arg1 } val args1 = (args, formals).zipped map typedArgToPoly - if (args1 exists {_.containsErrorOrIsErrorTyped()}) { - val allNestedErrors = findAllNestedErrors(args1.filter(_.containsError())) - if (allNestedErrors.isEmpty) SetErrorTree(tree) else PendingErrors(allNestedErrors) - } else { + if (args1 exists (_.tpe.isError)) setError(tree) + else { debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun" // returns those undetparams which have not been instantiated. - val undetparamsOrError = inferMethodInstance(fun, tparams, args1, pt) - if (undetparamsOrError.isLeft) { - context.undetparams = Nil - undetparamsOrError.left.get - } else { - val result = doTypedApply(tree, fun, args1, mode, pt) - context.undetparams = undetparamsOrError.right.get - result - } + val undetparams = inferMethodInstance(fun, tparams, args1, pt) + val result = doTypedApply(tree, fun, args1, mode, pt) + context.undetparams = undetparams + result } } } @@ -2715,15 +2581,12 @@ trait Typers extends Modes with Adaptations { doTypedApply(tree, fun setType fun.tpe.widen, args, mode, pt) case ErrorType => - if (tree.containsError()) - tree - else - ErroneousFunInTypeApplyError(fun, args) + setError(treeCopy.Apply(tree, fun, args)) /* --- begin unapply --- */ case otpe if inPatternMode(mode) && unapplyMember(otpe).exists => if (args.length > MaxTupleArity) - return TooManyArgsPatternError(fun) + error(fun.pos, "too many arguments for unapply pattern, maximum = "+MaxTupleArity) def freshArgType(tp: Type): (Type, List[Symbol]) = (tp: @unchecked) match { case MethodType(param :: _, _) => @@ -2731,10 +2594,9 @@ trait Typers extends Modes with Adaptations { case PolyType(tparams, restype) => val tparams1 = cloneSymbols(tparams) (freshArgType(restype)._1.substSym(tparams, tparams1), tparams1) - // No longer used, see test case neg/t960.scala (#960 has nothing to do with it) -// case OverloadedType(_, _) => -// error(fun.pos, "cannot resolve overloaded unapply") -// (ErrorType, Nil) + case OverloadedType(_, _) => + error(fun.pos, "cannot resolve overloaded unapply") + (ErrorType, Nil) } val unapp = unapplyMember(otpe) @@ -2749,11 +2611,7 @@ trait Typers extends Modes with Adaptations { freeVars foreach context1.scope.enter val typer1 = newTyper(context1) - val pattp0 = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe) - val pattp = pattp0 match { - case Left(err) => return err // Fail quickly - case Right(tp) => tp - } + val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe) // turn any unresolved type variables in freevars into existential skolems val skolems = freeVars map { fv => @@ -2769,14 +2627,7 @@ trait Typers extends Modes with Adaptations { // setType null is necessary so that ref will be stabilized; see bug 881 val fun1 = typedPos(fun.pos)(Apply(Select(fun setType null, unapp), List(arg))) - // Set error tree - if (fun1.containsError()) - ErroneousFunInTypeApplyError(fun1, args) - else if (fun1.tpe.isErroneous) { - assert(false, "Bug #4425 workaround is invalid") - //Bug4425Error(tree) - setError(tree) - } + if (fun1.tpe.isErroneous) setError(tree) else { val formals0 = unapplyTypeList(fun1.symbol, fun1.tpe) val formals1 = formalTypes(formals0, args.length) @@ -2791,13 +2642,14 @@ trait Typers extends Modes with Adaptations { arg.tpe = pt1 // restore type (arg is a dummy tree, just needs to pass typechecking) UnApply(fun1, args1) setPos tree.pos setType itype } - else - WrongNumberArgsPatternError(tree, fun) + else { + errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) + } } /* --- end unapply --- */ case _ => - ApplyWithoutArgsError(tree, fun) + errorTree(tree, fun.tpe+" does not take parameters") } } @@ -2809,10 +2661,8 @@ trait Typers extends Modes with Adaptations { def typedAnnotation(ann: Tree, mode: Int = EXPRmode, selfsym: Symbol = NoSymbol, annClass: Symbol = AnnotationClass, requireJava: Boolean = false): AnnotationInfo = { lazy val annotationError = AnnotationInfo(ErrorType, Nil, Nil) var hasError: Boolean = false - var pending: List[ErrorTree] = List() - - def reportAnnotationError(errTree: ErrorTree) = { - pending = errTree::pending + def error(pos: Position, msg: String) = { + context.error(pos, msg) hasError = true annotationError } @@ -2820,7 +2670,7 @@ trait Typers extends Modes with Adaptations { /** Calling constfold right here is necessary because some trees (negated * floats and literals in particular) are not yet folded. */ - def tryConst(tr: Tree, pt: Type): Either[ErrorTree, LiteralAnnotArg] = { + def tryConst(tr: Tree, pt: Type): Option[LiteralAnnotArg] = { val const: Constant = typed(constfold(tr), EXPRmode, pt) match { case l @ Literal(c) if !l.isErroneous => c case tree => tree.tpe match { @@ -2828,37 +2678,37 @@ trait Typers extends Modes with Adaptations { case tpe => null } } + def fail(msg: String) = { error(tr.pos, msg) ; None } - if (const == null) { - Left(AnnotationNotAConstantError(tr)) - } else if (const.value == null) - Left(AnnotationArgNullError(tr)) + if (const == null) + fail("annotation argument needs to be a constant; found: " + tr) + else if (const.value == null) + fail("annotation argument cannot be null") else - Right(LiteralAnnotArg(const)) + Some(LiteralAnnotArg(const)) } /** Converts an untyped tree to a ClassfileAnnotArg. If the conversion fails, * an error message is reported and None is returned. */ - def tree2ConstArg(tree: Tree, pt: Type): Either[Tree, ClassfileAnnotArg] = tree match { + def tree2ConstArg(tree: Tree, pt: Type): Option[ClassfileAnnotArg] = tree match { case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) if (pt.typeSymbol == ArrayClass) => - Left(ArrayConstantsError(tree)) + error(tree.pos, "Array constants have to be specified using the `Array(...)' factory method") + None case ann @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => val annInfo = typedAnnotation(ann, mode, NoSymbol, pt.typeSymbol, true) if (annInfo.atp.isErroneous) { + // recursive typedAnnotation call already printed an error, so don't call "error" hasError = true - Left(NullErrorTree) - } else - Right(NestedAnnotArg(annInfo)) + None + } else Some(NestedAnnotArg(annInfo)) // use of Array.apply[T: ClassManifest](xs: T*): Array[T] // and Array.apply(x: Int, xs: Int*): Array[Int] (and similar) case Apply(fun, args) => val typedFun = typed(fun, forFunMode(mode), WildcardType) - if (typedFun.containsError()) { - Left(typedFun) - } else if (typedFun.symbol.owner == ArrayModule.moduleClass && typedFun.symbol.name == nme.apply) + if (typedFun.symbol.owner == ArrayModule.moduleClass && typedFun.symbol.name == nme.apply) pt match { case TypeRef(_, ArrayClass, targ :: _) => trees2ConstArg(args, targ) @@ -2867,24 +2717,21 @@ trait Typers extends Modes with Adaptations { // BT = Int, .., String, Class[_], JavaAnnotClass // T = BT | Array[BT] // So an array literal as argument can only be valid if pt is Array[_] - Left(ArrayConstantsTypeMismatchError(tree, pt)) + error(tree.pos, "found array constant, expected argument of type "+ pt) + None } - else tryConst(tree, pt) + else + tryConst(tree, pt) - case Typed(t, _) => - tree2ConstArg(t, pt) + case Typed(t, _) => tree2ConstArg(t, pt) case tree => tryConst(tree, pt) } - - def trees2ConstArg(trees: List[Tree], pt: Type): Either[ErrorTree, ArrayAnnotArg] = { + def trees2ConstArg(trees: List[Tree], pt: Type): Option[ArrayAnnotArg] = { val args = trees.map(tree2ConstArg(_, pt)) - val par = args.filter(_.isLeft) - if (!par.isEmpty) - Left(PendingErrors(findAllNestedErrors(par.map(_.left.get)))) - else - Right(ArrayAnnotArg(args.map(_.right.get).toArray)) + if (args.exists(_.isEmpty)) None + else Some(ArrayAnnotArg(args.flatten.toArray)) } // begin typedAnnotation @@ -2896,18 +2743,14 @@ trait Typers extends Modes with Adaptations { case Select(New(tpt), nme.CONSTRUCTOR) => (fun, outerArgss) case _ => - (UnexpectedTreeAnnotation(fun), outerArgss) + error(fun.pos, "unexpected tree in annotation: "+ fun) + (setError(fun), outerArgss) } extract(ann, List()) } - - // It seems that fun.isErroneous was used due to check for deep error within fun? - // We don't need it now because deep error within fun - // is now detected by containsError() - val res = if (fun.containsErrorOrIsErrorTyped()) { - annotationError - } else { + if (fun.isErroneous) annotationError + else { val typedFun @ Select(New(tpt), _) = typed(fun, forFunMode(mode), WildcardType) val annType = tpt.tpe @@ -2916,9 +2759,9 @@ trait Typers extends Modes with Adaptations { // annotation to be saved as java classfile annotation val isJava = typedFun.symbol.owner.isJavaDefined if (!annType.typeSymbol.isNonBottomSubClass(annClass)) { - reportAnnotationError(AnnotationTypeMismatchError(tpt, annClass.tpe, annType)) + error(tpt.pos, "expected annotation of type "+ annClass.tpe +", found "+ annType) } else if (argss.length > 1) { - reportAnnotationError(MultipleArgumentListForAnnotationError(ann)) + error(ann.pos, "multiple argument lists on classfile annotation") } else { val args = if (argss.head.length == 1 && !isNamed(argss.head.head)) @@ -2934,37 +2777,33 @@ trait Typers extends Modes with Adaptations { val sym = if (isJava) annScope.lookup(name) else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol) if (sym == NoSymbol) { - reportAnnotationError(UnknownAnnotationNameError(arg, name)) + error(arg.pos, "unknown annotation argument name: " + name) (nme.ERROR, None) } else if (!names.contains(sym)) { - reportAnnotationError(DuplicateValueAnnotationError(arg, name)) + error(arg.pos, "duplicate value for annotation argument " + name) (nme.ERROR, None) } else { names -= sym if (isJava) sym.cookJavaRawInfo() // #3429 val annArg = tree2ConstArg(rhs, sym.tpe.resultType) - if (annArg.isLeft) { - errorTreesFinder(annArg.left.get).foreach(reportAnnotationError) - (nme.ERROR, None) - } else - (sym.name, Some(annArg.right.get)) + (sym.name, annArg) } case arg => - reportAnnotationError(ClassfileAnnotationsAsNamedArgsError(arg)) + error(arg.pos, "classfile annotation arguments have to be supplied as named arguments") (nme.ERROR, None) } for (name <- names) { if (!name.annotations.contains(AnnotationInfo(AnnotationDefaultAttr.tpe, List(), List())) && !name.hasDefaultFlag) - reportAnnotationError(AnnotationMissingArgError(ann, annType, name)) + error(ann.pos, "annotation " + annType.typeSymbol.fullName + " is missing argument " + name.name) } if (hasError) annotationError else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setPos(ann.pos) } } else if (requireJava) { - reportAnnotationError(NestedAnnotationError(ann, annType)) + error(ann.pos, "nested classfile annotations must be defined in java; found: "+ annType) } else { val typedAnn = if (selfsym == NoSymbol) { typed(ann, mode, annClass.tpe) @@ -2992,9 +2831,6 @@ trait Typers extends Modes with Adaptations { List(selfsym.info, annClass.tpe)) (typed(func, mode, funcType): @unchecked) match { - case t if t.containsError() => - reportAnnotationError(NullErrorTree) - t case t @ Function(List(arg), rhs) => val subs = new TreeSymSubstituter(List(arg.symbol),List(selfsym)) @@ -3019,27 +2855,16 @@ trait Typers extends Modes with Adaptations { annInfo(fun) case _ => - reportAnnotationError(UnexpectedTreeAnnotationError(t, typedAnn)) + error(t.pos, "unexpected tree after typing annotation: "+ typedAnn) } if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2) unit.deprecationWarning(ann.pos, "@deprecated now takes two arguments; see the scaladoc.") - if (typedAnn.containsError() || (typedAnn.tpe == null) || typedAnn.tpe.isErroneous) annotationError + if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) annotationError else annInfo(typedAnn) } } - - if (hasError) { - // We got errors, so now is the last chance to report them - try { - pending.foreach(_.emit(context)) - } catch { - case _: TypeError => - assert(false, "Cannot throw type errors when creating AnnotationInfo") - } - annotationError - } else res } def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type? @@ -3098,8 +2923,7 @@ trait Typers extends Modes with Adaptations { } /** convert skolems to existentials */ - def packedType(tree: Tree, owner: Symbol): (Type, List[ErrorTree]) = { - var pending: List[ErrorTree] = List() + def packedType(tree: Tree, owner: Symbol): Type = { def defines(tree: Tree, sym: Symbol) = sym.isExistentialSkolem && sym.unpackLocation == tree || tree.isDef && tree.symbol == sym @@ -3125,7 +2949,7 @@ trait Typers extends Modes with Adaptations { if (sym.isAliasType && containsLocal(tp)) apply(tp.normalize) else { if (pre.isVolatile) - pending = InferTypeWithVolatileTypeSelectionError(tree, tp)::pending + context.error(tree.pos, "Inferred type "+tree.tpe+" contains type selection from volatile type "+pre) mapOver(tp) } case _ => @@ -3142,7 +2966,8 @@ trait Typers extends Modes with Adaptations { localSyms += sym remainingSyms += sym } else { - pending = AbstractExistentiallyOverParamerizedTpeError(tree, tp)::pending + unit.error(tree.pos, + "can't existentially abstract over parameterized type " + tp) } } } @@ -3171,10 +2996,10 @@ trait Typers extends Modes with Adaptations { } for (sym <- remainingSyms) addLocals(sym.existentialBound) } + val normalizedTpe = normalizeLocals(tree.tpe) addLocals(normalizedTpe) - val res = packSymbols(localSyms.toList, normalizedTpe) - (res, pending.reverse) + packSymbols(localSyms.toList, normalizedTpe) } protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = { @@ -3182,23 +3007,19 @@ trait Typers extends Modes with Adaptations { if (wc.symbol == NoSymbol) { namer.enterSym(wc); wc.symbol setFlag EXISTENTIAL } else context.scope enter wc.symbol val whereClauses1 = typedStats(tree.whereClauses, context.owner) - var pending: List[ErrorTree] = List() for (vd @ ValDef(_, _, _, _) <- tree.whereClauses) if (vd.symbol.tpe.isVolatile) - pending = AbstractionFromVolatileTypeError(vd)::pending + error(vd.pos, "illegal abstraction from value with volatile type "+vd.symbol.tpe) val tpt1 = typedType(tree.tpt, mode) val (typeParams, tpe) = existentialTransform(tree.whereClauses map (_.symbol), tpt1.tpe) - val tt = TypeTree(ExistentialType(typeParams, tpe)) setOriginal tree - if (pending.isEmpty) tt else tt.setErrorCause(PendingErrors(pending.reverse)) + //println(tpe + ": " + tpe.getClass ) + TypeTree(ExistentialType(typeParams, tpe)) setOriginal tree } // lifted out of typed1 because it's needed in typedImplicit0 protected def typedTypeApply(tree: Tree, mode: Int, fun: Tree, args: List[Tree]): Tree = fun.tpe match { case OverloadedType(pre, alts) => - inferPolyAlternatives(fun, args map (_.tpe)) match { - case Some(err) => return err - case _ => - } + inferPolyAlternatives(fun, args map (_.tpe)) val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) val args1 = if (sameLength(args, tparams)) { //@M: in case TypeApply we can't check the kind-arities of the type arguments, @@ -3211,7 +3032,7 @@ trait Typers extends Modes with Adaptations { // Martin, I'm using fake trees, because, if you use args or arg.map(typedType), // inferPolyAlternatives loops... -- I have no idea why :-( // ...actually this was looping anyway, see bug #278. - return TypedApplyWrongNumberOfTpeParametersError(fun, fun) + return errorTree(fun, "wrong number of type parameters for "+treeSymTypeMsg(fun)) typedTypeApply(tree, mode, fun, args1) case SingleType(_, _) => @@ -3219,36 +3040,30 @@ trait Typers extends Modes with Adaptations { case PolyType(tparams, restpe) if tparams.nonEmpty => if (sameLength(tparams, args)) { val targs = args map (_.tpe) - checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "") match { - case Some(err) => - err - case None => - if (fun.symbol == Predef_classOf) { - checkClassType(args.head, true, false) match { - case Some(err) => err - case _ => atPos(tree.pos) { gen.mkClassOf(targs.head) } - } - } else { - if (phase.id <= currentRun.typerPhase.id && - fun.symbol == Any_isInstanceOf && !targs.isEmpty) - checkCheckable(tree.pos, targs.head, "") - val resultpe = restpe.instantiateTypeParams(tparams, targs) - //@M substitution in instantiateParams needs to be careful! - //@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int] - //@M --> first, m[a] gets changed to m[Int], then m gets substituted for List, - // this must preserve m's type argument, so that we end up with List[Int], and not List[a] - //@M related bug: #1438 - //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe) - treeCopy.TypeApply(tree, fun, args) setType resultpe - } + checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "") + if (fun.symbol == Predef_classOf) { + checkClassType(args.head, true, false) + atPos(tree.pos) { gen.mkClassOf(targs.head) } + } else { + if (phase.id <= currentRun.typerPhase.id && + fun.symbol == Any_isInstanceOf && !targs.isEmpty) + checkCheckable(tree.pos, targs.head, "") + val resultpe = restpe.instantiateTypeParams(tparams, targs) + //@M substitution in instantiateParams needs to be careful! + //@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int] + //@M --> first, m[a] gets changed to m[Int], then m gets substituted for List, + // this must preserve m's type argument, so that we end up with List[Int], and not List[a] + //@M related bug: #1438 + //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe) + treeCopy.TypeApply(tree, fun, args) setType resultpe } } else { - TypedApplyWrongNumberOfTpeParametersError(tree, fun) + errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun)) } case ErrorType => setError(tree) case _ => - TypedApplyDoesNotTakeTpeParametersError(tree, fun) + errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.") } @inline final def deindentTyping() = context.typingIndentLevel -= 2 @@ -3318,10 +3133,9 @@ trait Typers extends Modes with Adaptations { atype0 // do not record selfsym if // this annotation did not need it - if (ainfo.isErroneous) { - // Erroneous annotations were already reported in typedAnnotation + if (ainfo.isErroneous) arg1 // simply drop erroneous annotations - } else { + else { ann.tpe = atype TypeTree(atype) setOriginal tree } @@ -3355,24 +3169,18 @@ trait Typers extends Modes with Adaptations { tree setSymbol vble setType vble.tpe } def typedBindTerm(name: TermName) = { - def typedBindTerm0() = { - val body1 = typed(body, mode, pt) - vble.setInfo( - if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) - else body1.tpe) - treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // burak, was: pt - } if (vble == NoSymbol) vble = context.owner.newValue(tree.pos, name) if (vble.name.toTermName != nme.WILDCARD) { - vble = namer.enterInScope(vble) - if ((mode & ALTmode) != 0) - VariableInPatternAlternativeError(tree) - else { - typedBindTerm0() - } - } else typedBindTerm0() + error(tree.pos, "illegal variable in pattern alternative") + vble = namer.enterInScope(vble) + } + val body1 = typed(body, mode, pt) + vble.setInfo( + if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) + else body1.tpe) + treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // burak, was: pt } name match { case x: TypeName => typedBindType(x) @@ -3392,12 +3200,15 @@ trait Typers extends Modes with Adaptations { def typedAssign(lhs: Tree, rhs: Tree): Tree = { 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.containsErrorOrIsErrorTyped()) - lhs1 - else // see #2494 for double error message example - AssignmentError(tree, varsym) + if (!lhs1.tpe.isError) + error(tree.pos, failMsg) + + setError(tree) } if (varsym == null) return fail @@ -3442,12 +3253,12 @@ trait Typers extends Modes with Adaptations { enclMethod.owner.isConstructor || context.enclClass.enclMethod == enclMethod // i.e., we are in a constructor of a local class ) { - ReturnOutsideOfDefError(tree) + errorTree(tree, "return outside method definition") } else { val DefDef(_, name, _, _, restpt, _) = enclMethod.tree - if (restpt.tpe eq null) { - ReturnWithoutTypeError(tree, enclMethod.owner) - } else { + if (restpt.tpe eq null) + errorTree(tree, enclMethod.owner + " has return statement; needs result type") + else { context.enclMethod.returnsSeen = true val expr1: Tree = typed(expr, EXPRmode | BYVALmode, restpt.tpe) // Warn about returning a value if no value can be returned. @@ -3466,15 +3277,12 @@ trait Typers extends Modes with Adaptations { def typedNew(tpt: Tree) = { val tpt1 = { val tpt0 = typedTypeConstructor(tpt) - checkClassType(tpt0, false, true) match { - case Some(err) => err - case _ => - if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) { - context.undetparams = cloneSymbols(tpt0.symbol.typeParams) - TypeTree().setOriginal(tpt0) - .setType(appliedType(tpt0.tpe, context.undetparams map (_.tpeHK))) // @PP: tpeHK! #3343, #4018, #4347. - } else tpt0 - } + checkClassType(tpt0, false, true) + if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) { + context.undetparams = cloneSymbols(tpt0.symbol.typeParams) + TypeTree().setOriginal(tpt0) + .setType(appliedType(tpt0.tpe, context.undetparams map (_.tpeHK))) // @PP: tpeHK! #3343, #4018, #4347. + } else tpt0 } /** If current tree appears in > @@ -3493,15 +3301,17 @@ trait Typers extends Modes with Adaptations { val tp = tpt1.tpe val sym = tp.typeSymbol if (sym.isAbstractType || sym.hasAbstractFlag) - IsAbstractError(tree, sym) + error(tree.pos, sym + " is abstract; cannot be instantiated") else if (!( tp == sym.initialize.thisSym.tpe // when there's no explicit self type -- with (#3612) or without self variable // sym.thisSym.tpe == tp.typeOfThis (except for objects) || narrowRhs(tp) <:< tp.typeOfThis || phase.erasedTypes )) { - DoesNotConformToSelfTypeError(tree, sym, tp.typeOfThis) - } else - treeCopy.New(tree, tpt1).setType(tp) + error(tree.pos, sym + + " cannot be instantiated because it does not conform to its self-type "+ + tp.typeOfThis) + } + treeCopy.New(tree, tpt1).setType(tp) } def typedEta(expr1: Tree): Tree = expr1.tpe match { @@ -3539,23 +3349,22 @@ trait Typers extends Modes with Adaptations { case ErrorType => expr1 case _ => - UnderscoreEtaError(expr1) + errorTree(expr1, "_ must follow method; cannot follow " + expr1.tpe) } /** * @param args ... * @return ... */ - def tryTypedArgs(args: List[Tree], mode: Int): List[Tree] = { + def tryTypedArgs(args: List[Tree], mode: Int, other: TypeError): List[Tree] = { val c = context.makeSilent(false) c.retyping = true try { newTyper(c).typedArgs(args, mode) } catch { - case ex: CyclicReference => - throw ex - case _: TypeError => - List(NullErrorTree) + case ex: CyclicReference => throw ex + case ex: TypeError => + null } } @@ -3564,8 +3373,10 @@ trait Typers extends Modes with Adaptations { */ def tryTypedApply(fun: Tree, args: List[Tree]): Tree = { val start = startTimer(failedApplyNanos) - - def onError(treeWithError: Tree): Tree = { + silent(_.doTypedApply(tree, fun, args, mode, pt)) match { + case t: Tree => + t + case ex: TypeError => stopTimer(failedApplyNanos, start) // If the problem is with raw types, copnvert to existentials and try again. @@ -3588,42 +3399,26 @@ trait Typers extends Modes with Adaptations { case Typed(r, Function(Nil, EmptyTree)) => treesInResult(r) case _ => Nil }) - // Get correct posiition for the error - val firstToReport = quickErrorTreeFinder(treeWithError) - val ePos = firstToReport.pos - def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ePos) - - val retry = (ePos != null) && (fun :: tree :: args exists errorInResult) - if (settings.errortrees.value) - println("[ErrorTree retry] " + retry + " with " + treeWithError + " " + firstToReport.exception) + def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ex.pos) + val retry = fun :: tree :: args exists errorInResult printTyping { val funStr = ptTree(fun) + " and " + (args map ptTree mkString ", ") if (retry) "second try: " + funStr - else "no second try: " + funStr + " because error not in result: " + ePos+"!="+tree.pos + else "no second try: " + funStr + " because error not in result: " + ex.pos+"!="+tree.pos } if (retry) { val Select(qual, name) = fun - val args1 = tryTypedArgs(args, forArgMode(fun, mode)) - val invalidArgs = args1.length == 1 && (args1.head.containsError() || args1.head.tpe.isErroneous) + val args1 = tryTypedArgs(args, forArgMode(fun, mode), ex) val qual1 = - if (!invalidArgs && !pt.isError) adaptToArguments(qual, name, args1, pt) + if ((args1 ne null) && !pt.isError) adaptToArguments(qual, name, args1, pt) else qual if (qual1 ne qual) { val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos return typed1(tree1, mode | SNDTRYmode, pt) } } - - firstToReport - } - - silent(_.doTypedApply(tree, fun, args, mode, pt)) match { - case t: Tree if !t.containsError() => - t - case t: Tree => - onError(t) - case ex: TypeError => - onError(TypedApplyError(fun, ex)) + reportTypeError(tree.pos, ex) + setError(tree) } } @@ -3636,32 +3431,10 @@ trait Typers extends Modes with Adaptations { val funpt = if (isPatternMode) pt else WildcardType val appStart = startTimer(failedApplyNanos) val opeqStart = startTimer(failedOpEqNanos) - - def onError(reportError: => Tree): Tree = { - fun match { - case Select(qual, name) - if !isPatternMode && nme.isOpAssignmentName(name.decode) => - val qual1 = typedQualifier(qual) - if (treeInfo.isVariableOrGetter(qual1)) { - stopTimer(failedOpEqNanos, opeqStart) - convertToAssignment(fun, qual1, name, args) - } else { - stopTimer(failedApplyNanos, appStart) - if ((qual1.symbol ne null) && qual1.symbol.isValue) - AssignmentTypedApplyError(tree) - else - reportError - } - case _ => - stopTimer(failedApplyNanos, appStart) - reportError - } - } - silent(_.typed(fun, forFunMode(mode), funpt), if ((mode & EXPRmode) != 0) false else context.reportAmbiguousErrors, if ((mode & EXPRmode) != 0) tree else context.tree) match { - case fun1: Tree if !fun1.containsErrorOrIsErrorTyped() => + case fun1: Tree => val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1 incCounter(typedApplyCount) def isImplicitMethod(tpe: Type) = tpe match { @@ -3687,29 +3460,39 @@ trait Typers extends Modes with Adaptations { //if (fun2.hasSymbol && fun2.symbol.name == nme.apply && fun2.symbol.owner == ArrayClass) { // But this causes cyclic reference for Array class in Cleanup. It is easy to overcome this // by calling ArrayClass.info here (or some other place before specialize). - if (fun2.symbol == Array_apply && !res.containsError()) { + if (fun2.symbol == Array_apply) { val checked = gen.mkCheckInit(res) // this check is needed to avoid infinite recursion in Duplicators // (calling typed1 more than once for the same tree) if (checked ne res) typed { atPos(tree.pos)(checked) } else res } else res - - case eTree: Tree => - if (settings.errortrees.value) - println("[ErrorTree silent] Encounter error in silent typing of apply") - - onError(if (eTree.containsError()) {val ex = quickErrorTreeFinder(eTree); if (ex.exception == null) ex else TypedApplyError(fun, ex.exception)} else eTree) - case ex: TypeError => - onError(TypedApplyError(fun, ex)) - - + fun match { + case Select(qual, name) + if !isPatternMode && nme.isOpAssignmentName(name.decode) => + val qual1 = typedQualifier(qual) + if (treeInfo.isVariableOrGetter(qual1)) { + stopTimer(failedOpEqNanos, opeqStart) + convertToAssignment(fun, qual1, name, args, ex) + } else { + stopTimer(failedApplyNanos, appStart) + if ((qual1.symbol ne null) && qual1.symbol.isValue) + error(tree.pos, "reassignment to val") + else + reportTypeError(fun.pos, ex) + setError(tree) + } + case _ => + stopTimer(failedApplyNanos, appStart) + reportTypeError(fun.pos, ex) + setError(tree) + } } } } - def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = { + def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree], ex: TypeError): Tree = { val prefix = name.subName(0, name.length - nme.EQL.length) def mkAssign(vble: Tree): Tree = Assign( @@ -3750,11 +3533,10 @@ trait Typers extends Modes with Adaptations { case Apply(fn, indices) => treeInfo.methPart(fn) match { case Select(table, nme.apply) => mkUpdate(table, indices) - case _ => UnexpectedTreeAssignmentConversionError(qual) + case _ => errorTree(qual, "Unexpected tree during assignment conversion.") } } typed1(tree1, mode, pt) - /* debuglog("retry assign: "+tree1) silent(_.typed1(tree1, mode, pt)) match { @@ -3767,8 +3549,8 @@ trait Typers extends Modes with Adaptations { */ } - def qualifyingClassSym(qual: Name): Either[ErrorTree, Symbol] = - if (tree.symbol != NoSymbol) Right(tree.symbol) else qualifyingClass(tree, qual, false) + def qualifyingClassSym(qual: Name): Symbol = + if (tree.symbol != NoSymbol) tree.symbol else qualifyingClass(tree, qual, false) def typedSuper(qual: Tree, mix: TypeName) = { val qual1 = typed(qual) @@ -3779,7 +3561,7 @@ trait Typers extends Modes with Adaptations { } //println(clazz+"/"+qual1.tpe.typeSymbol+"/"+qual1) - def findMixinSuper(site: Type): Either[ErrorTree, Type] = { + def findMixinSuper(site: Type): Type = { var ps = site.parents filter (_.typeSymbol.name == mix) if (ps.isEmpty) ps = site.parents filter (_.typeSymbol.toInterface.name == mix) @@ -3794,48 +3576,35 @@ trait Typers extends Modes with Adaptations { // println(mix) // the reference to super class got lost during erasure restrictionError(tree.pos, unit, "traits may not select fields or methods from super[C] where C is a class") - Left(NullErrorTree) } else { - Left(MixinMissingParentClassNameError(tree, mix, clazz)) + error(tree.pos, mix+" does not name a parent class of "+clazz) } + ErrorType } else if (!ps.tail.isEmpty) { - Left(AmbiguousParentClassError(tree)) + error(tree.pos, "ambiguous parent class qualifier") + ErrorType } else { - Right(ps.head) + ps.head } } val owntype = if (mix.isEmpty) { if ((mode & SUPERCONSTRmode) != 0) - if (clazz.info.parents.isEmpty) Right(AnyRefClass.tpe) // can happen due to cyclic references ==> #1036 - else Right(clazz.info.parents.head) - else Right(intersectionType(clazz.info.parents)) + if (clazz.info.parents.isEmpty) AnyRefClass.tpe // can happen due to cyclic references ==> #1036 + else clazz.info.parents.head + else intersectionType(clazz.info.parents) } else { findMixinSuper(clazz.tpe) } - val owntype1 = if (owntype.isLeft) { - // Is there any way we can push the error tree into super? - // Report here for the moment - try { - owntype.left.get.emit(context) - } catch { - case _: TypeError => - assert(false, "Invalid type error when typing Super") - } - ErrorType - } else owntype.right.get - - treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype1) + treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype) } def typedThis(qual: Name) = { - val clazzOrError = qualifyingClassSym(qual) - if (clazzOrError.isLeft) clazzOrError.left.get - else if (clazzOrError.right.get == NoSymbol) setError(tree) + val clazz = qualifyingClassSym(qual) + if (clazz == NoSymbol) setError(tree) else { - val clazz = clazzOrError.right.get tree setSymbol clazz setType clazz.thisType.underlying if (isStableContext(tree, mode, pt)) tree setType clazz.thisType tree @@ -3869,14 +3638,9 @@ trait Typers extends Modes with Adaptations { } if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) { val qual1 = - if (member(qual, name) != NoSymbol) NullErrorTree + if (member(qual, name) != NoSymbol) qual else adaptToMemberWithArgs(tree, qual, name, mode) - if (!qual1.containsError()) { - if (qual1 ne qual) - return typed(treeCopy.Select(tree, qual1, name), mode, pt) - } else { - return qual1 - } + if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt) } if (!reallyExists(sym)) { @@ -3907,7 +3671,7 @@ trait Typers extends Modes with Adaptations { ) } - def makeInteractiveErrorTree = { + def makeErrorTree = { val tree1 = tree match { case Select(_, _) => treeCopy.Select(tree, qual, name) case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) @@ -3915,15 +3679,16 @@ trait Typers extends Modes with Adaptations { setError(tree1) } + if (name == nme.ERROR && forInteractive) + return makeErrorTree - if (forInteractive) - makeInteractiveErrorTree - else if (!qual.tpe.widen.isErroneous) { + if (!qual.tpe.widen.isErroneous) { val lastTry = missingHook(qual.tpe.typeSymbol, name) if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt) - NotAMemberError(tree, qual, name) - } else - NotAMemberErroneous(tree) + notAMemberError(tree.pos, qual, name) + } + + if (forInteractive) makeErrorTree else setError(tree) } else { val tree1 = tree match { case Select(_, _) => treeCopy.Select(tree, qual, name) @@ -3949,32 +3714,16 @@ trait Typers extends Modes with Adaptations { result, (TypeTreeWithDeferredRefCheck(){ () => val tp = qual.tpe; val sym = tp.typeSymbolDirect // will execute during refchecks -- TODO: make private checkTypeRef in refchecks public and call that one? - checkBounds(qual.pos, tp.prefix, sym.owner, sym.typeParams, tp.typeArgs, "") match { - case Some(err) => Left(err) - case _ => Right(qual) // you only get to see the wrapped tree after running this check :-p - } + checkBounds(qual.pos, tp.prefix, sym.owner, sym.typeParams, tp.typeArgs, "") + qual // you only get to see the wrapped tree after running this check :-p }) setType qual.tpe, name) - case tt if tt.containsError() => - val errTree = quickErrorTreeFinder(tt) - errTree match { - case accError: AccessError => - val qual1 = - try adaptToMemberWithArgs(tree, qual, name, mode) - catch { - case _: TypeError => - // Ambigues implicits throw TypeError - // and then they are reported here. - NullErrorTree - } - if (!qual1.containsError() && (qual1 ne qual)) { - typed(Select(qual1, name) setPos tree.pos, mode, pt) - } else { - accError - } - case _ => - tt - } + case accErr: Inferencer#AccessError => + val qual1 = + try adaptToMemberWithArgs(tree, qual, name, mode) + catch { case _: TypeError => qual } + if (qual1 ne qual) typed(Select(qual1, name) setPos tree.pos, mode, pt) + else accErr.emit() case _ => result } @@ -3982,8 +3731,7 @@ trait Typers extends Modes with Adaptations { // getClass, we have to catch it immediately so expressions // like x.getClass().newInstance() are typed with the type of x. val isRefinableGetClass = ( - !selection.containsError() - && selection.symbol.name == nme.getClass_ + selection.symbol.name == nme.getClass_ && selection.tpe.params.isEmpty // TODO: If the type of the qualifier is inaccessible, we can cause private types // to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this @@ -3991,7 +3739,7 @@ trait Typers extends Modes with Adaptations { && qual.tpe.typeSymbol.isPublic ) if (isRefinableGetClass) - selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe)) + selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe)) else selection } @@ -4005,17 +3753,8 @@ trait Typers extends Modes with Adaptations { * (2) Change imported symbols to selections */ def typedIdent(name: Name): Tree = { - var errorContainer: Tree = null - @inline - def ambiguousError(msg: String) = { - assert(errorContainer == null, "Cannot set ambiguous error twice for identifier") - errorContainer = AmbiguousIdentError(tree, name, msg) - } - @inline - def identError(tree: ErrorTree) = { - assert(errorContainer == null, "Cannot set ambiguous error twice for identifier") - errorContainer = tree - } + def ambiguousError(msg: String) = + error(tree.pos, "reference to " + name + " is ambiguous;\n" + msg) var defSym: Symbol = tree.symbol // the directly found symbol var pre: Type = NoPrefix // the prefix type of defSym, if a class member @@ -4117,7 +3856,7 @@ trait Typers extends Modes with Adaptations { ambiguousError( "it is imported twice in the same scope by\n"+imports.head + "\nand "+imports1.head) } - while (errorContainer == null && !imports1.isEmpty && + while (!imports1.isEmpty && (!imports.head.isExplicitImport(name) || imports1.head.depth == imports.head.depth)) { var impSym1 = imports1.head.importedSymbol(name) @@ -4132,17 +3871,11 @@ trait Typers extends Modes with Adaptations { } imports1 = imports1.tail } - if (errorContainer == null) { - if (imports.head.qual.containsError()) { - defSym = context.owner.newErrorSymbol(name) - } else { - defSym = impSym - val qual0 = imports.head.qual - if (!(shortenImports && qual0.symbol.isPackage)) // optimization: don't write out package prefixes - qual = atPos(tree.pos.focusStart)(resetPos(qual0.duplicate)) - pre = qual.tpe - } - } + defSym = impSym + val qual0 = imports.head.qual + if (!(shortenImports && qual0.symbol.isPackage)) // optimization: don't write out package prefixes + qual = atPos(tree.pos.focusStart)(resetPos(qual0.duplicate)) + pre = qual.tpe } else if (settings.exposeEmptyPackage.value && checkEmptyPackage()) log("Allowing empty package member " + name + " due to settings.") @@ -4156,53 +3889,50 @@ trait Typers extends Modes with Adaptations { if (inaccessibleSym eq NoSymbol) { // Avoiding some spurious error messages: see SI-2388. if (reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME)) () - else identError(SymbolNotFound(tree, name, context.owner)) - } else { - identError(AccessError( - tree, inaccessibleSym, context.enclClass.owner.thisType, context.enclClass.owner, - inaccessibleExplanation - )) + else error(tree.pos, "not found: "+decodeWithKind(name, context.owner)) } + else new AccessError( + tree, inaccessibleSym, context.enclClass.owner.thisType, + inaccessibleExplanation + ).emit() defSym = context.owner.newErrorSymbol(name) } } } - - if (errorContainer != null) { - errorContainer + if (defSym.owner.isPackageClass) pre = defSym.owner.thisType + if (defSym.isThisSym) { + typed1(This(defSym.owner) setPos tree.pos, mode, pt) } else { - if (defSym.owner.isPackageClass) pre = defSym.owner.thisType - if (defSym.isThisSym) { - typed1(This(defSym.owner) setPos tree.pos, mode, pt) - } else { - val tree1 = if (qual == EmptyTree) tree - else atPos(tree.pos)(Select(qual, name)) - // atPos necessary because qualifier might come from startContext - val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual) - // assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right? - stabilize(tree2, pre2, mode, pt) + val tree1 = if (qual == EmptyTree) tree + else atPos(tree.pos)(Select(qual, name)) + // atPos necessary because qualifier might come from startContext + val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual) + // assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right? + stabilize(tree2, pre2, mode, pt) match { + case accErr: Inferencer#AccessError => accErr.emit() + case result => result } } } def typedCompoundTypeTree(templ: Template) = { val parents1 = templ.parents mapConserve (typedType(_, mode)) - if (parents1 exists (_.containsErrorOrIsErrorTyped())) tree setType ErrorType + if (parents1 exists (_.tpe.isError)) tree setType ErrorType else { val decls = new Scope //Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id) val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls, templ.pos) newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ.body) - tree.setType(self) + tree setType self } } def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = { val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType) - if (tpt1.containsErrorOrIsErrorTyped()) { - setError(treeCopy.AppliedTypeTree(tree, tpt1, args)) + if (tpt1.tpe.isError) { + setError(tree) } else if (!tpt1.hasSymbol) { - AppliedTypeNoParametersError(tree, tpt1.tpe) + errorTree(tree, tpt1.tpe+" does not take type parameters") } else { val tparams = tpt1.symbol.typeParams if (sameLength(tparams, args)) { @@ -4235,18 +3965,16 @@ trait Typers extends Modes with Adaptations { // wrap the tree and include the bounds check -- refchecks will perform this check (that the beta reduction was indeed allowed) and unwrap // we can't simply use original in refchecks because it does not contains types // (and the only typed trees we have have been mangled so they're not quite the original tree anymore) - checkBounds(result.pos, tpt1.tpe.prefix, tpt1.symbol.owner, tpt1.symbol.typeParams, argtypes, "") match { - case Some(err) => Left(err) - case _ => Right(result) // you only get to see the wrapped tree after running this check :-p - } + checkBounds(result.pos, tpt1.tpe.prefix, tpt1.symbol.owner, tpt1.symbol.typeParams, argtypes, "") + result // you only get to see the wrapped tree after running this check :-p }).setType(result.tpe) else result } else if (tparams.isEmpty) { - AppliedTypeNoParametersError(tree, tpt1.tpe) + errorTree(tree, tpt1.tpe+" does not take type parameters") } else { //Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}") if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info)//debug - AppliedTypeWrongNumberOfArgsError(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length) + errorTree(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length) } } } @@ -4260,12 +3988,7 @@ trait Typers extends Modes with Adaptations { //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG tree match { case PackageDef(pid, stats) => - val pid1 = typedQualifier(pid) match { - case e: ErrorTree => - RefTreeError(e, pid.name) - case t: RefTree => - t - } + val pid1 = typedQualifier(pid).asInstanceOf[RefTree] assert(sym.moduleClass ne NoSymbol, sym) // complete lazy annotations val annots = sym.annotations @@ -4300,9 +4023,6 @@ trait Typers extends Modes with Adaptations { typer1.silent(_.typedUseCase(useCase)) match { case ex: TypeError => unit.warning(useCase.pos, ex.msg) - case tree: Tree if tree.containsError() => - val ex = quickErrorTreeFinder(tree) - unit.warning(useCase.pos, ex.exception.msg) case _ => } for (useCaseSym <- useCase.defined) { @@ -4325,14 +4045,9 @@ trait Typers extends Modes with Adaptations { treeCopy.Alternative(tree, alts1) setType pt case Star(elem) => - val err0 = checkStarPatOK(tree.pos, mode) + checkStarPatOK(tree.pos, mode) val elem1 = typed(elem, mode, pt) - val elem2 = err0 match { - case Some(err) => - wrapInBlock(err, elem1) - case _ => elem1 - } - treeCopy.Star(tree, elem2) setType makeFullyDefined(pt) + treeCopy.Star(tree, elem1) setType makeFullyDefined(pt) case Bind(name, body) => typedBind(name, body) @@ -4416,32 +4131,25 @@ trait Typers extends Modes with Adaptations { val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt) ExistentialType(List(tparam), arrayType(tparam.tpe)) } - - if (expr0.containsError()) - treeCopy.Typed(tree, expr0, tpt setType ErrorType) setType ErrorType - else { - val (expr1, baseClass) = expr0.tpe.typeSymbol match { - case ArrayClass => (adapt(expr0, onlyStickyModes(mode), subArrayType(pt)), ArrayClass) - case _ => (adapt(expr0, onlyStickyModes(mode), seqType(pt)), SeqClass) - } - expr1.tpe.baseType(baseClass) match { - case TypeRef(_, _, List(elemtp)) => - treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp - case _ => - setError(tree) - } + val (expr1, baseClass) = expr0.tpe.typeSymbol match { + case ArrayClass => (adapt(expr0, onlyStickyModes(mode), subArrayType(pt)), ArrayClass) + case _ => (adapt(expr0, onlyStickyModes(mode), seqType(pt)), SeqClass) + } + expr1.tpe.baseType(baseClass) match { + case TypeRef(_, _, List(elemtp)) => + treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp + case _ => + setError(tree) } case Typed(expr, tpt) => val tpt1 = typedType(tpt, mode) val expr1 = typed(expr, onlyStickyModes(mode), tpt1.tpe.deconst) - val (expr2, ownType) = if (isPatternMode) - inferTypedPattern(tpt1.pos, tpt1.tpe, pt) match { - case Left(err) => - (wrapInBlock(expr1, err), ErrorType) - case Right(tp) => (expr1, tp) - } else (expr1, tpt1.tpe) - treeCopy.Typed(tree, expr1, tpt1) setType ownType + val owntype = + 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 case TypeApply(fun, args) => // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer) @@ -4484,8 +4192,6 @@ trait Typers extends Modes with Adaptations { case Apply(fun, args) => typedApply(fun, args) match { - case tree1 if tree1.containsError() => - tree1 case Apply(Select(New(tpt), name), args) if (tpt.tpe != null && tpt.tpe.typeSymbol == ArrayClass && @@ -4495,14 +4201,12 @@ trait Typers extends Modes with Adaptations { // convert new Array^N[T](len) for N > 1 to evidence[ClassManifest[T]].newArrayN(len) val Some((level, manifType)) = erasure.GenericArray.unapply(tpt.tpe) if (level > MaxArrayDims) - MultiDimensionalArrayError(tree) - else { - val newArrayApp = atPos(tree.pos) { - val manif = getManifestTree(tree.pos, manifType, false) - new ApplyToImplicitArgs(Select(manif, if (level == 1) "newArray" else "newArray"+level), args) - } - typed(newArrayApp, mode, pt) + error(tree.pos, "cannot create a generic multi-dimensional array of more than "+MaxArrayDims+" dimensions") + val newArrayApp = atPos(tree.pos) { + val manif = getManifestTree(tree.pos, manifType, false) + new ApplyToImplicitArgs(Select(manif, if (level == 1) "newArray" else "newArray"+level), args) } + typed(newArrayApp, mode, pt) case tree1 => tree1 } @@ -4531,26 +4235,20 @@ trait Typers extends Modes with Adaptations { if (name.isTypeName) qual1 = checkStable(qual1) val tree1 = // temporarily use `filter` and an alternative for `withFilter` - if (qual1.containsError()) - treeCopy.Select(tree, qual1, name) setType ErrorType - else if (name == nme.withFilter) + if (name == nme.withFilter) silent(_ => typedSelect(qual1, name)) match { - case result1: Tree if !result1.containsError() => + case result1: Tree => result1 - case ex1 => + case ex1: TypeError => silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match { case result2: Tree => unit.deprecationWarning( tree.pos, "`withFilter' method does not yet exist on "+qual1.tpe.widen+ ", using `filter' method instead") result2 - case _: TypeError => - val ex2 = ex1 match { - case te: TypeError => te - case t: Tree => - quickErrorTreeFinder(t).exception - } - WithFilterError(tree, ex2) + case ex2: TypeError => + reportTypeError(tree.pos, ex1) + setError(tree) } } else @@ -4575,17 +4273,12 @@ trait Typers extends Modes with Adaptations { case SingletonTypeTree(ref) => val ref1 = checkStable( typed(ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe)) - if (ref1.containsError()) - treeCopy.SingletonTypeTree(tree, ref1) setType ErrorType - else - tree setType ref1.tpe.resultType + tree setType ref1.tpe.resultType case SelectFromTypeTree(qual, selector) => val qual1 = typedType(qual, mode) - if (qual1.tpe.isVolatile) - TypeSelectionFromVolatileTypeError(tree, qual) - else - typedSelect(qual1, selector) + if (qual1.tpe.isVolatile) error(tree.pos, "illegal type selection from volatile type "+qual.tpe) + typedSelect(qual1, selector) case CompoundTypeTree(templ) => typedCompoundTypeTree(templ) @@ -4618,39 +4311,6 @@ trait Typers extends Modes with Adaptations { } } - def handleErrorTree(t: Tree) { - val allErrors = errorTreesFinder(t) - - // Report any errors if possible in the current context - // If an error tree throws type error (we are in silent mode), then we will not mark - // tree as visited and it will be reported later if necessary - allErrors.foreach { t0 => - try { - if (settings.errortrees.value) { - println("[ErrorTree emit] " + t0) - if (t0.exception != null) { - println(t0.exception.getClass) - } - } - t0.emit(context) - t0.reported = true - } catch { - case te: TypeError => - // Catch all type errors if we are in typer phase. - // All typer errors will be reported at some point anyway. - if (settings.errortrees.value) - println("[ErrorTree TypeError] Throws " + te) - - // After typer all bets are off - // and we do not try to hide TypeError within error tree - if (phase.id > currentRun.typerPhase.id) { - t0.reported = true - throw te - } - } - } - } - /** * @param tree ... * @param mode ... @@ -4694,36 +4354,22 @@ trait Typers extends Modes with Adaptations { tree1 } - if (tree1.containsError()) { - handleErrorTree(tree1) - if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, tree1) - tree1 - } else { - tree1.tpe = addAnnotations(tree1, tree1.tpe) - val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree) + tree1.tpe = addAnnotations(tree1, tree1.tpe) + val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree) - if (!alreadyTyped) { - printTyping("adapted %s: %s to %s, %s".format( - tree1, tree1.tpe.widen, pt, context.undetparamsString) - ) //DEBUG - } - if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result) - if (result.containsError()) handleErrorTree(result) - result + if (!alreadyTyped) { + printTyping("adapted %s: %s to %s, %s".format( + tree1, tree1.tpe.widen, pt, context.undetparamsString) + ) //DEBUG } + +// for (t <- tree1.tpe) assert(t != WildcardType) +// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) + if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result) + result } catch { case ex: TypeError => tree.tpe = null - // At some point we might want to get rid of the code below - // because everything will be handled by error trees. - // The only problematic case are Cyclic errors which can pop up almost anywhere - if (settings.errortrees.value) { - println("[ErrorTree CAUGHT] %s: while typing %s".format(ex, tree)) - println("TODO with error trees shouldn't throw non-cyclic errors") - ex.printStackTrace() - println("----------") - } - printTyping("caught %s: while typing %s".format(ex, tree)) //DEBUG reportTypeError(tree.pos, ex) setError(tree) @@ -4827,12 +4473,12 @@ trait Typers extends Modes with Adaptations { // to see are those in the signatures. These do not need a unique object as a prefix. // The situation is different for new's and super's, but scalac does not look deep // enough to see those. See #3938 - return ConstructorPrefixError(tree, restpe) + error(tree.pos, restpe.prefix+" is not a legal prefix for a constructor") } //@M fix for #2208 // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef - if (result.tpe.typeArgs.isEmpty && !result.containsError()) { + if(result.tpe.typeArgs.isEmpty) { // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) { // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not // designed to deal with the cycles in the scala package (ScalaObject extends @@ -4848,23 +4494,10 @@ trait Typers extends Modes with Adaptations { def typedTypeConstructor(tree: Tree): Tree = typedTypeConstructor(tree, NOmode) - // Because this is called from Namers and pattern matcher, we - // have to report missing errors (if any) def computeType(tree: Tree, pt: Type): Type = { val tree1 = typed(tree, pt) - if (tree1.containsError()) - ErrorType - else { - transformed(tree) = tree1 - val (tpe, errs) = packedType(tree1, context.owner) - try { - errs.foreach(_.emit(context)) - tpe - } catch { - case _: TypeError => - ErrorType - } - } + transformed(tree) = tree1 + packedType(tree1, context.owner) } def transformedOrTyped(tree: Tree, mode: Int, pt: Type): Tree = transformed.get(tree) match { @@ -4882,7 +4515,8 @@ trait Typers extends Modes with Adaptations { def getManifestTree(pos: Position, tp: Type, full: Boolean): Tree = { val manifestOpt = findManifest(tp, full) if (manifestOpt.tree.isEmpty) { - MissingManifestError(pos, full, tp) + error(pos, "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp) + Literal(Constant(null)) } else { manifestOpt.tree } -- cgit v1.2.3