summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-01-26 09:45:32 +0100
committerMartin Odersky <odersky@gmail.com>2012-01-26 09:45:32 +0100
commit0976bd8e1285b83af7cc036537bb7831eadc6a2a (patch)
treeabd19c1f5bf93782afbbd9605350d0a510721a61 /src/compiler
parenta1c99ffc7b0c53f4a95bd8fe934e65f4a03002d6 (diff)
parentc94d342b385fa510882721b8b7f2070750c60f0e (diff)
downloadscala-0976bd8e1285b83af7cc036537bb7831eadc6a2a.tar.gz
scala-0976bd8e1285b83af7cc036537bb7831eadc6a2a.tar.bz2
scala-0976bd8e1285b83af7cc036537bb7831eadc6a2a.zip
Merge branch 'master' into topic/inline
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/AnnotationCheckers.scala1
-rw-r--r--src/compiler/scala/reflect/internal/AnnotationInfos.scala2
-rw-r--r--src/compiler/scala/reflect/internal/BaseTypeSeqs.scala51
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala129
-rw-r--r--src/compiler/scala/reflect/internal/Importers.scala4
-rw-r--r--src/compiler/scala/reflect/internal/InfoTransformers.scala2
-rw-r--r--src/compiler/scala/reflect/internal/NameManglers.scala33
-rw-r--r--src/compiler/scala/reflect/internal/Names.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Scopes.scala50
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala29
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala5
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala153
-rw-r--r--src/compiler/scala/reflect/internal/TreePrinters.scala1
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala3
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala512
-rw-r--r--src/compiler/scala/reflect/runtime/ConversionUtil.scala48
-rw-r--r--src/compiler/scala/reflect/runtime/JavaToScala.scala4
-rw-r--r--src/compiler/scala/reflect/runtime/Loaders.scala4
-rw-r--r--src/compiler/scala/reflect/runtime/Mirror.scala18
-rw-r--r--src/compiler/scala/reflect/runtime/SymbolTable.scala2
-rw-r--r--src/compiler/scala/reflect/runtime/SynchronizedOps.scala51
-rw-r--r--src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala119
-rw-r--r--src/compiler/scala/reflect/runtime/SynchronizedTypes.scala87
-rw-r--r--src/compiler/scala/reflect/runtime/ToolBoxes.scala2
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/ant/sabbus/ScalacFork.scala3
-rw-r--r--src/compiler/scala/tools/ant/templates/tool-windows.tmpl4
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala8
-rw-r--r--src/compiler/scala/tools/nsc/MacroContext.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala122
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala6
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala4
-rw-r--r--src/compiler/scala/tools/nsc/io/MsilFile.scala4
-rw-r--r--src/compiler/scala/tools/nsc/io/NoAbstractFile.scala30
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala2
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugins.scala2
-rw-r--r--src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala15
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala8
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala70
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala44
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/OverridingPairs.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala1052
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala131
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala139
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala352
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala148
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala114
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala30
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala72
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala29
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala108
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1235
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala23
-rw-r--r--src/compiler/scala/tools/nsc/util/Statistics.scala4
73 files changed, 3406 insertions, 1767 deletions
diff --git a/src/compiler/scala/reflect/internal/AnnotationCheckers.scala b/src/compiler/scala/reflect/internal/AnnotationCheckers.scala
index 666c1d74cb..449b0ca0bc 100644
--- a/src/compiler/scala/reflect/internal/AnnotationCheckers.scala
+++ b/src/compiler/scala/reflect/internal/AnnotationCheckers.scala
@@ -49,6 +49,7 @@ trait AnnotationCheckers {
def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree
}
+ // Syncnote: Annotation checkers inaccessible to reflection, so no sync in var necessary.
/** The list of annotation checkers that have been registered */
private var annotationCheckers: List[AnnotationChecker] = Nil
diff --git a/src/compiler/scala/reflect/internal/AnnotationInfos.scala b/src/compiler/scala/reflect/internal/AnnotationInfos.scala
index 255e69c3c6..c3dde3e6d1 100644
--- a/src/compiler/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/compiler/scala/reflect/internal/AnnotationInfos.scala
@@ -178,7 +178,7 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
private var rawpos: Position = NoPosition
def pos = rawpos
- def setPos(pos: Position): this.type = {
+ def setPos(pos: Position): this.type = { // Syncnote: Setpos inaccessible to reflection, so no sync in rawpos necessary.
rawpos = pos
this
}
diff --git a/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala b/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala
index 38277b5a09..9e5c93753f 100644
--- a/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala
@@ -29,7 +29,14 @@ trait BaseTypeSeqs {
this: SymbolTable =>
import definitions._
- class BaseTypeSeq(parents: List[Type], elems: Array[Type]) {
+ protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
+ new BaseTypeSeq(parents, elems)
+
+ /** Note: constructor is protected to force everyone to use the factory method newBaseTypeSeq instead.
+ * This is necessary because when run from reflection every base type sequence needs to have a
+ * SynchronizedBaseTypeSeq as mixin.
+ */
+ class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
incCounter(baseTypeSeqCount)
incCounter(baseTypeSeqLenTotal, elems.length)
@@ -41,7 +48,7 @@ trait BaseTypeSeqs {
// (while NoType is in there to indicate a cycle in this BTS, during the execution of
// the mergePrefixAndArgs below, the elems get copied without the pending map,
// so that NoType's are seen instead of the original type --> spurious compile error)
- val pending = new mutable.BitSet(length)
+ private val pending = new mutable.BitSet(length)
/** The type at i'th position in this sequence; lazy types are returned evaluated. */
def apply(i: Int): Type =
@@ -89,11 +96,11 @@ trait BaseTypeSeqs {
/** Return all evaluated types in this sequence as a list */
def toList: List[Type] = elems.toList
- protected def copy(head: Type, offset: Int): BaseTypeSeq = {
+ def copy(head: Type, offset: Int): BaseTypeSeq = {
val arr = new Array[Type](elems.length + offset)
compat.Platform.arraycopy(elems, 0, arr, offset, elems.length)
arr(0) = head
- new BaseTypeSeq(parents, arr)
+ newBaseTypeSeq(parents, arr)
}
/** Compute new base type sequence with `tp` prepended to this sequence */
@@ -113,21 +120,10 @@ trait BaseTypeSeqs {
arr(i) = f(elems(i))
i += 1
}
- new BaseTypeSeq(parents, arr)
+ newBaseTypeSeq(parents, arr)
}
- def lateMap(f: Type => Type): BaseTypeSeq = new BaseTypeSeq(parents map f, elems) {
- override def apply(i: Int) = f(self.apply(i))
- override def rawElem(i: Int) = f(self.rawElem(i))
- override def typeSymbol(i: Int) = self.typeSymbol(i)
- override def toList = self.toList map f
- override protected def copy(head: Type, offset: Int) = (self map f).copy(head, offset)
- override def map(g: Type => Type) = lateMap(g)
- override def lateMap(g: Type => Type) = self.lateMap(x => g(f(x)))
- override def exists(p: Type => Boolean) = elems exists (x => p(f(x)))
- override protected def maxDepthOfElems: Int = elems map (x => maxDpth(f(x))) max
- override def toString = elems.mkString("MBTS(", ",", ")")
- }
+ def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f)
def exists(p: Type => Boolean): Boolean = elems exists p
@@ -177,10 +173,10 @@ trait BaseTypeSeqs {
/** A merker object for a base type sequence that's no yet computed.
* used to catch inheritance cycles
*/
- val undetBaseTypeSeq: BaseTypeSeq = new BaseTypeSeq(List(), Array())
+ val undetBaseTypeSeq: BaseTypeSeq = newBaseTypeSeq(List(), Array())
/** Create a base type sequence consisting of a single type */
- def baseTypeSingletonSeq(tp: Type): BaseTypeSeq = new BaseTypeSeq(List(), Array(tp))
+ def baseTypeSingletonSeq(tp: Type): BaseTypeSeq = newBaseTypeSeq(List(), Array(tp))
/** Create the base type sequence of a compound type wuth given tp.parents */
def compoundBaseTypeSeq(tp: Type): BaseTypeSeq = {
@@ -244,8 +240,21 @@ trait BaseTypeSeqs {
val elems = new Array[Type](btsSize)
buf.copyToArray(elems, 0)
// Console.println("computed baseTypeSeq of " + tsym.tpe + " " + parents + ": "+elems.toString)//DEBUG
- new BaseTypeSeq(parents, elems)
+ newBaseTypeSeq(parents, elems)
}
-
+
+ class MappedBaseTypeSeq(orig: BaseTypeSeq, f: Type => Type) extends BaseTypeSeq(orig.parents map f, orig.elems) {
+ override def apply(i: Int) = f(orig.apply(i))
+ override def rawElem(i: Int) = f(orig.rawElem(i))
+ override def typeSymbol(i: Int) = orig.typeSymbol(i)
+ override def toList = orig.toList map f
+ override def copy(head: Type, offset: Int) = (orig map f).copy(head, offset)
+ override def map(g: Type => Type) = lateMap(g)
+ override def lateMap(g: Type => Type) = orig.lateMap(x => g(f(x)))
+ override def exists(p: Type => Boolean) = elems exists (x => p(f(x)))
+ override protected def maxDepthOfElems: Int = elems map (x => maxDpth(f(x))) max
+ override def toString = elems.mkString("MBTS(", ",", ")")
+ }
+
val CyclicInheritance = new Throwable
}
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index d38b62cbb4..1490d80d7a 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -16,7 +16,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
private def newClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = {
val clazz = owner.newClassSymbol(name, NoPosition, flags)
- clazz setInfoAndEnter ClassInfoType(parents, new Scope, clazz)
+ clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz)
}
private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = {
val msym = owner.newMethod(name.encode, NoPosition, flags)
@@ -29,8 +29,13 @@ trait Definitions extends reflect.api.StandardDefinitions {
self: definitions.type =>
private[Definitions] def valueCache(name: Name) = {
- if (name.isTypeName) ScalaPackageClass.info member name
- else ScalaPackageClass.info member name suchThat (_ hasFlag MODULE)
+ val res = (
+ if (name.isTypeName) ScalaPackageClass.info member name
+ else ScalaPackageClass.info member name suchThat (_ hasFlag MODULE)
+ )
+ if (res eq NoSymbol)
+ abort("Could not find value classes! This is a catastrophic failure. scala " + scala.util.Properties.versionString)
+ else res
}
private[Definitions] def valueModuleMethod(className: Name, methodName: Name): Symbol = {
valueCache(className.toTermName).moduleClass.tpe member methodName
@@ -206,7 +211,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
sealed abstract class BottomClassSymbol(name: TypeName, parent: Symbol) extends ClassSymbol(ScalaPackageClass, NoPosition, name) {
locally {
this initFlags ABSTRACT | TRAIT | FINAL
- this setInfoAndEnter ClassInfoType(List(parent.tpe), new Scope, this)
+ this setInfoAndEnter ClassInfoType(List(parent.tpe), newScope, this)
}
final override def isBottomClass = true
}
@@ -352,7 +357,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
)
lazy val EqualsPatternClass = {
val clazz = newClass(ScalaPackageClass, tpnme.EQUALS_PATTERN_NAME, Nil)
- clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, new Scope, clazz))
+ clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, newScope, clazz))
}
lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy")
@@ -393,6 +398,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// scala.reflect
lazy val ReflectApiUniverse = getRequiredClass("scala.reflect.api.Universe")
+ lazy val ReflectMacroContext = getRequiredClass("scala.reflect.macro.Context")
lazy val ReflectRuntimeMirror = getRequiredModule("scala.reflect.runtime.Mirror")
def freeValueMethod = getMember(ReflectRuntimeMirror, nme.freeValue)
lazy val ReflectPackage = getPackageObject("scala.reflect")
@@ -609,7 +615,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val ValueTypeClass: Symbol = getClass(sn.ValueType)
// System.MulticastDelegate
lazy val DelegateClass: Symbol = getClass(sn.Delegate)
- var Delegate_scalaCallers: List[Symbol] = List()
+ var Delegate_scalaCallers: List[Symbol] = List() // Syncnote: No protection necessary yet as only for .NET where reflection is not supported.
// Symbol -> (Symbol, Type): scalaCaller -> (scalaMethodSym, DelegateType)
// var Delegate_scalaCallerInfos: HashMap[Symbol, (Symbol, Type)] = _
lazy val Delegate_scalaCallerTargets: mutable.HashMap[Symbol, Symbol] = mutable.HashMap()
@@ -629,31 +635,47 @@ trait Definitions extends reflect.api.StandardDefinitions {
case _ => false
})
}
-
+
// members of class scala.Any
- var Any_== : Symbol = _
- var Any_!= : Symbol = _
- var Any_equals : Symbol = _
- var Any_hashCode : Symbol = _
- var Any_toString : Symbol = _
- var Any_getClass : Symbol = _
- var Any_isInstanceOf: Symbol = _
- var Any_asInstanceOf: Symbol = _
- var Any_## : Symbol = _
-
- // members of class java.lang.{Object, String}
- var Object_eq : Symbol = _
- var Object_ne : Symbol = _
- var Object_== : Symbol = _
- var Object_!= : Symbol = _
- var Object_## : Symbol = _
- var Object_synchronized: Symbol = _
+ lazy val Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL)
+ lazy val Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL)
+ lazy val Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype)
+ lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype)
+ lazy val Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype)
+ lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL)
+
+ // Any_getClass requires special handling. The return type is determined on
+ // a per-call-site basis as if the function being called were actually:
+ //
+ // // Assuming `target.getClass()`
+ // def getClass[T](target: T): Class[_ <: T]
+ //
+ // Since getClass is not actually a polymorphic method, this requires compiler
+ // participation. At the "Any" level, the return type is Class[_] as it is in
+ // java.lang.Object. Java also special cases the return type.
+ lazy val Any_getClass =
+ newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED)
+ lazy val Any_isInstanceOf = newPolyMethod(
+ AnyClass, nme.isInstanceOf_, tparam => NullaryMethodType(booltype)) setFlag FINAL
+ lazy val Any_asInstanceOf = newPolyMethod(
+ AnyClass, nme.asInstanceOf_, tparam => NullaryMethodType(tparam.typeConstructor)) setFlag FINAL
+
+ // members of class java.lang.{ Object, String }
+ lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL)
+ lazy val Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL)
+ lazy val Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL)
+ lazy val Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL)
+ lazy val Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL)
+ lazy val Object_synchronized = newPolyMethodCon(
+ ObjectClass, nme.synchronized_,
+ tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL
lazy val Object_isInstanceOf = newPolyMethod(
ObjectClass, newTermName("$isInstanceOf"),
tparam => MethodType(List(), booltype)) setFlag (FINAL | SYNTHETIC)
lazy val Object_asInstanceOf = newPolyMethod(
ObjectClass, newTermName("$asInstanceOf"),
tparam => MethodType(List(), tparam.typeConstructor)) setFlag (FINAL | SYNTHETIC)
+ lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL)
def Object_getClass = getMember(ObjectClass, nme.getClass_)
def Object_clone = getMember(ObjectClass, nme.clone_)
@@ -664,7 +686,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
def Object_hashCode = getMember(ObjectClass, nme.hashCode_)
def Object_toString = getMember(ObjectClass, nme.toString_)
- var String_+ : Symbol = _
// boxed classes
lazy val ObjectRefClass = getRequiredClass("scala.runtime.ObjectRef")
@@ -823,7 +844,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
clazz.setInfo(
polyType(
List(tparam),
- ClassInfoType(List(AnyRefClass.tpe, p), new Scope, clazz)))
+ ClassInfoType(List(AnyRefClass.tpe, p), newScope, clazz)))
}
private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol =
@@ -940,43 +961,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
RootClass.info.decls enter EmptyPackage
RootClass.info.decls enter RootPackage
-
- // members of class scala.Any
- Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL)
- Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL)
- Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype)
- Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype)
- Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype)
- Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL)
-
- // Any_getClass requires special handling. The return type is determined on
- // a per-call-site basis as if the function being called were actually:
- //
- // // Assuming `target.getClass()`
- // def getClass[T](target: T): Class[_ <: T]
- //
- // Since getClass is not actually a polymorphic method, this requires compiler
- // participation. At the "Any" level, the return type is Class[_] as it is in
- // java.lang.Object. Java also special cases the return type.
- Any_getClass =
- newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED)
- Any_isInstanceOf = newPolyMethod(
- AnyClass, nme.isInstanceOf_, tparam => NullaryMethodType(booltype)) setFlag FINAL
- Any_asInstanceOf = newPolyMethod(
- AnyClass, nme.asInstanceOf_, tparam => NullaryMethodType(tparam.typeConstructor)) setFlag FINAL
-
- // members of class java.lang.{ Object, String }
- Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL)
- Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL)
- Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL)
- Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL)
- Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL)
- Object_synchronized = newPolyMethodCon(
- ObjectClass, nme.synchronized_,
- tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL
-
- String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL)
-
+
val forced = List( // force initialization of every symbol that is entered as a side effect
AnnotationDefaultAttr, // #2264
RepeatedParamClass,
@@ -989,8 +974,24 @@ trait Definitions extends reflect.api.StandardDefinitions {
NothingClass,
SingletonClass,
EqualsPatternClass,
+ Any_==,
+ Any_!=,
+ Any_equals,
+ Any_hashCode,
+ Any_toString,
+ Any_getClass,
+ Any_isInstanceOf,
+ Any_asInstanceOf,
+ Any_##,
+ Object_eq,
+ Object_ne,
+ Object_==,
+ Object_!=,
+ Object_##,
+ Object_synchronized,
Object_isInstanceOf,
- Object_asInstanceOf
+ Object_asInstanceOf,
+ String_+
)
/** Removing the anyref parent they acquire from having a source file.
diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala
index 53380952c0..23b443919a 100644
--- a/src/compiler/scala/reflect/internal/Importers.scala
+++ b/src/compiler/scala/reflect/internal/Importers.scala
@@ -210,9 +210,9 @@ trait Importers { self: SymbolTable =>
result
}
- // !!! todo: override to vcater for PackageScopes
+ // !!! todo: override to cater for PackageScopes
def importScope(decls: from.Scope): Scope =
- new Scope(decls.toList map importSymbol)
+ newScopeWith(decls.toList map importSymbol: _*)
def importName(name: from.Name): Name =
if (name.isTypeName) newTypeName(name.toString) else newTermName(name.toString)
diff --git a/src/compiler/scala/reflect/internal/InfoTransformers.scala b/src/compiler/scala/reflect/internal/InfoTransformers.scala
index 9c54b1b4cd..96d9d8f076 100644
--- a/src/compiler/scala/reflect/internal/InfoTransformers.scala
+++ b/src/compiler/scala/reflect/internal/InfoTransformers.scala
@@ -9,6 +9,8 @@ package internal
trait InfoTransformers {
self: SymbolTable =>
+ /* Syncnote: This should not need to be protected, as reflection does not run in multiple phases.
+ */
abstract class InfoTransformer {
var prev: InfoTransformer = this
var next: InfoTransformer = this
diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala
index ef092f16bb..97a74c2383 100644
--- a/src/compiler/scala/reflect/internal/NameManglers.scala
+++ b/src/compiler/scala/reflect/internal/NameManglers.scala
@@ -85,7 +85,7 @@ trait NameManglers {
def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR
def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX
- def isImplClassName(name: Name) = stripAnonNumberSuffix(name) endsWith IMPL_CLASS_SUFFIX
+ def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX
def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX
def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING
def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
@@ -176,25 +176,18 @@ trait NameManglers {
else name.toTermName
}
- /** !!! I'm putting this logic in place because I can witness
- * trait impls get lifted and acquiring names like 'Foo$class$1'
- * while clearly still being what they were. It's only being used on
- * isImplClassName. However, it's anyone's guess how much more
- * widely this logic actually ought to be applied. Anything which
- * tests for how a name ends is a candidate for breaking down once
- * something is lifted from a method.
- *
- * TODO: resolve this significant problem.
- */
- def stripAnonNumberSuffix(name: Name): Name = {
- val str = "" + name
- if (str == "" || !str.endChar.isDigit) name
- else {
- val idx = name.lastPos('$')
- if (idx < 0 || str.substring(idx + 1).exists(c => !c.isDigit)) name
- else name.subName(0, idx)
- }
- }
+ // This isn't needed at the moment since I fixed $class$1 but
+ // I expect it will be at some point.
+ //
+ // def anonNumberSuffix(name: Name): Name = {
+ // ("" + name) lastIndexOf '$' match {
+ // case -1 => nme.EMPTY
+ // case idx =>
+ // val s = name drop idx
+ // if (s.toString forall (_.isDigit)) s
+ // else nme.EMPTY
+ // }
+ // }
def stripModuleSuffix(name: Name): Name = (
if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name
diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala
index b960695f51..907b564d4c 100644
--- a/src/compiler/scala/reflect/internal/Names.scala
+++ b/src/compiler/scala/reflect/internal/Names.scala
@@ -77,7 +77,11 @@ trait Names extends api.Names {
def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length)
def newTypeName(cs: Array[Char]): TypeName = newTypeName(cs, 0, cs.length)
- /** Create a term name from the characters in cs[offset..offset+len-1]. */
+ /** Create a term name from the characters in cs[offset..offset+len-1].
+ * TODO - have a mode where name validation is performed at creation time
+ * (e.g. if a name has the string "$class" in it, then fail if that
+ * string is not at the very end.)
+ */
protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TermName = {
val h = hashValue(cs, offset, len) & HASH_MASK
var n = termHashtable(h)
diff --git a/src/compiler/scala/reflect/internal/Scopes.scala b/src/compiler/scala/reflect/internal/Scopes.scala
index fb3012adff..54d3de09cd 100644
--- a/src/compiler/scala/reflect/internal/Scopes.scala
+++ b/src/compiler/scala/reflect/internal/Scopes.scala
@@ -37,9 +37,18 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
def unapplySeq(decls: Scope): Some[Seq[Symbol]] = Some(decls.toList)
}
- class Scope(initElems: ScopeEntry) extends Iterable[Symbol] {
+ /** Note: constructor is protected to force everyone to use the factory methods newScope or newNestedScope instead.
+ * This is necessary because when run from reflection every scope needs to have a
+ * SynchronizedScope as mixin.
+ */
+ class Scope protected[Scopes] (initElems: ScopeEntry = null) extends Iterable[Symbol] {
+
+ protected[Scopes] def this(base: Scope) = {
+ this(base.elems)
+ nestinglevel = base.nestinglevel + 1
+ }
- var elems: ScopeEntry = initElems
+ private[scala] var elems: ScopeEntry = initElems
/** The number of times this scope is nested in another
*/
@@ -65,20 +74,8 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
if (size >= MIN_HASH) createHash()
- def this() = this(null: ScopeEntry)
-
- def this(base: Scope) = {
- this(base.elems)
- nestinglevel = base.nestinglevel + 1
- }
-
- def this(decls: List[Symbol]) = {
- this()
- decls foreach enter
- }
-
/** Returns a new scope with the same content as this one. */
- def cloneScope: Scope = new Scope(this.toList)
+ def cloneScope: Scope = newScopeWith(this.toList: _*)
/** is the scope empty? */
override def isEmpty: Boolean = elems eq null
@@ -311,7 +308,7 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
override def foreach[U](p: Symbol => U): Unit = toList foreach p
override def filter(p: Symbol => Boolean): Scope =
- if (!(toList forall p)) new Scope(toList filter p) else this
+ if (!(toList forall p)) newScopeWith(toList filter p: _*) else this
override def mkString(start: String, sep: String, end: String) =
toList.map(_.defString).mkString(start, sep, end)
@@ -321,21 +318,26 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Create a new scope */
- def newScope: Scope = new Scope
+ def newScope: Scope = new Scope()
+
+ /** Create a new scope nested in another one with which it shares its elements */
+ def newNestedScope(outer: Scope): Scope = new Scope(outer)
+
+ /** Create a new scope with given initial elements */
+ def newScopeWith(elems: Symbol*): Scope = {
+ val scope = newScope
+ elems foreach scope.enter
+ scope
+ }
/** Create new scope for the members of package `pkg` */
- def newPackageScope(pkgClass: Symbol): Scope = new Scope
+ def newPackageScope(pkgClass: Symbol): Scope = newScope
/** Transform scope of members of `owner` using operation `op`
* This is overridden by the reflective compiler to avoid creating new scopes for packages
*/
def scopeTransform(owner: Symbol)(op: => Scope): Scope = op
- def newScopeWith(elems: Symbol*): Scope = {
- val scope = newScope
- elems foreach scope.enter
- scope
- }
/** The empty scope (immutable).
*/
@@ -347,7 +349,7 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
/** The error scope.
*/
- class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry)
+ class ErrorScope(owner: Symbol) extends Scope
private final val maxRecursions = 1000
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index 507621ea42..aba00088f9 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -13,7 +13,7 @@ import annotation.switch
trait StdNames extends NameManglers { self: SymbolTable =>
def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str))
-
+
implicit def lowerTermNames(n: TermName): String = "" + n
// implicit def stringToTermName(s: String): TermName = newTermName(s)
@@ -182,7 +182,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
trait TermNames extends Keywords with CommonNames {
// Compiler internal names
val EXPAND_SEPARATOR_STRING = "$$"
-
+
val ANYNAME: NameType = "<anyname>"
val CONSTRUCTOR: NameType = "<init>"
val FAKE_LOCAL_THIS: NameType = "this$"
@@ -207,7 +207,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
final val Predef: NameType = "Predef"
final val ScalaRunTime: NameType = "ScalaRunTime"
final val Some: NameType = "Some"
-
+
val _1 : NameType = "_1"
val _2 : NameType = "_2"
val _3 : NameType = "_3"
@@ -301,6 +301,8 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val classOf: NameType = "classOf"
val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure
val conforms: NameType = "conforms"
+ val context : NameType = "_context"
+ val contextImplicit : NameType = "$context"
val copy: NameType = "copy"
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
@@ -324,7 +326,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val freeValue : NameType = "freeValue"
val genericArrayOps: NameType = "genericArrayOps"
val get: NameType = "get"
- val glob : NameType = "glob"
val hasNext: NameType = "hasNext"
val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode"
val hash_ : NameType = "hash"
@@ -430,7 +431,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val REFINE_CLASS_NAME: NameType = "<refinement>"
val ANON_CLASS_NAME: NameType = "$anon"
}
-
+
/** For fully qualified type names.
*/
object fulltpnme extends TypeNames {
@@ -450,11 +451,11 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val RuntimeNothing = toBinary(fulltpnme.RuntimeNothing).toTypeName
val RuntimeNull = toBinary(fulltpnme.RuntimeNull).toTypeName
}
-
+
object fullnme extends TermNames {
type NameType = TermName
protected implicit def createNameType(name: String): TermName = newTermNameCached(name)
-
+
val MirrorPackage: NameType = "scala.reflect.mirror"
}
@@ -516,7 +517,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
def moduleVarName(name: TermName): TermName =
newTermNameCached("" + name + MODULE_VAR_SUFFIX)
-
+
val ROOTPKG: TermName = "_root_"
/** Base strings from which synthetic names are derived. */
@@ -531,7 +532,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val INTERPRETER_VAR_PREFIX = "res"
val INTERPRETER_WRAPPER_SUFFIX = "$object"
val WHILE_PREFIX = "while$"
-
+
val EQEQ_LOCAL_VAR: TermName = newTermName(EQEQ_LOCAL_VAR_STRING)
def getCause = sn.GetCause
@@ -568,18 +569,18 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val UNARY_+ = encode("unary_+")
val UNARY_- = encode("unary_-")
val UNARY_! = encode("unary_!")
-
+
// Grouped here so Cleanup knows what tests to perform.
val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE)
val ConversionNames = Set[Name](toByte, toChar, toDouble, toFloat, toInt, toLong, toShort)
val BooleanOpNames = Set[Name](ZOR, ZAND, UNARY_!) ++ CommonOpNames
val NumberOpNames = (
- Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT)
- ++ Set(UNARY_+, UNARY_-, UNARY_!)
+ Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT)
+ ++ Set(UNARY_+, UNARY_-, UNARY_!)
++ ConversionNames
++ CommonOpNames
)
-
+
val add: NameType = "add"
val complement: NameType = "complement"
val divide: NameType = "divide"
@@ -670,7 +671,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
reflMethodName
)
def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _)
-
+
@switch def productAccessorName(j: Int): TermName = j match {
case 1 => nme._1
case 2 => nme._2
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index ace4d55b90..717693fa1f 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -271,4 +271,9 @@ abstract class SymbolTable extends api.Universe
/** The phase which has given index as identifier. */
val phaseWithId: Array[Phase]
+
+ /** Is this symbol table part of reflexive mirror? In this case
+ * operations need to be made thread safe.
+ */
+ def inReflexiveMirror = false
}
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index b4d2b1531f..9f8476a6fe 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -16,10 +16,13 @@ import api.Modifier
trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
- private var ids = 0
+ protected var ids = 0
+
+ val emptySymbolArray = new Array[Symbol](0)
+
def symbolCount = ids // statistics
- val emptySymbolArray = new Array[Symbol](0)
+ protected def nextId() = { ids += 1; ids }
/** Used for deciding in the IDE whether we can interrupt the compiler */
//protected var activeLocks = 0
@@ -31,7 +34,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private var recursionTable = immutable.Map.empty[Symbol, Int]
private var nextexid = 0
- private def freshExistentialName(suffix: String) = {
+ protected def freshExistentialName(suffix: String) = {
nextexid += 1
newTypeName("_" + nextexid + suffix)
}
@@ -42,6 +45,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
m setModuleClass moduleClass
m
}
+
/** Create a new free variable. Its owner is NoSymbol.
*/
def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar =
@@ -68,7 +72,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** The class for all symbols */
- abstract class Symbol(initOwner: Symbol, initPos: Position, initName: Name)
+ abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
extends AbsSymbolImpl
with HasFlags
with Annotatable[Symbol] {
@@ -77,14 +81,24 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
type AccessBoundaryType = Symbol
type AnnotationType = AnnotationInfo
- var rawowner = initOwner
- var rawname = initName
- var rawflags = 0L
-
+ private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api
+ private[this] var _rawname = initName
+ private[this] var _rawflags = 0L
+
+ def rawowner = _rawowner
+ def rawname = _rawname
+ def rawflags = _rawflags
+
+ protected def rawflags_=(x: FlagsType) { _rawflags = x }
+
private var rawpos = initPos
- val id = { ids += 1; ids } // identity displayed when -uniqid
+
+ val id = nextId() // identity displayed when -uniqid
- var validTo: Period = NoPeriod
+ private[this] var _validTo: Period = NoPeriod
+
+ def validTo = _validTo
+ def validTo_=(x: Period) { _validTo = x}
def pos = rawpos
def setPos(pos: Position): this.type = { this.rawpos = pos; this }
@@ -336,7 +350,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// True if the symbol is unlocked.
// True if the symbol is locked but still below the allowed recursion depth.
// False otherwise
- def lockOK: Boolean = {
+ private[scala] def lockOK: Boolean = {
((rawflags & LOCKED) == 0L) ||
((settings.Yrecursion.value != 0) &&
(recursionTable get this match {
@@ -345,33 +359,37 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
// Lock a symbol, using the handler if the recursion depth becomes too great.
- def lock(handler: => Unit) = {
+ private[scala] def lock(handler: => Unit): Boolean = {
if ((rawflags & LOCKED) != 0L) {
if (settings.Yrecursion.value != 0) {
recursionTable get this match {
case Some(n) =>
if (n > settings.Yrecursion.value) {
handler
+ false
} else {
recursionTable += (this -> (n + 1))
+ true
}
case None =>
recursionTable += (this -> 1)
+ true
}
- } else { handler }
+ } else { handler; false }
} else {
rawflags |= LOCKED
+ true
// activeLocks += 1
// lockedSyms += this
}
}
// Unlock a symbol
- def unlock() = {
+ private[scala] def unlock() = {
if ((rawflags & LOCKED) != 0L) {
// activeLocks -= 1
// lockedSyms -= this
- rawflags = rawflags & ~LOCKED
+ _rawflags = rawflags & ~LOCKED
if (settings.Yrecursion.value != 0)
recursionTable -= this
}
@@ -736,7 +754,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ owner attribute --------------------------------------------------------------
def owner: Symbol = rawowner
- final def owner_=(owner: Symbol) {
+ def owner_=(owner: Symbol) {
// don't keep the original owner in presentation compiler runs
// (the map will grow indefinitely, and the only use case is the
// backend).
@@ -744,8 +762,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (originalOwner contains this) ()
else originalOwner(this) = rawowner
}
-
- rawowner = owner
+ assert(!inReflexiveMirror, "owner_= is not thread-safe; cannot be run in reflexive code")
+ _rawowner = owner
}
def ownerChain: List[Symbol] = this :: owner.ownerChain
@@ -778,7 +796,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def name: Name = rawname
- final def name_=(name: Name) {
+ def name_=(name: Name) {
if (name != rawname) {
if (owner.isClass) {
var ifs = owner.infos
@@ -787,7 +805,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
ifs = ifs.prev
}
}
- rawname = name
+ _rawname = name
}
}
@@ -855,20 +873,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
val fs = rawflags & phase.flagMask
(fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift)
}
- final def flags_=(fs: Long) = rawflags = fs
+ def flags_=(fs: Long) = _rawflags = fs
/** Set the symbol's flags to the given value, asserting
* that the previous value was 0.
*/
def initFlags(mask: Long): this.type = {
assert(rawflags == 0L, this)
- rawflags = mask
+ _rawflags = mask
this
}
- def setFlag(mask: Long): this.type = { rawflags = rawflags | mask ; this }
- def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask ; this }
+ def setFlag(mask: Long): this.type = { _rawflags = rawflags | mask ; this }
+ def resetFlag(mask: Long): this.type = { _rawflags = rawflags & ~mask ; this }
final def getFlag(mask: Long): Long = flags & mask
- final def resetFlags() { rawflags = rawflags & TopLevelCreationFlags }
+ final def resetFlags() { _rawflags = rawflags & TopLevelCreationFlags }
/** Does symbol have ANY flag in `mask` set? */
final def hasFlag(mask: Long): Boolean = (flags & mask) != 0L
@@ -954,7 +972,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
throw CyclicReference(this, tp)
}
} else {
- rawflags |= LOCKED
+ _rawflags |= LOCKED
// activeLocks += 1
// lockedSyms += this
}
@@ -963,7 +981,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
phase = phaseOf(infos.validFrom)
tp.complete(this)
} finally {
- // if (id == 431) println("completer ran "+tp.getClass+" for "+fullName)
unlock()
phase = current
}
@@ -984,7 +1001,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
assert(info ne null)
infos = TypeHistory(currentPeriod, info, null)
unlock()
- validTo = if (info.isComplete) currentPeriod else NoPeriod
+ _validTo = if (info.isComplete) currentPeriod else NoPeriod
}
/** Set initial info. */
@@ -1003,11 +1020,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** Set new info valid from start of this phase. */
- final def updateInfo(info: Type): Symbol = {
+ def updateInfo(info: Type): Symbol = {
assert(phaseId(infos.validFrom) <= phase.id)
if (phaseId(infos.validFrom) == phase.id) infos = infos.prev
infos = TypeHistory(currentPeriod, info, infos)
- validTo = if (info.isComplete) currentPeriod else NoPeriod
+ _validTo = if (info.isComplete) currentPeriod else NoPeriod
this
}
@@ -1045,11 +1062,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
infos = TypeHistory(currentPeriod + 1, info1, infos)
this.infos = infos
}
- validTo = currentPeriod + 1 // to enable reads from same symbol during info-transform
+ _validTo = currentPeriod + 1 // to enable reads from same symbol during info-transform
itr = itr.next
}
- validTo = if (itr.pid == NoPhase.id) curPeriod
- else period(currentRunId, itr.pid)
+ _validTo = if (itr.pid == NoPhase.id) curPeriod
+ else period(currentRunId, itr.pid)
}
} finally {
phase = current
@@ -1060,7 +1077,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
// adapt to new run in fsc.
- private def adaptInfos(infos: TypeHistory): TypeHistory =
+ private def adaptInfos(infos: TypeHistory): TypeHistory = {
+ assert(!inReflexiveMirror)
if (infos == null || runId(infos.validFrom) == currentRunId) {
infos
} else {
@@ -1069,7 +1087,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else {
val pid = phaseId(infos.validFrom)
- validTo = period(currentRunId, pid)
+ _validTo = period(currentRunId, pid)
phase = phaseWithId(pid)
val info1 = (
@@ -1085,6 +1103,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
}
}
+ }
/** Initialize the symbol */
final def initialize: this.type = {
@@ -1094,6 +1113,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Was symbol's type updated during given phase? */
final def isUpdatedAt(pid: Phase#Id): Boolean = {
+ assert(!inReflexiveMirror)
var infos = this.infos
while ((infos ne null) && phaseId(infos.validFrom) != pid + 1) infos = infos.prev
infos ne null
@@ -1101,6 +1121,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Was symbol's type updated during given phase? */
final def hasTypeAt(pid: Phase#Id): Boolean = {
+ assert(!inReflexiveMirror)
var infos = this.infos
while ((infos ne null) && phaseId(infos.validFrom) > pid) infos = infos.prev
infos ne null
@@ -1212,7 +1233,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def reset(completer: Type) {
resetFlags()
infos = null
- validTo = NoPeriod
+ _validTo = NoPeriod
//limit = NoPhase.id
setInfo(completer)
}
@@ -1239,7 +1260,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ----- annotations ------------------------------------------------------------
// null is a marker that they still need to be obtained.
- private var _annotations: List[AnnotationInfo] = Nil
+ private[this] var _annotations: List[AnnotationInfo] = Nil
def annotationsString = if (annotations.isEmpty) "" else annotations.mkString("(", ", ", ")")
@@ -1425,7 +1446,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def sourceModule: Symbol = NoSymbol
- /** The implementation class of a trait. */
+ /** The implementation class of a trait. If available it will be the
+ * symbol with the same owner, and the name of this symbol with $class
+ * appended to it.
+ */
final def implClass: Symbol = owner.info.decl(nme.implClassName(name))
/** The class that is logically an outer class of given `clazz`.
@@ -2046,15 +2070,18 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** A class for term symbols */
- class TermSymbol(initOwner: Symbol, initPos: Position, initName: TermName)
+ class TermSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
extends Symbol(initOwner, initPos, initName) {
final override def isTerm = true
override def name: TermName = rawname.toTermName
privateWithin = NoSymbol
- var referenced: Symbol = NoSymbol
-
+ private[this] var _referenced: Symbol = NoSymbol
+
+ def referenced: Symbol = _referenced
+ def referenced_=(x: Symbol) { _referenced = x }
+
def existentialBound = singletonBounds(this.tpe)
def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
@@ -2136,7 +2163,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** A class for module symbols */
- class ModuleSymbol(initOwner: Symbol, initPos: Position, initName: TermName)
+ class ModuleSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
extends TermSymbol(initOwner, initPos, initName) {
private var flatname: TermName = null
@@ -2159,7 +2186,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** A class for method symbols */
- class MethodSymbol(initOwner: Symbol, initPos: Position, initName: TermName)
+ class MethodSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
extends TermSymbol(initOwner, initPos, initName) {
private var mtpePeriod = NoPeriod
private var mtpePre: Type = _
@@ -2185,7 +2212,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
}
- class AliasTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName)
+ class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {
// Temporary programmatic help tracking down who might do such a thing
override def setFlag(mask: Long): this.type = {
@@ -2226,7 +2253,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** A class of type symbols. Alias and abstract types are direct instances
* of this class. Classes are instances of a subclass.
*/
- sealed abstract class TypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends Symbol(initOwner, initPos, initName) {
+ abstract class TypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) extends Symbol(initOwner, initPos, initName) {
privateWithin = NoSymbol
private var tyconCache: Type = null
private var tyconRunId = NoRunId
@@ -2364,7 +2391,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
*/
- class TypeSkolem(initOwner: Symbol, initPos: Position, initName: TypeName, origin: AnyRef)
+ class TypeSkolem protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName, origin: AnyRef)
extends TypeSymbol(initOwner, initPos, initName) {
/** The skolemization level in place when the skolem was constructed */
@@ -2393,11 +2420,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** A class for class symbols */
- class ClassSymbol(initOwner: Symbol, initPos: Position, initName: TypeName)
+ class ClassSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {
- private var flatname: TypeName = null
- private var source: AbstractFileType = null
- private var thissym: Symbol = this
+ private[this] var flatname: TypeName = null
+ private[this] var source: AbstractFileType = null
+ private[this] var thissym: Symbol = this
final override def isClass = true
final override def isNonClassType = false
@@ -2459,7 +2486,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
typeOfThisCache
}
- else thissym.tpe
+ else thisSym.tpe
}
/** Sets the self type of the class */
@@ -2479,7 +2506,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def sourceModule =
if (isModuleClass) companionModule else NoSymbol
- private var childSet: Set[Symbol] = Set()
+ private[this] var childSet: Set[Symbol] = Set()
override def children = childSet
override def addChild(sym: Symbol) { childSet = childSet + sym }
@@ -2490,7 +2517,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* Note: Not all module classes are of this type; when unpickled, we get
* plain class symbols!
*/
- class ModuleClassSymbol(owner: Symbol, pos: Position, name: TypeName)
+ class ModuleClassSymbol protected[Symbols] (owner: Symbol, pos: Position, name: TypeName)
extends ClassSymbol(owner, pos, name) {
private var module: Symbol = null
private var implicitMembersCacheValue: List[Symbol] = List()
@@ -2523,10 +2550,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** An object representing a missing symbol */
- object NoSymbol extends Symbol(null, NoPosition, nme.NO_NAME) {
- setInfo(NoType)
- privateWithin = this
- override def info_=(info: Type) {
+ class NoSymbol protected[Symbols]() extends Symbol(null, NoPosition, nme.NO_NAME) {
+ synchronized {
+ setInfo(NoType)
+ privateWithin = this
+ }
+ override def info_=(info: Type) = {
infos = TypeHistory(1, NoType, null)
unlock()
validTo = currentPeriod
@@ -2538,7 +2567,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def enclClass: Symbol = this
override def toplevelClass: Symbol = this
override def enclMethod: Symbol = this
- override def owner: Symbol = abort("no-symbol does not have owner")
override def sourceFile: AbstractFileType = null
override def ownerChain: List[Symbol] = List()
override def ownersIterator: Iterator[Symbol] = Iterator.empty
@@ -2551,8 +2579,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def accessBoundary(base: Symbol): Symbol = RootClass
def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = abort()
override def originalEnclosingMethod = this
+
+ override def owner: Symbol =
+ abort("no-symbol does not have an owner (this is a bug: scala " + scala.util.Properties.versionString + ")")
+ override def typeConstructor: Type =
+ abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)")
}
+ protected def makeNoSymbol = new NoSymbol
+
+ lazy val NoSymbol = makeNoSymbol
+
/** Derives a new list of symbols from the given list by mapping the given
* list across the given function. Then fixes the info of all the new symbols
* by substituting the new symbols for the original symbols.
diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala
index dcc395ddd2..3a0717d344 100644
--- a/src/compiler/scala/reflect/internal/TreePrinters.scala
+++ b/src/compiler/scala/reflect/internal/TreePrinters.scala
@@ -397,7 +397,6 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
// case SelectFromArray(qualifier, name, _) =>
// print(qualifier); print(".<arr>"); print(symName(tree, name))
-
case tree =>
xprintTree(this, tree)
}
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index a2c55a89d6..5bb0c98bfb 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -129,6 +129,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree
def shortClass: String = tree.getClass.getName split "[.$]" last
+
+ def isErrorTyped = (tree.tpe ne null) && tree.tpe.isError
+
/** When you want to know a little more than the class, but a lot
* less than the whole tree.
*/
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 73f1f3db84..35d26493f8 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -109,15 +109,19 @@ trait Types extends api.Types { self: SymbolTable =>
/** A log of type variable with their original constraints. Used in order
* to undo constraints in the case of isSubType/isSameType failure.
*/
- object undoLog {
- private type UndoLog = List[(TypeVar, TypeConstraint)]
- private[scala] var log: UndoLog = List()
-
+ lazy val undoLog = newUndoLog
+
+ protected def newUndoLog = new UndoLog
+
+ class UndoLog {
+ private type UndoPairs = List[(TypeVar, TypeConstraint)]
+ private var log: UndoPairs = List()
+
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
/** Undo all changes to constraints to type variables upto `limit`. */
- private def undoTo(limit: UndoLog) {
+ private def undoTo(limit: UndoPairs) {
while ((log ne limit) && log.nonEmpty) {
val (tv, constr) = log.head
tv.constr = constr
@@ -125,9 +129,14 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- private[Types] def record(tv: TypeVar) = {
+ /** No sync necessary, because record should only
+ * be called from within a undo or undoUnless block,
+ * which is already synchronized.
+ */
+ private[reflect] def record(tv: TypeVar) = {
log ::= ((tv, tv.constr.cloneInternal))
}
+
private[scala] def clear() {
if (settings.debug.value)
self.log("Clearing " + log.size + " entries from the undoLog.")
@@ -249,8 +258,7 @@ trait Types extends api.Types { self: SymbolTable =>
abstract class AbsTypeImpl extends AbsType { this: Type =>
def declaration(name: Name): Symbol = decl(name)
def nonPrivateDeclaration(name: Name): Symbol = nonPrivateDecl(name)
- def allDeclarations = decls
- def allMembers = members
+ def declarations = decls
def typeArguments = typeArgs
def erasedType = transformedType(this)
}
@@ -873,16 +881,7 @@ trait Types extends api.Types { self: SymbolTable =>
* after `maxTostringRecursions` recursion levels. Uses `safeToString`
* to produce a string on each level.
*/
- override def toString: String =
- if (tostringRecursions >= maxTostringRecursions)
- "..."
- else
- try {
- tostringRecursions += 1
- safeToString
- } finally {
- tostringRecursions -= 1
- }
+ override def toString: String = typeToString(this)
/** Method to be implemented in subclasses.
* Converts this type to a string in calling toString for its parts.
@@ -992,7 +991,9 @@ trait Types extends api.Types { self: SymbolTable =>
if (membertpe eq null) membertpe = self.memberType(member)
(membertpe matches self.memberType(sym))
})) {
- members = new Scope(List(member, sym))
+ members = newScope
+ members enter member
+ members enter sym
}
} else {
var prevEntry = members.lookupEntry(sym.name)
@@ -1105,7 +1106,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** A base class for types that represent a single value
* (single-types and this-types).
*/
- abstract class SingletonType extends SubType with SimpleTypeProxy with AbsSingletonType {
+ abstract class SingletonType extends SubType with SimpleTypeProxy {
def supertype = underlying
override def isTrivial = false
override def isStable = true
@@ -1231,18 +1232,15 @@ trait Types extends api.Types { self: SymbolTable =>
override val isTrivial: Boolean = pre.isTrivial
// override def isNullable = underlying.isNullable
override def isNotNull = underlying.isNotNull
- private var underlyingCache: Type = NoType
- private var underlyingPeriod = NoPeriod
+ private[reflect] var underlyingCache: Type = NoType
+ private[reflect] var underlyingPeriod = NoPeriod
override def underlying: Type = {
- val period = underlyingPeriod
- if (period != currentPeriod) {
- underlyingPeriod = currentPeriod
- if (!isValid(period)) {
- underlyingCache = pre.memberType(sym).resultType;
- assert(underlyingCache ne this, this)
- }
+ val cache = underlyingCache
+ if (underlyingPeriod == currentPeriod && cache != null) cache
+ else {
+ defineUnderlyingOfSingleType(this)
+ underlyingCache
}
- underlyingCache
}
// more precise conceptually, but causes cyclic errors: (paramss exists (_ contains sym))
@@ -1281,6 +1279,17 @@ trait Types extends api.Types { self: SymbolTable =>
unique(new UniqueSingleType(pre, sym))
}
}
+
+ protected def defineUnderlyingOfSingleType(tpe: SingleType) = {
+ val period = tpe.underlyingPeriod
+ if (period != currentPeriod) {
+ tpe.underlyingPeriod = currentPeriod
+ if (!isValid(period)) {
+ tpe.underlyingCache = tpe.pre.memberType(tpe.sym).resultType;
+ assert(tpe.underlyingCache ne tpe, tpe)
+ }
+ }
+ }
abstract case class SuperType(thistpe: Type, supertpe: Type) extends SingletonType {
override val isTrivial: Boolean = thistpe.isTrivial && supertpe.isTrivial
@@ -1333,105 +1342,36 @@ trait Types extends api.Types { self: SymbolTable =>
*/
abstract class CompoundType extends Type {
- var baseTypeSeqCache: BaseTypeSeq = _
- private var baseTypeSeqPeriod = NoPeriod
- private var baseClassesCache: List[Symbol] = _
- private var baseClassesPeriod = NoPeriod
+ private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
+ private[reflect] var baseTypeSeqPeriod = NoPeriod
+ private[reflect] var baseClassesCache: List[Symbol] = _
+ private[reflect] var baseClassesPeriod = NoPeriod
override def baseTypeSeq: BaseTypeSeq = {
- val period = baseTypeSeqPeriod;
- if (period != currentPeriod) { // no caching in IDE
- baseTypeSeqPeriod = currentPeriod
- if (!isValidForBaseClasses(period)) {
- if (parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
- // rename type vars to fresh type params, take base type sequence of
- // resulting type, and rename back all the entries in that sequence
- var tvs = Set[TypeVar]()
- for (p <- parents)
- for (t <- p) t match {
- case tv: TypeVar => tvs += tv
- case _ =>
- }
- val varToParamMap: Map[Type, Symbol] = tvs map (tv => tv -> tv.origin.typeSymbol.cloneSymbol) toMap
- val paramToVarMap = varToParamMap map (_.swap)
- val varToParam = new TypeMap {
- def apply(tp: Type) = varToParamMap get tp match {
- case Some(sym) => sym.tpe
- case _ => mapOver(tp)
- }
- }
- val paramToVar = new TypeMap {
- def apply(tp: Type) = tp match {
- case TypeRef(_, tsym, _) if paramToVarMap.isDefinedAt(tsym) => paramToVarMap(tsym)
- case _ => mapOver(tp)
- }
- }
- val bts = copyRefinedType(this.asInstanceOf[RefinedType], parents map varToParam, varToParam mapOver decls).baseTypeSeq
- baseTypeSeqCache = bts lateMap paramToVar
- } else {
- incCounter(compoundBaseTypeSeqCount)
- baseTypeSeqCache = undetBaseTypeSeq
- baseTypeSeqCache = if (typeSymbol.isRefinementClass)
- memo(compoundBaseTypeSeq(this))(_.baseTypeSeq updateHead typeSymbol.tpe)
- else
- compoundBaseTypeSeq(this)
- // [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
- // when compiling with
- // scalac scala.collection.IterableViewLike.scala scala.collection.IterableLike.scala
- // I have not yet figured out precisely why this is the case.
- // My current assumption is that taking memos forces baseTypeSeqs to be computed
- // at stale types (i.e. the underlying typeSymbol has already another type).
- // I do not yet see precisely why this would cause a problem, but it looks
- // fishy in any case.
- }
- }
- //Console.println("baseTypeSeq(" + typeSymbol + ") = " + baseTypeSeqCache.toList);//DEBUG
+ val cached = baseTypeSeqCache
+ if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq)
+ cached
+ else {
+ defineBaseTypeSeqOfCompoundType(this)
+ if (baseTypeSeqCache eq undetBaseTypeSeq)
+ throw new RecoverableCyclicReference(typeSymbol)
+
+ baseTypeSeqCache
}
- if (baseTypeSeqCache eq undetBaseTypeSeq)
- throw new TypeError("illegal cyclic inheritance involving " + typeSymbol)
- baseTypeSeqCache
}
override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth
override def baseClasses: List[Symbol] = {
- def computeBaseClasses: List[Symbol] =
- if (parents.isEmpty) List(typeSymbol)
- else {
- //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG
- // optimized, since this seems to be performance critical
- val superclazz = parents.head
- var mixins = parents.tail
- val sbcs = superclazz.baseClasses
- var bcs = sbcs
- def isNew(clazz: Symbol): Boolean = (
- superclazz.baseTypeIndex(clazz) < 0 &&
- { var p = bcs;
- while ((p ne sbcs) && (p.head != clazz)) p = p.tail;
- p eq sbcs
- }
- );
- while (!mixins.isEmpty) {
- def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] =
- if (mbcs.isEmpty) bcs
- else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail)
- else addMixinBaseClasses(mbcs.tail);
- bcs = addMixinBaseClasses(mixins.head.baseClasses)
- mixins = mixins.tail
- }
- typeSymbol :: bcs
- }
- val period = baseClassesPeriod
- if (period != currentPeriod) {
- baseClassesPeriod = currentPeriod
- if (!isValidForBaseClasses(period)) {
- baseClassesCache = null
- baseClassesCache = memo(computeBaseClasses)(typeSymbol :: _.baseClasses.tail)
- }
+ val cached = baseClassesCache
+ if (baseClassesPeriod == currentPeriod && cached != null) cached
+ else {
+ defineBaseClassesOfCompoundType(this)
+ if (baseClassesCache eq null)
+ throw new RecoverableCyclicReference(typeSymbol)
+
+ baseClassesCache
}
- if (baseClassesCache eq null)
- throw new TypeError("illegal cyclic reference involving " + typeSymbol)
- baseClassesCache
}
/** The slightly less idiomatic use of Options is due to
@@ -1475,6 +1415,97 @@ trait Types extends api.Types { self: SymbolTable =>
(if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
decls.mkString("{", "; ", "}") else "")
}
+
+ protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = {
+ val period = tpe.baseTypeSeqPeriod;
+ if (period != currentPeriod) {
+ tpe.baseTypeSeqPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ if (tpe.parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
+ // rename type vars to fresh type params, take base type sequence of
+ // resulting type, and rename back all the entries in that sequence
+ var tvs = Set[TypeVar]()
+ for (p <- tpe.parents)
+ for (t <- p) t match {
+ case tv: TypeVar => tvs += tv
+ case _ =>
+ }
+ val varToParamMap: Map[Type, Symbol] = tvs map (tv => tv -> tv.origin.typeSymbol.cloneSymbol) toMap
+ val paramToVarMap = varToParamMap map (_.swap)
+ val varToParam = new TypeMap {
+ def apply(tp: Type) = varToParamMap get tp match {
+ case Some(sym) => sym.tpe
+ case _ => mapOver(tp)
+ }
+ }
+ val paramToVar = new TypeMap {
+ def apply(tp: Type) = tp match {
+ case TypeRef(_, tsym, _) if paramToVarMap.isDefinedAt(tsym) => paramToVarMap(tsym)
+ case _ => mapOver(tp)
+ }
+ }
+ val bts = copyRefinedType(tpe.asInstanceOf[RefinedType], tpe.parents map varToParam, varToParam mapOver tpe.decls).baseTypeSeq
+ tpe.baseTypeSeqCache = bts lateMap paramToVar
+ } else {
+ incCounter(compoundBaseTypeSeqCount)
+ tpe.baseTypeSeqCache = undetBaseTypeSeq
+ tpe.baseTypeSeqCache = if (tpe.typeSymbol.isRefinementClass)
+ tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe)
+ else
+ compoundBaseTypeSeq(tpe)
+ // [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
+ // when compiling with
+ // scalac scala.collection.IterableViewLike.scala scala.collection.IterableLike.scala
+ // I have not yet figured out precisely why this is the case.
+ // My current assumption is that taking memos forces baseTypeSeqs to be computed
+ // at stale types (i.e. the underlying typeSymbol has already another type).
+ // I do not yet see precisely why this would cause a problem, but it looks
+ // fishy in any case.
+ }
+ }
+ }
+ //Console.println("baseTypeSeq(" + typeSymbol + ") = " + baseTypeSeqCache.toList);//DEBUG
+ if (tpe.baseTypeSeqCache eq undetBaseTypeSeq)
+ throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol)
+ }
+
+ protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = {
+ def computeBaseClasses: List[Symbol] =
+ if (tpe.parents.isEmpty) List(tpe.typeSymbol)
+ else {
+ //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG
+ // optimized, since this seems to be performance critical
+ val superclazz = tpe.parents.head
+ var mixins = tpe.parents.tail
+ val sbcs = superclazz.baseClasses
+ var bcs = sbcs
+ def isNew(clazz: Symbol): Boolean =
+ superclazz.baseTypeIndex(clazz) < 0 &&
+ { var p = bcs;
+ while ((p ne sbcs) && (p.head != clazz)) p = p.tail;
+ p eq sbcs
+ }
+ while (!mixins.isEmpty) {
+ def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] =
+ if (mbcs.isEmpty) bcs
+ else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail)
+ else addMixinBaseClasses(mbcs.tail)
+ bcs = addMixinBaseClasses(mixins.head.baseClasses)
+ mixins = mixins.tail
+ }
+ tpe.typeSymbol :: bcs
+ }
+ val period = tpe.baseClassesPeriod
+ if (period != currentPeriod) {
+ tpe.baseClassesPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ tpe.baseClassesCache = null
+ tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail)
+ }
+ }
+ if (tpe.baseClassesCache eq null)
+ throw new TypeError("illegal cyclic reference involving " + tpe.typeSymbol)
+ }
/** A class representing intersection types with refinements of the form
* `<parents_0> with ... with <parents_n> { decls }`
@@ -1583,7 +1614,7 @@ trait Types extends api.Types { self: SymbolTable =>
* by a path which contains at least one expansive reference.
* @See Kennedy, Pierce: On Decidability of Nominal Subtyping with Variance
*/
- def expansiveRefs(tparam: Symbol) = {
+ private[scala] def expansiveRefs(tparam: Symbol) = {
if (state == UnInitialized) {
computeRefs()
while (state != Initialized) propagate()
@@ -1597,10 +1628,16 @@ trait Types extends api.Types { self: SymbolTable =>
/** The type parameters which are referenced type parameters of this class.
* Two entries: refs(0): Non-expansive references
* refs(1): Expansive references
+ * Syncnote: This var need not be protected with synchronized, because
+ * it is accessed only from expansiveRefs, which is called only from
+ * Typer.
*/
private var refs: Array[RefMap] = _
/** The initialization state of the class: UnInialized --> Initializing --> Initialized
+ * Syncnote: This var need not be protected with synchronized, because
+ * it is accessed only from expansiveRefs, which is called only from
+ * Typer.
*/
private var state = UnInitialized
@@ -1750,6 +1787,10 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected
+ * with synchronized, because they are accessed only from isVolatile, which is called only from
+ * Typer.
+ */
private var volatileRecursions: Int = 0
private val pendingVolatiles = new mutable.HashSet[Symbol]
@@ -1831,13 +1872,18 @@ trait Types extends api.Types { self: SymbolTable =>
if (sym == clazz) this
else transform(sym.info.baseType(clazz))
}
+
trait NonClassTypeRef extends TypeRef {
require(sym.isNonClassType, sym)
+ /* Syncnote: These are pure caches for performance; no problem to evaluate these
+ * several times. Hence, no need to protected with synchronzied in a mutli-threaded
+ * usage scenario.
+ */
private var relativeInfoCache: Type = _
private var memberInfoCache: Type = _
- private def relativeInfo = {
+ private[Types] def relativeInfo = {
val memberInfo = pre.memberInfo(sym)
if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) {
memberInfoCache = memberInfo
@@ -1846,25 +1892,27 @@ trait Types extends api.Types { self: SymbolTable =>
relativeInfoCache
}
- override def baseType(clazz: Symbol): Type = (
- if (sym == clazz) this else try {
- basetypeRecursions += 1
- if (basetypeRecursions < LogPendingBaseTypesThreshold)
- relativeInfo.baseType(clazz)
- else if (pendingBaseTypes contains this)
- if (clazz == AnyClass) clazz.tpe else NoType
- else
- try {
- pendingBaseTypes += this
- relativeInfo.baseType(clazz)
- } finally {
- pendingBaseTypes -= this
- }
+ override def baseType(clazz: Symbol): Type =
+ if (sym == clazz) this else baseTypeOfNonClassTypeRef(this, clazz)
+ }
+
+ protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = try {
+ basetypeRecursions += 1
+ if (basetypeRecursions < LogPendingBaseTypesThreshold)
+ tpe.relativeInfo.baseType(clazz)
+ else if (pendingBaseTypes contains tpe)
+ if (clazz == AnyClass) clazz.tpe else NoType
+ else
+ try {
+ pendingBaseTypes += tpe
+ tpe.relativeInfo.baseType(clazz)
} finally {
- basetypeRecursions -= 1
+ pendingBaseTypes -= tpe
}
- )
+ } finally {
+ basetypeRecursions -= 1
}
+
trait AliasTypeRef extends NonClassTypeRef {
require(sym.isAliasType, sym)
@@ -1912,6 +1960,8 @@ trait Types extends api.Types { self: SymbolTable =>
trait AbstractTypeRef extends NonClassTypeRef {
require(sym.isAbstractType, sym)
+ /** Syncnote: Pure performance caches; no need to synchronize in multi-threaded environment
+ */
private var symInfoCache: Type = _
private var thisInfoCache: Type = _
@@ -1938,6 +1988,7 @@ trait Types extends api.Types { self: SymbolTable =>
volatileRecursions -= 1
}
}
+
override def thisInfo = {
val symInfo = sym.info
if (thisInfoCache == null || (symInfo ne symInfoCache)) {
@@ -1946,7 +1997,7 @@ trait Types extends api.Types { self: SymbolTable =>
// If a subtyping cycle is not detected here, we'll likely enter an infinite
// loop before a sensible error can be issued. SI-5093 is one example.
case x: SubType if x.supertype eq this =>
- throw new TypeError("illegal cyclic reference involving " + sym)
+ throw new RecoverableCyclicReference(sym)
case tp => tp
}
}
@@ -1955,7 +2006,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isStable = bounds.hi.typeSymbol isSubClass SingletonClass
override def bounds = thisInfo.bounds
// def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies)
- override protected def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this
+ override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this
}
/** A class for named types of the form
@@ -1966,11 +2017,11 @@ trait Types extends api.Types { self: SymbolTable =>
* @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty
*/
abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type {
- private var parentsCache: List[Type] = _
- private var parentsPeriod = NoPeriod
- private var baseTypeSeqCache: BaseTypeSeq = _
- private var baseTypeSeqPeriod = NoPeriod
- private var normalized: Type = _
+ private[reflect] var parentsCache: List[Type] = _
+ private[reflect] var parentsPeriod = NoPeriod
+ private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
+ private[reflect] var baseTypeSeqPeriod = NoPeriod
+ private var normalized: Type = _
// @M: propagate actual type params (args) to `tp`, by replacing
// formal type parameters with actual ones. If tp is higher kinded,
@@ -2030,16 +2081,12 @@ trait Types extends api.Types { self: SymbolTable =>
sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull
override def parents: List[Type] = {
- val period = parentsPeriod
- if (period != currentPeriod) {
- parentsPeriod = currentPeriod
- if (!isValidForBaseClasses(period)) {
- parentsCache = thisInfo.parents map transform
- } else if (parentsCache == null) { // seems this can happen if things are corrupted enough, see #2641
- parentsCache = List(AnyClass.tpe)
- }
+ val cache = parentsCache
+ if (parentsPeriod == currentPeriod && cache != null) cache
+ else {
+ defineParentsOfTypeRef(this)
+ parentsCache
}
- parentsCache
}
override def decls: Scope = {
@@ -2051,21 +2098,19 @@ trait Types extends api.Types { self: SymbolTable =>
thisInfo.decls
}
- protected def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform
+ protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform
override def baseTypeSeq: BaseTypeSeq = {
- val period = baseTypeSeqPeriod
- if (period != currentPeriod) {
- baseTypeSeqPeriod = currentPeriod
- if (!isValidForBaseClasses(period)) {
- incCounter(typerefBaseTypeSeqCount)
- baseTypeSeqCache = undetBaseTypeSeq
- baseTypeSeqCache = baseTypeSeqImpl
- }
+ val cache = baseTypeSeqCache
+ if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq)
+ cache
+ else {
+ defineBaseTypeSeqOfTypeRef(this)
+ if (baseTypeSeqCache == undetBaseTypeSeq)
+ throw new RecoverableCyclicReference(sym)
+
+ baseTypeSeqCache
}
- if (baseTypeSeqCache == undetBaseTypeSeq)
- throw new TypeError("illegal cyclic inheritance involving " + sym)
- baseTypeSeqCache
}
private def preString = (
@@ -2074,11 +2119,11 @@ trait Types extends api.Types { self: SymbolTable =>
else pre.prefixString
)
private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")
- private def refinementString = (
+ def refinementString = (
if (sym.isStructuralRefinement) (
decls filter (sym => sym.isPossibleInRefinement && sym.isPublic)
map (_.defString)
- mkString(" {", "; ", "}")
+ mkString("{", "; ", "}")
)
else ""
)
@@ -2151,6 +2196,32 @@ trait Types extends api.Types { self: SymbolTable =>
}
})
}
+
+ protected def defineParentsOfTypeRef(tpe: TypeRef) = {
+ val period = tpe.parentsPeriod
+ if (period != currentPeriod) {
+ tpe.parentsPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ tpe.parentsCache = tpe.thisInfo.parents map tpe.transform
+ } else if (tpe.parentsCache == null) { // seems this can happen if things are corrupted enough, see #2641
+ tpe.parentsCache = List(AnyClass.tpe)
+ }
+ }
+ }
+
+ protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = {
+ val period = tpe.baseTypeSeqPeriod
+ if (period != currentPeriod) {
+ tpe.baseTypeSeqPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ incCounter(typerefBaseTypeSeqCount)
+ tpe.baseTypeSeqCache = undetBaseTypeSeq
+ tpe.baseTypeSeqCache = tpe.baseTypeSeqImpl
+ }
+ }
+ if (tpe.baseTypeSeqCache == undetBaseTypeSeq)
+ throw new TypeError("illegal cyclic inheritance involving " + tpe.sym)
+ }
/** A class representing a method type with parameters.
* Note that a parameterless method is represented by a NullaryMethodType:
@@ -2498,7 +2569,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (args.isEmpty && params.isEmpty) new TypeVar(origin, constr)
else if (args.size == params.size) new AppliedTypeVar(origin, constr, params zip args)
else if (args.isEmpty) new HKTypeVar(origin, constr, params)
- else throw new TypeError("Invalid TypeVar construction: " + ((origin, constr, args, params)))
+ else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params)))
)
trace("create", "In " + tv.originLocation)(tv)
@@ -2577,7 +2648,12 @@ trait Types extends api.Types { self: SymbolTable =>
override def typeArgs: List[Type] = Nil
override def isHigherKinded = false
- /** The constraint associated with the variable */
+ /** The constraint associated with the variable
+ * Syncnote: Type variables are assumed to be used from only one
+ * thread. They are not exposed in api.Types and are used only locally
+ * in operations that are exposed from types. Hence, no syncing of `constr`
+ * or `encounteredHigherLevel` or `suspended` accesses should be necessary.
+ */
var constr = constr0
def instValid = constr.instValid
@@ -2599,7 +2675,7 @@ trait Types extends api.Types { self: SymbolTable =>
TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv)
}
else
- throw new TypeError("Invalid type application in TypeVar: " + params + ", " + newArgs)
+ throw new Error("Invalid type application in TypeVar: " + params + ", " + newArgs)
)
// newArgs.length may differ from args.length (could've been empty before)
//
@@ -3048,7 +3124,7 @@ trait Types extends api.Types { self: SymbolTable =>
* @return ...
*/
def refinedType(parents: List[Type], owner: Symbol): Type =
- refinedType(parents, owner, new Scope, owner.pos)
+ refinedType(parents, owner, newScope, owner.pos)
def copyRefinedType(original: RefinedType, parents: List[Type], decls: Scope) =
if ((parents eq original.parents) && (decls eq original.decls)) original
@@ -3079,7 +3155,7 @@ trait Types extends api.Types { self: SymbolTable =>
// don't expand cyclical type alias
// we require that object is initialized, thus info.typeParams instead of typeParams.
if (sym1.isAliasType && sameLength(sym1.info.typeParams, args) && !sym1.lockOK)
- throw new TypeError("illegal cyclic reference involving " + sym1)
+ throw new RecoverableCyclicReference(sym1)
val pre1 = pre match {
case x: SuperType if sym1.isEffectivelyFinal || sym1.isDeferred =>
@@ -3101,7 +3177,7 @@ trait Types extends api.Types { self: SymbolTable =>
def copyTypeRef(tp: Type, pre: Type, sym: Symbol, args: List[Type]): Type = tp match {
case TypeRef(pre0, sym0, _) if pre == pre0 && sym0.name == sym.name =>
if (sym.isAliasType && sameLength(sym.info.typeParams, args) && !sym.lockOK)
- throw new TypeError("illegal cyclic reference involving " + sym)
+ throw new RecoverableCyclicReference(sym)
TypeRef(pre, sym, args)
case _ =>
@@ -3266,6 +3342,20 @@ trait Types extends api.Types { self: SymbolTable =>
mapOver(tp)
}
}
+
+ /** Type with all top-level occurrences of abstract types replaced by their bounds */
+ def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala )
+ case TypeRef(_, sym, _) if sym.isAbstractType =>
+ abstractTypesToBounds(tp.bounds.hi)
+ case TypeRef(_, sym, _) if sym.isAliasType =>
+ abstractTypesToBounds(tp.normalize)
+ case rtp @ RefinedType(parents, decls) =>
+ copyRefinedType(rtp, parents mapConserve abstractTypesToBounds, decls)
+ case AnnotatedType(_, underlying, _) =>
+ abstractTypesToBounds(underlying)
+ case _ =>
+ tp
+ }
// Set to true for A* => Seq[A]
// (And it will only rewrite A* in method result types.)
@@ -3338,7 +3428,7 @@ trait Types extends api.Types { self: SymbolTable =>
private var uniques: util.HashSet[Type] = _
private var uniqueRunId = NoRunId
- private def unique[T <: Type](tp: T): T = {
+ protected def unique[T <: Type](tp: T): T = {
incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = util.HashSet[Type]("uniques", initialUniquesCapacity)
@@ -3362,6 +3452,12 @@ trait Types extends api.Types { self: SymbolTable =>
def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType)
def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi))
def this() = this(List(), List())
+
+ /* Syncnote: Type constraints are assumed to be used from only one
+ * thread. They are not exposed in api.Types and are used only locally
+ * in operations that are exposed from types. Hence, no syncing of any
+ * variables should be ncessesary.
+ */
/** Guard these lists against AnyClass and NothingClass appearing,
* else loBounds.isEmpty will have different results for an empty
@@ -3634,7 +3730,7 @@ trait Types extends api.Types { self: SymbolTable =>
val elems = scope.toList
val elems1 = mapOver(elems)
if (elems1 eq elems) scope
- else new Scope(elems1)
+ else newScopeWith(elems1: _*)
}
/** Map this function over given list of symbols */
@@ -3699,6 +3795,11 @@ trait Types extends api.Types { self: SymbolTable =>
def traverse(tp: Type): Unit
def apply(tp: Type): Type = { traverse(tp); tp }
}
+
+ abstract class TypeTraverserWithResult[T] extends TypeTraverser {
+ def result: T
+ def clear(): Unit
+ }
abstract class TypeCollector[T](initial: T) extends TypeTraverser {
var result: T = _
@@ -3753,7 +3854,7 @@ trait Types extends api.Types { self: SymbolTable =>
* the conversion of raw types to existential types might not have taken place
* in ClassFileparser.sigToType (where it is usually done).
*/
- object rawToExistential extends TypeMap {
+ def rawToExistential = new TypeMap {
private var expanded = immutable.Set[Symbol]()
private var generated = immutable.Set[Type]()
def apply(tp: Type): Type = tp match {
@@ -3971,15 +4072,17 @@ trait Types extends api.Types { self: SymbolTable =>
else instParamRelaxed(ps.tail, as.tail)
//Console.println("instantiating " + sym + " from " + basesym + " with " + basesym.typeParams + " and " + baseargs+", pre = "+pre+", symclazz = "+symclazz);//DEBUG
- if (sameLength(basesym.typeParams, baseargs)) {
+ if (sameLength(basesym.typeParams, baseargs))
instParam(basesym.typeParams, baseargs)
- } else {
- throw new TypeError(
- "something is wrong (wrong class file?): "+basesym+
- " with type parameters "+
- basesym.typeParams.map(_.name).mkString("[",",","]")+
- " gets applied to arguments "+baseargs.mkString("[",",","]")+", phase = "+phase)
- }
+ else
+ if (symclazz.tpe.parents.exists(_.isErroneous))
+ ErrorType // don't be to overzealous with throwing exceptions, see #2641
+ else
+ throw new Error(
+ "something is wrong (wrong class file?): "+basesym+
+ " with type parameters "+
+ basesym.typeParams.map(_.name).mkString("[",",","]")+
+ " gets applied to arguments "+baseargs.mkString("[",",","]")+", phase = "+phase)
case ExistentialType(tparams, qtpe) =>
capturedSkolems = capturedSkolems union tparams
toInstance(qtpe, clazz)
@@ -4365,15 +4468,20 @@ trait Types extends api.Types { self: SymbolTable =>
private def commonOwner(tps: List[Type]): Symbol = {
if (tps.isEmpty) NoSymbol
else {
- commonOwnerMap.result = null
+ commonOwnerMap.clear()
tps foreach (commonOwnerMap traverse _)
val result = if (commonOwnerMap.result ne null) commonOwnerMap.result else NoSymbol
debuglog(tps.mkString("commonOwner(", ", ", ") == " + result))
result
}
}
- private object commonOwnerMap extends TypeTraverser {
+
+ protected def commonOwnerMap: CommonOwnerMap = commonOwnerMapObj
+
+ protected class CommonOwnerMap extends TypeTraverserWithResult[Symbol] {
var result: Symbol = _
+
+ def clear() { result = null }
private def register(sym: Symbol) {
// First considered type is the trivial result.
@@ -4390,12 +4498,15 @@ trait Types extends api.Types { self: SymbolTable =>
case _ => mapOver(tp)
}
}
+
+ private lazy val commonOwnerMapObj = new CommonOwnerMap
class MissingAliasControl extends ControlThrowable
val missingAliasException = new MissingAliasControl
class MissingTypeControl extends ControlThrowable
object adaptToNewRunMap extends TypeMap {
+
private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = {
if (phase.flatClasses) {
sym
@@ -5832,7 +5943,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
/** The least upper bound wrt <:< of a list of types */
- def lub(ts: List[Type], depth: Int): Type = {
+ private def lub(ts: List[Type], depth: Int): Type = {
def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match {
case List() => NothingClass.tpe
case List(t) => t
@@ -5983,7 +6094,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** The greatest lower bound wrt <:< of a list of types, which have been normalized
* wrt elimSuper */
- private def glbNorm(ts: List[Type], depth: Int): Type = {
+ protected def glbNorm(ts: List[Type], depth: Int): Type = {
def glb0(ts0: List[Type]): Type = ts0 match {
case List() => AnyClass.tpe
case List(t) => t
@@ -6264,6 +6375,12 @@ trait Types extends api.Types { self: SymbolTable =>
def this(msg: String) = this(NoPosition, msg)
}
+ // TODO: RecoverableCyclicReference should be separated from TypeError,
+ // but that would be a big change. Left for further refactoring.
+ /** An exception for cyclic references from which we can recover */
+ case class RecoverableCyclicReference(sym: Symbol)
+ extends TypeError("illegal cyclic reference involving " + sym)
+
class NoCommonType(tps: List[Type]) extends Throwable(
"lub/glb of incompatible types: " + tps.mkString("", " and ", "")) with ControlThrowable
@@ -6272,14 +6389,11 @@ trait Types extends api.Types { self: SymbolTable =>
def this(pre: Type, tp: String) = this("malformed type: " + pre + "#" + tp)
}
- /** An exception signalling a variance annotation/usage conflict */
- class VarianceError(msg: String) extends TypeError(msg)
-
/** The current indentation string for traces */
private var indent: String = ""
/** Perform operation `p` on arguments `tp1`, `arg2` and print trace of computation. */
- private def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
+ protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
Console.println(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.getClass+")"*/)
indent = indent + " "
val result = p(tp1, arg2)
@@ -6324,4 +6438,16 @@ trait Types extends api.Types { self: SymbolTable =>
final val maxTostringRecursions = 50
private var tostringRecursions = 0
+
+ protected def typeToString(tpe: Type): String =
+ if (tostringRecursions >= maxTostringRecursions)
+ "..."
+ else
+ try {
+ tostringRecursions += 1
+ tpe.safeToString
+ } finally {
+ tostringRecursions -= 1
+ }
+
}
diff --git a/src/compiler/scala/reflect/runtime/ConversionUtil.scala b/src/compiler/scala/reflect/runtime/ConversionUtil.scala
index bd40200310..e75fd78590 100644
--- a/src/compiler/scala/reflect/runtime/ConversionUtil.scala
+++ b/src/compiler/scala/reflect/runtime/ConversionUtil.scala
@@ -17,36 +17,42 @@ trait ConversionUtil { self: SymbolTable =>
private val toScalaMap = new HashMap[J, S]
private val toJavaMap = new HashMap[S, J]
- def enter(j: J, s: S) = {
+ def enter(j: J, s: S) = synchronized {
debugInfo("cached: "+j+"/"+s)
toScalaMap(j) = s
toJavaMap(s) = j
}
- def toScala(key: J)(body: => S): S = toScalaMap get key match {
- case Some(v) =>
- v
- case none =>
- val result = body
- enter(key, result)
- result
+ def toScala(key: J)(body: => S): S = synchronized {
+ toScalaMap get key match {
+ case Some(v) =>
+ v
+ case none =>
+ val result = body
+ enter(key, result)
+ result
+ }
}
- def toJava(key: S)(body: => J): J = toJavaMap get key match {
- case Some(v) =>
- v
- case none =>
- val result = body
- enter(result, key)
- result
+ def toJava(key: S)(body: => J): J = synchronized {
+ toJavaMap get key match {
+ case Some(v) =>
+ v
+ case none =>
+ val result = body
+ enter(result, key)
+ result
+ }
}
- def toJavaOption(key: S)(body: => Option[J]): Option[J] = toJavaMap get key match {
- case None =>
- val result = body
- for (value <- result) enter(value, key)
- result
- case some => some
+ def toJavaOption(key: S)(body: => Option[J]): Option[J] = synchronized {
+ toJavaMap get key match {
+ case None =>
+ val result = body
+ for (value <- result) enter(value, key)
+ result
+ case some => some
+ }
}
}
diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala
index 61b03a9a29..b4bcc52a23 100644
--- a/src/compiler/scala/reflect/runtime/JavaToScala.scala
+++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala
@@ -45,7 +45,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
def javaClass(path: String): jClass[_] =
javaClass(path, defaultReflectiveClassLoader())
def javaClass(path: String, classLoader: JClassLoader): jClass[_] =
- classLoader.loadClass(path)
+ Class.forName(path, true, classLoader)
/** Does `path` correspond to a Java class with that fully qualified name? */
def isJavaClass(path: String): Boolean =
@@ -175,7 +175,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
load(sym)
completeRest()
}
- def completeRest(): Unit = {
+ def completeRest(): Unit = self.synchronized {
val tparams = clazz.rawInfo.typeParams
val parents = try {
diff --git a/src/compiler/scala/reflect/runtime/Loaders.scala b/src/compiler/scala/reflect/runtime/Loaders.scala
index 7aca052fa9..4b35a5b37e 100644
--- a/src/compiler/scala/reflect/runtime/Loaders.scala
+++ b/src/compiler/scala/reflect/runtime/Loaders.scala
@@ -97,9 +97,9 @@ trait Loaders { self: SymbolTable =>
0 < dp && dp < (name.length - 1)
}
- class PackageScope(pkgClass: Symbol) extends Scope {
+ class PackageScope(pkgClass: Symbol) extends Scope() with SynchronizedScope {
assert(pkgClass.isType)
- private var negatives = mutable.Set[Name]()
+ private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected.
override def lookupEntry(name: Name): ScopeEntry = {
val e = super.lookupEntry(name)
if (e != null)
diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala
index 9490dc4ad7..4808326902 100644
--- a/src/compiler/scala/reflect/runtime/Mirror.scala
+++ b/src/compiler/scala/reflect/runtime/Mirror.scala
@@ -12,7 +12,16 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
import definitions._
- def classWithName(name: String): Symbol = classToScala(javaClass(name))
+ def classWithName(name: String): Symbol = {
+ val clazz = javaClass(name, defaultReflectiveClassLoader())
+ classToScala(clazz)
+ }
+
+ def getCompanionObject(clazz: Symbol): AnyRef = {
+ val singleton = ReflectionUtils.singletonInstance(clazz.fullName, defaultReflectiveClassLoader())
+ singleton
+ }
+
def getClass(obj: AnyRef): Symbol = classToScala(obj.getClass)
def getType(obj: AnyRef): Type = typeToScala(obj.getClass)
// to do add getClass/getType for instances of primitive types, probably like this:
@@ -32,7 +41,9 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
case nme.update => return Array.set(receiver, args(0).asInstanceOf[Int], args(1))
}
}
- methodToJava(meth).invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
+
+ val jmeth = methodToJava(meth)
+ jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
}
override def classToType(jclazz: java.lang.Class[_]): Type = typeToScala(jclazz)
@@ -40,7 +51,8 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
override def typeToClass(tpe: Type): java.lang.Class[_] = typeToJavaClass(tpe)
override def symbolToClass(sym: Symbol): java.lang.Class[_] = classToJava(sym)
-
+
+ override def inReflexiveMirror = true
}
object Mirror extends Mirror
diff --git a/src/compiler/scala/reflect/runtime/SymbolTable.scala b/src/compiler/scala/reflect/runtime/SymbolTable.scala
index d1a806bcef..5331f0a53e 100644
--- a/src/compiler/scala/reflect/runtime/SymbolTable.scala
+++ b/src/compiler/scala/reflect/runtime/SymbolTable.scala
@@ -6,7 +6,7 @@ package runtime
* It can be used either from the reflexive mirror itself (class Universe), or else from
* a runtime compiler that uses reflection to get a class information (class scala.tools.nsc.ReflectGlobal)
*/
-trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava with Loaders {
+trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava with Loaders with SynchronizedOps {
/** If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package
* <owner>.<name>, otherwise return NoSymbol.
diff --git a/src/compiler/scala/reflect/runtime/SynchronizedOps.scala b/src/compiler/scala/reflect/runtime/SynchronizedOps.scala
new file mode 100644
index 0000000000..72adbd4004
--- /dev/null
+++ b/src/compiler/scala/reflect/runtime/SynchronizedOps.scala
@@ -0,0 +1,51 @@
+package scala.reflect
+package runtime
+
+trait SynchronizedOps extends internal.SymbolTable
+ with SynchronizedSymbols
+ with SynchronizedTypes { self: SymbolTable =>
+
+// Names
+
+ private lazy val nameLock = new Object
+
+ override def newTermName(s: String): TermName = nameLock.synchronized { super.newTermName(s) }
+ override def newTypeName(s: String): TypeName = nameLock.synchronized { super.newTypeName(s) }
+
+// BaseTypeSeqs
+
+ override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
+ new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq
+
+ trait SynchronizedBaseTypeSeq extends BaseTypeSeq {
+ override def apply(i: Int): Type = synchronized { super.apply(i) }
+ override def rawElem(i: Int) = synchronized { super.rawElem(i) }
+ override def typeSymbol(i: Int): Symbol = synchronized { super.typeSymbol(i) }
+ override def toList: List[Type] = synchronized { super.toList }
+ override def copy(head: Type, offset: Int): BaseTypeSeq = synchronized { super.copy(head, offset) }
+ override def map(f: Type => Type): BaseTypeSeq = synchronized { super.map(f) }
+ override def exists(p: Type => Boolean): Boolean = synchronized { super.exists(p) }
+ override lazy val maxDepth = synchronized { maxDepthOfElems }
+ override def toString = synchronized { super.toString }
+
+ override def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq
+ }
+
+// Scopes
+
+ override def newScope = new Scope() with SynchronizedScope
+ override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
+
+ trait SynchronizedScope extends Scope {
+ override def isEmpty: Boolean = synchronized { super.isEmpty }
+ override def size: Int = synchronized { super.size }
+ override def enter(sym: Symbol) = synchronized { super.enter(sym) }
+ override def rehash(sym: Symbol, newname: Name) = synchronized { super.rehash(sym, newname) }
+ override def unlink(e: ScopeEntry) = synchronized { super.unlink(e) }
+ override def unlink(sym: Symbol) = synchronized { super.unlink(sym) }
+ override def lookupAll(name: Name) = synchronized { super.lookupAll(name) }
+ override def lookupEntry(name: Name) = synchronized { super.lookupEntry(name) }
+ override def lookupNextEntry(entry: ScopeEntry) = synchronized { super.lookupNextEntry(entry) }
+ override def toList: List[Symbol] = synchronized { super.toList }
+ }
+}
diff --git a/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala b/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala
new file mode 100644
index 0000000000..9baf94f71d
--- /dev/null
+++ b/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -0,0 +1,119 @@
+package scala.reflect
+package runtime
+
+import internal.Flags.DEFERRED
+
+trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
+
+ override protected def nextId() = synchronized { super.nextId() }
+
+ override protected def freshExistentialName(suffix: String) =
+ synchronized { super.freshExistentialName(suffix) }
+
+ // Set the fields which point companions at one another. Returns the module.
+ override def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol =
+ synchronized { super.connectModuleToClass(m, moduleClass) }
+
+ override def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar =
+ new FreeVar(name, value) with SynchronizedTermSymbol initFlags newFlags setInfo tpe
+
+ override protected def makeNoSymbol = new NoSymbol with SynchronizedSymbol
+
+ trait SynchronizedSymbol extends Symbol {
+
+ override def rawowner = synchronized { super.rawowner }
+ override def rawname = synchronized { super.rawname }
+ override def rawflags = synchronized { super.rawflags }
+
+ override def rawflags_=(x: FlagsType) = synchronized { super.rawflags_=(x) }
+ override def name_=(x: Name) = synchronized { super.name_=(x) }
+ override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) }
+
+ override def validTo = synchronized { super.validTo }
+ override def validTo_=(x: Period) = synchronized { super.validTo_=(x) }
+
+ override def pos = synchronized { super.pos }
+ override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this }
+
+ override def privateWithin = synchronized { super.privateWithin }
+ override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) }
+
+ override def info = synchronized { super.info }
+ override def info_=(info: Type) = synchronized { super.info_=(info) }
+ override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) }
+ override def rawInfo: Type = synchronized { super.rawInfo }
+
+ override def typeParams: List[Symbol] = synchronized { super.typeParams }
+
+ override def reset(completer: Type) = synchronized { super.reset(completer) }
+
+ override def infosString: String = synchronized { super.infosString }
+
+ override def annotations: List[AnnotationInfo] = synchronized { super.annotations }
+ override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this }
+
+
+// ------ creators -------------------------------------------------------------------
+
+ override def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
+
+ override def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol =
+ new AbstractTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags
+
+ override def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol =
+ new AliasTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags
+
+ override def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
+ new ModuleSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
+
+ override def newMethodSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol =
+ new MethodSymbol(this, pos, name) with SynchronizedMethodSymbol initFlags newFlags
+
+ override def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol =
+ new ClassSymbol(this, pos, name) with SynchronizedClassSymbol initFlags newFlags
+
+ override def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
+ new ModuleClassSymbol(this, pos, name) with SynchronizedModuleClassSymbol initFlags newFlags
+
+ override def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem =
+ if ((newFlags & DEFERRED) == 0L)
+ new TypeSkolem(this, pos, name, origin) with SynchronizedTypeSymbol initFlags newFlags
+ else
+ new TypeSkolem(this, pos, name, origin) with AbstractTypeMixin with SynchronizedTypeSymbol initFlags newFlags
+ }
+
+// ------- subclasses ---------------------------------------------------------------------
+
+ trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol {
+ override def referenced: Symbol = synchronized { super.referenced }
+ override def referenced_=(x: Symbol) = synchronized { super.referenced_=(x) }
+ }
+
+ trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol {
+ override def typeAsMemberOf(pre: Type): Type = synchronized { super.typeAsMemberOf(pre) }
+ }
+
+ trait SynchronizedTypeSymbol extends TypeSymbol with SynchronizedSymbol {
+ override def typeConstructor: Type = synchronized { super.typeConstructor }
+ override def tpe: Type = synchronized { super.tpe }
+ }
+
+ trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol {
+ override def sourceFile = synchronized { super.sourceFile }
+ override def sourceFile_=(f: AbstractFileType) = synchronized { super.sourceFile_=(f) }
+ override def thisSym: Symbol = synchronized { super.thisSym }
+ override def thisType: Type = synchronized { super.thisType }
+ override def typeOfThis: Type = synchronized { super.typeOfThis }
+ override def typeOfThis_=(tp: Type) = synchronized { super.typeOfThis_=(tp) }
+ override def children = synchronized { super.children }
+ override def addChild(sym: Symbol) = synchronized { super.addChild(sym) }
+ }
+
+ trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol {
+ override def sourceModule = synchronized { super.sourceModule }
+ override def sourceModule_=(module: Symbol) = synchronized { super.sourceModule_=(module: Symbol) }
+ override def implicitMembers: List[Symbol] = synchronized { super.implicitMembers }
+ }
+}
+
diff --git a/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala b/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala
new file mode 100644
index 0000000000..c842d3dd01
--- /dev/null
+++ b/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala
@@ -0,0 +1,87 @@
+package scala.reflect
+package runtime
+
+/** This trait overrides methods in reflect.internal, bracketing
+ * them in synchronized { ... } to make them thread-safe
+ */
+trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
+
+ // No sharing of map objects:
+ override protected def commonOwnerMap = new CommonOwnerMap
+
+ private val uniqueLock = new Object
+ override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) }
+
+ class SynchronizedUndoLog extends UndoLog {
+
+ override def clear() =
+ synchronized { super.clear() }
+
+ override def undo[T](block: => T): T =
+ synchronized { super.undo(block) }
+
+ override def undoUnless(block: => Boolean): Boolean =
+ synchronized { super.undoUnless(block) }
+ }
+
+ override protected def newUndoLog = new SynchronizedUndoLog
+
+ override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) =
+ synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) }
+
+ private val subsametypeLock = new Object
+
+ override def isSameType(tp1: Type, tp2: Type): Boolean =
+ subsametypeLock.synchronized { super.isSameType(tp1, tp2) }
+
+ override def isDifferentType(tp1: Type, tp2: Type): Boolean =
+ subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) }
+
+ override def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean =
+ subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) }
+
+ private val lubglbLock = new Object
+
+ override def glb(ts: List[Type]): Type =
+ lubglbLock.synchronized { super.glb(ts) }
+
+ override def lub(ts: List[Type]): Type =
+ lubglbLock.synchronized { super.lub(ts) }
+
+ private val indentLock = new Object
+
+ override protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
+ indentLock.synchronized { super.explain(op, p, tp1, arg2) }
+ }
+
+ private val toStringLock = new Object
+
+ override protected def typeToString(tpe: Type): String =
+ toStringLock.synchronized(super.typeToString(tpe))
+
+ /* The idea of caches is as follows.
+ * When in reflexive mode, a cache is either null, or one sentinal
+ * value representing undefined or the final defined
+ * value. Hence, we can ask in non-synchronized ode whether the cache field
+ * is non null and different from the sentinel (if a sentinel exists).
+ * If that's true, the cache value is current.
+ * Otherwise we arrive in one of the defined... methods listed below
+ * which go through all steps in synchronized mode.
+ */
+
+ override protected def defineUnderlyingOfSingleType(tpe: SingleType) =
+ tpe.synchronized { super.defineUnderlyingOfSingleType(tpe) }
+
+ override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) =
+ tpe.synchronized { super.defineBaseTypeSeqOfCompoundType(tpe) }
+
+ override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) =
+ tpe.synchronized { super.defineBaseClassesOfCompoundType(tpe) }
+
+ override protected def defineParentsOfTypeRef(tpe: TypeRef) =
+ tpe.synchronized { super.defineParentsOfTypeRef(tpe) }
+
+ override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) =
+ tpe.synchronized { super.defineBaseTypeSeqOfTypeRef(tpe) }
+
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
index 8afd6d2231..9ab12c6a86 100644
--- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala
+++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
@@ -57,7 +57,7 @@ trait ToolBoxes extends { self: Universe =>
def wrapInObject(expr: Tree, fvs: List[Symbol]): ModuleDef = {
val obj = EmptyPackageClass.newModule(nextWrapperModuleName())
- val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), new Scope, obj.moduleClass)
+ val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), newScope, obj.moduleClass)
obj.moduleClass setInfo minfo
obj setInfo obj.moduleClass.tpe
val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName))
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index 7aff4e3e8e..04ff0c440d 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -608,7 +608,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
if (!deprecation.isEmpty) settings.deprecation.value = deprecation.get
if (!nobootcp.isEmpty) settings.nobootcp.value = nobootcp.get
if (!nowarn.isEmpty) settings.nowarn.value = nowarn.get
- if (!optimise.isEmpty) settings.XO.value = optimise.get
+ if (!optimise.isEmpty) settings.optimise.value = optimise.get
if (!unchecked.isEmpty) settings.unchecked.value = unchecked.get
if (!usejavacp.isEmpty) settings.usejavacp.value = usejavacp.get
diff --git a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala
index a39de64c5a..5199e273d7 100644
--- a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala
+++ b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala
@@ -13,6 +13,7 @@ import java.io.{ File, FileWriter }
import org.apache.tools.ant.Project
import org.apache.tools.ant.taskdefs.Java
import org.apache.tools.ant.util.{ GlobPatternMapper, SourceFileScanner }
+import org.apache.tools.ant.BuildException
import scala.tools.nsc.io
import scala.tools.nsc.util.ScalaClassLoader
@@ -150,7 +151,7 @@ class ScalacFork extends ScalaMatchingTask with ScalacShared with TaskArgs {
val res = execWithArgFiles(java, paths)
if (failOnError && res != 0)
- sys.error("Compilation failed because of an internal compiler error;"+
+ throw new BuildException("Compilation failed because of an internal compiler error;"+
" see the error output for details.")
}
}
diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
index 9f1fbc4524..5949689b24 100644
--- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
@@ -86,4 +86,6 @@ goto :eof
:end
@@endlocal
-exit /b %errorlevel%
+
+REM exit code fix, see http://stackoverflow.com/questions/4632891/exiting-batch-with-exit-b-x-where-x-1-acts-as-if-command-completed-successfu
+@@%COMSPEC% /C exit %errorlevel% >nul
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index c8db996de2..426700f3b2 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -615,7 +615,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
object icodeChecker extends icodeCheckers.ICodeChecker()
object typer extends analyzer.Typer(
- analyzer.NoContext.make(EmptyTree, Global.this.definitions.RootClass, new Scope)
+ analyzer.NoContext.make(EmptyTree, Global.this.definitions.RootClass, newScope)
)
/** Add the internal compiler phases to the phases set.
@@ -901,6 +901,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
/** Counts for certain classes of warnings during this run. */
var deprecationWarnings: List[(Position, String)] = Nil
var uncheckedWarnings: List[(Position, String)] = Nil
+
+ /** A flag whether macro expansions failed */
+ var macroExpansionFailed = false
/** Progress tracking. Measured in "progress units" which are 1 per
* compilation unit per phase completed.
@@ -1083,6 +1086,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
)
warn(deprecationWarnings.size, "deprecation", settings.deprecation)
warn(uncheckedWarnings.size, "unchecked", settings.unchecked)
+ if (macroExpansionFailed)
+ warning("some macros could not be expanded and code fell back to overridden methods;"+
+ "\nrecompiling with generated classfiles on the classpath might help.")
// todo: migrationWarnings
}
}
diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala
index e739eade3a..72662291f8 100644
--- a/src/compiler/scala/tools/nsc/MacroContext.scala
+++ b/src/compiler/scala/tools/nsc/MacroContext.scala
@@ -2,7 +2,7 @@ package scala.tools.nsc
import symtab.Flags._
-trait MacroContext extends reflect.api.MacroContext { self: Global =>
+trait MacroContext extends reflect.macro.Context { self: Global =>
def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
index 7b5de1f3dd..c1d6c1a4d4 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -33,17 +33,16 @@ abstract class TreeBrowsers {
val borderSize = 10
-
def create(): SwingBrowser = new SwingBrowser();
/** Pseudo tree class, so that all JTree nodes are treated uniformly */
case class ProgramTree(units: List[UnitTree]) extends Tree {
- override def toString(): String = "Program"
+ override def toString: String = "Program"
}
/** Pseudo tree class, so that all JTree nodes are treated uniformly */
case class UnitTree(unit: CompilationUnit) extends Tree {
- override def toString(): String = unit.toString()
+ override def toString: String = unit.toString
}
/**
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 88a9b5e18b..3a2c5f61b2 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -17,7 +17,6 @@ import scala.reflect.internal.Flags.TRAIT
trait Trees extends reflect.internal.Trees { self: Global =>
// --- additional cases --------------------------------------------------------
-
/** Only used during parsing */
case class Parens(args: List[Tree]) extends Tree
@@ -31,7 +30,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
override def isType = definition.isType
}
-
/** Either an assignment or a named argument. Only appears in argument lists,
* eliminated by typecheck (doTypedApply)
*/
@@ -40,7 +38,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
/** Array selection <qualifier> . <name> only used during erasure */
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
- extends TermTree with RefTree { }
+ extends TermTree with RefTree
/** emitted by typer, eliminated by refchecks */
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
@@ -163,7 +161,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
traverser.traverse(qualifier)
case ReferenceToBoxed(idt) =>
traverser.traverse(idt)
- case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree?
+ case TypeTreeWithDeferredRefCheck() =>
// (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check)
case _ => super.xtraverse(traverser, tree)
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index ce41bc456e..fe6dcc9138 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2449,7 +2449,7 @@ self =>
else {
val nameOffset = in.offset
val name = ident()
- if (name == nme.macro_ && isIdent && settings.Xexperimental.value)
+ if (name == nme.macro_ && isIdent && settings.Xmacros.value)
funDefRest(start, in.offset, mods | Flags.MACRO, ident())
else
funDefRest(start, nameOffset, mods, name)
@@ -2480,6 +2480,9 @@ self =>
restype = scalaUnitConstr
blockExpr()
} else {
+ if (name == nme.macro_ && isIdent && in.token != EQUALS) {
+ warning("this syntactically invalid code resembles a macro definition. have you forgotten to enable -Xmacros?")
+ }
equalsExpr()
}
DefDef(newmods, name, tparams, vparamss, restype, rhs)
@@ -2539,7 +2542,7 @@ self =>
newLinesOpt()
atPos(start, in.offset) {
val name = identForType()
- if (name == nme.macro_.toTypeName && isIdent && settings.Xexperimental.value) {
+ if (name == nme.macro_.toTypeName && isIdent && settings.Xmacros.value) {
funDefRest(start, in.offset, mods | Flags.MACRO, identForType())
} else {
// @M! a type alias as well as an abstract type may declare type parameters
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 15b4c8c708..badf5d70d1 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1528,7 +1528,7 @@ abstract class GenICode extends SubComponent {
if (mustUseAnyComparator) {
// when -optimise is on we call the @inline-version of equals, found in ScalaRunTime
val equalsMethod =
- if (!settings.XO.value) {
+ if (!settings.optimise.value) {
def default = platform.externalEquals
platform match {
case x: JavaPlatform =>
@@ -1550,7 +1550,7 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(l, ctx, ObjectReference)
val ctx2 = genLoad(r, ctx1, ObjectReference)
- ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.XO.value) Dynamic else Static(false)))
+ ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false)))
ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
ctx2.bb.close
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 3e8ef3f611..66f802f74f 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -62,6 +62,15 @@ abstract class Inliners extends SubComponent {
override def apply(c: IClass) {
inliner analyzeClass c
}
+
+ override def run() {
+ try {
+ super.run()
+ } finally {
+ inliner.NonPublicRefs.usesNonPublics.clear()
+ inliner.recentTFAs.clear
+ }
+ }
}
def isBottomType(sym: Symbol) = sym == NullClass || sym == NothingClass
@@ -79,17 +88,10 @@ abstract class Inliners extends SubComponent {
val Private, Protected, Public = Value
/** Cache whether a method calls private members. */
- val usesNonPublics: mutable.Map[IMethod, Value] = perRunCaches.newMap()
+ val usesNonPublics = mutable.Map.empty[IMethod, Value]
}
import NonPublicRefs._
- /* fresh name counter */
- val fresh = perRunCaches.newMap[String, Int]() withDefaultValue 0
- def freshName(s: String): TermName = {
- fresh(s) += 1
- newTermName(s + fresh(s))
- }
-
private def hasInline(sym: Symbol) = sym hasAnnotation ScalaInlineClass
private def hasNoInline(sym: Symbol) = sym hasAnnotation ScalaNoInlineClass
@@ -97,6 +99,28 @@ abstract class Inliners extends SubComponent {
private var currentIClazz: IClass = _
private def warn(pos: Position, msg: String) = currentIClazz.cunit.warning(pos, msg)
+ val recentTFAs = mutable.Map.empty[Symbol, Tuple2[Boolean, analysis.MethodTFA]]
+ private def getRecentTFA(incm: IMethod): (Boolean, analysis.MethodTFA) = {
+
+ def containsRETURN(blocks: List[BasicBlock]) = blocks exists { bb => bb.lastInstruction.isInstanceOf[RETURN] }
+
+ val opt = recentTFAs.get(incm.symbol)
+ if(opt.isDefined) {
+ // FYI val cachedBBs = opt.get._2.in.keySet
+ // FYI assert(incm.blocks.toSet == cachedBBs)
+ // incm.code.touched plays no role here
+ return opt.get
+ }
+
+ val hasRETURN = containsRETURN(incm.code.blocksList) || (incm.exh exists { eh => containsRETURN(eh.blocks) })
+ var a: analysis.MethodTFA = null
+ if(hasRETURN) { a = new analysis.MethodTFA(incm); a.run }
+
+ if(hasInline(incm.symbol)) { recentTFAs.put(incm.symbol, (hasRETURN, a)) }
+
+ (hasRETURN, a)
+ }
+
def analyzeClass(cls: IClass): Unit =
if (settings.inline.value) {
debuglog("Analyzing " + cls)
@@ -106,7 +130,7 @@ abstract class Inliners extends SubComponent {
ms foreach { im =>
if(hasInline(im.symbol)) {
log("Not inlining into " + im.symbol.originalName.decode + " because it is marked @inline.")
- } else if(im.hasCode) {
+ } else if(im.hasCode && !im.symbol.isBridge) {
analyzeMethod(im)
}
}
@@ -114,20 +138,21 @@ abstract class Inliners extends SubComponent {
val tfa = new analysis.MTFAGrowable()
tfa.stat = global.opt.printStats
- val staleOut = new mutable.ListBuffer[BasicBlock]
+ val staleOut = new mutable.ListBuffer[BasicBlock]
val splicedBlocks = mutable.Set.empty[BasicBlock]
- val staleIn = mutable.Set.empty[BasicBlock]
-
- // how many times have we already inlined this method here?
- private val inlinedMethodCount = perRunCaches.newMap[Symbol, Int]() withDefaultValue 0
+ val staleIn = mutable.Set.empty[BasicBlock]
def analyzeMethod(m: IMethod): Unit = {
- var sizeBeforeInlining = if (m.hasCode) m.code.blockCount else 0
- var instrBeforeInlining = if (m.hasCode) m.code.instructionCount else 0
+ var sizeBeforeInlining = m.code.blockCount
+ var instrBeforeInlining = m.code.instructionCount
var retry = false
var count = 0
- fresh.clear()
- inlinedMethodCount.clear()
+
+ // fresh name counter
+ val fresh = mutable.HashMap.empty[String, Int] withDefaultValue 0
+ // how many times have we already inlined this method here?
+ val inlinedMethodCount = mutable.HashMap.empty[Symbol, Int] withDefaultValue 0
+
val caller = new IMethodInfo(m)
var info: tfa.lattice.Elem = null
@@ -146,17 +171,20 @@ abstract class Inliners extends SubComponent {
warn(i.pos, "Could not inline required method %s because %s.".format(msym.originalName.decode, reason))
}
- if (shouldLoadImplFor(concreteMethod, receiver)) {
+ def isAvailable = icodes available concreteMethod.enclClass
+
+ if (!isAvailable && shouldLoadImplFor(concreteMethod, receiver)) {
// Until r22824 this line was:
// icodes.icode(concreteMethod.enclClass, true)
//
- // Changing it to the below was the proximate cause for SI-3882:
+ // Changing it to
+ // icodes.load(concreteMethod.enclClass)
+ // was the proximate cause for SI-3882:
// error: Illegal index: 0 overlaps List((variable par1,LONG))
// error: Illegal index: 0 overlaps List((variable par1,LONG))
icodes.load(concreteMethod.enclClass)
}
- def isAvailable = icodes available concreteMethod.enclClass
def isCandidate = (
isClosureClass(receiver)
|| concreteMethod.isEffectivelyFinal
@@ -179,7 +207,7 @@ abstract class Inliners extends SubComponent {
lookupIMethod(concreteMethod, receiver) match {
case Some(callee) =>
val inc = new IMethodInfo(callee)
- val pair = new CallerCalleeInfo(caller, inc)
+ val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount)
if (pair isStampedForInlining info.stack) {
retry = true
@@ -196,6 +224,7 @@ abstract class Inliners extends SubComponent {
* might have changed after the inlining.
*/
usesNonPublics -= m
+ recentTFAs -= m.symbol
}
else {
if (settings.debug.value)
@@ -315,11 +344,10 @@ abstract class Inliners extends SubComponent {
def inline = hasInline(sym)
def noinline = hasNoInline(sym)
- def numInlined = inlinedMethodCount(sym)
def isBridge = sym.isBridge
def isInClosure = isClosureClass(owner)
- def isHigherOrder = isHigherOrderMethod(sym)
+ val isHigherOrder = isHigherOrderMethod(sym)
def isMonadic = isMonadicMethod(sym)
def handlers = m.exh
@@ -328,7 +356,7 @@ abstract class Inliners extends SubComponent {
def length = blocks.length
def openBlocks = blocks filterNot (_.closed)
def instructions = m.code.instructions
- def linearized = linearizer linearize m
+ // def linearized = linearizer linearize m
def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10
def isLarge = length > MAX_INLINE_SIZE
@@ -347,9 +375,14 @@ abstract class Inliners extends SubComponent {
def addHandlers(exhs: List[ExceptionHandler]) = m.exh = exhs ::: m.exh
}
- class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo) {
+ class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo, fresh: mutable.Map[String, Int], inlinedMethodCount: collection.Map[Symbol, Int]) {
def isLargeSum = caller.length + inc.length - 1 > SMALL_METHOD_SIZE
+ private def freshName(s: String): TermName = {
+ fresh(s) += 1
+ newTermName(s + fresh(s))
+ }
+
/** Inline 'inc' into 'caller' at the given block and instruction.
* The instruction must be a CALL_METHOD.
*/
@@ -364,7 +397,7 @@ abstract class Inliners extends SubComponent {
def newLocal(baseName: String, kind: TypeKind) =
new Local(caller.sym.newVariable(freshName(baseName), targetPos), kind, false)
- val a = new analysis.MethodTFA(inc.m)
+ val (hasRETURN, a) = getRecentTFA(inc.m)
/* The exception handlers that are active at the current block. */
val activeHandlers = caller.handlers filter (_ covered block)
@@ -393,7 +426,7 @@ abstract class Inliners extends SubComponent {
case x => newLocal("$retVal", x)
}
- val inlinedLocals = perRunCaches.newMap[Local, Local]()
+ val inlinedLocals = mutable.HashMap.empty[Local, Local]
/** Add a new block in the current context. */
def newBlock() = {
@@ -475,9 +508,6 @@ abstract class Inliners extends SubComponent {
inlinedBlock(b).varsInScope ++= (b.varsInScope map inlinedLocals)
}
- // analyse callee
- a.run
-
// re-emit the instructions before the call
block.open
block.clear
@@ -494,7 +524,7 @@ abstract class Inliners extends SubComponent {
// duplicate the other blocks in the callee
val calleeLin = inc.m.linearizedBlocks()
calleeLin foreach { bb =>
- var info = a in bb
+ var info = if(hasRETURN) (a in bb) else null
def emitInlined(i: Instruction) = inlinedBlock(bb).emit(i, targetPos)
def emitDrops(toDrop: Int) = info.stack.types drop toDrop foreach (t => emitInlined(DROP(t)))
@@ -510,7 +540,7 @@ abstract class Inliners extends SubComponent {
case _ => ()
}
emitInlined(map(i))
- info = a.interpret(info, i)
+ info = if(hasRETURN) a.interpret(info, i) else null
}
inlinedBlock(bb).close
}
@@ -538,7 +568,7 @@ abstract class Inliners extends SubComponent {
| isSafeToInline: %s
| shouldInline: %s
""".stripMargin.format(
- inc.m, sameSymbols, inc.numInlined < 2,
+ inc.m, sameSymbols, inlinedMethodCount(inc.sym) < 2,
inc.m.hasCode, isSafeToInline(stack), shouldInline
)
)
@@ -635,28 +665,22 @@ abstract class Inliners extends SubComponent {
var score = 0
- // better not inline inside closures, but hope that the closure itself
- // is repeatedly inlined
- if (caller.isInClosure) score -= 2
+ // better not inline inside closures, but hope that the closure itself is repeatedly inlined
+ if (caller.isInClosure) score -= 2
else if (caller.inlinedCalls < 1) score -= 1 // only monadic methods can trigger the first inline
- if (inc.isSmall)
- score += 1
+ if (inc.isSmall) score += 1;
+ if (inc.isLarge) score -= 1;
if (caller.isSmall && isLargeSum) {
score -= 1
debuglog("shouldInline: score decreased to " + score + " because small " + caller + " would become large")
}
- if (inc.isLarge)
- score -= 1
- if (inc.isMonadic)
- score += 3
- else if (inc.isHigherOrder)
- score += 1
- if (inc.isInClosure)
- score += 2
- if (inc.numInlined > 2)
- score -= 2
+ if (inc.isMonadic) score += 3
+ else if (inc.isHigherOrder) score += 1
+
+ if (inc.isInClosure) score += 2;
+ if (inlinedMethodCount(inc.sym) > 2) score -= 2;
log("shouldInline(" + inc.m + ") score: " + score)
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 0fea0a2d92..477cec8c8e 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -1060,6 +1060,8 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
implicit def addOnTypeError[T](x: => T): OnTypeError[T] = new OnTypeError(x)
+ // OnTypeError should still catch TypeError because of cyclic references,
+ // but DivergentImplicit shouldn't leak anymore here
class OnTypeError[T](op: => T) {
def onTypeError(alt: => T) = try {
op
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 0dc51d5eb0..7c71438b98 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -110,7 +110,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
class ILoopInterpreter extends IMain(settings, out) {
outer =>
- private class ThreadStoppingLineManager extends Line.Manager(parentClassLoader) {
+ private class ThreadStoppingLineManager(classLoader: ClassLoader) extends Line.Manager(classLoader) {
override def onRunaway(line: Line[_]): Unit = {
val template = """
|// She's gone rogue, captain! Have to take her out!
@@ -126,8 +126,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
override lazy val formatting = new Formatting {
def prompt = ILoop.this.prompt
}
- override protected def createLineManager(): Line.Manager =
- new ThreadStoppingLineManager
+ override protected def createLineManager(classLoader: ClassLoader): Line.Manager =
+ new ThreadStoppingLineManager(classLoader)
override protected def parentClassLoader =
settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader )
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 0f0ab69e6d..8cdd2334ab 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -269,7 +269,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** Create a line manager. Overridable. */
protected def noLineManager = ReplPropsKludge.noThreadCreation(settings)
- protected def createLineManager(): Line.Manager = new Line.Manager(_classLoader)
+ protected def createLineManager(classLoader: ClassLoader): Line.Manager = new Line.Manager(classLoader)
/** Instantiate a compiler. Overridable. */
protected def newCompiler(settings: Settings, reporter: Reporter) = {
@@ -304,7 +304,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
final def ensureClassLoader() {
if (_classLoader == null) {
_classLoader = makeClassLoader()
- _lineManager = if (noLineManager) null else createLineManager()
+ _lineManager = if (noLineManager) null else createLineManager(_classLoader)
}
}
def classLoader: AbstractFileClassLoader = {
diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala
index 69db23923d..d970d0e9c9 100644
--- a/src/compiler/scala/tools/nsc/io/MsilFile.scala
+++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala
@@ -13,4 +13,6 @@ import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ }
* uniformly, as AbstractFiles.
*/
class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) {
-} \ No newline at end of file
+}
+
+object NoMsilFile extends MsilFile(null) { }
diff --git a/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala b/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala
new file mode 100644
index 0000000000..36cf42d7ec
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala
@@ -0,0 +1,30 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package io
+
+import java.io.InputStream
+
+/** A distinguished object so you can avoid both null
+ * and Option.
+ */
+object NoAbstractFile extends AbstractFile {
+ def absolute: AbstractFile = this
+ def container: AbstractFile = this
+ def create(): Unit = ???
+ def delete(): Unit = ???
+ def file: JFile = null
+ def input: InputStream = null
+ def isDirectory: Boolean = false
+ def iterator: Iterator[AbstractFile] = Iterator.empty
+ def lastModified: Long = 0L
+ def lookupName(name: String, directory: Boolean): AbstractFile = null
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = null
+ def name: String = ""
+ def output: java.io.OutputStream = null
+ def path: String = ""
+ override def toByteArray = Array[Byte]()
+}
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index e5748b7c23..18409cfffe 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -37,7 +37,7 @@ trait Patterns extends ast.TreeDSL {
// }
private lazy val dummyMethod =
- new TermSymbol(NoSymbol, NoPosition, newTermName("matching$dummy"))
+ NoSymbol.newTermSymbol(newTermName("matching$dummy"))
// Fresh patterns
def emptyPatterns(i: Int): List[Pattern] = List.fill(i)(NoPattern)
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
index 36227c1052..da913a1601 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
@@ -28,7 +28,7 @@ trait Plugins {
val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map Path.apply
val classes = Plugin.loadAllFrom(jars, dirs, settings.disable.value)
- // Lach plugin must only be instantiated once. A common pattern
+ // Each plugin must only be instantiated once. A common pattern
// is to register annotation checkers during object construction, so
// creating multiple plugin instances will leave behind stale checkers.
classes map (Plugin.instantiate(_, this))
diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
index 967b582f11..c76a04c6ba 100644
--- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
@@ -47,20 +47,7 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr
/** Prints the message with the given position indication. */
def printMessage(posIn: Position, msg: String) {
- val pos = if (posIn eq null) NoPosition
- else if (posIn.isDefined) posIn.inUltimateSource(posIn.source)
- else posIn
- pos match {
- case FakePos(fmsg) =>
- printMessage(fmsg+" "+msg)
- case NoPosition =>
- printMessage(msg)
- case _ =>
- val buf = new StringBuilder(msg)
- val file = pos.source.file
- printMessage((if (shortname) file.name else file.path)+":"+pos.line+": "+msg)
- printSourceLine(pos)
- }
+ printMessage(Position.formatMessage(posIn, msg, shortname))
}
def print(pos: Position, msg: String, severity: Severity) {
printMessage(pos, clabel(severity) + msg)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index efd5323ce2..6806ca03ba 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -96,6 +96,7 @@ trait ScalaSettings extends AbsScalaSettings
val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions.") .
withPostSetHook(set => List(YmethodInfer, overrideObjects) foreach (_.value = set.value))
// YdepMethTpes, YvirtClasses,
+ val Xmacros = BooleanSetting ("-Xmacros", "Enable macros.")
/** Compatibility stubs for options whose value name did
* not previously match the option name.
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 4205c2ff36..942ec1fa86 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -207,7 +207,7 @@ abstract class SymbolLoaders {
protected def doComplete(root: Symbol) {
assert(root.isPackageClass, root)
- root.setInfo(new PackageClassInfoType(new Scope(), root))
+ root.setInfo(new PackageClassInfoType(newScope, root))
val sourcepaths = classpath.sourcepaths
for (classRep <- classpath.classes if platform.doLoad(classRep)) {
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 099145d3ae..811bb6ee05 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -536,8 +536,8 @@ abstract class ClassfileParser {
addEnclosingTParams(clazz)
parseInnerClasses() // also sets the isScala / isScalaRaw / hasMeta flags, see r15956
// get the class file parser to reuse scopes.
- instanceDefs = new Scope
- staticDefs = new Scope
+ instanceDefs = newScope
+ staticDefs = newScope
val classInfo = ClassInfoType(parseParents, instanceDefs, clazz)
val staticInfo = ClassInfoType(List(), staticDefs, statics)
@@ -606,7 +606,7 @@ abstract class ClassfileParser {
def parseField() {
val jflags = in.nextChar
var sflags = toScalaFieldFlags(jflags)
- if ((sflags & PRIVATE) != 0L && !global.settings.XO.value) {
+ if ((sflags & PRIVATE) != 0L && !global.settings.optimise.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
@@ -637,7 +637,7 @@ abstract class ClassfileParser {
def parseMethod() {
val jflags = in.nextChar.toInt
var sflags = toScalaMethodFlags(jflags)
- if (isPrivate(jflags) && !global.settings.XO.value) {
+ if (isPrivate(jflags) && !global.settings.optimise.value) {
val name = pool.getName(in.nextChar)
if (name == nme.CONSTRUCTOR)
sawPrivateConstructor = true
@@ -645,7 +645,7 @@ abstract class ClassfileParser {
} else {
if ((jflags & JAVA_ACC_BRIDGE) != 0)
sflags |= BRIDGE
- if ((sflags & PRIVATE) != 0L && global.settings.XO.value) {
+ if ((sflags & PRIVATE) != 0L && global.settings.optimise.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala
index ead431c8d7..eb8e7a14a5 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala
@@ -108,7 +108,7 @@ abstract class MetaParser{
}
protected def parseClass() {
- locals = new Scope
+ locals = newScope
def parse(): Type = {
nextToken()
if (token == "[") {
@@ -130,7 +130,7 @@ abstract class MetaParser{
protected def parseMethod() {
val globals = locals
- locals = if (locals eq null) new Scope else new Scope(locals)
+ locals = if (locals eq null) newScope else newNestedScope(locals)
def parse(): Type = {
nextToken();
if (token == "[") PolyType(parseTypeParams(), parse())
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 2eddd36db0..25ae6f33d2 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -59,7 +59,7 @@ abstract class Pickler extends SubComponent {
}
}
// If there are any erroneous types in the tree, then we will crash
- // when we pickle it: so let's report an erorr instead. We know next
+ // when we pickle it: so let's report an error instead. We know next
// to nothing about what happened, but our supposition is a lot better
// than "bad type: <error>" in terms of explanatory power.
for (t <- unit.body ; if t.isErroneous) {
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
index 6c238f52cc..e11a5a4ad9 100644
--- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
@@ -165,7 +165,7 @@ abstract class TypeParser {
clrTypes.sym2type(typMgdPtr) = clazzMgdPtr
/* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance,
because there's no metadata-level representation for a "boxed valuetype" */
- val instanceDefsMgdPtr = new Scope
+ val instanceDefsMgdPtr = newScope
val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr)
clazzMgdPtr.setFlag(flags)
clazzMgdPtr.setInfo(classInfoMgdPtr)
@@ -196,8 +196,8 @@ abstract class TypeParser {
}
}
/* END CLR generics (snippet 2) */
- instanceDefs = new Scope
- staticDefs = new Scope
+ instanceDefs = newScope
+ staticDefs = newScope
val classInfoAsInMetadata = {
val ifaces: Array[MSILType] = typ.getInterfaces()
@@ -212,7 +212,7 @@ abstract class TypeParser {
}
// methods, properties, events, fields are entered in a moment
if (canBeTakenAddressOf) {
- val instanceDefsBoxed = new Scope
+ val instanceDefsBoxed = newScope
ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed)
} else
ClassInfoType(parents.toList, instanceDefs, clazz)
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 8f5d308b8f..1c41e68532 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -77,31 +77,51 @@ abstract class AddInterfaces extends InfoTransform {
def implClassPhase = currentRun.erasurePhase.next
/** Return the implementation class of a trait; create a new one of one does not yet exist */
- def implClass(iface: Symbol): Symbol = implClassMap.getOrElse(iface, {
- atPhase(implClassPhase) {
- val implName = nme.implClassName(iface.name)
- var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
- if (impl != NoSymbol && settings.XO.value) {
- log("unlinking impl class " + impl)
- iface.owner.info.decls.unlink(impl)
- impl = NoSymbol
- }
- if (impl == NoSymbol) {
- impl = iface.cloneSymbolImpl(iface.owner)
- impl.name = implName
- impl.sourceFile = iface.sourceFile
- if (iface.owner.isClass)
- iface.owner.info.decls enter impl
+ def implClass(iface: Symbol): Symbol = {
+ iface.info
+
+ implClassMap.getOrElse(iface, {
+ atPhase(implClassPhase) {
+ log("%s.implClass == %s".format(iface, iface.implClass))
+ val implName = nme.implClassName(iface.name)
+ var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
+ impl.info
+
+ val originalImpl = impl
+ val originalImplString = originalImpl.hasFlagsToString(-1L)
+ if (impl != NoSymbol) {
+ // Unlink a pre-existing symbol only if the implementation class is
+ // visible on the compilation classpath. In general this is true under
+ // -optimise and not otherwise, but the classpath can use arbitrary
+ // logic so the classpath must be queried.
+ if (classPath.context.isValidName(implName + ".class")) {
+ log("unlinking impl class " + impl)
+ iface.owner.info.decls.unlink(impl)
+ impl = NoSymbol
+ }
+ else log("not unlinking existing " + impl + " as the impl class is not visible on the classpath.")
+ }
+ if (impl == NoSymbol) {
+ impl = iface.cloneSymbolImpl(iface.owner)
+ impl.name = implName
+ impl.sourceFile = iface.sourceFile
+ if (iface.owner.isClass)
+ iface.owner.info.decls enter impl
+ }
+ if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
+ impl setPos iface.pos
+ impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
+ impl setInfo new LazyImplClassType(iface)
+ implClassMap(iface) = impl
+ debuglog(
+ "generating impl class " + impl + " " + impl.hasFlagsToString(-1L) + " in " + iface.owner + (
+ if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.fullLocationString + " " + originalImplString + ")"
+ )
+ )
+ impl
}
- if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
- impl setPos iface.pos
- impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
- impl setInfo new LazyImplClassType(iface)
- implClassMap(iface) = impl
- debuglog("generating impl class " + impl + " in " + iface.owner)//debug
- impl
- }
- })
+ })
+ }
/** A lazy type to set the info of an implementation class
* The parents of an implementation class for trait iface are:
@@ -119,7 +139,7 @@ abstract class AddInterfaces extends InfoTransform {
* given the decls ifaceDecls of its interface.
*/
private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = {
- val decls = new Scope
+ val decls = newScope
if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol)
decls enter (
implClass.newMethod(nme.MIXIN_CONSTRUCTOR, implClass.pos)
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 23817545e2..d1c71faf1e 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -447,7 +447,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val closureClass = clazz.newClass(nme.delayedInitArg.toTypeName, impl.pos, SYNTHETIC | FINAL)
val closureParents = List(AbstractFunctionClass(0).tpe, ScalaObjectClass.tpe)
- closureClass setInfoAndEnter new ClassInfoType(closureParents, new Scope, closureClass)
+ closureClass setInfoAndEnter new ClassInfoType(closureParents, newScope, closureClass)
val outerField = (
closureClass
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 71696c24e6..b342b95742 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -742,7 +742,7 @@ abstract class Erasure extends AddInterfaces
//println("computing bridges for " + owner)//DEBUG
assert(phase == currentRun.erasurePhase)
val site = owner.thisType
- val bridgesScope = new Scope
+ val bridgesScope = newScope
val bridgeTarget = new mutable.HashMap[Symbol, Symbol]
var bridges: List[Tree] = List()
val opc = atPhase(currentRun.explicitouterPhase) {
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index b17fd7b9b0..4fa5b52de3 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -65,7 +65,7 @@ abstract class Flatten extends InfoTransform {
case ClassInfoType(parents, decls, clazz) =>
var parents1 = parents
val decls1 = scopeTransform(clazz) {
- val decls1 = new Scope()
+ val decls1 = newScope
if (clazz.isPackageClass) {
atPhase(phase.next)(decls foreach (decls1 enter _))
} else {
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 0f11161914..712298bd89 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -9,7 +9,8 @@ package transform
import symtab._
import Flags._
import util.TreeSet
-import scala.collection.mutable.{ LinkedHashMap, ListBuffer }
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.LinkedHashMap
abstract class LambdaLift extends InfoTransform {
import global._
@@ -64,6 +65,8 @@ abstract class LambdaLift extends InfoTransform {
/** The set of symbols that need to be renamed. */
private val renamable = newSymSet
+ private val renamableImplClasses = mutable.HashMap[Name, Symbol]() withDefaultValue NoSymbol
+
/** A flag to indicate whether new free variables have been found */
private var changedFreeVars: Boolean = _
@@ -152,7 +155,21 @@ abstract class LambdaLift extends InfoTransform {
tree match {
case ClassDef(_, _, _, _) =>
liftedDefs(tree.symbol) = Nil
- if (sym.isLocal) renamable addEntry sym
+ if (sym.isLocal) {
+ // Don't rename implementation classes independently of their interfaces. If
+ // the interface is to be renamed, then we will rename the implementation
+ // class at that time. You'd think we could call ".implClass" on the trait
+ // rather than collecting them in another map, but that seems to fail for
+ // exactly the traits being renamed here (i.e. defined in methods.)
+ //
+ // !!! - it makes no sense to have methods like "implClass" and
+ // "companionClass" which fail for an arbitrary subset of nesting
+ // arrangements, and then have separate methods which attempt to compensate
+ // for that failure. There should be exactly one method for any given
+ // entity which always gives the right answer.
+ if (sym.isImplClass) renamableImplClasses(nme.interfaceName(sym.name)) = sym
+ else renamable addEntry sym
+ }
case DefDef(_, _, _, _, _, _) =>
if (sym.isLocal) {
renamable addEntry sym
@@ -196,8 +213,8 @@ abstract class LambdaLift extends InfoTransform {
for (caller <- called.keys ; callee <- called(caller) ; fvs <- free get callee ; fv <- fvs)
markFree(fv, caller)
} while (changedFreeVars)
-
- for (sym <- renamable) {
+
+ def renameSym(sym: Symbol) {
val originalName = sym.name
val base = sym.name + nme.NAME_JOIN_STRING + (
if (sym.isAnonymousFunction && sym.owner.isMethod)
@@ -211,6 +228,25 @@ abstract class LambdaLift extends InfoTransform {
debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name))
}
+ /** Rename a trait's interface and implementation class in coordinated fashion.
+ */
+ def renameTrait(traitSym: Symbol, implSym: Symbol) {
+ val originalImplName = implSym.name
+ renameSym(traitSym)
+ implSym.name = nme.implClassName(traitSym.name)
+
+ debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name))
+ }
+
+ for (sym <- renamable) {
+ // If we renamed a trait from Foo to Foo$1, we must rename the implementation
+ // class from Foo$class to Foo$1$class. (Without special consideration it would
+ // become Foo$class$1 instead.)
+ val implClass = if (sym.isTrait) renamableImplClasses(sym.name) else NoSymbol
+ if ((implClass ne NoSymbol) && (sym.owner == implClass.owner)) renameTrait(sym, implClass)
+ else renameSym(sym)
+ }
+
atPhase(phase.next) {
for ((owner, freeValues) <- free.toList) {
val newFlags = SYNTHETIC | ( if (owner.isClass) PARAMACCESSOR | PrivateLocal else PARAM )
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index bf19cf10e9..bd29336703 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -403,12 +403,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
assert(clazz.sourceModule != NoSymbol || clazz.isAnonymousClass,
clazz + " has no sourceModule: sym = " + sym + " sym.tpe = " + sym.tpe)
parents1 = List()
- decls1 = new Scope(decls.toList filter isImplementedStatically)
+ decls1 = newScopeWith(decls.toList filter isImplementedStatically: _*)
} else if (!parents.isEmpty) {
parents1 = parents.head :: (parents.tail map toInterface)
}
}
- //decls1 = atPhase(phase.next)(new Scope(decls1.toList))//debug
+ //decls1 = atPhase(phase.next)(newScopeWith(decls1.toList: _*))//debug
if ((parents1 eq parents) && (decls1 eq decls)) tp
else ClassInfoType(parents1, decls1, clazz)
@@ -480,7 +480,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** The rootContext used for typing */
private val rootContext =
- erasure.NoContext.make(EmptyTree, RootClass, new Scope)
+ erasure.NoContext.make(EmptyTree, RootClass, newScope)
/** The typer */
private var localTyper: erasure.Typer = _
diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
index 70f8d37585..1200e973c5 100644
--- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
+++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
@@ -74,7 +74,7 @@ abstract class OverridingPairs {
}
/** The symbols that can take part in an overriding pair */
- private val decls = new Scope
+ private val decls = newScope
// fill `decls` with overriding shadowing overridden */
{ def fillDecls(bcs: List[Symbol], deferredflag: Int) {
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index fd826fb6d8..4a104857db 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -502,7 +502,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
typeEnv(sClass) = env
this.specializedClass((clazz, env0)) = sClass
- val decls1 = new Scope // declarations of the newly specialized class 'sClass'
+ val decls1 = newScope // declarations of the newly specialized class 'sClass'
var oldClassTParams: List[Symbol] = Nil // original unspecialized type parameters
var newClassTParams: List[Symbol] = Nil // unspecialized type parameters of 'specializedClass' (cloned)
@@ -1089,7 +1089,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
if (tparams.nonEmpty) " (poly)" else "",
clazz, parents1, phase)
)
- val newScope = new Scope(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz))
+ val newScope = newScopeWith(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz): _*)
// If tparams.isEmpty, this is just the ClassInfoType.
polyType(tparams, ClassInfoType(parents1, newScope, clazz))
case _ =>
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 56d9658377..ab4a2141a9 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -259,7 +259,7 @@ abstract class UnCurry extends InfoTransform
else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
- anonClass setInfo ClassInfoType(parents, new Scope, anonClass)
+ anonClass setInfo ClassInfoType(parents, newScope, anonClass)
val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL)
applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe)
anonClass addAnnotation serialVersionUIDAnnotation
@@ -422,7 +422,7 @@ abstract class UnCurry extends InfoTransform
if (tp.typeSymbol.isBottomClass) getManifest(AnyClass.tpe)
else if (!manifestOpt.tree.isEmpty) manifestOpt.tree
else if (tp.bounds.hi ne tp) getManifest(tp.bounds.hi)
- else localTyper.getManifestTree(tree.pos, tp, false)
+ else localTyper.getManifestTree(tree, tp, false)
}
atPhase(phase.next) {
localTyper.typedPos(pos) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 16d55c26ca..18c7635b1e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -23,6 +23,7 @@ trait Analyzer extends AnyRef
with Macros
with NamesDefaults
with TypeDiagnostics
+ with ContextErrors
{
val global : Global
import global._
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
new file mode 100644
index 0000000000..a762e44bda
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -0,0 +1,1052 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.tools.nsc
+package typechecker
+
+import scala.collection.{ mutable, immutable }
+import scala.tools.util.StringOps.{ countElementsAsString, countAsString }
+import symtab.Flags.{ PRIVATE, PROTECTED }
+import scala.tools.util.EditDistance.similarString
+
+trait ContextErrors {
+ self: Analyzer =>
+
+ import global._
+
+ object ErrorKinds extends Enumeration {
+ type ErrorKind = Value
+ val Normal, Access, Ambiguous, Divergent = Value
+ }
+
+ import ErrorKinds.ErrorKind
+
+ trait AbsTypeError extends Throwable {
+ def errPos: Position
+ def errMsg: String
+ def kind: ErrorKind
+ }
+
+ case class NormalTypeError(underlyingTree: Tree, errMsg: String, kind: ErrorKind = ErrorKinds.Normal)
+ extends AbsTypeError {
+
+ def errPos:Position = underlyingTree.pos
+ override def toString() = "[Type error at:" + underlyingTree.pos + "] " + errMsg
+ }
+
+ case class SymbolTypeError(underlyingSym: Symbol, errMsg: String, kind: ErrorKind = ErrorKinds.Normal)
+ extends AbsTypeError {
+
+ def errPos = underlyingSym.pos
+ }
+
+ case class TypeErrorWrapper(ex: TypeError, kind: ErrorKind = ErrorKinds.Normal)
+ extends AbsTypeError {
+ def errMsg = ex.msg
+ def errPos = ex.pos
+ }
+
+ case class TypeErrorWithUnderlyingTree(tree: Tree, ex: TypeError, kind: ErrorKind = ErrorKinds.Normal)
+ extends AbsTypeError {
+ def errMsg = ex.msg
+ def errPos = tree.pos
+ }
+
+ case class AmbiguousTypeError(underlyingTree: Tree, errPos: Position, errMsg: String, kind: ErrorKind = ErrorKinds.Ambiguous) extends AbsTypeError
+
+ case class PosAndMsgTypeError(errPos: Position, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError
+
+ object ErrorUtils {
+ def issueNormalTypeError(tree: Tree, msg: String)(implicit context: Context) {
+ issueTypeError(NormalTypeError(tree, msg))
+ }
+
+ def issueSymbolTypeError(sym: Symbol, msg: String)(implicit context: Context) {
+ issueTypeError(SymbolTypeError(sym, msg))
+ }
+
+ def issueDivergentImplicitsError(tree: Tree, msg: String)(implicit context: Context) {
+ issueTypeError(NormalTypeError(tree, msg, ErrorKinds.Divergent))
+ }
+
+ def issueAmbiguousTypeError(pre: Type, sym1: Symbol, sym2: Symbol, err: AmbiguousTypeError)(implicit context: Context) {
+ context.issueAmbiguousError(pre, sym1, sym2, err)
+ }
+
+ def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) }
+
+ def typeErrorMsg(found: Type, req: Type, possiblyMissingArgs: Boolean) = {
+ def missingArgsMsg = if (possiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else ""
+ "type mismatch" + foundReqMsg(found, req) + missingArgsMsg
+ }
+ }
+
+ import ErrorUtils._
+
+ trait TyperContextErrors {
+ self: Typer =>
+
+ import infer.setError
+
+ object TyperErrorGen {
+ implicit val context0: Context = infer.getContext
+
+ def UnstableTreeError(tree: Tree) = {
+ def addendum = {
+ "\n Note that "+tree.symbol+" is not stable because its type, "+tree.tpe+", is volatile."
+ }
+ issueNormalTypeError(tree,
+ "stable identifier required, but "+tree+" found." + (
+ if (isStableExceptVolatile(tree)) addendum else ""))
+ setError(tree)
+ }
+
+ def NoImplicitFoundError(tree: Tree, param: Symbol) = {
+ 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
+ }
+ }
+ issueNormalTypeError(tree, errMsg)
+ }
+
+ def AdaptTypeError(tree: Tree, found: Type, req: Type) = {
+ // 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
+ // members present, then display along with the expected members. This is done here because
+ // this is the last point where we still have access to the original tree, rather than just
+ // the found/req types.
+ val foundType: Type = req.normalize match {
+ case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass =>
+ val retyped = typed (tree.duplicate setType null)
+ val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic)
+
+ if (foundDecls.isEmpty) found
+ else {
+ // The members arrive marked private, presumably because there was no
+ // expected type and so they're considered members of an anon class.
+ foundDecls foreach (_ resetFlag (PRIVATE | PROTECTED))
+ // TODO: if any of the found parents match up with required parents after normalization,
+ // print the error so that they match. The major beneficiary there would be
+ // java.lang.Object vs. AnyRef.
+ refinedType(found.parents, found.typeSymbol.owner, foundDecls, tree.pos)
+ }
+ case _ =>
+ found
+ }
+ assert(!found.isErroneous && !req.isErroneous)
+
+ issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req))) )
+ if (settings.explaintypes.value)
+ explainTypes(found, req)
+ }
+
+ def WithFilterError(tree: Tree, ex: AbsTypeError) = {
+ issueTypeError(ex)
+ setError(tree)
+ }
+
+ def ParentTypesError(templ: Template, ex: TypeError) = {
+ templ.tpe = null
+ issueNormalTypeError(templ, ex.getMessage())
+ }
+
+ // additional parentTypes errors
+ def ConstrArgsInTraitParentTpeError(arg: Tree, parent: Symbol) =
+ issueNormalTypeError(arg, parent + " is a trait; does not take constructor arguments")
+
+ def MissingTypeArgumentsParentTpeError(supertpt: Tree) =
+ issueNormalTypeError(supertpt, "missing type arguments")
+
+ // typedIdent
+ def AmbiguousIdentError(tree: Tree, name: Name, msg: String) =
+ NormalTypeError(tree, "reference to " + name + " is ambiguous;\n" + msg)
+
+ def SymbolNotFoundError(tree: Tree, name: Name, owner: Symbol, startingIdentCx: Context) = {
+ // This laborious determination arrived at to keep the tests working.
+ val calcSimilar = (
+ name.length > 2 && (
+ startingIdentCx.reportErrors
+ || startingIdentCx.enclClassOrMethod.reportErrors
+ )
+ )
+ // avoid calculating if we're in "silent" mode.
+ // name length check to limit unhelpful suggestions for e.g. "x" and "b1"
+ val similar = {
+ if (!calcSimilar) ""
+ else {
+ val allowed = (
+ startingIdentCx.enclosingContextChain
+ flatMap (ctx => ctx.scope.toList ++ ctx.imports.flatMap(_.allImportedSymbols))
+ filter (sym => sym.isTerm == name.isTermName)
+ filterNot (sym => sym.isPackage || sym.isSynthetic || sym.hasMeaninglessName)
+ )
+ val allowedStrings = (
+ allowed.map("" + _.name).distinct.sorted
+ filterNot (s => (s contains '$') || (s contains ' '))
+ )
+ similarString("" + name, allowedStrings)
+ }
+ }
+ NormalTypeError(tree, "not found: "+decodeWithKind(name, owner) + similar)
+ }
+
+ // typedAppliedTypeTree
+ def AppliedTypeNoParametersError(tree: Tree, errTpe: Type) = {
+ issueNormalTypeError(tree, errTpe + " does not take type parameters")
+ setError(tree)
+ }
+
+ def AppliedTypeWrongNumberOfArgsError(tree: Tree, tpt: Tree, tparams: List[Symbol]) = {
+ val tptSafeString: String = try {
+ tpt.tpe.toString()
+ } catch {
+ case _: CyclicReference =>
+ tpt.toString()
+ }
+ val msg = "wrong number of type arguments for "+tptSafeString+", should be "+tparams.length
+ issueNormalTypeError(tree, msg)
+ setError(tree)
+ }
+
+ // typedTypeDef
+ def LowerBoundError(tree: TypeDef, lowB: Type, highB: Type) =
+ issueNormalTypeError(tree, "lower bound "+lowB+" does not conform to upper bound "+highB)
+
+ def HiddenSymbolWithError[T <: Tree](tree: T): T =
+ setError(tree)
+
+ def SymbolEscapesScopeError[T <: Tree](tree: T, badSymbol: Symbol): T = {
+ val modifierString = if (badSymbol.isPrivate) "private " else ""
+ issueNormalTypeError(tree, modifierString + badSymbol + " escapes its defining scope as part of type "+tree.tpe)
+ setError(tree)
+ }
+
+ // typedDefDef
+ def StarParamNotLastError(param: Tree) =
+ issueNormalTypeError(param, "*-parameter must come last")
+
+ def StarWithDefaultError(meth: Symbol) =
+ issueSymbolTypeError(meth, "a parameter section with a `*'-parameter is not allowed to have default arguments")
+
+ def InvalidConstructorDefError(ddef: Tree) =
+ issueNormalTypeError(ddef, "constructor definition not allowed here")
+
+ def DeprecatedParamNameError(param: Symbol, name: Name) =
+ issueSymbolTypeError(param, "deprecated parameter name "+ name +" has to be distinct from any other parameter name (deprecated or not).")
+
+ // computeParamAliases
+ def SuperConstrReferenceError(tree: Tree) =
+ NormalTypeError(tree, "super constructor cannot be passed a self reference unless parameter is declared by-name")
+
+ def SuperConstrArgsThisReferenceError(tree: Tree) =
+ NormalTypeError(tree, "super constructor arguments cannot reference unconstructed `this`")
+
+ // typedValDef
+ def VolatileValueError(vdef: Tree) =
+ issueNormalTypeError(vdef, "values cannot be volatile")
+
+ def FinalVolatileVarError(vdef: Tree) =
+ issueNormalTypeError(vdef, "final vars cannot be volatile")
+
+ def LocalVarUninitializedError(vdef: Tree) =
+ issueNormalTypeError(vdef, "local variables must be initialized")
+
+ //typedAssign
+ def AssignmentError(tree: Tree, varSym: Symbol) = {
+ issueNormalTypeError(tree,
+ if (varSym != null && varSym.isValue) "reassignment to val"
+ else "assignment to non variable")
+ setError(tree)
+ }
+
+ def UnexpectedTreeAssignmentConversionError(tree: Tree) = {
+ issueNormalTypeError(tree, "Unexpected tree during assignment conversion.")
+ setError(tree)
+ }
+
+ def MultiDimensionalArrayError(tree: Tree) = {
+ issueNormalTypeError(tree, "cannot create a generic multi-dimensional array of more than "+ definitions.MaxArrayDims+" dimensions")
+ setError(tree)
+ }
+
+ //typedSuper
+ def MixinMissingParentClassNameError(tree: Tree, mix: Name, clazz: Symbol) =
+ issueNormalTypeError(tree, mix+" does not name a parent class of "+clazz)
+
+ def AmbiguousParentClassError(tree: Tree) =
+ issueNormalTypeError(tree, "ambiguous parent class qualifier")
+
+ //typedSelect
+ def NotAMemberError(sel: Tree, qual: Tree, name: Name) = {
+ 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
+ )
+ }
+ issueNormalTypeError(sel, errMsg)
+ // the error has to be set for the copied tree, otherwise
+ // the error remains persistent acros multiple compilations
+ // and causes problems
+ //setError(sel)
+ }
+
+ //typedNew
+ def IsAbstractError(tree: Tree, sym: Symbol) = {
+ issueNormalTypeError(tree, sym + " is abstract; cannot be instantiated")
+ setError(tree)
+ }
+
+ def DoesNotConformToSelfTypeError(tree: Tree, sym: Symbol, tpe0: Type) = {
+ issueNormalTypeError(tree, sym + " cannot be instantiated because it does not conform to its self-type " + tpe0)
+ setError(tree)
+ }
+
+ //typedEta
+ def UnderscoreEtaError(tree: Tree) = {
+ issueNormalTypeError(tree, "_ must follow method; cannot follow " + tree.tpe)
+ setError(tree)
+ }
+
+ //typedReturn
+ def ReturnOutsideOfDefError(tree: Tree) = {
+ issueNormalTypeError(tree, "return outside method definition")
+ setError(tree)
+ }
+
+ def ReturnWithoutTypeError(tree: Tree, owner: Symbol) = {
+ issueNormalTypeError(tree, owner + " has return statement; needs result type")
+ setError(tree)
+ }
+
+ //typedBind
+ def VariableInPatternAlternativeError(tree: Tree) = {
+ issueNormalTypeError(tree, "illegal variable in pattern alternative")
+ //setError(tree)
+ }
+
+ //typedCase
+ def StarPositionInPatternError(tree: Tree) =
+ issueNormalTypeError(tree, "_* may only come last")
+
+ //typedFunction
+ def MaxFunctionArityError(fun: Tree) = {
+ issueNormalTypeError(fun, "implementation restricts functions to " + definitions.MaxFunctionArity + " parameters")
+ setError(fun)
+ }
+
+ def WrongNumberOfParametersError(tree: Tree, argpts: List[Type]) = {
+ issueNormalTypeError(tree, "wrong number of parameters; expected = " + argpts.length)
+ setError(tree)
+ }
+
+ def MissingParameterTypeError(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
+ })
+
+ issueNormalTypeError(vparam, "missing parameter type" + suffix)
+ }
+
+ def ConstructorsOrderError(tree: Tree) = {
+ issueNormalTypeError(tree, "called constructor's definition must precede calling constructor's definition")
+ setError(tree)
+ }
+
+ def OnlyDeclarationsError(tree: Tree) = {
+ issueNormalTypeError(tree, "only declarations allowed here")
+ setError(tree)
+ }
+
+ // typedAnnotation
+ def AnnotationNotAConstantError(tree: Tree) =
+ NormalTypeError(tree, "annotation argument needs to be a constant; found: " + tree)
+
+ def AnnotationArgNullError(tree: Tree) =
+ NormalTypeError(tree, "annotation argument cannot be null")
+
+ def ArrayConstantsError(tree: Tree) =
+ NormalTypeError(tree, "Array constants have to be specified using the `Array(...)' factory method")
+
+ def ArrayConstantsTypeMismatchError(tree: Tree, pt: Type) =
+ NormalTypeError(tree, "found array constant, expected argument of type " + pt)
+
+ def UnexpectedTreeAnnotation(tree: Tree) =
+ NormalTypeError(tree, "unexpected tree in annotation: "+ tree)
+
+ def AnnotationTypeMismatchError(tree: Tree, expected: Type, found: Type) =
+ NormalTypeError(tree, "expected annotation of type " + expected + ", found " + found)
+
+ def MultipleArgumentListForAnnotationError(tree: Tree) =
+ NormalTypeError(tree, "multiple argument lists on classfile annotation")
+
+ def UnknownAnnotationNameError(tree: Tree, name: Name) =
+ NormalTypeError(tree, "unknown annotation argument name: " + name)
+
+ def DuplicateValueAnnotationError(tree: Tree, name: Name) =
+ NormalTypeError(tree, "duplicate value for annotation argument " + name)
+
+ def ClassfileAnnotationsAsNamedArgsError(tree: Tree) =
+ NormalTypeError(tree, "classfile annotation arguments have to be supplied as named arguments")
+
+ def AnnotationMissingArgError(tree: Tree, annType: Type, sym: Symbol) =
+ NormalTypeError(tree, "annotation " + annType.typeSymbol.fullName + " is missing argument " + sym.name)
+
+ def NestedAnnotationError(tree: Tree, annType: Type) =
+ NormalTypeError(tree, "nested classfile annotations must be defined in java; found: "+ annType)
+
+ def UnexpectedTreeAnnotationError(tree: Tree, unexpected: Tree) =
+ NormalTypeError(tree, "unexpected tree after typing annotation: "+ unexpected)
+
+ // TODO no test case
+ //typedExistentialTypeTree
+ def AbstractionFromVolatileTypeError(vd: ValDef) =
+ issueNormalTypeError(vd, "illegal abstraction from value with volatile type "+vd.symbol.tpe)
+
+ def TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree) = {
+ issueNormalTypeError(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ setError(tree)
+ }
+
+ def TypedApplyDoesNotTakeTpeParametersError(tree: Tree, fun: Tree) = {
+ issueNormalTypeError(tree, treeSymTypeMsg(fun)+" does not take type parameters.")
+ setError(tree)
+ }
+
+ // doTypeApply
+ //tryNamesDefaults
+ def WrongNumberOfArgsError(tree: Tree, fun: Tree) =
+ NormalTypeError(tree, "wrong number of arguments for "+ treeSymTypeMsg(fun))
+
+ def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree) =
+ NormalTypeError(tree, "too many arguments for "+treeSymTypeMsg(fun))
+
+ // can it still happen? see test case neg/t960.scala
+ // TODO no test case
+ def OverloadedUnapplyError(tree: Tree) =
+ issueNormalTypeError(tree, "cannot resolve overloaded unapply")
+
+ def UnapplyWithSingleArgError(tree: Tree) =
+ issueNormalTypeError(tree, "an unapply method must accept a single argument.")
+
+ def MultipleVarargError(tree: Tree) =
+ NormalTypeError(tree, "when using named arguments, the vararg parameter has to be specified exactly once")
+
+ def ModuleUsingCompanionClassDefaultArgsErrror(tree: Tree) =
+ NormalTypeError(tree, "module extending its companion class cannot use default constructor arguments")
+
+ def NotEnoughArgsError(tree: Tree, fun0: Tree, missing0: List[Symbol]) = {
+ 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
+ }
+ NormalTypeError(tree, notEnoughArgumentsMsg(fun0, missing0))
+ }
+
+ //doTypedApply - patternMode
+ // TODO: missing test case
+ def TooManyArgsPatternError(fun: Tree) =
+ NormalTypeError(fun, "too many arguments for unapply pattern, maximum = "+definitions.MaxTupleArity)
+
+ def WrongNumberArgsPatternError(tree: Tree, fun: Tree) =
+ NormalTypeError(tree, "wrong number of arguments for "+treeSymTypeMsg(fun))
+
+ def ApplyWithoutArgsError(tree: Tree, fun: Tree) =
+ NormalTypeError(tree, fun.tpe+" does not take parameters")
+
+ //checkClassType
+ def TypeNotAStablePrefixError(tpt: Tree, pre: Type) = {
+ issueNormalTypeError(tpt, "type "+pre+" is not a stable prefix")
+ setError(tpt)
+ }
+
+ def ClassTypeRequiredError(tree: Tree, found: AnyRef) = {
+ issueNormalTypeError(tree, "class type required but "+found+" found")
+ setError(tree)
+ }
+
+ // validateParentClasses
+ def ParentSuperSubclassError(parent: Tree, superclazz: Symbol,
+ parentSym: Symbol, mixin: Symbol) =
+ NormalTypeError(parent, "illegal inheritance; super"+superclazz+
+ "\n is not a subclass of the super"+parentSym+
+ "\n of the mixin " + mixin)
+
+ def ParentNotATraitMixinError(parent: Tree, mixin: Symbol) =
+ NormalTypeError(parent, mixin+" needs to be a trait to be mixed in")
+
+ def ParentFinalInheritanceError(parent: Tree, mixin: Symbol) =
+ NormalTypeError(parent, "illegal inheritance from final "+mixin)
+
+ def ParentSealedInheritanceError(parent: Tree, psym: Symbol) =
+ NormalTypeError(parent, "illegal inheritance from sealed " + psym + ": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath)
+
+ def ParentSelfTypeConformanceError(parent: Tree, selfType: Type) =
+ NormalTypeError(parent,
+ "illegal inheritance;\n self-type "+selfType+" does not conform to "+
+ parent +"'s selftype "+parent.tpe.typeOfThis)
+
+ // TODO: missing test case
+ def ParentInheritedTwiceError(parent: Tree, parentSym: Symbol) =
+ NormalTypeError(parent, parentSym+" is inherited twice")
+
+ //adapt
+ def MissingArgsForMethodTpeError(tree: Tree, meth: Symbol) = {
+ issueNormalTypeError(tree,
+ "missing arguments for " + meth.fullLocationString + (
+ if (meth.isConstructor) ""
+ else ";\nfollow this method with `_' if you want to treat it as a partially applied function"
+ ))
+ setError(tree)
+ }
+
+ def MissingTypeParametersError(tree: Tree) = {
+ issueNormalTypeError(tree, tree.symbol+" takes type parameters")
+ setError(tree)
+ }
+
+ def KindArityMismatchError(tree: Tree, pt: Type) = {
+ issueNormalTypeError(tree,
+ tree.tpe+" takes "+countElementsAsString(tree.tpe.typeParams.length, "type parameter")+
+ ", expected: "+countAsString(pt.typeParams.length))
+ setError(tree)
+ }
+
+ def CaseClassConstructorError(tree: Tree) = {
+ issueNormalTypeError(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
+ setError(tree)
+ }
+
+ //TODO Needs test case
+ def ConstructorPrefixError(tree: Tree, restpe: Type) = {
+ issueNormalTypeError(tree, restpe.prefix+" is not a legal prefix for a constructor")
+ setError(tree)
+ }
+
+ // SelectFromTypeTree
+ def TypeSelectionFromVolatileTypeError(tree: Tree, qual: Tree) = {
+ issueNormalTypeError(tree, "illegal type selection from volatile type "+qual.tpe)
+ setError(tree)
+ }
+
+ // packedType
+ def InferTypeWithVolatileTypeSelectionError(tree: Tree, pre: Type) =
+ issueNormalTypeError(tree, "Inferred type "+tree.tpe+" contains type selection from volatile type "+pre)
+
+ def AbstractExistentiallyOverParamerizedTpeError(tree: Tree, tp: Type) =
+ issueNormalTypeError(tree, "can't existentially abstract over parameterized type " + tp)
+
+ //manifestTreee
+ def MissingManifestError(tree: Tree, full: Boolean, tp: Type) = {
+ issueNormalTypeError(tree, "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp)
+ setError(tree)
+ }
+
+ // TODO needs test case
+ // cases where we do not necessarily return trees
+ def DependentMethodTpeConversionToFunctionError(tree: Tree, tp: Type) =
+ issueNormalTypeError(tree, "method with dependent type "+tp+" cannot be converted to function value")
+
+ //checkStarPatOK
+ def StarPatternWithVarargParametersError(tree: Tree) =
+ issueNormalTypeError(tree, "star patterns must correspond with varargs parameters")
+
+ // TODO missing test case
+ def FinitaryError(tparam: Symbol) =
+ issueSymbolTypeError(tparam, "class graph is not finitary because type parameter "+tparam.name+" is expansively recursive")
+
+ // TODO missing test case for a second case
+ def QualifyingClassError(tree: Tree, qual: Name) = {
+ issueNormalTypeError(tree,
+ if (qual.isEmpty) tree + " can be used only in a class, object, or template"
+ else qual + " is not an enclosing class")
+ setError(tree)
+ }
+
+ // def stabilize
+ def NotAValueError(tree: Tree, sym: Symbol) = {
+ issueNormalTypeError(tree, sym.kindString + " " + sym.fullName + " is not a value")
+ setError(tree)
+ }
+
+ // checkNoDoubleDefs...
+ def DefDefinedTwiceError(sym0: Symbol, sym1: Symbol) =
+ issueSymbolTypeError(sym0, sym1+" is defined twice"+
+ {if(!settings.debug.value) "" else " in "+context0.unit}+
+ {if (sym0.isMacro && sym1.isMacro) " \n(note that macros cannot be overloaded)" else ""})
+
+ // cyclic errors
+ def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) =
+ issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0))
+
+ def CyclicReferenceError(errPos: Position, lockedSym: Symbol) =
+ issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym))
+
+ def MacroExpandError(tree: Tree, t: Any) = {
+ issueNormalTypeError(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass)
+ setError(tree)
+ }
+ }
+ }
+
+ trait InferencerContextErrors {
+ 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
+ }
+ }
+
+ object InferErrorGen {
+
+ implicit val context0 = getContext
+
+ object PolyAlternativeErrorKind extends Enumeration {
+ type ErrorType = Value
+ val WrongNumber, NoParams, ArgsDoNotConform = Value
+ }
+
+ private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) =
+ if (sym1.hasDefaultFlag && sym2.hasDefaultFlag && sym1.enclClass == sym2.enclClass) {
+ val methodName = nme.defaultGetterToMethod(sym1.name)
+ (sym1.enclClass.pos,
+ "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
+ " define default arguments")
+ } else {
+ (pos,
+ ("ambiguous reference to overloaded definition,\n" +
+ "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
+ "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
+ "\nmatch " + rest)
+ )
+ }
+
+ def AccessError(tree: Tree, sym: Symbol, pre: Type, owner0: Symbol, explanation: String) = {
+ def errMsg = {
+ val location = if (sym.isClassConstructor) owner0 else pre.widen
+
+ underlying(sym).fullLocationString + " cannot be accessed in " +
+ location + explanation
+ }
+ NormalTypeError(tree, errMsg, ErrorKinds.Access)
+ }
+
+ def NoMethodInstanceError(fn: Tree, args: List[Tree], msg: String) =
+ issueNormalTypeError(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)
+
+ // TODO: no test case
+ def NoConstructorInstanceError(tree: Tree, restpe: Type, pt: Type, msg: String) = {
+ issueNormalTypeError(tree,
+ "constructor of type " + restpe +
+ " cannot be uniquely instantiated to expected type " + pt +
+ "\n --- because ---\n" + msg)
+ setError(tree)
+ }
+
+ def ConstrInstantiationError(tree: Tree, restpe: Type, pt: Type) = {
+ issueNormalTypeError(tree,
+ "constructor cannot be instantiated to expected type" + foundReqMsg(restpe, pt))
+ setError(tree)
+ }
+
+ def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) =
+ issueNormalTypeError(tree,
+ applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
+
+ def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol,
+ firstCompeting: Symbol, argtpes: List[Type], pt: Type) = {
+ val msg0 =
+ "argument types " + argtpes.mkString("(", ",", ")") +
+ (if (pt == WildcardType) "" else " and expected result type " + pt)
+ val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0)
+ issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg))
+ }
+
+ def NoBestExprAlternativeError(tree: Tree, pt: Type) =
+ issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(tree.symbol.tpe, pt, isPossiblyMissingArgs(tree.symbol.tpe, pt))))
+
+ def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type) = {
+ val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, "expected type " + pt)
+ setError(tree)
+ issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg))
+ }
+
+ // checkBounds
+ def KindBoundErrors(tree: Tree, prefix: String, targs: List[Type],
+ tparams: List[Symbol], kindErrors: List[String]) = {
+ issueNormalTypeError(tree,
+ 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", ", ", ""))
+ }
+
+ def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type],
+ tparams: List[Symbol], kindErrors: List[String]) = {
+ 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))
+ ()
+ }
+
+ issueNormalTypeError(tree,
+ prefix + "type arguments " + targs.mkString("[", ",", "]") +
+ " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
+ (tparams map (_.defString)).mkString("[", ",", "]"))
+ }
+
+ //substExpr
+ def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) =
+ issueNormalTypeError(tree,
+ "polymorphic expression cannot be instantiated to expected type" +
+ foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt))
+
+ //checkCheckable
+ def TypePatternOrIsInstanceTestError(tree: Tree, tp: Type) =
+ issueNormalTypeError(tree, "type "+tp+" cannot be used in a type pattern or isInstanceOf test")
+
+ def PatternTypeIncompatibleWithPtError1(tree: Tree, pattp: Type, pt: Type) =
+ issueNormalTypeError(tree, "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt))
+
+ def IncompatibleScrutineeTypeError(tree: Tree, pattp: Type, pt: Type) =
+ issueNormalTypeError(tree, "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt))
+
+ def PatternTypeIncompatibleWithPtError2(pat: Tree, pt1: Type, pt: Type) = {
+ 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
+ }
+ issueNormalTypeError(pat, errMsg)
+ }
+
+ def PolyAlternativeError(tree: Tree, argtypes: List[Type], sym: Symbol, err: PolyAlternativeErrorKind.ErrorType) = {
+ import PolyAlternativeErrorKind._
+ val msg =
+ err match {
+ case WrongNumber =>
+ "wrong number of type parameters for " + treeSymTypeMsg(tree)
+ case NoParams =>
+ treeSymTypeMsg(tree) + " does not take type parameters"
+ case ArgsDoNotConform =>
+ "type arguments " + argtypes.mkString("[", ",", "]") +
+ " conform to the bounds of none of the overloaded alternatives of\n "+sym+
+ ": "+sym.info
+ }
+ issueNormalTypeError(tree, msg)
+ ()
+ }
+ }
+ }
+
+ trait NamerContextErrors {
+ self: Namer =>
+
+ object NamerErrorGen {
+
+ implicit val context0 = context
+
+ object SymValidateErrors extends Enumeration {
+ val ImplicitConstr, ImplicitNotTerm, ImplicitTopObject,
+ OverrideClass, SealedNonClass, AbstractNonClass,
+ OverrideConstr, AbstractOverride, LazyAndEarlyInit,
+ ByNameParameter, AbstractVar = Value
+ }
+
+ object DuplicatesErrorKinds extends Enumeration {
+ val RenamedTwice, AppearsTwice = Value
+ }
+
+ import SymValidateErrors._
+ import DuplicatesErrorKinds._
+ import symtab.Flags
+
+ def TypeSigError(tree: Tree, ex: TypeError) = {
+ ex match {
+ case CyclicReference(sym, info: TypeCompleter) =>
+ issueNormalTypeError(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+ case _ =>
+ context0.issue(TypeErrorWithUnderlyingTree(tree, ex))
+ }
+ }
+
+ def GetterDefinedTwiceError(getter: Symbol) =
+ issueSymbolTypeError(getter, getter+" is defined twice")
+
+ def ValOrValWithSetterSuffixError(tree: Tree) =
+ issueNormalTypeError(tree, "Names of vals or vars may not end in `_='")
+
+ def PrivateThisCaseClassParameterError(tree: Tree) =
+ issueNormalTypeError(tree, "private[this] not allowed for case class parameters")
+
+ def BeanPropertyAnnotationLimitationError(tree: Tree) =
+ issueNormalTypeError(tree, "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import")
+
+ def BeanPropertyAnnotationFieldWithoutLetterError(tree: Tree) =
+ issueNormalTypeError(tree, "`BeanProperty' annotation can be applied only to fields that start with a letter")
+
+ def BeanPropertyAnnotationPrivateFieldError(tree: Tree) =
+ issueNormalTypeError(tree, "`BeanProperty' annotation can be applied only to non-private fields")
+
+ def DoubleDefError(currentSym: Symbol, prevSym: Symbol) = {
+ val s1 = if (prevSym.isModule) "case class companion " else ""
+ val s2 = if (prevSym.isSynthetic) "(compiler-generated) " + s1 else ""
+ val s3 = if (prevSym.isCase) "case class " + prevSym.name else "" + prevSym
+
+ issueSymbolTypeError(currentSym, prevSym.name + " is already defined as " + s2 + s3)
+ }
+
+ def MaxParametersCaseClassError(tree: Tree) =
+ issueNormalTypeError(tree, "Implementation restriction: case classes cannot have more than " + definitions.MaxFunctionArity + " parameters.")
+
+ def InheritsItselfError(tree: Tree) =
+ issueNormalTypeError(tree, tree.tpe.typeSymbol+" inherits itself")
+
+ def MissingParameterOrValTypeError(vparam: Tree) =
+ issueNormalTypeError(vparam, "missing parameter type")
+
+ def RootImportError(tree: Tree) =
+ issueNormalTypeError(tree, "_root_ cannot be imported")
+
+ def SymbolValidationError(sym: Symbol, errKind: SymValidateErrors.Value) {
+ val msg = errKind match {
+ case ImplicitConstr =>
+ "`implicit' modifier not allowed for constructors"
+
+ case ImplicitNotTerm =>
+ "`implicit' modifier can be used only for values, variables and methods"
+
+ case ImplicitTopObject =>
+ "`implicit' modifier cannot be used for top-level objects"
+
+ case OverrideClass =>
+ "`override' modifier not allowed for classes"
+
+ case SealedNonClass =>
+ "`sealed' modifier can be used only for classes"
+
+ case AbstractNonClass =>
+ "`abstract' modifier can be used only for classes; it should be omitted for abstract members"
+
+ case OverrideConstr =>
+ "`override' modifier not allowed for constructors"
+
+ case AbstractOverride =>
+ "`abstract override' modifier only allowed for members of traits"
+
+ case LazyAndEarlyInit =>
+ "`lazy' definitions may not be initialized early"
+
+ case ByNameParameter =>
+ "pass-by-name arguments not allowed for case class parameters"
+
+ case AbstractVar =>
+ "only classes can have declared but undefined members" + abstractVarMessage(sym)
+
+ }
+ issueSymbolTypeError(sym, msg)
+ }
+
+
+ def AbstractMemberWithModiferError(sym: Symbol, flag: Int) =
+ issueSymbolTypeError(sym, "abstract member may not have " + Flags.flagsToString(flag) + " modifier")
+
+ def IllegalModifierCombination(sym: Symbol, flag1: Int, flag2: Int) =
+ issueSymbolTypeError(sym, "illegal combination of modifiers: %s and %s for: %s".format(
+ Flags.flagsToString(flag1), Flags.flagsToString(flag2), sym))
+
+ def IllegalDependentMethTpeError(sym: Symbol)(context: Context) = {
+ val errorAddendum =
+ ": parameter appears in the type of another parameter in the same section or an earlier one"
+ issueSymbolTypeError(sym, "illegal dependent method type" + errorAddendum)(context)
+ }
+
+ def DuplicatesError(tree: Tree, name: Name, kind: DuplicatesErrorKinds.Value) = {
+ val msg = kind match {
+ case RenamedTwice =>
+ "is renamed twice"
+ case AppearsTwice =>
+ "appears twice as a target of a renaming"
+ }
+
+ issueNormalTypeError(tree, name.decode + " " + msg)
+ }
+ }
+ }
+
+ trait ImplicitsContextErrors {
+ self: ImplicitSearch =>
+
+ import definitions._
+
+ def AmbiguousImplicitError(info1: ImplicitInfo, info2: ImplicitInfo,
+ pre1: String, pre2: String, trailer: String)
+ (isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = {
+ if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) {
+ val coreMsg =
+ pre1+" "+info1.sym.fullLocationString+" of type "+info1.tpe+"\n "+
+ pre2+" "+info2.sym.fullLocationString+" of type "+info2.tpe+"\n "+
+ trailer
+ val errMsg =
+ if (isView) {
+ val found = pt.typeArgs(0)
+ val req = pt.typeArgs(1)
+ def defaultExplanation =
+ "Note that implicit conversions are not applicable because they are ambiguous:\n "+
+ coreMsg+"are possible conversion functions from "+ found+" to "+req
+
+ def explanation = {
+ val sym = found.typeSymbol
+ // Explain some common situations a bit more clearly.
+ if (AnyRefClass.tpe <:< req) {
+ if (sym == AnyClass || sym == UnitClass) {
+ "Note: " + sym.name + " is not implicitly converted to AnyRef. You can safely\n" +
+ "pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so."
+ }
+ else boxedClass get sym match {
+ case Some(boxed) =>
+ "Note: an implicit exists from " + sym.fullName + " => " + boxed.fullName + ", but\n" +
+ "methods inherited from Object are rendered ambiguous. This is to avoid\n" +
+ "a blanket implicit which would convert any " + sym.fullName + " to any AnyRef.\n" +
+ "You may wish to use a type ascription: `x: " + boxed.fullName + "`."
+ case _ =>
+ defaultExplanation
+ }
+ }
+ else defaultExplanation
+ }
+
+ typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + "\n" + explanation
+ } else {
+ "ambiguous implicit values:\n "+coreMsg + "match expected type "+pt
+ }
+ context.issueAmbiguousError(AmbiguousTypeError(tree, tree.pos, errMsg))
+ }
+ }
+
+ def DivergingImplicitExpansionError(tree: Tree, pt: Type, sym: Symbol)(implicit context0: Context) =
+ issueDivergentImplicitsError(tree,
+ "diverging implicit expansion for type "+pt+"\nstarting with "+
+ sym.fullLocationString)
+ }
+
+ object NamesDefaultsErrorsGen {
+ import typer.infer.setError
+
+ def NameClashError(sym: Symbol, arg: Tree)(implicit context: Context) = {
+ setError(arg) // to distinguish it from ambiguous reference error
+
+ 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)
+ issueSymbolTypeError(sym, errMsg)
+ }
+
+ def AmbiguousReferenceInNamesDefaultError(arg: Tree, name: Name)(implicit context: Context) = {
+ if (!arg.isErroneous) { // check if name clash wasn't reported already
+ issueNormalTypeError(arg,
+ "reference to "+ name +" is ambiguous; it is both a method parameter "+
+ "and a variable in scope.")
+ setError(arg)
+ } else arg
+ }
+
+ def UnknownParameterNameNamesDefaultError(arg: Tree, name: Name)(implicit context: Context) = {
+ issueNormalTypeError(arg, "unknown parameter name: " + name)
+ setError(arg)
+ }
+
+ def DoubleParamNamesDefaultError(arg: Tree, name: Name)(implicit context: Context) = {
+ issueNormalTypeError(arg, "parameter specified twice: "+ name)
+ setError(arg)
+ }
+
+ def PositionalAfterNamedNamesDefaultError(arg: Tree)(implicit context: Context) = {
+ issueNormalTypeError(arg, "positional after named argument.")
+ setError(arg)
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index faff4ccab2..a1ade61dad 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc
package typechecker
import symtab.Flags._
-import scala.collection.mutable.ListBuffer
+import scala.collection.mutable.{LinkedHashSet, Set}
import annotation.tailrec
/**
@@ -66,8 +66,7 @@ trait Contexts { self: Analyzer =>
sc.depth += 1
}
val c = sc.make(unit, tree, sc.owner, sc.scope, sc.imports)
- c.reportAmbiguousErrors = !erasedTypes
- c.reportGeneralErrors = !erasedTypes
+ if (erasedTypes) c.setThrowErrors() else c.setReportErrors()
c.implicitsEnabled = !erasedTypes
c
}
@@ -83,7 +82,17 @@ trait Contexts { self: Analyzer =>
}
}
+ private object Errors {
+ final val ReportErrors = 1 << 0
+ final val BufferErrors = 1 << 1
+ final val AmbiguousErrors = 1 << 2
+ final val notThrowMask = ReportErrors | BufferErrors
+ final val AllMask = ReportErrors | BufferErrors | AmbiguousErrors
+ }
+
class Context private[typechecker] {
+ import Errors._
+
var unit: CompilationUnit = NoCompilationUnit
var tree: Tree = _ // Tree associated with this context
var owner: Symbol = NoSymbol // The current owner
@@ -109,8 +118,6 @@ trait Contexts { self: Analyzer =>
// (the call to the super or self constructor in the first line of a constructor)
// in this context the object's fields should not be in scope
- var reportAmbiguousErrors = false
- var reportGeneralErrors = false
var diagnostic: List[String] = Nil // these messages are printed when issuing an error
var implicitsEnabled = false
var checking = false
@@ -138,12 +145,41 @@ trait Contexts { self: Analyzer =>
tparams
}
- def withoutReportingErrors[T](op: => T): T = {
- val saved = reportGeneralErrors
- reportGeneralErrors = false
- try op
- finally reportGeneralErrors = saved
+ private[this] var mode = 0
+ private[this] val buffer = LinkedHashSet[AbsTypeError]()
+
+ def errBuffer = buffer
+ def hasErrors = buffer.nonEmpty
+
+ def state: Int = mode
+ def restoreState(state0: Int) = mode = state0
+
+ def reportErrors = (state & ReportErrors) != 0
+ def bufferErrors = (state & BufferErrors) != 0
+ def ambiguousErrors = (state & AmbiguousErrors) != 0
+ def throwErrors = (state & notThrowMask) == 0
+
+ def setReportErrors() = mode = (ReportErrors | AmbiguousErrors)
+ def setBufferErrors() = {
+ assert(bufferErrors || !hasErrors, "When entering the buffer state, context has to be clean. Current buffer: " + buffer)
+ mode = BufferErrors
+ }
+ def setThrowErrors() = mode &= (~AllMask)
+ def setAmbiguousErrors(report: Boolean) = if (report) mode |= AmbiguousErrors else mode &= notThrowMask
+
+ def updateBuffer(errors: Set[AbsTypeError]) = buffer ++= errors
+ def condBufferFlush(removeP: AbsTypeError => Boolean) {
+ val elems = buffer.filter(removeP)
+ buffer --= elems
}
+ def flushBuffer() { buffer.clear() }
+ def flushAndReturnBuffer(): Set[AbsTypeError] = {
+ val current = buffer.clone()
+ buffer.clear()
+ current
+ }
+
+ def logError(err: AbsTypeError) = buffer += err
def withImplicitsDisabled[T](op: => T): T = {
val saved = implicitsEnabled
@@ -183,8 +219,7 @@ trait Contexts { self: Analyzer =>
c.depth = if (scope == this.scope) this.depth else this.depth + 1
c.imports = imports
c.inSelfSuperCall = inSelfSuperCall
- c.reportAmbiguousErrors = this.reportAmbiguousErrors
- c.reportGeneralErrors = this.reportGeneralErrors
+ c.restoreState(this.state)
c.diagnostic = this.diagnostic
c.typingIndentLevel = typingIndentLevel
c.implicitsEnabled = this.implicitsEnabled
@@ -196,10 +231,10 @@ trait Contexts { self: Analyzer =>
c
}
+ // TODO: remove? Doesn't seem to be used
def make(unit: CompilationUnit): Context = {
val c = make(unit, EmptyTree, owner, scope, imports)
- c.reportAmbiguousErrors = true
- c.reportGeneralErrors = true
+ c.setReportErrors()
c.implicitsEnabled = true
c
}
@@ -218,7 +253,7 @@ trait Contexts { self: Analyzer =>
make(unit, tree, owner, scope, imports)
def makeNewScope(tree: Tree, owner: Symbol): Context =
- make(tree, owner, new Scope(scope))
+ make(tree, owner, newNestedScope(scope))
// IDE stuff: distinguish between scopes created for typing and scopes created for naming.
def make(tree: Tree, owner: Symbol): Context =
@@ -229,8 +264,8 @@ trait Contexts { self: Analyzer =>
def makeSilent(reportAmbiguousErrors: Boolean, newtree: Tree = tree): Context = {
val c = make(newtree)
- c.reportGeneralErrors = false
- c.reportAmbiguousErrors = reportAmbiguousErrors
+ c.setBufferErrors()
+ c.setAmbiguousErrors(reportAmbiguousErrors)
c
}
@@ -242,13 +277,11 @@ trait Contexts { self: Analyzer =>
def makeConstructorContext = {
var baseContext = enclClass.outer
- //todo: find out why we need next line
while (baseContext.tree.isInstanceOf[Template])
baseContext = baseContext.outer
val argContext = baseContext.makeNewScope(tree, owner)
argContext.inSelfSuperCall = true
- argContext.reportGeneralErrors = this.reportGeneralErrors
- argContext.reportAmbiguousErrors = this.reportAmbiguousErrors
+ argContext.restoreState(this.state)
def enterElems(c: Context) {
def enterLocalElems(e: ScopeEntry) {
if (e != null && e.owner == c.scope) {
@@ -275,41 +308,41 @@ trait Contexts { self: Analyzer =>
private def unitError(pos: Position, msg: String) =
unit.error(pos, if (checking) "\n**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
+ def issue(err: AbsTypeError) {
+ if (reportErrors) unitError(err.errPos, addDiagString(err.errMsg))
+ else if (bufferErrors) { buffer += err }
+ else throw new TypeError(err.errPos, err.errMsg)
+ }
+
+ def issueAmbiguousError(pre: Type, sym1: Symbol, sym2: Symbol, err: AbsTypeError) {
+ if (ambiguousErrors) {
+ if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
+ unitError(err.errPos, err.errMsg)
+ } else if (bufferErrors) { buffer += err }
+ else throw new TypeError(err.errPos, err.errMsg)
+ }
+
+ def issueAmbiguousError(err: AbsTypeError) {
+ if (ambiguousErrors)
+ unitError(err.errPos, addDiagString(err.errMsg))
+ else if (bufferErrors) { buffer += err }
+ else throw new TypeError(err.errPos, err.errMsg)
+ }
+
+ // TODO remove
def error(pos: Position, err: Throwable) =
- if (reportGeneralErrors) unitError(pos, addDiagString(err.getMessage()))
+ if (reportErrors) unitError(pos, addDiagString(err.getMessage()))
else throw err
def error(pos: Position, msg: String) = {
val msg1 = addDiagString(msg)
- if (reportGeneralErrors) unitError(pos, msg1)
+ if (reportErrors) unitError(pos, msg1)
else throw new TypeError(pos, msg1)
}
- def warning(pos: Position, msg: String) = {
- if (reportGeneralErrors) unit.warning(pos, msg)
- }
-
- def ambiguousError(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) {
- val (reportPos, msg) = (
- if (sym1.hasDefaultFlag && sym2.hasDefaultFlag && sym1.enclClass == sym2.enclClass) {
- val methodName = nme.defaultGetterToMethod(sym1.name)
- (sym1.enclClass.pos,
- "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
- " define default arguments")
- }
- else {
- (pos,
- ("ambiguous reference to overloaded definition,\n" +
- "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
- "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
- "\nmatch " + rest)
- )
- }
- )
- if (reportAmbiguousErrors) {
- if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
- unit.error(reportPos, msg)
- } else throw new TypeError(pos, msg)
+ def warning(pos: Position, msg: String): Unit = warning(pos, msg, false)
+ def warning(pos: Position, msg: String, force: Boolean) {
+ if (reportErrors || force) unit.warning(pos, msg)
}
def isLocal(): Boolean = tree match {
@@ -343,8 +376,8 @@ trait Contexts { self: Analyzer =>
def enclosingContextChain: List[Context] = this :: outer.enclosingContextChain
- override def toString = "Context(%s@%s unit=%s scope=%s)".format(
- owner.fullName, tree.shortClass, unit, scope.##
+ override def toString = "Context(%s@%s unit=%s scope=%s errors=%b)".format(
+ owner.fullName, tree.shortClass, unit, scope.##, hasErrors
)
/** Is `sub` a subclass of `base` or a companion object of such a subclass?
*/
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 53e88b33c8..eaf1b1ffbc 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -31,20 +31,26 @@ trait Implicits {
import typeDebug.{ ptTree, ptBlock, ptLine }
import global.typer.{ printTyping, deindentTyping, indentTyping, printInference }
+ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult =
+ inferImplicit(tree, pt, reportAmbiguous, isView, context, true)
+
/** Search for an implicit value. See the comment on `result` at the end of class `ImplicitSearch`
* for more info how the search is conducted.
- * @param tree The tree for which the implicit needs to be inserted.
- * (the inference might instantiate some of the undetermined
- * type parameters of that tree.
- * @param pt The expected type of the implicit.
- * @param reportAmbiguous Should ambiguous implicit errors be reported?
- * False iff we search for a view to find out
- * whether one type is coercible to another.
- * @param isView We are looking for a view
- * @param context The current context
- * @return A search result
+ * @param tree The tree for which the implicit needs to be inserted.
+ * (the inference might instantiate some of the undetermined
+ * type parameters of that tree.
+ * @param pt The expected type of the implicit.
+ * @param reportAmbiguous Should ambiguous implicit errors be reported?
+ * False iff we search for a view to find out
+ * whether one type is coercible to another.
+ * @param isView We are looking for a view
+ * @param context The current context
+ * @param saveAmbiguousDivergent False if any divergent/ambiguous errors should be ignored after
+ * implicits search,
+ * true if they should be reported (used in further typechecking).
+ * @return A search result
*/
- def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = {
+ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context, saveAmbiguousDivergent: Boolean): SearchResult = {
printInference("[infer %s] %s with pt=%s in %s".format(
if (isView) "view" else "implicit",
tree, pt, context.owner.enclClass)
@@ -64,8 +70,10 @@ trait Implicits {
val start = startTimer(implicitNanos)
if (printInfers && !tree.isEmpty && !context.undetparams.isEmpty)
printTyping("typing implicit: %s %s".format(tree, context.undetparamsString))
-
- val result = new ImplicitSearch(tree, pt, isView, context.makeImplicit(reportAmbiguous)).bestImplicit
+ val implicitSearchContext = context.makeImplicit(reportAmbiguous)
+ val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext).bestImplicit
+ if (saveAmbiguousDivergent && implicitSearchContext.hasErrors)
+ context.updateBuffer(implicitSearchContext.errBuffer.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent))
printInference("[infer implicit] inferred " + result)
context.undetparams = context.undetparams filterNot result.subst.from.contains
@@ -94,21 +102,13 @@ trait Implicits {
private val ManifestSymbols = Set(PartialManifestClass, FullManifestClass, OptManifestClass)
- /** Map all type params in given list to WildcardType
- * @param tparams The list of type parameters to map
- * @param tp The type in which to do the mapping
- */
- private def tparamsToWildcards(tparams: List[Symbol], tp: Type) =
- if (tparams.isEmpty) tp
- else tp.instantiateTypeParams(tparams, tparams map (_ => WildcardType))
-
/* Map a polytype to one in which all type parameters and argument-dependent types are replaced by wildcards.
* Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate DebruijnIndex types
* when checking whether `b` is a valid implicit, as we haven't even searched a value for the implicit arg `x`,
* so we have to approximate (otherwise it is excluded a priori).
*/
private def depoly(tp: Type): Type = tp match {
- case PolyType(tparams, restpe) => tparamsToWildcards(tparams, ApproximateDependentMap(restpe))
+ case PolyType(tparams, restpe) => deriveTypeWithWildcards(tparams)(ApproximateDependentMap(restpe))
case _ => ApproximateDependentMap(tp)
}
@@ -213,7 +213,7 @@ trait Implicits {
/** An extractor for types of the form ? { name: (? >: argtpe <: Any*)restp }
*/
object HasMethodMatching {
- val dummyMethod = new TermSymbol(NoSymbol, NoPosition, newTermName("typer$dummy"))
+ val dummyMethod = NoSymbol.newTermSymbol(newTermName("typer$dummy"))
def templateArgType(argtpe: Type) = new BoundedWildcardType(TypeBounds.lower(argtpe))
def apply(name: Name, argtpes: List[Type], restpe: Type): Type = {
@@ -252,7 +252,8 @@ trait Implicits {
* @param isView We are looking for a view
* @param context0 The context used for the implicit search
*/
- class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context) extends Typer(context0) {
+ class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context)
+ extends Typer(context0) with ImplicitsContextErrors {
printTyping(
ptBlock("new ImplicitSearch",
"tree" -> tree,
@@ -335,50 +336,6 @@ trait Implicits {
incCounter(implicitSearchCount)
- /** Issues an error signalling ambiguous implicits */
- private def ambiguousImplicitError(info1: ImplicitInfo, info2: ImplicitInfo,
- pre1: String, pre2: String, trailer: String) =
- if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) {
- val coreMsg =
- pre1+" "+info1.sym.fullLocationString+" of type "+info1.tpe+"\n "+
- pre2+" "+info2.sym.fullLocationString+" of type "+info2.tpe+"\n "+
- trailer
- error(tree.pos,
- if (isView) {
- val found = pt.typeArgs(0)
- val req = pt.typeArgs(1)
- def defaultExplanation =
- "Note that implicit conversions are not applicable because they are ambiguous:\n "+
- coreMsg+"are possible conversion functions from "+ found+" to "+req
-
- def explanation = {
- val sym = found.typeSymbol
- // Explain some common situations a bit more clearly.
- if (AnyRefClass.tpe <:< req) {
- if (sym == AnyClass || sym == UnitClass) {
- "Note: " + sym.name + " is not implicitly converted to AnyRef. You can safely\n" +
- "pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so."
- }
- else boxedClass get sym match {
- case Some(boxed) =>
- "Note: an implicit exists from " + sym.fullName + " => " + boxed.fullName + ", but\n" +
- "methods inherited from Object are rendered ambiguous. This is to avoid\n" +
- "a blanket implicit which would convert any " + sym.fullName + " to any AnyRef.\n" +
- "You may wish to use a type ascription: `x: " + boxed.fullName + "`."
- case _ =>
- defaultExplanation
- }
- }
- else defaultExplanation
- }
-
- typeErrorMsg(found, req) + "\n" + explanation
- }
- else {
- "ambiguous implicit values:\n "+coreMsg + "match expected type "+pt
- })
- }
-
/** The type parameters to instantiate */
val undetParams = if (isView) List() else context.outer.undetparams
@@ -408,9 +365,7 @@ trait Implicits {
// println("DivergentImplicit for pt:"+ pt +", open implicits:"+context.openImplicits) //@MDEBUG
if (context.openImplicits.tail.isEmpty) {
if (!(pt.isErroneous))
- context.unit.error(
- tree.pos, "diverging implicit expansion for type "+pt+"\nstarting with "+
- info.sym.fullLocationString)
+ DivergingImplicitExpansionError(tree, pt, info.sym)(context)
SearchFailure
} else {
throw DivergentImplicit
@@ -586,6 +541,9 @@ trait Implicits {
else
typed1(itree, EXPRmode, wildPt)
+ if (context.hasErrors)
+ return fail("typed implicit %s has errors".format(info.sym.fullLocationString))
+
incCounter(typedImplicits)
printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt))
@@ -605,8 +563,8 @@ trait Implicits {
}
}
- if (itree2.tpe.isError)
- SearchFailure
+ if (context.hasErrors)
+ fail("hasMatchingSymbol reported threw error(s)")
else if (!hasMatchingSymbol(itree1))
fail("candidate implicit %s is shadowed by other implicit %s".format(
info.sym.fullLocationString, itree1.symbol.fullLocationString))
@@ -628,7 +586,9 @@ trait Implicits {
false, lubDepth(List(itree2.tpe, pt)))
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
- checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
+ checkBounds(itree2, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
+ if (context.hasErrors)
+ return fail("type parameters weren't correctly instantiated outside of the implicit tree")
// filter out failures from type inference, don't want to remove them from undetParams!
// we must be conservative in leaving type params in undetparams
@@ -654,21 +614,29 @@ trait Implicits {
// re-typecheck)
// TODO: the return tree is ignored. This seems to make
// no difference, but it's bad practice regardless.
- itree2 match {
+
+
+ val checked = 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
}
- val result = new SearchResult(itree2, subst)
- incCounter(foundImplicits)
- printInference("[success] found %s for pt %s".format(result, ptInstantiated))
- result
+
+ if (context.hasErrors)
+ fail("typing TypeApply reported errors for the implicit tree")
+ else {
+ val result = new SearchResult(checked, subst)
+ incCounter(foundImplicits)
+ printInference("[success] found %s for pt %s".format(result, ptInstantiated))
+ result
+ }
}
else fail("incompatible: %s does not match expected type %s".format(itree2.tpe, ptInstantiated))
}
}
catch {
- case ex: TypeError => fail(ex.getMessage())
+ case ex: TypeError =>
+ fail(ex.getMessage())
}
}
@@ -802,7 +770,11 @@ trait Implicits {
catch divergenceHandler
tryImplicitInfo(i) match {
- case SearchFailure => rankImplicits(is, acc)
+ case SearchFailure =>
+ // We don't want errors that occur during checking implicit info
+ // to influence the check of further infos.
+ context.condBufferFlush(_.kind != ErrorKinds.Divergent)
+ rankImplicits(is, acc)
case newBest =>
best = newBest
val newPending = undoLog undo {
@@ -837,7 +809,8 @@ trait Implicits {
case chosen :: rest =>
rest find (alt => !improves(chosen, alt)) match {
case Some(competing) =>
- ambiguousImplicitError(chosen, competing, "both", "and", "")
+ AmbiguousImplicitError(chosen, competing, "both", "and", "")(isView, pt, tree)(context)
+ return SearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala
case _ =>
if (isView) chosen.useCountView += 1
else chosen.useCountArg += 1
@@ -1238,12 +1211,14 @@ trait Implicits {
incCounter(inscopeImplicitHits)
}
if (result == SearchFailure) {
+ val previousErrs = context.flushAndReturnBuffer()
val failstart = startTimer(oftypeFailNanos)
val succstart = startTimer(oftypeSucceedNanos)
result = implicitManifestOrOfExpectedType(pt)
if (result == SearchFailure) {
+ context.updateBuffer(previousErrs)
stopTimer(oftypeFailNanos, failstart)
} else {
stopTimer(oftypeSucceedNanos, succstart)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index b1612f24ef..eac657da19 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -191,12 +191,14 @@ trait Infer {
private val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR)
/** The context-dependent inferencer part */
- class Inferencer(context: Context) {
+ class Inferencer(context: Context) extends InferencerContextErrors {
+ import InferErrorGen._
+
/* -- Error Messages --------------------------------------------------- */
def setError[T <: Tree](tree: T): T = {
def name = newTermName("<error: " + tree.symbol + ">")
- def errorClass = if (context.reportGeneralErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass
- def errorValue = if (context.reportGeneralErrors) context.owner.newErrorValue(name) else stdErrorValue
+ def errorClass = if (context.reportErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass
+ def errorValue = if (context.reportErrors) context.owner.newErrorValue(name) else stdErrorValue
def errorSym = if (tree.isType) errorClass else errorValue
if (tree.hasSymbol)
@@ -205,59 +207,12 @@ trait Infer {
tree setType ErrorType
}
- def error(pos: Position, msg: String) {
- context.error(pos, msg)
- }
-
- 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)
- }
- }
-
- def typeErrorMsg(found: Type, req: Type) = {
- def isPossiblyMissingArgs = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req)
- def missingArgsMsg = if (isPossiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else ""
-
- "type mismatch" + foundReqMsg(found, req) + missingArgsMsg
- }
-
- def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = {
- // 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
- // members present, then display along with the expected members. This is done here because
- // this is the last point where we still have access to the original tree, rather than just
- // the found/req types.
- val foundType: Type = req.normalize match {
- case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass =>
- val retyped = typer typed (tree.duplicate setType null)
- val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic)
-
- if (foundDecls.isEmpty) found
- else {
- // The members arrive marked private, presumably because there was no
- // expected type and so they're considered members of an anon class.
- foundDecls foreach (_ resetFlag (PRIVATE | PROTECTED))
- // TODO: if any of the found parents match up with required parents after normalization,
- // print the error so that they match. The major beneficiary there would be
- // java.lang.Object vs. AnyRef.
- refinedType(found.parents, found.typeSymbol.owner, foundDecls, tree.pos)
- }
- case _ =>
- found
- }
- typeError(tree.pos, foundType, req)
- setError(tree)
- }
+ def getContext = context
+ def issue(err: AbsTypeError): Unit = context.issue(err)
+
+ def isPossiblyMissingArgs(found: Type, req: Type) = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req)
+
def explainTypes(tp1: Type, tp2: Type) =
withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2))
@@ -279,7 +234,6 @@ trait Infer {
var sym1 = sym filter (alt => context.isAccessible(alt, pre, site.isInstanceOf[Super]))
// Console.println("check acc " + (sym, sym1) + ":" + (sym.tpe, sym1.tpe) + " from " + pre);//DEBUG
-
if (sym1 == NoSymbol && sym.isJavaDefined && context.unit.isJava) // don't try to second guess Java; see #4402
sym1 = sym
@@ -289,7 +243,7 @@ trait Infer {
Console.println(tree)
Console.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType))
}
- new AccessError(tree, sym, pre,
+ ErrorUtils.issueTypeError(AccessError(tree, sym, pre, context.enclClass.owner,
if (settings.check.isDefault)
analyzer.lastAccessCheckDetails
else
@@ -303,7 +257,8 @@ trait Infer {
"context.owner" -> context.owner,
"context.outer.enclClass.owner" -> context.outer.enclClass.owner
)
- )
+ ))(context)
+ setError(tree)
}
else {
if (sym1.isTerm)
@@ -316,10 +271,11 @@ trait Infer {
if (settings.debug.value) ex.printStackTrace
val sym2 = underlyingSymbol(sym1)
val itype = pre.memberType(sym2)
- 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)).emit()
+ ErrorUtils.issueTypeError(
+ AccessError(tree, sym, pre, context.enclClass.owner,
+ "\n because its instance type "+itype+
+ (if ("malformed type: "+itype.toString==ex.msg) " is malformed"
+ else " contains a "+ex.msg)))(context)
ErrorType
}
}
@@ -762,25 +718,20 @@ trait Infer {
false
}
- /** Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors).
+ /**
+ * Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors).
+ * The chance of TypeErrors should be reduced through context errors
*/
private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type,
argtpes0: List[Type], pt: Type): Boolean = {
- val reportAmbiguousErrors = context.reportAmbiguousErrors
- context.reportAmbiguousErrors = false
- try {
- isApplicable(undetparams, ftpe, argtpes0, pt)
- } catch {
- case ex: TypeError =>
- try {
- isApplicable(undetparams, ftpe, argtpes0, WildcardType)
- } catch {
- case ex: TypeError =>
- false
- }
- } finally {
- context.reportAmbiguousErrors = reportAmbiguousErrors
- }
+ val silentContext = context.makeSilent(false)
+ val typer0 = newTyper(silentContext)
+ val res1 = typer0.infer.isApplicable(undetparams, ftpe, argtpes0, pt)
+ if (pt != WildcardType && silentContext.hasErrors) {
+ silentContext.flushBuffer()
+ val res2 = typer0.infer.isApplicable(undetparams, ftpe, argtpes0, WildcardType)
+ if (silentContext.hasErrors) false else res2
+ } else res1
}
/** Is type <code>ftpe1</code> strictly more specific than type <code>ftpe2</code>
@@ -942,38 +893,22 @@ trait Infer {
*/
/** error if arguments not within bounds. */
- def checkBounds(pos: Position, pre: Type, owner: Symbol,
- tparams: List[Symbol], targs: List[Type], prefix: String) = {
+ def checkBounds(tree: Tree, pre: Type, owner: Symbol,
+ tparams: List[Symbol], targs: List[Type], prefix: String): Boolean = {
//@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) ()
- 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(!kindErrors.isEmpty) {
+ if (targs contains WildcardType) true
+ else { KindBoundErrors(tree, prefix, targs, tparams, kindErrors); false }
+ } 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))
- ()
- }
- }
- }
+ NotWithinBounds(tree, prefix, targs, tparams, kindErrors)
+ false
+ } else true
+ } else true
}
def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = {
@@ -1055,8 +990,7 @@ trait Infer {
targs: List[Type], pt: Type) {
if (targs eq null) {
if (!tree.tpe.isErroneous && !pt.isErroneous)
- error(tree.pos, "polymorphic expression cannot be instantiated to expected type" +
- foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt))
+ PolymorphicExpressionInstantiationError(tree, undetparams, pt)
} else {
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
}
@@ -1092,43 +1026,28 @@ trait Infer {
(okparams map (_.name), okargs).zipped.map(_ + "=" + _).mkString("solved: ", ", ", "")
))
- checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")
- val treeSubst = new TreeTypeSubstituter(okparams, okargs)
- treeSubst traverseTrees fn :: args
+ if (checkBounds(fn, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")) {
+ val treeSubst = new TreeTypeSubstituter(okparams, okargs)
+ treeSubst traverseTrees fn :: args
- leftUndet match {
- case Nil => Nil
- case xs =>
- // #3890
- val xs1 = treeSubst.typeMap mapOver xs
- if (xs ne xs1)
- new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args
+ leftUndet match {
+ case Nil => Nil
+ case xs =>
+ // #3890
+ val xs1 = treeSubst.typeMap mapOver xs
+ if (xs ne xs1)
+ new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args
- xs1
- }
+ xs1
+ }
+ } else Nil
}
catch ifNoInstance { 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
+ NoMethodInstanceError(fn, args, msg); List()
}
}
- /** Type with all top-level occurrences of abstract types replaced by their bounds */
- def widen(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala )
- case TypeRef(_, sym, _) if sym.isAbstractType =>
- widen(tp.bounds.hi)
- case TypeRef(_, sym, _) if sym.isAliasType =>
- widen(tp.normalize)
- case rtp @ RefinedType(parents, decls) =>
- copyRefinedType(rtp, parents mapConserve widen, decls)
- case AnnotatedType(_, underlying, _) =>
- widen(underlying)
- case _ =>
- tp
- }
+ def widen(tp: Type): Type = abstractTypesToBounds(tp)
/** Substitute free type variables <code>undetparams</code> of type constructor
* <code>tree</code> in pattern, given prototype <code>pt</code>.
@@ -1149,20 +1068,16 @@ trait Infer {
try {
val targs = solvedTypes(tvars, undetparams, undetparams map varianceInType(restpe),
true, lubDepth(List(restpe, pt)))
-// checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
+// checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
// no checkBounds here. If we enable it, test bug602 fails.
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
- } catch {
- case ex: NoInstance =>
- errorTree(tree, "constructor of type " + restpe +
- " cannot be uniquely instantiated to expected type " + pt +
- "\n --- because ---\n" + ex.getMessage())
+ } catch ifNoInstance{ msg =>
+ NoConstructorInstanceError(tree, restpe, pt, msg)
}
def instError = {
if (settings.debug.value) Console.println("ici " + tree + " " + undetparams + " " + pt)
if (settings.explaintypes.value) explainTypes(restpe.instantiateTypeParams(undetparams, tvars), pt)
- errorTree(tree, "constructor cannot be instantiated to expected type" +
- foundReqMsg(restpe, pt))
+ ConstrInstantiationError(tree, restpe, pt)
}
if (restpe.instantiateTypeParams(undetparams, tvars) <:< pt) {
computeArgs
@@ -1232,9 +1147,9 @@ trait Infer {
}
}
- def checkCheckable(pos: Position, tp: Type, kind: String) {
+ def checkCheckable(tree: Tree, 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")
+ context.unit.uncheckedWarning(tree.pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure")
}
def check(tp: Type, bound: List[Symbol]) {
def isLocalBinding(sym: Symbol) =
@@ -1253,7 +1168,7 @@ trait Infer {
} else if (sym.isAliasType) {
check(tp.normalize, bound)
} else if (sym == NothingClass || sym == NullClass || sym == AnyValClass) {
- error(pos, "type "+tp+" cannot be used in a type pattern or isInstanceOf test")
+ TypePatternOrIsInstanceTestError(tree, tp)
} else {
for (arg <- args) {
if (sym == ArrayClass) check(arg, bound)
@@ -1277,11 +1192,12 @@ trait Infer {
case ExistentialType(quantified, tp1) =>
check(tp1, bound ::: quantified)
case ThisType(_) =>
- ;
+ ()
case NoPrefix =>
- ;
+ ()
case _ =>
patternWarning(tp, "type ")
+ ()
}
}
check(tp, List())
@@ -1304,7 +1220,7 @@ trait Infer {
}
}
- def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = {
+ def inferTypedPattern(tree0: Tree, pattp: Type, pt0: Type): Type = {
val pt = widen(pt0)
val ptparams = freeTypeParamsOfTerms.collect(pt)
val tpparams = freeTypeParamsOfTerms.collect(pattp)
@@ -1316,10 +1232,12 @@ trait Infer {
* This is the case if the scrutinee has no unresolved type arguments
* and is a "final type", meaning final + invariant in all type parameters.
*/
- if (pt.isFinalType && ptparams.isEmpty && !ptMatchesPattp)
- error(pos, "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt))
+ if (pt.isFinalType && ptparams.isEmpty && !ptMatchesPattp) {
+ IncompatibleScrutineeTypeError(tree0, pattp, pt)
+ return ErrorType
+ }
- checkCheckable(pos, pattp, "pattern ")
+ checkCheckable(tree0, pattp, "pattern ")
if (pattp <:< pt) ()
else {
debuglog("free type params (1) = " + tpparams)
@@ -1342,8 +1260,8 @@ trait Infer {
if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars) || pattpMatchesPt)
ptvars foreach instantiateTypeVar
else {
- error(pos, "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt))
- return pattp
+ PatternTypeIncompatibleWithPtError1(tree0, pattp, pt)
+ return ErrorType
}
}
tvars foreach instantiateTypeVar
@@ -1364,30 +1282,8 @@ trait Infer {
val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
if (pat.tpe <:< pt1)
ptvars foreach instantiateTypeVar
- 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)
- }
+ else
+ PatternTypeIncompatibleWithPtError2(pat, pt1, pt)
}
object toOrigin extends TypeMap {
@@ -1464,7 +1360,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): Unit = tree.tpe match {
+ def inferExprAlternative(tree: Tree, pt: Type) = tree.tpe match {
case OverloadedType(pre, alts) => tryTwice {
val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt))
val secondTry = alts0.isEmpty
@@ -1495,15 +1391,10 @@ trait Infer {
case _ =>
}
}
- typeErrorTree(tree, tree.symbol.tpe, pt)
+ NoBestExprAlternativeError(tree, pt)
} else if (!competing.isEmpty) {
- if (secondTry) {
- typeErrorTree(tree, tree.symbol.tpe, pt)
- } else {
- if (!pt.isErroneous)
- context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt)
- setError(tree)
- }
+ if (secondTry) NoBestExprAlternativeError(tree, pt)
+ else { if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt) }
} else {
// val applicable = alts1 filter (alt =>
// global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt))
@@ -1513,9 +1404,11 @@ trait Infer {
}
}
- @inline private def wrapTypeError(expr: => Boolean): Boolean =
- try expr
- catch { case _: TypeError => false }
+ @inline private def inSilentMode(expr: Typer => Boolean): Boolean = {
+ val silentContext = context.makeSilent(context.ambiguousErrors)
+ val res = expr(newTyper(silentContext))
+ if (silentContext.hasErrors) false else res
+ }
// Checks against the name of the parameter and also any @deprecatedName.
private def paramMatchesName(param: Symbol, name: Name) =
@@ -1585,9 +1478,7 @@ trait Infer {
val applicable = resolveOverloadedMethod(argtpes, {
alts filter { alt =>
- // TODO: this will need to be re-written once we substitute throwing exceptions
- // with generating error trees. We wrap this applicability in try/catch because of #4457.
- wrapTypeError(isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) &&
+ inSilentMode(typer0 => typer0.infer.isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) &&
(!varArgsOnly || isVarArgsList(alt.tpe.params))
}
})
@@ -1603,16 +1494,13 @@ 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) {
- errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
- } else {
+ if (pt == WildcardType)
+ NoBestMethodAlternativeError(tree, argtpes, pt)
+ else
inferMethodAlternative(tree, undetparams, argtpes, WildcardType)
- }
} else if (!competing.isEmpty) {
if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous)
- context.ambiguousError(tree.pos, pre, best, competing.head,
- "argument types " + argtpes.mkString("(", ",", ")") +
- (if (pt == WildcardType) "" else " and expected result type " + pt))
+ AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt)
setError(tree)
()
} else {
@@ -1628,18 +1516,27 @@ trait Infer {
*
* @param infer ...
*/
- def tryTwice(infer: => Unit) {
+ def tryTwice(infer: => Unit): Unit = {
if (context.implicitsEnabled) {
- val reportGeneralErrors = context.reportGeneralErrors
- context.reportGeneralErrors = false
- try context.withImplicitsDisabled(infer)
- catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError =>
- context.reportGeneralErrors = reportGeneralErrors
+ val saved = context.state
+ var fallback = false
+ context.setBufferErrors()
+ val res = try {
+ context.withImplicitsDisabled(infer)
+ if (context.hasErrors) {
+ fallback = true
+ context.restoreState(saved)
+ context.flushBuffer()
infer
+ }
+ } catch {
+ case ex: CyclicReference => throw ex
+ case ex: TypeError => // recoverable cyclic references
+ context.restoreState(saved)
+ if (!fallback) infer else ()
}
- context.reportGeneralErrors = reportGeneralErrors
+ context.restoreState(saved)
+ res
}
else infer
}
@@ -1654,13 +1551,13 @@ trait Infer {
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): Unit = error(tree.pos, msg)
+ def fail(kind: PolyAlternativeErrorKind.ErrorType) =
+ PolyAlternativeError(tree, argtypes, sym0, kind)
- if (sym0 == NoSymbol) return fail(
+ if (sym0 == NoSymbol) return (
if (alts exists (_.typeParams.nonEmpty))
- "wrong number of type parameters for " + treeSymTypeMsg(tree)
- else treeSymTypeMsg(tree) + " does not take type parameters"
- )
+ fail(PolyAlternativeErrorKind.WrongNumber)
+ else fail(PolyAlternativeErrorKind.NoParams))
val (resSym, resTpe) = {
if (!sym0.isOverloaded)
@@ -1668,11 +1565,8 @@ trait Infer {
else {
val sym = sym0 filter (alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes))
if (sym == NoSymbol) {
- 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
- )
+ if (argtypes forall (x => !x.isErroneous))
+ fail(PolyAlternativeErrorKind.ArgsDoNotConform)
return
}
else if (sym.isOverloaded) {
@@ -1689,24 +1583,6 @@ trait Infer {
// Side effects tree with symbol and type
tree setSymbol resSym setType resTpe
}
-
- 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 = underlyingSymbol(sym)
- errorTree(tree, realsym.fullLocationString + " cannot be accessed in " + location + explanation)
- }
- }
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index b9264aae55..c63ae90ef6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -2,6 +2,8 @@ package scala.tools.nsc
package typechecker
import symtab.Flags._
+import scala.tools.nsc.util._
+import scala.reflect.ReflectionUtils
trait Macros { self: Analyzer =>
import global._
@@ -13,6 +15,20 @@ trait Macros { self: Analyzer =>
owner.info.decl(nme.macroMethodName(mac.name))
}
+ def macroArgs(tree: Tree): (List[List[Tree]]) = tree match {
+ case Apply(fn, args) =>
+ macroArgs(fn) :+ args
+ case TypeApply(fn, args) =>
+ macroArgs(fn) :+ args
+ case Select(qual, name) if !isStaticMacro(tree.symbol) =>
+ List(List(qual))
+ case _ =>
+ List(List())
+ }
+
+ private def isStaticMacro(mac: Symbol): Boolean =
+ mac.owner.isModuleClass
+
/**
* The definition of the method implementing a macro. Example:
* Say we have in a class C
@@ -33,25 +49,32 @@ trait Macros { self: Analyzer =>
*/
def macroMethDef(mdef: DefDef): Tree = {
def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree)
- val universeType = TypeTree(ReflectApiUniverse.tpe)
- val globParamSec = List(paramDef(nme.glob, universeType))
- def globSelect(name: Name) = Select(Ident(nme.glob), name)
+ val contextType = TypeTree(ReflectMacroContext.tpe)
+ val globParamSec = List(paramDef(nme.context, contextType))
+ def globSelect(name: Name) = Select(Ident(nme.context), name)
def globTree = globSelect(newTypeName("Tree"))
def globType = globSelect(newTypeName("Type"))
- val thisParamSec = if (mdef.symbol.owner.isModuleClass) List() else List(paramDef(newTermName("_this"), globTree))
+ val thisParamSec = if (isStaticMacro(mdef.symbol)) List() else List(paramDef(newTermName("_this"), globTree))
def tparamInMacro(tdef: TypeDef) = paramDef(tdef.name.toTermName, globType)
- def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, globTree)
+ def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, vdef.tpt match {
+ case tpt @ AppliedTypeTree(hk, _) if treeInfo.isRepeatedParamType(tpt) => AppliedTypeTree(hk, List(globTree))
+ case _ => globTree
+ })
def wrapImplicit(tree: Tree) = atPos(tree.pos) {
- Block(List(ValDef(Modifiers(IMPLICIT), newTermName("$" + nme.glob), universeType, Ident(nme.glob))), tree)
+ // implicit hasn't proven useful so far, so I'm disabling it
+ //val implicitDecl = ValDef(Modifiers(IMPLICIT), nme.contextImplicit, SingletonTypeTree(Ident(nme.context)), Ident(nme.context))
+ val importGlob = Import(Ident(nme.context), List(ImportSelector(nme.WILDCARD, -1, null, -1)))
+ Block(List(importGlob), tree)
}
+ var formals = (mdef.vparamss map (_ map vparamInMacro))
+ if (mdef.tparams.nonEmpty) formals = (mdef.tparams map tparamInMacro) :: formals
atPos(mdef.pos) {
new DefDef( // can't call DefDef here; need to find out why
- mods = mdef.mods &~ MACRO,
+ mods = mdef.mods &~ MACRO &~ OVERRIDE,
name = nme.macroMethodName(mdef.name),
tparams = List(),
- vparamss = globParamSec :: thisParamSec :: (mdef.tparams map tparamInMacro) ::
- (mdef.vparamss map (_ map vparamInMacro)),
+ vparamss = globParamSec :: thisParamSec :: formals,
tpt = globTree,
wrapImplicit(mdef.rhs))
}
@@ -59,11 +82,110 @@ trait Macros { self: Analyzer =>
def addMacroMethods(templ: Template, namer: Namer): Unit = {
for (ddef @ DefDef(mods, _, _, _, _, _) <- templ.body if mods hasFlag MACRO) {
- val sym = namer.enterSyntheticSym(util.trace("macro def: ")(macroMethDef(ddef)))
- println("added to "+namer.context.owner.enclClass+": "+sym)
+ val trace = scala.tools.nsc.util.trace when settings.debug.value
+ val sym = namer.enterSyntheticSym(trace("macro def: ")(macroMethDef(ddef)))
+ trace("added to "+namer.context.owner.enclClass+": ")(sym)
}
}
- def macroExpand(tree: Tree): Tree = ???
+ lazy val mirror = new scala.reflect.runtime.Mirror {
+ lazy val libraryClassLoader = {
+ val classpath = global.classPath.asURLs
+ ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+ }
-} \ No newline at end of file
+ override def defaultReflectiveClassLoader() = libraryClassLoader
+ }
+
+ /** Return optionally address of companion object and implementation method symbol
+ * of given macro; or None if implementation classfile cannot be loaded or does
+ * not contain the macro implementation.
+ */
+ def macroImpl(mac: Symbol): Option[(AnyRef, mirror.Symbol)] = {
+ try {
+ val mmeth = macroMeth(mac)
+ if (mmeth == NoSymbol) None
+ else {
+ val receiverClass: mirror.Symbol = mirror.classWithName(mmeth.owner.fullName)
+ val receiverObj = receiverClass.companionModule
+ if (receiverObj == NoSymbol) None
+ else {
+ val receiver = mirror.getCompanionObject(receiverClass)
+ val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString))
+ Some((receiver, rmeth))
+ }
+ }
+ } catch {
+ case ex: ClassNotFoundException =>
+ None
+ }
+ }
+
+ /** Return result of macro expansion.
+ * Or, if that fails, and the macro overrides a method return
+ * tree that calls this method instead of the macro.
+ */
+ def macroExpand(tree: Tree, context: Context): Option[Any] = {
+ val macroDef = tree.symbol
+ macroImpl(macroDef) match {
+ case Some((receiver, rmeth)) =>
+ val argss = List(global) :: macroArgs(tree)
+ val paramss = macroMeth(macroDef).paramss
+ val rawArgss = for ((as, ps) <- argss zip paramss) yield {
+ if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
+ else as
+ }
+ val rawArgs: Seq[Any] = rawArgss.flatten
+ try {
+ Some(mirror.invoke(receiver, rmeth, rawArgs: _*))
+ } catch {
+ case ex =>
+ val realex = ReflectionUtils.unwrapThrowable(ex)
+ val stacktrace = new java.io.StringWriter()
+ realex.printStackTrace(new java.io.PrintWriter(stacktrace))
+ val msg = System.getProperty("line.separator") + stacktrace
+ context.unit.error(tree.pos, "exception during macro expansion: " + msg)
+ None
+ }
+ case None =>
+ val trace = scala.tools.nsc.util.trace when settings.debug.value
+ def notFound() = {
+ context.unit.error(tree.pos, "macro implementation not found: " + macroDef.name)
+ None
+ }
+ def fallBackToOverridden(tree: Tree): Option[Tree] = {
+ tree match {
+ case Select(qual, name) if (macroDef.isMacro) =>
+ macroDef.allOverriddenSymbols match {
+ case first :: _ =>
+ Some(Select(qual, name) setPos tree.pos setSymbol first)
+ case _ =>
+ trace("macro is not overridden: ")(tree)
+ notFound()
+ }
+ case Apply(fn, args) =>
+ fallBackToOverridden(fn) match {
+ case Some(fn1) => Some(Apply(fn1, args) setPos tree.pos)
+ case _ => None
+ }
+ case TypeApply(fn, args) =>
+ fallBackToOverridden(fn) match {
+ case Some(fn1) => Some(TypeApply(fn1, args) setPos tree.pos)
+ case _ => None
+ }
+ case _ =>
+ trace("unexpected tree in fallback: ")(tree)
+ notFound()
+ }
+ }
+ fallBackToOverridden(tree) match {
+ case Some(tree1) =>
+ trace("falling back to ")(tree1)
+ currentRun.macroExpansionFailed = true
+ Some(tree1)
+ case None =>
+ None
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 29dffd99d6..c6ca9870c3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -32,10 +32,12 @@ trait MethodSynthesis {
trait MethodSynth {
self: Namer =>
+ import NamerErrorGen._
+
def enterGetterSetter(tree: ValDef) {
val ValDef(mods, name, _, _) = tree
if (nme.isSetterName(name))
- context.error(tree.pos, "Names of vals or vars may not end in `_='")
+ ValOrValWithSetterSuffixError(tree)
val getter = Getter(tree).createAndEnterSymbol()
@@ -43,7 +45,7 @@ trait MethodSynthesis {
if (mods.isLazy) enterLazyVal(tree, getter)
else {
if (mods.isPrivateLocal)
- context.error(tree.pos, "private[this] not allowed for case class parameters")
+ PrivateThisCaseClassParameterError(tree)
// Create the setter if necessary.
if (mods.isMutable)
Setter(tree).createAndEnterSymbol()
@@ -187,7 +189,7 @@ trait MethodSynthesis {
override def validate() {
assert(derivedSym != NoSymbol, tree)
if (derivedSym.isOverloaded)
- context.error(derivedSym.pos, derivedSym+" is defined twice")
+ GetterDefinedTwiceError(derivedSym)
super.validate()
}
@@ -255,8 +257,7 @@ trait MethodSynthesis {
if (derivedSym == NoSymbol) {
// the namer decides whether to generate these symbols or not. at that point, we don't
// have symbolic information yet, so we only look for annotations named "BeanProperty".
- context.error(tree.pos,
- "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import")
+ BeanPropertyAnnotationLimitationError(tree)
}
super.validate()
}
@@ -304,9 +305,9 @@ trait MethodSynthesis {
val beans = beanAccessorsFromNames(tree)
if (beans.nonEmpty) {
if (!name(0).isLetter)
- context.error(tree.pos, "`BeanProperty' annotation can be applied only to fields that start with a letter")
+ BeanPropertyAnnotationFieldWithoutLetterError(tree)
else if (mods.isPrivate) // avoids name clashes with private fields in traits
- context.error(tree.pos, "`BeanProperty' annotation can be applied only to non-private fields")
+ BeanPropertyAnnotationPrivateFieldError(tree)
// Create and enter the symbols here, add the trees in finishGetterSetter.
beans foreach (_.createAndEnterSymbol())
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 86c014a181..0cc7478c59 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -73,7 +73,9 @@ trait Namers extends MethodSynthesis {
classAndNamerOfModule.clear()
}
- abstract class Namer(val context: Context) extends MethodSynth {
+ abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors {
+
+ import NamerErrorGen._
val typer = newTyper(context)
private lazy val innerNamer =
@@ -87,7 +89,7 @@ trait Namers extends MethodSynthesis {
newNamer(context.makeNewScope(tree, sym))
}
def createInnerNamer() = {
- newNamer(context.make(context.tree, owner, new Scope))
+ newNamer(context.make(context.tree, owner, newScope))
}
def createPrimaryConstructorParameterNamer: Namer = { //todo: can we merge this with SCCmode?
val classContext = context.enclClass
@@ -109,9 +111,10 @@ trait Namers extends MethodSynthesis {
protected def owner = context.owner
private def contextFile = context.unit.source.file
- private def typeErrorHandler[T](pos: Position, alt: T): PartialFunction[Throwable, T] = {
+ private def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = {
case ex: TypeError =>
- typer.reportTypeError(pos, ex)
+ // H@ need to ensure that we handle only cyclic references
+ TypeSigError(tree, ex)
alt
}
// PRIVATE | LOCAL are fields generated for primary constructor arguments
@@ -129,10 +132,17 @@ trait Namers extends MethodSynthesis {
|| vd.symbol.isLazy
)
- def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = {
+ def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym =
if (sym.isPrivateLocal || !mods.hasAccessBoundary) sym
- else sym setPrivateWithin typer.qualifyingClass(tree, mods.privateWithin, true)
- }
+ else sym setPrivateWithin (
+ typer.qualifyingClass(tree, mods.privateWithin, true) match {
+ case None =>
+ NoSymbol
+ case Some(sym) =>
+ sym
+ }
+ )
+
def setPrivateWithin(tree: MemberDef, sym: Symbol): Symbol =
setPrivateWithin(tree, sym, tree.mods)
@@ -195,14 +205,6 @@ trait Namers extends MethodSynthesis {
)
)
- 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 ""
- val s3 = if (sym.isCase) "case class " + sym.name else "" + sym
-
- context.error(pos, sym.name + " is already defined as " + s2 + s3)
- }
-
private def allowsOverload(sym: Symbol) = (
sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass
)
@@ -221,7 +223,7 @@ trait Namers extends MethodSynthesis {
if (!allowsOverload(sym)) {
val prev = scope.lookupEntry(sym.name)
if ((prev ne null) && prev.owner == scope && conflict(sym, prev.sym)) {
- doubleDefError(sym.pos, prev.sym)
+ DoubleDefError(sym, prev.sym)
sym setInfo ErrorType
scope unlink prev.sym // let them co-exist...
// FIXME: The comment "let them co-exist" is confusing given that the
@@ -250,7 +252,7 @@ trait Namers extends MethodSynthesis {
returnContext
}
tree.symbol match {
- case NoSymbol => try dispatch() catch typeErrorHandler(tree.pos, this.context)
+ case NoSymbol => try dispatch() catch typeErrorHandler(tree, this.context)
case sym => enterExistingSym(sym)
}
}
@@ -447,6 +449,7 @@ trait Namers extends MethodSynthesis {
}
private def checkSelectors(tree: Import): Unit = {
+ import DuplicatesErrorKinds._
val Import(expr, selectors) = tree
val base = expr.tpe
@@ -483,8 +486,10 @@ trait Namers extends MethodSynthesis {
typeSig(tree)
}
// for Java code importing Scala objects
- else if (!nme.isModuleName(from) || isValid(nme.stripModuleSuffix(from)))
- notAMemberError(tree.pos, expr, from)
+ else if (!nme.isModuleName(from) || isValid(nme.stripModuleSuffix(from))) {
+ typer.TyperErrorGen.NotAMemberError(tree, expr, from)
+ typer.infer.setError(tree)
+ }
}
// Setting the position at the import means that if there is
// more than one hidden name, the second will not be warned.
@@ -492,20 +497,21 @@ trait Namers extends MethodSynthesis {
checkNotRedundant(tree.pos withPoint fromPos, from, to)
}
}
- def noDuplicates(names: List[Name], message: String) {
+
+ def noDuplicates(names: List[Name], check: DuplicatesErrorKinds.Value) {
def loop(xs: List[Name]): Unit = xs match {
case Nil => ()
case hd :: tl =>
if (hd == nme.WILDCARD || !(tl contains hd)) loop(tl)
- else context.error(tree.pos, hd.decode + " " + message)
+ else DuplicatesError(tree, hd, check)
}
loop(names filterNot (x => x == null || x == nme.WILDCARD))
}
selectors foreach checkSelector
// checks on the whole set
- noDuplicates(selectors map (_.name), "is renamed twice")
- noDuplicates(selectors map (_.rename), "appears twice as a target of a renaming")
+ noDuplicates(selectors map (_.name), RenamedTwice)
+ noDuplicates(selectors map (_.rename), AppearsTwice)
}
def enterCopyMethodOrGetter(tree: Tree, tparams: List[TypeDef]): Symbol = {
@@ -620,7 +626,7 @@ trait Namers extends MethodSynthesis {
if (mods.isCase) {
if (treeInfo.firstConstructorArgs(impl.body).size > MaxFunctionArity)
- context.error(tree.pos, "Implementation restriction: case classes cannot have more than " + MaxFunctionArity + " parameters.")
+ MaxParametersCaseClassError(tree)
val m = ensureCompanionObject(tree, caseModuleDef)
classOfModuleClass(m.moduleClass) = new WeakReference(tree)
@@ -823,7 +829,7 @@ trait Namers extends MethodSynthesis {
val tp = tpt.tpe
val inheritsSelf = tp.typeSymbol == owner
if (inheritsSelf)
- context.error(tpt.pos, ""+tp.typeSymbol+" inherits itself")
+ InheritsItselfError(tpt)
if (inheritsSelf || tp.isError) AnyRefClass.tpe
else tp
@@ -838,7 +844,7 @@ trait Namers extends MethodSynthesis {
enterSelf(templ.self)
- val decls = new Scope
+ val decls = newScope
val templateNamer = newNamer(context.make(templ, clazz, decls))
templateNamer enterSyms templ.body
@@ -848,10 +854,10 @@ trait Namers extends MethodSynthesis {
Namers.this.classOfModuleClass get clazz foreach { cdefRef =>
val cdef = cdefRef()
if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer)
- addMacroMethods(cdef.impl, templateNamer)
+ if (settings.Xmacros.value) addMacroMethods(cdef.impl, templateNamer)
classOfModuleClass -= clazz
}
- addMacroMethods(templ, templateNamer)
+ if (settings.Xmacros.value) addMacroMethods(templ, templateNamer)
}
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
@@ -924,7 +930,7 @@ trait Namers extends MethodSynthesis {
}
def thisMethodType(restpe: Type) = {
- val checkDependencies = new DependentTypeChecker(context)
+ val checkDependencies = new DependentTypeChecker(context)(this)
checkDependencies check vparamSymss
// DEPMETTODO: check not needed when they become on by default
checkDependencies(restpe)
@@ -1000,7 +1006,7 @@ trait Namers extends MethodSynthesis {
}
mforeach(vparamss) { vparam =>
if (vparam.tpt.isEmpty) {
- context.error(vparam.pos, "missing parameter type")
+ MissingParameterOrValTypeError(vparam)
vparam.tpt defineType ErrorType
}
}
@@ -1268,7 +1274,7 @@ trait Namers extends MethodSynthesis {
val typer1 = typer.constrTyperIf(isBeforeSupercall)
if (tpt.isEmpty) {
if (rhs.isEmpty) {
- context.error(tpt.pos, "missing parameter type");
+ MissingParameterOrValTypeError(tpt)
ErrorType
}
else assignTypeToTree(vdef, newTyper(typer1.context.make(vdef, sym)), WildcardType)
@@ -1282,7 +1288,7 @@ trait Namers extends MethodSynthesis {
val expr1 = typer.typedQualifier(expr)
typer checkStable expr1
if (expr1.symbol != null && expr1.symbol.isRootPackage)
- context.error(tree.pos, "_root_ cannot be imported")
+ RootImportError(tree)
val newImport = treeCopy.Import(tree, expr1, selectors).asInstanceOf[Import]
checkSelectors(newImport)
@@ -1296,7 +1302,7 @@ trait Namers extends MethodSynthesis {
val result =
try getSig
- catch typeErrorHandler(tree.pos, ErrorType)
+ catch typeErrorHandler(tree, ErrorType)
result match {
case PolyType(tparams @ (tp :: _), _) if tp.owner.isTerm => typer.deskolemizeTypeParams(tparams)(result)
@@ -1343,43 +1349,43 @@ trait Namers extends MethodSynthesis {
* - declarations only in mixins or abstract classes (when not @native)
*/
def validate(sym: Symbol) {
- def fail(msg: String) = context.error(sym.pos, msg)
+ import SymValidateErrors._
+ def fail(kind: SymValidateErrors.Value) = SymbolValidationError(sym, kind)
+
def checkWithDeferred(flag: Int) {
if (sym hasFlag flag)
- fail("abstract member may not have " + flagsToString(flag) + " modifier")
+ AbstractMemberWithModiferError(sym, flag)
}
def checkNoConflict(flag1: Int, flag2: Int) {
if (sym hasAllFlags flag1 | flag2)
- fail("illegal combination of modifiers: %s and %s for: %s".format(
- flagsToString(flag1), flagsToString(flag2), sym))
+ IllegalModifierCombination(sym, flag1, flag2)
}
if (sym.isImplicit) {
if (sym.isConstructor)
- fail("`implicit' modifier not allowed for constructors")
+ fail(ImplicitConstr)
if (!sym.isTerm)
- fail("`implicit' modifier can be used only for values, variables and methods")
+ fail(ImplicitNotTerm)
if (sym.owner.isPackageClass)
- fail("`implicit' modifier cannot be used for top-level objects")
+ fail(ImplicitTopObject)
}
if (sym.isClass) {
if (sym.isAnyOverride && !sym.hasFlag(TRAIT))
- fail("`override' modifier not allowed for classes")
- }
- else {
+ fail(OverrideClass)
+ } else {
if (sym.isSealed)
- fail("`sealed' modifier can be used only for classes")
+ fail(SealedNonClass)
if (sym.hasFlag(ABSTRACT))
- fail("`abstract' modifier can be used only for classes; it should be omitted for abstract members")
+ fail(AbstractNonClass)
}
if (sym.isConstructor && sym.isAnyOverride)
- fail("`override' modifier not allowed for constructors")
+ fail(OverrideConstr)
if (sym.isAbstractOverride && !sym.owner.isTrait)
- fail("`abstract override' modifier only allowed for members of traits")
+ fail(AbstractOverride)
if (sym.isLazy && sym.hasFlag(PRESUPER))
- fail("`lazy' definitions may not be initialized early")
+ fail(LazyAndEarlyInit)
if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass)
- fail("pass-by-name arguments not allowed for case class parameters")
+ fail(ByNameParameter)
if (sym.isDeferred) {
// Is this symbol type always allowed the deferred flag?
@@ -1397,7 +1403,7 @@ trait Namers extends MethodSynthesis {
if (sym hasAnnotation NativeAttr)
sym resetFlag DEFERRED
else if (!symbolAllowsDeferred && ownerRequiresConcrete)
- fail("only classes can have declared but undefined members" + abstractVarMessage(sym))
+ fail(AbstractVar)
checkWithDeferred(PRIVATE)
checkWithDeferred(FINAL)
@@ -1462,14 +1468,14 @@ trait Namers extends MethodSynthesis {
// def foo[T, T2](a: T, x: T2)(implicit w: ComputeT2[T, T2])
// moreover, the latter is not an encoding of the former, which hides type
// inference of T2, so you can specify T while T2 is purely computed
- private class DependentTypeChecker(ctx: Context) extends TypeTraverser {
+ private class DependentTypeChecker(ctx: Context)(namer: Namer) extends TypeTraverser {
private[this] val okParams = mutable.Set[Symbol]()
private[this] val method = ctx.owner
def traverse(tp: Type) = tp match {
case SingleType(_, sym) =>
if (sym.owner == method && sym.isValueParameter && !okParams(sym))
- ctx.error(sym.pos, "illegal dependent method type" + errorAddendum)
+ namer.NamerErrorGen.IllegalDependentMethTpeError(sym)(ctx)
case _ => mapOver(tp)
}
@@ -1482,8 +1488,6 @@ trait Namers extends MethodSynthesis {
okParams ++= vps
}
}
- private def errorAddendum =
- ": parameter appears in the type of another parameter in the same section or an earlier one"
}
@deprecated("Use underlyingSymbol instead", "2.10.0")
@@ -1512,7 +1516,7 @@ trait Namers extends MethodSynthesis {
}
catch {
case e: InvalidCompanions =>
- ctx.error(original.pos, e.getMessage)
+ ctx.unit.error(original.pos, e.getMessage)
NoSymbol
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 79cb211215..3a3c244d1c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -17,6 +17,7 @@ trait NamesDefaults { self: Analyzer =>
import global._
import definitions._
+ import NamesDefaultsErrorsGen._
val defaultParametersOfMethod =
perRunCaches.newWeakMap[Symbol, Set[Symbol]]() withDefaultValue Set()
@@ -312,8 +313,7 @@ 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.tpe.isError) setError(tree)
+ if (typedApp.isErrorTyped) 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.
@@ -384,6 +384,7 @@ trait NamesDefaults { self: Analyzer =>
if (missing forall (_.hasDefaultFlag)) {
val defaultArgs = missing flatMap (p => {
val defGetter = defaultGetter(p, context)
+ // TODO #3649 can create spurious errors when companion object is gone (because it becomes unlinked from scope)
if (defGetter == NoSymbol) None // prevent crash in erroneous trees, #3649
else {
var default1 = qual match {
@@ -434,12 +435,12 @@ trait NamesDefaults { self: Analyzer =>
private def savingUndeterminedTParams[T](context: Context)(fn: List[Symbol] => T): T = {
val savedParams = context.extractUndetparams()
- val savedReporting = context.reportAmbiguousErrors
+ val savedReporting = context.ambiguousErrors
- context.reportAmbiguousErrors = false
+ context.setAmbiguousErrors(false)
try fn(savedParams)
finally {
- context.reportAmbiguousErrors = savedReporting
+ context.setAmbiguousErrors(savedReporting)
//@M note that we don't get here when an ambiguity was detected (during the computation of res),
// as errorTree throws an exception
context.undetparams = savedParams
@@ -488,7 +489,7 @@ trait NamesDefaults { self: Analyzer =>
// is called, and EmptyTree can only be typed NoType. Thus we need to
// disable conforms as a view...
try typer.silent(_.typed(arg, subst(paramtpe))) match {
- case t: Tree => !t.isErroneous
+ case SilentResultValue(t) => !t.isErroneous // #4041
case _ => false
}
catch {
@@ -496,9 +497,7 @@ trait NamesDefaults { self: Analyzer =>
// CyclicReferences. Fix for #3685
case cr @ CyclicReference(sym, _) =>
(sym.name == param.name) && sym.accessedOrSelf.isVariable && {
- context.error(sym.pos,
- "variable definition needs type because '%s' is used as a named argument in its body.".format(sym.name))
- typer.infer.setError(arg)
+ NameClashError(sym, arg)(typer.context)
true
}
}
@@ -514,18 +513,17 @@ trait NamesDefaults { self: Analyzer =>
* after named ones.
*/
def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = {
- import typer.context
+ implicit val context0 = typer.context
// maps indices from (order written by user) to (order of definition)
val argPos = Array.fill(args.length)(-1)
var positionalAllowed = true
val namelessArgs = mapWithIndex(args) { (arg, index) =>
- def fail(msg: String) = typer.infer.errorTree(arg, msg)
arg match {
case arg @ AssignOrNamedArg(Ident(name), rhs) =>
def matchesName(param: Symbol) = !param.isSynthetic && (
(param.name == name) || (param.deprecatedParamName match {
case Some(`name`) =>
- context.unit.deprecationWarning(arg.pos,
+ context0.unit.deprecationWarning(arg.pos,
"the parameter name "+ name +" has been deprecated. Use "+ param.name +" instead.")
true
case _ => false
@@ -539,12 +537,12 @@ trait NamesDefaults { self: Analyzer =>
// treat the arg as an assignment of type Unit
Assign(arg.lhs, rhs) setPos arg.pos
}
- else fail("unknown parameter name: " + name)
+ else UnknownParameterNameNamesDefaultError(arg, name)
}
else if (argPos contains pos)
- fail("parameter specified twice: " + name)
+ DoubleParamNamesDefaultError(arg, name)
else if (isAmbiguousAssignment(typer, params(pos), arg))
- fail("reference to " + name + " is ambiguous; it is both a method parameter and a variable in scope.")
+ AmbiguousReferenceInNamesDefaultError(arg, name)
else {
// if the named argument is on the original parameter
// position, positional after named is allowed.
@@ -556,7 +554,7 @@ trait NamesDefaults { self: Analyzer =>
case _ =>
argPos(index) = index
if (positionalAllowed) arg
- else fail("positional after named argument.")
+ else PositionalAfterNamedNamesDefaultError(arg)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
index 4104803194..73a43bf4a1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
@@ -315,7 +315,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
val extractorCall = try {
context.undetparams = Nil
silent(_.typed(Apply(Select(orig, extractor), List(Ident(nme.SELECTOR_DUMMY) setType fun.tpe.finalResultType)), EXPRmode, WildcardType), reportAmbiguousErrors = false) match {
- case extractorCall: Tree => extractorCall // if !extractorCall.containsError()
+ case SilentResultValue(extractorCall) => extractorCall // if !extractorCall.containsError()
case _ =>
// this fails to resolve overloading properly...
// Apply(typedOperator(Select(orig, extractor)), List(Ident(nme.SELECTOR_DUMMY))) // no need to set the type of the dummy arg, it will be replaced anyway
@@ -1128,62 +1128,48 @@ defined class Foo */
// }
// }
- def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (optimizingCodeGen) {
- def unfold(tms: List[TreeMaker], currLabel: Option[Symbol] = None, nextLabel: Option[Symbol] = None): List[CaseDef] = tms match {
- // constant
- case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._
- @inline
- def substedBody = btm.substitution(body)
- val labelledBody = currLabel match {
- case None => substedBody // currLabel.isEmpty implies nextLabel.isEmpty
- case Some(myLabel) =>
- LabelDef(myLabel, Nil,
- nextLabel match {
- case None => substedBody
- case Some(next) => ID(next) APPLY ()
- }
- )
- }
- List(CaseDef(const, EmptyTree, labelledBody))
-
- // alternatives
- case AlternativesTreeMaker(_, altss, _) :: bodyTm :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty)
- val labels = altss map { alts =>
- Some(freshSym(NoPosition, MethodType(Nil, pt), "$alt$") setFlag (METHOD | LABEL))
- }
-
- val caseDefs = (altss, labels, labels.tail :+ None).zipped.map { case (alts, currLabel, nextLabel) =>
- unfold(alts :+ bodyTm, currLabel, nextLabel)
- }
-
- if (caseDefs exists (_.isEmpty)) Nil
- else caseDefs.flatten
-
- case _ => Nil // failure
- }
+ def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (!optimizingCodeGen) None else {
+ def sequence[T](xs: List[Option[T]]): Option[List[T]] =
+ if (xs exists (_.isEmpty)) None else Some(xs.flatten)
val caseDefs = cases map { makers =>
removeSubstOnly(makers) match {
// default case (don't move this to unfold, as it may only occur on the top level, not as an alternative -- well, except in degenerate matches)
case (btm@BodyTreeMaker(body, _)) :: Nil =>
- List(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body)))
- case nonTrivialMakers =>
- unfold(nonTrivialMakers)
+ Some(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body)))
+ // constant
+ case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._
+ Some(CaseDef(const, EmptyTree, btm.substitution(body)))
+ // alternatives
+ case AlternativesTreeMaker(_, altss, _) :: (btm@BodyTreeMaker(body, _)) :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty)
+ val caseConstants = altss map {
+ case EqualityTestTreeMaker(_, const@SwitchablePattern(), _) :: Nil =>
+ Some(const)
+ case _ =>
+ None
+ }
+
+ sequence(caseConstants) map { contants =>
+ val substedBody = btm.substitution(body)
+ CaseDef(Alternative(contants), EmptyTree, substedBody)
+ }
+ case _ =>
+ None //failure (can't translate pattern to a switch)
}
}
- if (caseDefs exists (_.isEmpty)) None
- else { import CODE._
+ sequence(caseDefs) map { caseDefs =>
+ import CODE._
val matcher = BLOCK(
VAL(scrutSym) === scrut, // TODO: type test for switchable type if patterns allow switch but the scrutinee doesn't
- Match(REF(scrutSym), caseDefs.flatten) // match on scrutSym, not scrut to avoid duplicating scrut
+ Match(REF(scrutSym), caseDefs) // match on scrutSym, not scrut to avoid duplicating scrut
)
// matcher filter (tree => tree.tpe == null) foreach println
// treeBrowser browse matcher
- Some(matcher) // set type to avoid recursion in typedMatch
+ matcher // set type to avoid recursion in typedMatch
}
- } else None
+ }
def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[List[TreeMaker]] =
doCSE(prevBinder, doDCE(prevBinder, cases, pt), pt)
@@ -1471,7 +1457,7 @@ defined class Foo */
def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = {ctr += 1;
// assert(owner ne null)
// assert(owner ne NoSymbol)
- new TermSymbol(NoSymbol, pos, vpmName.counted(prefix, ctr)) setInfo repackExistential(tp)
+ NoSymbol.newTermSymbol(vpmName.counted(prefix, ctr), pos) setInfo repackExistential(tp)
}
def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 112aa47114..1a54b26307 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -955,7 +955,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
// Forward reference checking ---------------------------------------------------
class LevelInfo(val outer: LevelInfo) {
- val scope: Scope = if (outer eq null) new Scope else new Scope(outer.scope)
+ val scope: Scope = if (outer eq null) newScope else newNestedScope(outer.scope)
var maxindex: Int = Int.MinValue
var refpos: Position = _
var refsym: Symbol = _
@@ -1240,11 +1240,11 @@ 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, "")
+ private def checkBounds(tree0: Tree, pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type]): Unit =
+ try typer.infer.checkBounds(tree0, pre, owner, tparams, argtps, "")
catch {
case ex: TypeError =>
- unit.error(pos, ex.getMessage());
+ unit.error(tree0.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))
@@ -1374,22 +1374,22 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
false
}
- private def checkTypeRef(tp: Type, pos: Position) = tp match {
+ private def checkTypeRef(tp: Type, tree: Tree) = tp match {
case TypeRef(pre, sym, args) =>
- checkDeprecated(sym, pos)
+ checkDeprecated(sym, tree.pos)
if(sym.isJavaDefined)
sym.typeParams foreach (_.cookJavaRawInfo())
if (!tp.isHigherKinded)
- checkBounds(pre, sym.owner, sym.typeParams, args, pos)
+ checkBounds(tree, pre, sym.owner, sym.typeParams, args)
case _ =>
}
- private def checkAnnotations(tpes: List[Type], pos: Position) = tpes foreach (tp => checkTypeRef(tp, pos))
+ private def checkAnnotations(tpes: List[Type], tree: Tree) = tpes foreach (tp => checkTypeRef(tp, tree))
private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f
private def applyRefchecksToAnnotations(tree: Tree): Unit = {
def applyChecks(annots: List[AnnotationInfo]) = {
- checkAnnotations(annots map (_.atp), tree.pos)
+ checkAnnotations(annots map (_.atp), tree)
transformTrees(annots flatMap (_.args))
}
@@ -1404,7 +1404,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
case tpt@TypeTree() =>
if(tpt.original != null) {
tpt.original foreach {
- case dc@TypeTreeWithDeferredRefCheck() => applyRefchecksToAnnotations(dc.check()) // #2416
+ case dc@TypeTreeWithDeferredRefCheck() =>
+ applyRefchecksToAnnotations(dc.check()) // #2416
case _ =>
}
}
@@ -1450,7 +1451,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
unit.error(tree.pos, "too many dimensions for array creation")
Literal(Constant(null))
} else {
- localTyper.getManifestTree(tree.pos, etpe, false)
+ localTyper.getManifestTree(tree, etpe, false)
}
}
val newResult = localTyper.typedPos(tree.pos) {
@@ -1578,13 +1579,13 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
case ExistentialType(tparams, tpe) =>
existentialParams ++= tparams
case t: TypeRef =>
- checkTypeRef(deriveTypeWithWildcards(existentialParams.toList)(t), tree.pos)
+ checkTypeRef(deriveTypeWithWildcards(existentialParams.toList)(t), tree)
case _ =>
}
tree
case TypeApply(fn, args) =>
- checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (_.tpe), tree.pos)
+ checkBounds(tree, NoPrefix, NoSymbol, fn.tpe.typeParams, args map (_.tpe))
transformCaseApply(tree, ())
case x @ Apply(_, _) =>
@@ -1641,7 +1642,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 4e4fbe35cb..b109d57554 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -51,12 +51,21 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
private def checkPackedConforms(tree: Tree, pt: Type): Tree = {
+ def typeError(typer: analyzer.Typer, pos: Position, found: Type, req: Type) {
+ if (!found.isErroneous && !req.isErroneous) {
+ val msg = analyzer.ErrorUtils.typeErrorMsg(found, req, typer.infer.isPossiblyMissingArgs(found, req))
+ typer.context.error(pos, analyzer.withAddendum(pos)(msg))
+ if (settings.explaintypes.value)
+ explainTypes(found, req)
+ }
+ }
+
if (tree.tpe exists (_.typeSymbol.isExistentialSkolem)) {
val packed = localTyper.packedType(tree, NoSymbol)
if (!(packed <:< pt)) {
val errorContext = localTyper.context.make(localTyper.context.tree)
- errorContext.reportGeneralErrors = true
- analyzer.newTyper(errorContext).infer.typeError(tree.pos, packed, pt)
+ errorContext.setReportErrors()
+ typeError(analyzer.newTyper(errorContext), tree.pos, packed, pt)
}
}
tree
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index fe3ceafa2d..8c434a8838 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -93,37 +93,6 @@ trait TypeDiagnostics {
}
}
- def notAMemberMessage(pos: Position, qual: Tree, name: Name) = {
- 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 (posPrecedes(qual.pos, pos))
- "\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
- )
- }
-
/** An explanatory note to be added to error messages
* when there's a problem with abstract var defs */
def abstractVarMessage(sym: Symbol): String =
@@ -131,9 +100,6 @@ trait TypeDiagnostics {
"\n(Note that variables need to be initialized to be defined)"
else ""
- def notAMemberError(pos: Position, qual: Tree, name: Name) =
- context.error(pos, notAMemberMessage(pos, qual, name))
-
/** Only prints the parameter names if they're not synthetic,
* since "x$1: Int" does not offer any more information than "Int".
*/
@@ -154,21 +120,6 @@ trait TypeDiagnostics {
def alternativesString(tree: Tree) =
alternatives(tree) map (x => " " + methodTypeErrorString(x)) mkString ("", " <and>\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
- }
-
/** The symbol which the given accessor represents (possibly in part).
* This is used for error messages, where we want to speak in terms
* of the actual declaration or definition, not in terms of the generated setters
@@ -202,34 +153,6 @@ 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 })
@@ -446,8 +369,8 @@ trait TypeDiagnostics {
trait TyperDiagnostics {
self: Typer =>
- private def contextError(pos: Position, msg: String) = context.error(pos, msg)
- private def contextError(pos: Position, err: Throwable) = context.error(pos, err)
+ private def contextError(context0: Analyzer#Context, pos: Position, msg: String) = context0.error(pos, msg)
+ private def contextError(context0: Analyzer#Context, pos: Position, err: Throwable) = context0.error(pos, err)
private def contextWarning(pos: Position, msg: String) = context.unit.warning(pos, msg)
def permanentlyHiddenWarning(pos: Position, hidden: Name, defn: Symbol) =
@@ -466,14 +389,8 @@ trait TypeDiagnostics {
// Error suppression will squash some of these warnings unless we circumvent it.
// It is presumed if you are using a -Y option you would really like to hear
// the warnings you've requested.
- if (settings.warnDeadCode.value && context.unit.exists && treeOK(tree) && exprOK) {
- val saved = context.reportGeneralErrors
- try {
- context.reportGeneralErrors = true
- context.warning(tree.pos, "dead code following this construct")
- }
- finally context.reportGeneralErrors = saved
- }
+ if (settings.warnDeadCode.value && context.unit.exists && treeOK(tree) && exprOK)
+ context.warning(tree.pos, "dead code following this construct", true)
tree
}
@@ -485,8 +402,8 @@ trait TypeDiagnostics {
}
}
- def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded
- def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive"
+ 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"
/** Returns Some(msg) if the given tree is untyped apparently due
* to a cyclic reference, and None otherwise.
@@ -500,15 +417,18 @@ trait TypeDiagnostics {
"\nIf applicable, you may wish to try moving some members into another object."
)
}
-
+
/** Report a type error.
*
* @param pos0 The position where to report the error
* @param ex The exception that caused the error
*/
- def reportTypeError(pos: Position, ex: TypeError) {
+ def reportTypeError(context0: Context, pos: Position, ex: TypeError) {
if (ex.pos == NoPosition) ex.pos = pos
- if (!context.reportGeneralErrors) throw ex
+ // TODO: should be replaced by throwErrors
+ // but it seems that throwErrors excludes some of the errors that should actually be
+ // buffered, causing TypeErrors to fly around again. This needs some more investigation.
+ if (!context0.reportErrors) throw ex
if (settings.debug.value) ex.printStackTrace()
ex match {
@@ -517,12 +437,12 @@ trait TypeDiagnostics {
case Import(expr, _) => expr.pos
case _ => ex.pos
}
- contextError(pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+ contextError(context0, pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
if (sym == ObjectClass)
throw new FatalError("cannot redefine root "+sym)
case _ =>
- contextError(ex.pos, ex)
+ contextError(context0, ex.pos, ex)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b4221365be..889c04a59b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -12,14 +12,12 @@
package scala.tools.nsc
package typechecker
-import scala.collection.{ mutable, immutable }
+import scala.collection.mutable
import scala.tools.nsc.util.BatchSourceFile
import mutable.ListBuffer
import symtab.Flags._
import util.Statistics
import util.Statistics._
-import scala.tools.util.StringOps.{ countAsString, countElementsAsString }
-import scala.tools.util.EditDistance.similarString
// Suggestion check whether we can do without priming scopes with symbols of outer scopes,
// like the IDE does.
@@ -60,7 +58,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
super.traverse(tree)
}
}
-/* needed for experimental version where eraly types can be type arguments
+/* needed for experimental version where early 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) =>
@@ -71,6 +69,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
*/
+ sealed abstract class SilentResult[+T]
+ case class SilentTypeError(err: AbsTypeError) extends SilentResult[Nothing] { }
+ case class SilentResultValue[+T](value: T) extends SilentResult[T] { }
+
def newTyper(context: Context): Typer = new NormalTyper(context)
private class NormalTyper(context : Context) extends Typer(context)
@@ -80,9 +82,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
private def isPastTyper = phase.id > currentRun.typerPhase.id
- abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation {
+ abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with TyperContextErrors {
import context0.unit
import typeDebug.{ ptTree, ptBlock, ptLine }
+ import TyperErrorGen._
val infer = new Inferencer(context0) {
override def isCoercible(tp: Type, pt: Type): Boolean = undoLog undo { // #3281
@@ -102,15 +105,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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
@@ -127,8 +121,19 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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)
- context.error(fun.pos, errorMessage(param.name, param.tpe))
+ if (!param.hasDefault) {
+ context.errBuffer.find(_.kind == ErrorKinds.Divergent) match {
+ case Some(divergentImplicit) =>
+ // DivergentImplicit error has higher priority than "no implicit found"
+ // no need to issue the problem again if we are still in silent mode
+ if (context.reportErrors) {
+ context.issue(divergentImplicit)
+ context.condBufferFlush(_.kind == ErrorKinds.Divergent)
+ }
+ case None =>
+ NoImplicitFoundError(fun, param)
+ }
+ }
/* 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
@@ -149,6 +154,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case ErrorType =>
fun
}
+
+ def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree =
+ inferView(tree, from, to, reportAmbiguous, true)
/** Infer an implicit conversion (``view'') between two types.
* @param tree The tree which needs to be converted.
@@ -157,8 +165,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* @param reportAmbiguous Should ambiguous implicit errors be reported?
* False iff we search for a view to find out
* whether one type is coercible to another.
+ * @param saveErrors Should ambiguous and divergent implicit errors that were buffered
+ * during the inference of a view be put into the original buffer.
+ * False iff we don't care about them.
*/
- def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = {
+ def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
debuglog("infer view from "+from+" to "+to)//debug
if (isPastTyper) EmptyTree
else from match {
@@ -167,7 +178,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case PolyType(_, _) => EmptyTree
case _ =>
def wrapImplicit(from: Type): Tree = {
- val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context)
+ val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context, saveErrors)
if (result.subst != EmptyTreeTypeSubstituter) result.subst traverse tree
result.tree
}
@@ -205,22 +216,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* @return ...
*/
def checkStable(tree: Tree): Tree =
- if (treeInfo.isExprSafeToInline(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 ""))
+ if (treeInfo.isExprSafeToInline(tree)) tree else UnstableTreeError(tree)
/** Would tree be a stable (i.e. a pure expression) if the type
* of its symbol was not volatile?
*/
- private def isStableExceptVolatile(tree: Tree) = {
+ protected def isStableExceptVolatile(tree: Tree) = {
tree.hasSymbol && tree.symbol != NoSymbol && tree.tpe.isVolatile &&
{ val savedTpe = tree.symbol.info
val savedSTABLE = tree.symbol getFlag STABLE
@@ -234,21 +235,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
/** Check that `tpt` refers to a non-refinement class type */
- 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 {
+ def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean): Boolean = {
+ def errorNotClass(found: AnyRef) = { ClassTypeRequiredError(tpt, found); false }
+ def check(tpe: Type): Boolean = tpe.normalize match {
case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass =>
- if (stablePrefix && !isPastTyper) {
- if (!pre.isStable)
- 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 {
+ if (stablePrefix && !isPastTyper)
+ if (!pre.isStable) {
+ TypeNotAStablePrefixError(tpt, pre)
+ false
+ } else
+ // A type projection like X#Y can get by the stable check if the
+ // prefix is singleton-bounded, so peek at the tree too.
+ tpt match {
case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt)
- case _ => ;
- }
- }
- case ErrorType => ;
+ case _ => true
+ }
+ else
+ true
+ case ErrorType => true
case PolyType(_, restpe) => check(restpe)
case ExistentialType(_, restpe) if existentialOK => check(restpe)
case AnnotatedType(_, underlying, _) => check(underlying)
@@ -264,17 +268,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* @return <code>true</code> if <code>tp</code> is not a subtype of itself.
*/
def checkNonCyclic(pos: Position, tp: Type): Boolean = {
- def checkNotLocked(sym: Symbol): Boolean = {
+ def checkNotLocked(sym: Symbol) = {
sym.initialize
- sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false}
+ sym.lockOK || { CyclicAliasingOrSubtypingError(pos, sym); false }
}
tp match {
case TypeRef(pre, sym, args) =>
- (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)
- )
+ 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)
/*
@@ -293,10 +297,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = try {
- lockedSym.lock {
- throw new TypeError("illegal cyclic reference involving " + lockedSym)
- }
- checkNonCyclic(pos, tp)
+ if (!lockedSym.lock(CyclicReferenceError(pos, lockedSym))) false
+ else checkNonCyclic(pos, tp)
} finally {
lockedSym.unlock()
}
@@ -312,26 +314,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- 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 _ =>
- }
+ def checkParamsConvertible(tree: Tree, tpe0: Type) {
+ 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)
+ DependentMethodTpeConversionToFunctionError(tree, tpe)
+ checkParamsConvertible(tree, restpe)
+ case _ =>
+ }
+ checkParamsConvertible0(tpe0)
}
- def checkStarPatOK(pos: Position, mode: Int) =
- if ((mode & STARmode) == 0 && !isPastTyper)
- error(pos, "star patterns must correspond with varargs parameters")
-
/** Check that type of given tree does not contain local or private
* components.
*/
@@ -362,13 +362,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T =
check(NoSymbol, scope, pt, tree)
- def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = {
+ private 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)) setError(tree)
+ else if (hiddenSymbols exists (_.isErroneous)) HiddenSymbolWithError(tree)
else if (isFullyDefined(pt)) tree setType pt
else if (tp1.typeSymbol.isAnonymousClass)
check(owner, scope, pt, tree setType tp1.typeSymbol.classBound)
@@ -376,10 +376,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tree setType packSymbols(hiddenSymbols.reverse, tp1)
else if (!phase.erasedTypes) { // privates
val badSymbol = hiddenSymbols.head
- error(tree.pos,
- (if (badSymbol.isPrivate) "private " else "") + badSymbol +
- " escapes its defining scope as part of type "+tree.tpe)
- setError(tree)
+ SymbolEscapesScopeError(tree, badSymbol)
} else tree
}
@@ -441,28 +438,66 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
/** The qualifying class
* of a this or super with prefix <code>qual</code>.
+ * packageOk is equal false when qualifying class symbol
*/
- def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean): Symbol =
+ def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean = false): Option[Symbol] =
context.enclClass.owner.ownerChain.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
case Some(c) if packageOK || !c.isPackageClass =>
- c
+ Some(c)
case _ =>
- 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
+ QualifyingClassError(tree, qual)
+ None
}
/** The typer for an expression, depending on where we are. If we are before a superclass
* call, this is a typer over a constructor context; otherwise it is the current typer.
*/
- def constrTyperIf(inConstr: Boolean): Typer =
+ @inline
+ final def constrTyperIf(inConstr: Boolean): Typer =
if (inConstr) {
assert(context.undetparams.isEmpty)
newTyper(context.makeConstructorContext)
} else this
+ @inline
+ final def withCondConstrTyper[T](inConstr: Boolean)(f: Typer => T): T =
+ if (inConstr) {
+ assert(context.undetparams.isEmpty)
+ val c = context.makeConstructorContext
+ typerWithLocalContext(c)(f)
+ } else {
+ f(this)
+ }
+
+ @inline
+ final def typerWithCondLocalContext[T](c: => Context)(cond: Boolean)(f: Typer => T): T =
+ if (cond) typerWithLocalContext(c)(f) else f(this)
+
+ @inline
+ final def typerWithLocalContext[T](c: Context)(f: Typer => T): T = {
+ val res = f(newTyper(c))
+ if (c.hasErrors)
+ context.updateBuffer(c.flushAndReturnBuffer())
+ res
+ }
+
+ @inline
+ final def typerReportAnyContextErrors[T](c: Context)(f: Typer => T): T = {
+ val res = f(newTyper(c))
+ if (c.hasErrors)
+ context.issue(c.errBuffer.head)
+ res
+ }
+
+ @inline
+ final def withSavedContext[T](c: Context)(f: => T) = {
+ val savedErrors = c.flushAndReturnBuffer()
+ val res = f
+ c.updateBuffer(savedErrors)
+ res
+ }
+
+
/** The typer for a label definition. If this is part of a template we
* first have to enter the label definition.
*/
@@ -573,9 +608,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
inferExprAlternative(tree, pt)
val sym = tree.symbol
- def fail() = errorTree(tree, sym.kindString + " " + sym.fullName + " is not a value")
+ def fail() = NotAValueError(tree, sym)
- if (tree.tpe.isError) tree
+ if (tree.isErrorTyped) tree
else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1)
if (sym.isValue) checkStable(tree)
else fail()
@@ -629,15 +664,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def silent[T](op: Typer => T,
- reportAmbiguousErrors: Boolean = context.reportAmbiguousErrors,
- newtree: Tree = context.tree): Any /* in fact, TypeError or T */ = {
+ reportAmbiguousErrors: Boolean = context.ambiguousErrors,
+ newtree: Tree = context.tree): SilentResult[T] = {
val rawTypeStart = startCounter(rawTypeFailed)
val findMemberStart = startCounter(findMemberFailed)
val subtypeStart = startCounter(subtypeFailed)
val failedSilentStart = startTimer(failedSilentNanos)
try {
- if (context.reportGeneralErrors ||
- reportAmbiguousErrors != context.reportAmbiguousErrors ||
+ if (context.reportErrors ||
+ reportAmbiguousErrors != context.ambiguousErrors ||
newtree != context.tree) {
val context1 = context.makeSilent(reportAmbiguousErrors, newtree)
context1.undetparams = context.undetparams
@@ -648,38 +683,29 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
context.undetparams = context1.undetparams
context.savedTypeBounds = context1.savedTypeBounds
context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- result
+ if (context1.hasErrors) SilentTypeError(context1.errBuffer.head)
+ else SilentResultValue(result)
} else {
- op(this)
+ assert(context.bufferErrors || isPastTyper, "silent mode is not available past typer")
+ withSavedContext(context){
+ val res = op(this)
+ val errorsToReport = context.flushAndReturnBuffer()
+ if (errorsToReport.isEmpty) SilentResultValue(res) else SilentTypeError(errorsToReport.head)
+ }
}
} catch {
case ex: CyclicReference => throw ex
case ex: TypeError =>
+ // fallback in case TypeError is still thrown
+ // @H this happens for example in cps annotation checker
stopCounter(rawTypeFailed, rawTypeStart)
stopCounter(findMemberFailed, findMemberStart)
stopCounter(subtypeFailed, subtypeStart)
stopTimer(failedSilentNanos, failedSilentStart)
- ex
+ SilentTypeError(TypeErrorWrapper(ex))
}
}
- /** 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
@@ -724,8 +750,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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,
+ context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt,
// approximate types that depend on arguments since dependency on implicit argument is like dependency on type parameter
mt.approximate,
// if we are looking for a manifest, instantiate type to Nothing anyway,
@@ -736,18 +761,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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 => result
- case ex: TypeError =>
- debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original))
- val tree1 = typed(resetAllAttrs(original), mode, WildcardType)
- tree1.tpe = addAnnotations(tree1, tree1.tpe)
- if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree)
- }
- else
- typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)
+ // avoid throwing spurious DivergentImplicit errors
+ if (context.hasErrors)
+ return setError(tree)
+
+ withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree)){ typer1 =>
+ if (original != EmptyTree && pt != WildcardType)
+ typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match {
+ case SilentResultValue(result) =>
+ result
+ case _ =>
+ debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original))
+ val tree1 = typed(resetAllAttrs(original), mode, WildcardType)
+ tree1.tpe = addAnnotations(tree1, tree1.tpe)
+ if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree)
+ }
+ else
+ typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)
+ }
}
def instantiateToMethodType(mt: MethodType): Tree = {
@@ -758,7 +789,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (!meth.isConstructor && !meth.isMacro && isFunctionType(pt)) { // (4.2)
debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt)
- checkParamsConvertible(tree.pos, tree.tpe)
+ checkParamsConvertible(tree, tree.tpe)
val tree0 = etaExpand(context.unit, tree)
// println("eta "+tree+" ---> "+tree0+":"+tree0.tpe+" undet: "+context.undetparams+ " mode: "+Integer.toHexString(mode))
@@ -775,9 +806,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
} else if (!meth.isConstructor && mt.params.isEmpty) { // (4.3)
adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt, original)
} else if (context.implicitsEnabled) {
- 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"))
+ MissingArgsForMethodTpeError(tree, meth)
} else {
setError(tree)
}
@@ -792,8 +821,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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?
- errorTree(tree, tree.symbol + " takes type parameters")
- tree setType tree.tpe
+ MissingTypeParametersError(tree)
} 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)) &&
@@ -808,9 +836,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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).
- errorTree(tree, tree.tpe + " takes " + countElementsAsString(tree.tpe.typeParams.length, "type parameter") +
- ", expected: " + countAsString(pt.typeParams.length))
- tree setType tree.tpe
+ KindArityMismatchError(tree, pt)
} else tree match { // (6)
case TypeTree() => tree
case _ => TypeTree(tree.tpe) setOriginal (tree) setPos (tree.pos)
@@ -836,7 +862,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tree
}
} else {
- errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
+ CaseClassConstructorError(tree)
}
}
@@ -911,7 +937,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (tree.isType)
adaptType()
- else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode))
+ else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef) {
+ val tree1 = expandMacro(tree)
+ if (tree1.isErroneous) tree1 else typed(tree1, mode, pt)
+ } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode))
adaptConstrPattern()
else if (inAllModes(mode, EXPRmode | FUNmode) &&
!tree.tpe.isInstanceOf[MethodType] &&
@@ -957,7 +986,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!context.undetparams.isEmpty) {
return instantiate(tree, mode, pt)
}
- if (context.implicitsEnabled && !tree.tpe.isError && !pt.isError) {
+ if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
// (14); the condition prevents chains of views
debuglog("inferring view from " + tree.tpe + " to " + pt)
val coercion = inferView(tree, tree.tpe, pt, true)
@@ -974,8 +1003,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.echo(tree.pos, msg)
debuglog(msg)
- return newTyper(context.makeImplicit(context.reportAmbiguousErrors)).typed(
+ val silentContext = context.makeImplicit(context.ambiguousErrors)
+ val res = newTyper(silentContext).typed(
new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
+ if (silentContext.hasErrors) context.issue(silentContext.errBuffer.head) else return res
}
}
}
@@ -983,31 +1014,34 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
log("error tree = " + tree)
if (settings.explaintypes.value) explainTypes(tree.tpe, pt)
}
- try {
- typeErrorTree(tree, tree.tpe, pt)
- } catch {
- case ex: TypeError =>
- if (isPastTyper && pt.existentialSkolems.nonEmpty) {
- // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
- // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
- // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
- //
- // val x: T = expr
- //
- // where T is the type of expr, but T contains existential skolems ts.
- // In that case, this value definition does not typecheck.
- // The value definition
- //
- // val x: T forSome { ts } = expr
- //
- // would typecheck. Or one can simply leave out the type of the `val`:
- //
- // val x = expr
- 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, deriveTypeWithWildcards(pt.existentialSkolems)(pt))
- } else
- throw ex
+
+ val found = tree.tpe
+ val req = pt
+ if (!found.isErroneous && !req.isErroneous) {
+ if (!context.reportErrors && isPastTyper && req.existentialSkolems.nonEmpty) {
+ // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
+ // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
+ // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
+ //
+ // val x: T = expr
+ //
+ // where T is the type of expr, but T contains existential skolems ts.
+ // In that case, this value definition does not typecheck.
+ // The value definition
+ //
+ // val x: T forSome { ts } = expr
+ //
+ // would typecheck. Or one can simply leave out the type of the `val`:
+ //
+ // val x = expr
+ 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, deriveTypeWithWildcards(pt.existentialSkolems)(pt))
+ } else {
+ // create an actual error
+ AdaptTypeError(tree, found, req)
+ }
}
+ setError(tree)
}
}
}
@@ -1024,7 +1058,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def instantiateExpectingUnit(tree: Tree, mode: Int): Tree = {
val savedUndetparams = context.undetparams
silent(_.instantiate(tree, mode, UnitClass.tpe)) match {
- case t: Tree => t
+ case SilentResultValue(t) => t
case _ =>
context.undetparams = savedUndetparams
val valueDiscard = atPos(tree.pos)(Block(List(instantiate(tree, mode, WildcardType)), Literal(Constant())))
@@ -1050,15 +1084,20 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// Note: implicit arguments are still inferred (this kind of "chaining" is allowed)
)
}
+
+ def adaptToMember(qual: Tree, searchTemplate: Type): Tree =
+ adaptToMember(qual, searchTemplate, true, true)
+ def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree =
+ adaptToMember(qual, searchTemplate, reportAmbiguous, true)
- def adaptToMember(qual: Tree, searchTemplate: Type): Tree = {
+ def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
if (isAdaptableWithView(qual)) {
qual.tpe.widen.normalize match {
case et: ExistentialType =>
qual setType et.skolemizeExistential(context.owner, qual) // open the existential
case _ =>
}
- inferView(qual, qual.tpe, searchTemplate, true) match {
+ inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match {
case EmptyTree => qual
case coercion =>
if (settings.logImplicitConv.value)
@@ -1080,13 +1119,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* If no conversion is found, return `qual` unchanged.
*
*/
- def adaptToArguments(qual: Tree, name: Name, args: List[Tree], pt: Type): Tree = {
+ def adaptToArguments(qual: Tree, name: Name, args: List[Tree], pt: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
def doAdapt(restpe: Type) =
//util.trace("adaptToArgs "+qual+", name = "+name+", argtpes = "+(args map (_.tpe))+", pt = "+pt+" = ")
- adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe))
+ adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe), reportAmbiguous, saveErrors)
if (pt != WildcardType) {
silent(_ => doAdapt(pt)) match {
- case result: Tree if result != qual =>
+ case SilentResultValue(result) if result != qual =>
result
case _ =>
debuglog("fallback on implicits in adaptToArguments: "+qual+" . "+name)
@@ -1096,30 +1135,32 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
doAdapt(pt)
}
- /** 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`.
+ /** 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`.
*/
- def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Int): Tree = {
- 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)
+ def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Int, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
+ def onError(reportError: => Tree): Tree = {
context.tree match {
- case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => // try handling the arguments
- // println("typing args: "+args)
+ case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty =>
silent(_.typedArgs(args, mode)) match {
- case args: List[_] =>
- adaptToArguments(qual, name, args.asInstanceOf[List[Tree]], WildcardType)
- case _ =>
- throw ex
+ case SilentResultValue(xs) =>
+ val args = xs.asInstanceOf[List[Tree]]
+ if (args exists (_.isErrorTyped))
+ reportError
+ else
+ adaptToArguments(qual, name, args, WildcardType, reportAmbiguous, saveErrors)
+ case _ =>
+ reportError
}
case _ =>
- // println("not in an apply: "+context.tree+"/"+tree)
- throw ex
+ reportError
}
}
+ silent(_.adaptToMember(qual, HasMember(name), false)) match {
+ case SilentResultValue(res) => res
+ case SilentTypeError(err) => onError({if (reportAmbiguous) { context.issue(err) }; setError(tree)})
+ }
}
/** Try to apply an implicit conversion to `qual` to that it contains a
@@ -1159,7 +1200,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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.tpe.isError) {
+ if (!supertpt1.isErrorTyped) {
mixins = supertpt1 :: mixins
supertpt = TypeTree(supertpt1.tpe.parents.head) setPos supertpt.pos.focus
}
@@ -1203,14 +1244,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val cbody2 = newTyper(cscope) // called both during completion AND typing.
.typePrimaryConstrBody(clazz,
cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate)))
+
superCall match {
case Apply(_, _) =>
val sarg = treeInfo.firstArgument(superCall)
if (sarg != EmptyTree && supertpe.typeSymbol != firstParent)
- error(sarg.pos, firstParent+" is a trait; does not take constructor arguments")
- if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus
+ ConstrArgsInTraitParentTpeError(sarg, firstParent)
+ if (!supertparams.isEmpty)
+ supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus
case _ =>
- if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
+ if (!supertparams.isEmpty)
+ MissingTypeArgumentsParentTpeError(supertpt)
}
val preSuperVals = treeInfo.preSuperFields(templ.body)
@@ -1220,7 +1264,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe)
case _ =>
- if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
+ if (!supertparams.isEmpty)
+ MissingTypeArgumentsParentTpeError(supertpt)
}
/* experimental: early types as type arguments
val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef)
@@ -1253,8 +1298,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
catch {
case ex: TypeError =>
- templ.tpe = null
- reportTypeError(templ.pos, ex)
+ // fallback in case of cyclic errors
+ // @H none of the tests enter here but I couldn't rule it out
+ ParentTypesError(templ, ex)
List(TypeTree(AnyRefClass.tpe))
}
@@ -1273,30 +1319,29 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* </ul>
*/
def validateParentClasses(parents: List[Tree], selfType: Type) {
+ val pending = ListBuffer[AbsTypeError]()
def validateParentClass(parent: Tree, superclazz: Symbol) {
- if (!parent.tpe.isError) {
+ if (!parent.isErrorTyped) {
val psym = parent.tpe.typeSymbol.initialize
checkClassType(parent, false, true)
if (psym != superclazz) {
if (psym.isTrait) {
val ps = psym.info.parents
if (!ps.isEmpty && !superclazz.isSubClass(ps.head.typeSymbol))
- error(parent.pos, "illegal inheritance; super"+superclazz+
- "\n is not a subclass of the super"+ps.head.typeSymbol+
- "\n of the mixin " + psym)
+ pending += ParentSuperSubclassError(parent, superclazz, ps.head.typeSymbol, psym)
} else {
- error(parent.pos, psym+" needs to be a trait to be mixed in")
+ pending += ParentNotATraitMixinError(parent, psym)
}
}
- if (psym.isFinal) {
- error(parent.pos, "illegal inheritance from final "+psym)
- }
+ if (psym.isFinal)
+ pending += ParentFinalInheritanceError(parent, 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
- error(parent.pos, "illegal inheritance from sealed "+psym+": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath)
+ pending += ParentSealedInheritanceError(parent, psym)
}
if (!(selfType <:< parent.tpe.typeOfThis) &&
!phase.erasedTypes &&
@@ -1308,17 +1353,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
//Console.println(context.owner);//DEBUG
//Console.println(context.owner.unsafeTypeParams);//DEBUG
//Console.println(List.fromArray(context.owner.info.closure));//DEBUG
- error(parent.pos, "illegal inheritance;\n self-type "+
- selfType+" does not conform to "+parent +
- "'s selftype "+parent.tpe.typeOfThis)
+ pending += ParentSelfTypeConformanceError(parent, selfType)
if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis)
}
if (parents exists (p => p != parent && p.tpe.typeSymbol == psym && !psym.isError))
- error(parent.pos, psym+" is inherited twice")
+ pending += ParentInheritedTwiceError(parent, psym)
}
}
-
- if (!parents.isEmpty && !parents.head.tpe.isError)
+ if (!parents.isEmpty && parents.forall(!_.isErrorTyped))
for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol)
/*
@@ -1328,13 +1370,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
", baseclasses = "+(context.owner.info.baseClasses map (_.fullName))+
", lin = "+(context.owner.info.baseClasses map (context.owner.thisType.baseType)))
*/
+ pending.foreach(ErrorUtils.issueTypeError)
}
def checkFinitary(classinfo: ClassInfoType) {
val clazz = classinfo.typeSymbol
+
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,6 +1388,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case _ => newinfo
}
}
+ FinitaryError(tparam)
}
}
}
@@ -1360,8 +1404,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
assert(clazz != NoSymbol)
reenterTypeParams(cdef.tparams)
val tparams1 = cdef.tparams mapConserve (typedTypeDef)
- val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope))
- .typedTemplate(cdef.impl, parentTypes(cdef.impl))
+ val impl1 = typerReportAnyContextErrors(context.make(cdef.impl, clazz, newScope)) {
+ _.typedTemplate(cdef.impl, parentTypes(cdef.impl))
+ }
val impl2 = finishMethodSynthesis(impl1, clazz, context)
if ((clazz != ClassfileAnnotationClass) &&
(clazz isNonBottomSubClass ClassfileAnnotationClass))
@@ -1394,17 +1439,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val clazz = mdef.symbol.moduleClass
val typedMods = removeAnnotations(mdef.mods)
assert(clazz != NoSymbol, mdef)
-
- val typer0 = newTyper(context.make(mdef.impl, clazz, new Scope))
- val impl1 = typer0.typedTemplate(mdef.impl, {
- parentTypes(mdef.impl) ++ (
- if (linkedClass == NoSymbol || !linkedClass.isSerializable || clazz.isSerializable) Nil
- else {
- clazz.makeSerializable()
- List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus)
- }
- )
- })
+ val impl1 = typerReportAnyContextErrors(context.make(mdef.impl, clazz, newScope)) {
+ _.typedTemplate(mdef.impl, {
+ parentTypes(mdef.impl) ++ (
+ if (linkedClass == NoSymbol || !linkedClass.isSerializable || clazz.isSerializable) Nil
+ else {
+ clazz.makeSerializable()
+ List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus)
+ }
+ )
+ })
+ }
val impl2 = finishMethodSynthesis(impl1, clazz, context)
treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType
@@ -1513,14 +1558,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sym.hasAnnotation(definitions.VolatileAttr)) {
if (!sym.isMutable)
- error(vdef.pos, "values cannot be volatile")
+ VolatileValueError(vdef)
else if (sym.isFinal)
- error(vdef.pos, "final vars cannot be volatile")
+ FinalVolatileVarError(vdef)
}
val rhs1 =
if (vdef.rhs.isEmpty) {
if (sym.isVariable && sym.owner.isTerm && !isPastTyper)
- error(vdef.pos, "local variables must be initialized")
+ LocalVarUninitializedError(vdef)
vdef.rhs
} else {
val tpt2 = if (sym.hasDefault) {
@@ -1568,16 +1613,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val (superConstr, superArgs) = decompose(rhs)
assert(superConstr.symbol ne null)//debug
+ val pending = ListBuffer[AbsTypeError]()
// 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)
- error(tree.pos, "super constructor cannot be passed a self reference unless parameter is declared by-name")
+ pending += SuperConstrReferenceError(tree)
tree match {
case This(qual) =>
- error(tree.pos, "super constructor arguments cannot reference unconstructed `this`")
+ pending += SuperConstrArgsThisReferenceError(tree)
case _ => ()
}
}
@@ -1610,6 +1656,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
}
+ pending.foreach(ErrorUtils.issueTypeError)
}
/** Check if a structurally defined method violates implementation restrictions.
@@ -1658,7 +1705,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
lookupVariable(name.toString.substring(1), enclClass) match {
case Some(repl) =>
silent(_.typedTypeConstructor(stringParser(repl).typ())) match {
- case tpt: Tree =>
+ case SilentResultValue(tpt) =>
val alias = enclClass.newAliasType(name.toTypeName, useCase.pos)
val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias)
alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
@@ -1708,7 +1755,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1)
if (isRepeatedParamType(vparam1.symbol.tpe))
- error(vparam1.pos, "*-parameter must come last")
+ StarParamNotLastError(vparam1)
var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt))
checkNonCyclic(ddef, tpt1)
@@ -1720,7 +1767,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(!meth.owner.isClass ||
meth.owner.isModuleClass ||
meth.owner.isAnonOrRefinementClass))
- error(ddef.pos, "constructor definition not allowed here")
+ InvalidConstructorDefError(ddef)
typed(ddef.rhs)
} else if (meth.isMacro) {
EmptyTree
@@ -1735,30 +1782,26 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!isPastTyper && meth.owner.isClass &&
meth.paramss.exists(ps => ps.exists(_.hasDefaultFlag) && isRepeatedParamType(ps.last.tpe)))
- error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments")
+ StarWithDefaultError(meth)
if (!isPastTyper) {
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))))
- error(p.pos, "deprecated parameter name "+ n +" has to be distinct from any other parameter name (deprecated or not).")
+ DeprecatedParamNameError(p, n)
}
}
}
if (meth.isStructuralRefinementMember)
checkMethodStructuralCompatible(meth)
-
treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
}
- def typedTypeDef(tdef: TypeDef): TypeDef = {
- def typeDefTyper = {
- if(tdef.tparams isEmpty) Typer.this
- else newTyper(context.makeNewScope(tdef, tdef.symbol))
+ def typedTypeDef(tdef: TypeDef): TypeDef =
+ typerWithCondLocalContext(context.makeNewScope(tdef, tdef.symbol))(tdef.tparams.nonEmpty){
+ _.typedTypeDef0(tdef)
}
- typeDefTyper.typedTypeDef0(tdef)
- }
// call typedTypeDef instead
// a TypeDef with type parameters must always be type checked in a new scope
@@ -1780,10 +1823,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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 _ =>
+ case TypeBounds(lo1, hi1) if (!(lo1 <:< hi1)) => LowerBoundError(tdef, lo1, hi1)
+ case _ => ()
}
treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType
}
@@ -1903,9 +1944,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
// verify no _* except in last position
for (Apply(_, xs) <- cdef.pat ; x <- xs dropRight 1 ; if treeInfo isStar x)
- error(x.pos, "_* may only come last")
+ StarPositionInPatternError(x)
- val pat1: Tree = typedPattern(cdef.pat, pattpe)
+ val pat1 = 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
@@ -1949,7 +1990,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val codeExpected = !forMSIL && (pt.typeSymbol isNonBottomSubClass CodeClass)
if (numVparams > definitions.MaxFunctionArity)
- return errorTree(fun, "implementation restricts functions to " + definitions.MaxFunctionArity + " parameters")
+ return MaxFunctionArityError(fun)
def decompose(pt: Type): (Symbol, List[Type], Type) =
if ((isFunctionType(pt)
@@ -1965,9 +2006,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType)
val (clazz, argpts, respt) = decompose(if (codeExpected) pt.normalize.typeArgs.head else pt)
-
if (argpts.lengthCompare(numVparams) != 0)
- errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
+ WrongNumberOfParametersError(fun, argpts)
else {
val vparamSyms = map2(fun.vparams, argpts) { (vparam, argpt) =>
if (vparam.tpt.isEmpty) {
@@ -1977,7 +2017,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
fun match {
case etaExpansion(vparams, fn, args) if !codeExpected =>
silent(_.typed(fn, forFunMode(mode), pt)) match {
- case fn1: Tree if context.undetparams.isEmpty =>
+ case SilentResultValue(fn1) 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)
@@ -1988,7 +2028,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
case _ =>
}
- error(vparam.pos, missingParameterTypeMsg(fun, vparam, pt))
+ MissingParameterTypeError(fun, vparam, pt)
ErrorType
}
if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus
@@ -2002,12 +2042,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// for (vparam <- vparams) {
// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
// }
- var body = typed(fun.body, respt)
+ val body1 = typed(fun.body, respt)
val formals = vparamSyms map (_.tpe)
- val restpe = packedType(body, fun.symbol).deconst.resultType
+ val restpe = packedType(body1, fun.symbol).deconst.resultType
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)
+ val fun1 = treeCopy.Function(fun, vparams, body1).setType(funtpe)
if (codeExpected) lifted(fun1) else fun1
}
}
@@ -2022,7 +2062,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.toCheck += { () =>
// go to next outer context which is not silent, see #3614
var c = context
- while (!c.reportGeneralErrors) c = c.outer
+ while (c.bufferErrors) c = c.outer
val stats1 = newTyper(c).typedStats(stats, NoSymbol)
for (stat <- stats1 if stat.isDef) {
val member = stat.symbol
@@ -2038,11 +2078,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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 _ =>
- (treeInfo isExprSafeToInline tree) && {
+ !tree.isErrorTyped && (treeInfo isExprSafeToInline tree) && {
val sym = tree.symbol
(sym == null) || !(sym.isModule || sym.isLazy) || {
debuglog("'Pure' but side-effecting expression in statement position: " + tree)
@@ -2056,9 +2095,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def includesTargetPos(tree: Tree) =
tree.pos.isRange && context.unit.exists && (tree.pos includes context.unit.targetPos)
val localTarget = stats exists includesTargetPos
+ val statsErrors = scala.collection.mutable.LinkedHashSet[AbsTypeError]()
def typedStat(stat: Tree): Tree = {
if (context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(stat))
- errorTree(stat, "only declarations allowed here")
+ OnlyDeclarationsError(stat)
else
stat match {
case imp @ Import(_, _) =>
@@ -2071,20 +2111,25 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// the targetposition
stat
} else {
- val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this
- else newTyper(context.make(stat, exprOwner))
+ val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) {
+ context.flushBuffer()
+ this
+ } else newTyper(context.make(stat, exprOwner))
// 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))
+
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")
+ ConstructorsOrderError(stat)
}
+
if (isWarnablePureExpression(result)) context.warning(stat.pos,
"a pure expression does nothing in statement position; " +
"you may be omitting necessary parentheses"
)
+ statsErrors ++= localTyper.context.errBuffer
result
}
}
@@ -2118,9 +2163,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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)) {
- error(e.sym.pos, e1.sym+" is defined twice"+
- {if(!settings.debug.value) "" else " in "+unit.toString}+
- {if (e.sym.isMacro && e1.sym.isMacro) " \n(note that macros cannot be overloaded)" else ""})
+ DefDefinedTwiceError(e.sym, e1.sym)
scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
}
e1 = scope.lookupNextEntry(e1)
@@ -2165,14 +2208,20 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}) ::: newStats.toList
}
}
- val result = stats mapConserve typedStat
- if (phase.erasedTypes) result
- else checkNoDoubleDefsAndAddSynthetics(result)
+
+ val stats1 = withSavedContext(context) {
+ val result = stats mapConserve typedStat
+ context.flushBuffer()
+ result
+ }
+ context.updateBuffer(statsErrors)
+ if (phase.erasedTypes) stats1
+ else checkNoDoubleDefsAndAddSynthetics(stats1)
}
def typedArg(arg: Tree, mode: Int, newmode: Int, pt: Type): Tree = {
val typedMode = onlyStickyModes(mode) | newmode
- val t = constrTyperIf((mode & SCCmode) != 0).typed(arg, typedMode, pt)
+ val t = withCondConstrTyper((mode & SCCmode) != 0)(_.typed(arg, typedMode, pt))
checkDead.inMode(typedMode, t)
}
@@ -2241,8 +2290,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
// TODO_NMT: check the assumption that args nonEmpty
- def errTree = setError(treeCopy.Apply(tree, fun0, args))
- def errorTree(msg: String) = { error(tree.pos, msg); errTree }
+ def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
+ def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
var fun = fun0
if (fun.hasSymbol && fun.symbol.isOverloaded) {
@@ -2305,8 +2354,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
arg1
}
context.undetparams = undetparams
- inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
- doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ if (context.hasErrors)
+ setError(tree)
+ else {
+ 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
@@ -2326,7 +2379,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// the inner "doTypedApply" does "extractUndetparams" => restore when it fails
val savedUndetparams = context.undetparams
silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) match {
- case t: Tree =>
+ case SilentResultValue(t) =>
// Depending on user options, may warn or error here if
// a Unit or tuple was inserted.
Some(t) filter (tupledTree =>
@@ -2334,7 +2387,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
|| tupledTree.symbol == null
|| checkValidAdaptation(tupledTree, args)
)
- case ex =>
+ case _ =>
context.undetparams = savedUndetparams
None
}
@@ -2349,21 +2402,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def tryNamesDefaults: Tree = {
val lencmp = compareLengths(args, formals)
- if (mt.isErroneous) errTree
- else if (inPatternMode(mode))
+ if (mt.isErroneous) duplErrTree
+ else if (inPatternMode(mode)) {
// #2064
- errorTree("wrong number of arguments for "+ treeSymTypeMsg(fun))
- else if (lencmp > 0) {
- tryTupleApply getOrElse errorTree("too many arguments for "+treeSymTypeMsg(fun))
+ duplErrorTree(WrongNumberOfArgsError(tree, fun))
+ } else if (lencmp > 0) {
+ tryTupleApply getOrElse duplErrorTree(TooManyArgsNamesDefaultsError(tree, 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 (_.isErroneous)) {
- errTree
+ duplErrTree
} else if (!isIdentity(argPos) && !sameLength(formals, params))
// !isIdentity indicates that named arguments are used to re-order arguments
- errorTree("when using named arguments, the vararg parameter has to be specified exactly once")
+ duplErrorTree(MultipleVarargError(tree))
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 }"
@@ -2377,7 +2430,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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.isErroneous) errTree
+ if (fun1.isErroneous) duplErrTree
else {
assert(isNamedApplyBlock(fun1), fun1)
val NamedApplyInfo(qual, targs, previousArgss, _) = context.namedApplyBlockInfo.get._2
@@ -2394,17 +2447,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val lencmp2 = compareLengths(allArgs, formals)
if (!sameLength(allArgs, args) && callToCompanionConstr(context, funSym)) {
- errorTree("module extending its companion class cannot use default constructor arguments")
+ duplErrorTree(ModuleUsingCompanionClassDefaultArgsErrror(tree))
} else if (lencmp2 > 0) {
removeNames(Typer.this)(allArgs, params) // #3818
- errTree
+ duplErrTree
} 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 errorTree(notEnoughArgumentsMsg(fun, missing))
+ tryTupleApply getOrElse duplErrorTree(NotEnoughArgsError(tree, fun, missing))
}
}
}
@@ -2463,7 +2516,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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)
@@ -2485,11 +2537,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!argtparams.isEmpty) {
val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
- }
- arg1
+ arg1
+ } else arg1
}
val args1 = map2(args, formals)(typedArgToPoly)
- if (args1 exists (_.tpe.isError)) errTree
+ if (args1 exists {_.isErrorTyped}) duplErrTree
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"
@@ -2506,12 +2558,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
doTypedApply(tree, fun setType fun.tpe.widen, args, mode, pt)
case ErrorType =>
- setError(treeCopy.Apply(tree, fun, args))
+ if (!tree.isErrorTyped) setError(tree) else tree
+ // @H change to setError(treeCopy.Apply(tree, fun, args))
/* --- begin unapply --- */
case otpe if inPatternMode(mode) && unapplyMember(otpe).exists =>
if (args.length > MaxTupleArity)
- error(fun.pos, "too many arguments for unapply pattern, maximum = "+MaxTupleArity)
+ return duplErrorTree(TooManyArgsPatternError(fun))
//
def freshArgType(tp: Type): (List[Symbol], Type) = tp match {
@@ -2519,11 +2572,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(Nil, param.tpe)
case PolyType(tparams, restpe) =>
createFromClonedSymbols(tparams, freshArgType(restpe)._2)((ps, t) => ((ps, t)))
+ // 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")
+ OverloadedUnapplyError(fun)
(Nil, ErrorType)
case _ =>
- error(fun.pos, "an unapply method must accept a single argument.")
+ UnapplyWithSingleArgError(fun)
(Nil, ErrorType)
}
@@ -2539,7 +2593,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
freeVars foreach unapplyContext.scope.enter
val typer1 = newTyper(unapplyContext)
- val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe)
+ val pattp = typer1.infer.inferTypedPattern(tree, unappFormal, arg.tpe)
// turn any unresolved type variables in freevars into existential skolems
val skolems = freeVars map (fv => unapplyContext.owner.newExistentialSkolem(fv, fv))
@@ -2550,8 +2604,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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)))
- if (fun1.tpe.isErroneous) errTree
- else {
+ if (fun1.tpe.isErroneous) {
+ duplErrTree
+ } else {
val formals0 = unapplyTypeList(fun1.symbol, fun1.tpe)
val formals1 = formalTypes(formals0, args.length)
if (sameLength(formals1, args)) {
@@ -2564,15 +2619,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val itype = glb(List(pt1, arg.tpe))
arg.tpe = pt1 // restore type (arg is a dummy tree, just needs to pass typechecking)
UnApply(fun1, args1) setPos tree.pos setType itype
- }
- else {
- errorTree("wrong number of arguments for "+treeSymTypeMsg(fun))
- }
+ } else
+ duplErrorTree(WrongNumberArgsPatternError(tree, fun))
}
/* --- end unapply --- */
case _ =>
- errorTree(fun.tpe+" does not take parameters")
+ duplErrorTree(ApplyWithoutArgsError(tree, fun))
}
}
@@ -2584,8 +2637,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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
- def error(pos: Position, msg: String) = {
- context.error(pos, msg)
+ val pending = ListBuffer[AbsTypeError]()
+
+ def reportAnnotationError(err: AbsTypeError) = {
+ pending += err
hasError = true
annotationError
}
@@ -2601,13 +2656,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case tpe => null
}
}
- def fail(msg: String) = { error(tr.pos, msg) ; None }
- 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
+ if (const == null) {
+ reportAnnotationError(AnnotationNotAConstantError(tr)); None
+ } else if (const.value == null) {
+ reportAnnotationError(AnnotationArgNullError(tr)); None
+ } else
Some(LiteralAnnotArg(const))
}
@@ -2616,16 +2670,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
*/
def tree2ConstArg(tree: Tree, pt: Type): Option[ClassfileAnnotArg] = tree match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) if (pt.typeSymbol == ArrayClass) =>
- error(tree.pos, "Array constants have to be specified using the `Array(...)' factory method")
- None
+ reportAnnotationError(ArrayConstantsError(tree)); 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
- None
- } else Some(NestedAnnotArg(annInfo))
+ if (annInfo.atp.isErroneous) { hasError = true; 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)
@@ -2640,13 +2690,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// BT = Int, .., String, Class[_], JavaAnnotClass
// T = BT | Array[BT]
// So an array literal as argument can only be valid if pt is Array[_]
- error(tree.pos, "found array constant, expected argument of type "+ pt)
+ reportAnnotationError(ArrayConstantsTypeMismatchError(tree, 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)
@@ -2666,13 +2716,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Select(New(tpt), nme.CONSTRUCTOR) =>
(fun, outerArgss)
case _ =>
- error(fun.pos, "unexpected tree in annotation: "+ fun)
+ reportAnnotationError(UnexpectedTreeAnnotation(fun))
(setError(fun), outerArgss)
}
extract(ann, List())
}
- if (fun.isErroneous) annotationError
+ val res = if (fun.isErroneous) annotationError
else {
val typedFun @ Select(New(tpt), _) = typed(fun, forFunMode(mode), WildcardType)
val annType = tpt.tpe
@@ -2682,9 +2732,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// annotation to be saved as java classfile annotation
val isJava = typedFun.symbol.owner.isJavaDefined
if (!annType.typeSymbol.isNonBottomSubClass(annClass)) {
- error(tpt.pos, "expected annotation of type "+ annClass.tpe +", found "+ annType)
+ reportAnnotationError(AnnotationTypeMismatchError(tpt, annClass.tpe, annType))
} else if (argss.length > 1) {
- error(ann.pos, "multiple argument lists on classfile annotation")
+ reportAnnotationError(MultipleArgumentListForAnnotationError(ann))
} else {
val args =
if (argss.head.length == 1 && !isNamed(argss.head.head))
@@ -2700,10 +2750,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val sym = if (isJava) annScope.lookup(name)
else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol)
if (sym == NoSymbol) {
- error(arg.pos, "unknown annotation argument name: " + name)
+ reportAnnotationError(UnknownAnnotationNameError(arg, name))
(nme.ERROR, None)
} else if (!names.contains(sym)) {
- error(arg.pos, "duplicate value for annotation argument " + name)
+ reportAnnotationError(DuplicateValueAnnotationError(arg, name))
(nme.ERROR, None)
} else {
names -= sym
@@ -2712,21 +2762,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(sym.name, annArg)
}
case arg =>
- error(arg.pos, "classfile annotation arguments have to be supplied as named arguments")
+ reportAnnotationError(ClassfileAnnotationsAsNamedArgsError(arg))
(nme.ERROR, None)
}
for (sym <- names) {
// make sure the flags are up to date before erroring (jvm/t3415 fails otherwise)
sym.initialize
if (!sym.hasAnnotation(AnnotationDefaultAttr) && !sym.hasDefaultFlag)
- error(ann.pos, "annotation " + annType.typeSymbol.fullName + " is missing argument " + sym.name)
+ reportAnnotationError(AnnotationMissingArgError(ann, annType, sym))
}
if (hasError) annotationError
else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setPos(ann.pos)
}
} else if (requireJava) {
- error(ann.pos, "nested classfile annotations must be defined in java; found: "+ annType)
+ reportAnnotationError(NestedAnnotationError(ann, annType))
} else {
val typedAnn = if (selfsym == NoSymbol) {
typed(ann, mode, annClass.tpe)
@@ -2778,7 +2828,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
annInfo(fun)
case _ =>
- error(t.pos, "unexpected tree after typing annotation: "+ typedAnn)
+ reportAnnotationError(UnexpectedTreeAnnotationError(t, typedAnn))
}
if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2)
@@ -2788,6 +2838,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else annInfo(typedAnn)
}
}
+
+ if (hasError) {
+ pending.foreach(ErrorUtils.issueTypeError)
+ annotationError
+ } else res
}
def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
@@ -2835,9 +2890,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def packSymbols(hidden: List[Symbol], tp: Type): Type =
if (hidden.isEmpty) tp
else existentialTransform(hidden, tp)(existentialAbstraction)
+
+ def isReferencedFrom(ctx: Context, sym: Symbol): Boolean =
+ ctx.owner.isTerm &&
+ (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) ||
+ {
+ var ctx1 = ctx.outer
+ while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer
+ (ctx1 != NoContext) && isReferencedFrom(ctx1, sym)
+ }
def isCapturedExistential(sym: Symbol) =
- sym hasAllFlags (EXISTENTIAL | CAPTURED) // todo refine this
+ (sym hasAllFlags (EXISTENTIAL | CAPTURED)) && {
+ val start = startTimer(isReferencedNanos)
+ try !isReferencedFrom(context, sym)
+ finally stopTimer(isReferencedNanos, start)
+ }
def packCaptured(tpe: Type): Type = {
val captured = mutable.Set[Symbol]()
@@ -2874,7 +2942,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sym.isAliasType && containsLocal(tp)) apply(tp.normalize)
else {
if (pre.isVolatile)
- context.error(tree.pos, "Inferred type "+tree.tpe+" contains type selection from volatile type "+pre)
+ InferTypeWithVolatileTypeSelectionError(tree, pre)
mapOver(tp)
}
case _ =>
@@ -2891,8 +2959,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
localSyms += sym
remainingSyms += sym
} else {
- unit.error(tree.pos,
- "can't existentially abstract over parameterized type " + tp)
+ AbstractExistentiallyOverParamerizedTpeError(tree, tp)
}
}
}
@@ -2961,10 +3028,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
new DeSkolemizeMap mapOver tp
}
- def typedClassOf(tree: Tree, tpt: Tree) = {
- checkClassType(tpt, true, false)
- atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
- }
+ def typedClassOf(tree: Tree, tpt: Tree, noGen: Boolean = false) =
+ if (!checkClassType(tpt, true, false) && noGen) tpt
+ else atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = {
for (wc <- tree.whereClauses)
@@ -2973,7 +3039,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val whereClauses1 = typedStats(tree.whereClauses, context.owner)
for (vd @ ValDef(_, _, _, _) <- tree.whereClauses)
if (vd.symbol.tpe.isVolatile)
- error(vd.pos, "illegal abstraction from value with volatile type "+vd.symbol.tpe)
+ AbstractionFromVolatileTypeError(vd)
val tpt1 = typedType(tree.tpt, mode)
existentialTransform(tree.whereClauses map (_.symbol), tpt1.tpe)((tparams, tp) =>
TypeTree(newExistentialType(tparams, tp)) setOriginal tree
@@ -2996,7 +3062,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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 errorTree(fun, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ return TypedApplyWrongNumberOfTpeParametersError(fun, fun)
typedTypeApply(tree, mode, fun, args1)
case SingleType(_, _) =>
@@ -3004,12 +3070,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case PolyType(tparams, restpe) if tparams.nonEmpty =>
if (sameLength(tparams, args)) {
val targs = args map (_.tpe)
- checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "")
+ checkBounds(tree, NoPrefix, NoSymbol, tparams, targs, "")
if (fun.symbol == Predef_classOf)
- typedClassOf(tree, args.head)
+ typedClassOf(tree, args.head, true)
else {
if (!isPastTyper && fun.symbol == Any_isInstanceOf && !targs.isEmpty)
- checkCheckable(tree.pos, targs.head, "")
+ checkCheckable(tree, 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]
@@ -3020,12 +3086,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
treeCopy.TypeApply(tree, fun, args) setType resultpe
}
} else {
- errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ TypedApplyWrongNumberOfTpeParametersError(tree, fun)
}
case ErrorType =>
setError(treeCopy.TypeApply(tree, fun, args))
case _ =>
- errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.")
+ TypedApplyDoesNotTakeTpeParametersError(tree, fun)
}
@inline final def deindentTyping() = context.typingIndentLevel -= 2
@@ -3094,6 +3160,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// this annotation did not need it
if (ainfo.isErroneous)
+ // Erroneous annotations were already reported in typedAnnotation
arg1 // simply drop erroneous annotations
else {
ann.tpe = atype
@@ -3133,7 +3200,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
vble = context.owner.newValue(name, tree.pos)
if (vble.name.toTermName != nme.WILDCARD) {
if ((mode & ALTmode) != 0)
- error(tree.pos, "illegal variable in pattern alternative")
+ VariableInPatternAlternativeError(tree)
vble = namer.enterInScope(vble)
}
val body1 = typed(body, mode, pt)
@@ -3160,18 +3227,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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.tpe.isError)
- error(tree.pos, failMsg)
+ // see #2494 for double error message example
+ def fail() =
+ if (lhs1.isErrorTyped) lhs1
+ else AssignmentError(tree, varsym)
- setError(tree)
- }
if (varsym == null)
- return fail
+ return fail()
if (treeInfo.mayBeVarGetter(varsym)) {
treeInfo.methPart(lhs1) match {
@@ -3187,7 +3250,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val rhs1 = typed(rhs, EXPRmode | BYVALmode, lhs1.tpe)
treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe
}
- else fail
+ else fail()
}
def typedIf(cond: Tree, thenp: Tree, elsep: Tree) = {
@@ -3257,12 +3320,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
enclMethod.owner.isConstructor ||
context.enclClass.enclMethod == enclMethod // i.e., we are in a constructor of a local class
) {
- errorTree(tree, "return outside method definition")
+ ReturnOutsideOfDefError(tree)
} else {
val DefDef(_, name, _, _, restpt, _) = enclMethod.tree
- if (restpt.tpe eq null)
- errorTree(tree, enclMethod.owner + " has return statement; needs result type")
- else {
+ if (restpt.tpe eq null) {
+ ReturnWithoutTypeError(tree, enclMethod.owner)
+ } 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.
@@ -3281,12 +3344,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedNew(tpt: Tree) = {
val tpt1 = {
val tpt0 = typedTypeConstructor(tpt)
- 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 (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
+ else tpt0
}
/** If current tree <tree> appears in <val x(: T)? = <tree>>
@@ -3305,17 +3369,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val tp = tpt1.tpe
val sym = tp.typeSymbol.initialize
if (sym.isAbstractType || sym.hasAbstractFlag)
- error(tree.pos, sym + " is abstract; cannot be instantiated")
+ IsAbstractError(tree, sym)
else if (!( tp == sym.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
)) {
- error(tree.pos, sym +
- " cannot be instantiated because it does not conform to its self-type "+
- tp.typeOfThis)
- }
- treeCopy.New(tree, tpt1).setType(tp)
+ DoesNotConformToSelfTypeError(tree, sym, tp.typeOfThis)
+ } else
+ treeCopy.New(tree, tpt1).setType(tp)
}
def typedEta(expr1: Tree): Tree = expr1.tpe match {
@@ -3353,22 +3415,28 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case ErrorType =>
expr1
case _ =>
- errorTree(expr1, "_ must follow method; cannot follow " + expr1.tpe)
+ UnderscoreEtaError(expr1)
}
/**
* @param args ...
* @return ...
*/
- def tryTypedArgs(args: List[Tree], mode: Int, other: TypeError): List[Tree] = {
+ def tryTypedArgs(args: List[Tree], mode: Int): Option[List[Tree]] = {
val c = context.makeSilent(false)
c.retyping = true
try {
- newTyper(c).typedArgs(args, mode)
+ val res = newTyper(c).typedArgs(args, mode)
+ if (c.hasErrors) None else Some(res)
} catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError =>
- null
+ case ex: CyclicReference =>
+ throw ex
+ case te: TypeError =>
+ // @H some of typer erros can still leak,
+ // for instance in continuations
+ None
+ } finally {
+ c.flushBuffer()
}
}
@@ -3377,10 +3445,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
val start = startTimer(failedApplyNanos)
- silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
- case t: Tree =>
- t
- case ex: TypeError =>
+
+ def onError(typeError: AbsTypeError): Tree = {
stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
@@ -3403,27 +3469,39 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(r, Function(Nil, EmptyTree)) => treesInResult(r)
case _ => Nil
})
- def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ex.pos)
- val retry = fun :: tree :: args exists errorInResult
+ def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == typeError.errPos)
+
+ val retry = (typeError.errPos != null) && (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: " + ex.pos+"!="+tree.pos
+ else "no second try: " + funStr + " because error not in result: " + typeError.errPos+"!="+tree.pos
}
if (retry) {
val Select(qual, name) = fun
- val args1 = tryTypedArgs(args, forArgMode(fun, mode), ex)
- val qual1 =
- 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)
+ tryTypedArgs(args, forArgMode(fun, mode)) match {
+ case Some(args1) =>
+ assert((args1.length == 0) || !args1.head.tpe.isErroneous, "try typed args is ok")
+ val qual1 =
+ if (!pt.isError) adaptToArguments(qual, name, args1, pt, true, true)
+ 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)
+ }
+ case _ => ()
}
}
- reportTypeError(tree.pos, ex)
+ issue(typeError)
setError(treeCopy.Apply(tree, fun, args))
}
+
+ silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
+ case SilentResultValue(t) =>
+ t
+ case SilentTypeError(err) =>
+ onError(err)
+ }
}
def typedApply(fun: Tree, args: List[Tree]) = {
@@ -3435,10 +3513,28 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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(newTermName(name.decode)) =>
+ val qual1 = typedQualifier(qual)
+ if (treeInfo.isVariableOrGetter(qual1)) {
+ stopTimer(failedOpEqNanos, opeqStart)
+ convertToAssignment(fun, qual1, name, args)
+ } else {
+ stopTimer(failedApplyNanos, appStart)
+ reportError
+ }
+ case _ =>
+ stopTimer(failedApplyNanos, appStart)
+ reportError
+ }
+ }
silent(_.typed(fun, forFunMode(mode), funpt),
- if ((mode & EXPRmode) != 0) false else context.reportAmbiguousErrors,
+ if ((mode & EXPRmode) != 0) false else context.ambiguousErrors,
if ((mode & EXPRmode) != 0) tree else context.tree) match {
- case fun1: Tree =>
+ case SilentResultValue(fun1) =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
incCounter(typedApplyCount)
def isImplicitMethod(tpe: Type) = tpe match {
@@ -3465,40 +3561,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
//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) {
+ if (fun2.symbol == Array_apply && !res.isErrorTyped) {
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 if ((mode & FUNmode) == 0 && fun2.hasSymbol && fun2.symbol.isMacro)
- typed1(macroExpand(res), mode, pt)
- else
+ } else
res
- case ex: TypeError =>
- fun match {
- case Select(qual, name)
- if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) =>
- val qual1 = typedQualifier(qual)
- if (treeInfo.isVariableOrGetter(qual1)) {
- stopTimer(failedOpEqNanos, opeqStart)
- convertToAssignment(fun, qual1, name, args, ex)
- }
- else {
- stopTimer(failedApplyNanos, appStart)
- reportTypeError(fun.pos, ex)
- setError(tree)
- }
- case _ =>
- stopTimer(failedApplyNanos, appStart)
- reportTypeError(fun.pos, ex)
- setError(tree)
- }
+ case SilentTypeError(err) =>
+ onError({issue(err); setError(tree)})
}
}
}
- def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree], ex: TypeError): Tree = {
+ def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = {
val prefix = name.subName(0, name.length - nme.EQL.length)
def mkAssign(vble: Tree): Tree =
Assign(
@@ -3539,25 +3616,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Apply(fn, indices) =>
treeInfo.methPart(fn) match {
case Select(table, nme.apply) => mkUpdate(table, indices)
- case _ => errorTree(qual, "Unexpected tree during assignment conversion.")
+ case _ => UnexpectedTreeAssignmentConversionError(qual)
}
}
typed1(tree1, mode, pt)
-/*
- debuglog("retry assign: "+tree1)
- silent(_.typed1(tree1, mode, pt)) match {
- case t: Tree =>
- t
- case _ =>
- reportTypeError(tree.pos, ex)
- setError(tree)
- }
-*/
}
- 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)
@@ -3582,12 +3646,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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")
+ ErrorType
} else {
- error(tree.pos, mix+" does not name a parent class of "+clazz)
+ MixinMissingParentClassNameError(tree, mix, clazz)
+ ErrorType
}
- ErrorType
} else if (!ps.tail.isEmpty) {
- error(tree.pos, "ambiguous parent class qualifier")
+ AmbiguousParentClassError(tree)
ErrorType
} else {
ps.head
@@ -3604,16 +3669,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
findMixinSuper(clazz.tpe)
}
- treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
- }
+ treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
+ }
def typedThis(qual: Name) = {
- val clazz = qualifyingClassSym(qual)
- if (clazz == NoSymbol) setError(tree)
- else {
- tree setSymbol clazz setType clazz.thisType.underlying
- if (isStableContext(tree, mode, pt)) tree setType clazz.thisType
- tree
+ val qualifyingClassSym = if (tree.symbol != NoSymbol) Some(tree.symbol) else qualifyingClass(tree, qual)
+ qualifyingClassSym match {
+ case Some(clazz) =>
+ tree setSymbol clazz setType clazz.thisType.underlying
+ if (isStableContext(tree, mode, pt)) tree setType clazz.thisType
+ tree
+ case None => tree
}
}
@@ -3645,10 +3711,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) {
val qual1 =
if (member(qual, name) != NoSymbol) qual
- else adaptToMemberWithArgs(tree, qual, name, mode)
- if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt)
- }
+ else adaptToMemberWithArgs(tree, qual, name, mode, true, true)
+ if (qual1 ne qual)
+ return typed(treeCopy.Select(tree, qual1, name), mode, pt)
+ }
if (!reallyExists(sym)) {
if (context.owner.toplevelClass.isJavaDefined && name.isTypeName) {
val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
@@ -3677,7 +3744,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
)
}
- def makeErrorTree = {
+ def makeInteractiveErrorTree = {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
@@ -3686,24 +3753,31 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (name == nme.ERROR && forInteractive)
- return makeErrorTree
+ return makeInteractiveErrorTree
if (!qual.tpe.widen.isErroneous) {
if ((mode & QUALmode) != 0) {
val lastTry = missingHook(qual.tpe.typeSymbol, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
}
- notAMemberError(tree.pos, qual, name)
+ NotAMemberError(tree, qual, name)
}
- if (forInteractive) makeErrorTree else setError(tree)
+ if (forInteractive) makeInteractiveErrorTree else setError(tree)
} else {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
}
- val (tree2, pre2) = makeAccessible(tree1, sym, qual.tpe, qual)
- val result = stabilize(tree2, pre2, mode, pt)
+ val (result, accessibleError) = silent(_.makeAccessible(tree1, sym, qual.tpe, qual)) match {
+ case SilentTypeError(err) =>
+ if (err.kind != ErrorKinds.Access) {
+ context issue err
+ return setError(tree)
+ } else (tree1, Some(err))
+ case SilentResultValue(treeAndPre) =>
+ (stabilize(treeAndPre._1, treeAndPre._2, mode, pt), None)
+ }
def isPotentialNullDeference() = {
!isPastTyper &&
@@ -3722,16 +3796,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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, "")
+ checkBounds(qual, 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 setPos qual.pos,
name)
- 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 _ if accessibleError.isDefined =>
+ val qual1 = adaptToMemberWithArgs(tree, qual, name, mode, false, false)
+ if (!qual1.isErrorTyped && (qual1 ne qual))
+ typed(Select(qual1, name) setPos tree.pos, mode, pt)
+ else {
+ issue(accessibleError.get)
+ setError(tree)
+ }
case _ =>
result
}
@@ -3739,7 +3815,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// getClass, we have to catch it immediately so expressions
// like x.getClass().newInstance() are typed with the type of x.
val isRefinableGetClass = (
- selection.symbol.name == nme.getClass_
+ !selection.isErrorTyped
+ && 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
@@ -3747,7 +3824,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
&& qual.tpe.typeSymbol.isPublic
)
if (isRefinableGetClass)
- selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe))
+ selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe))
else
selection
}
@@ -3761,8 +3838,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* (2) Change imported symbols to selections
*/
def typedIdent(name: Name): Tree = {
- def ambiguousError(msg: String) =
- error(tree.pos, "reference to " + name + " is ambiguous;\n" + msg)
+ var errorContainer: AbsTypeError = 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: AbsTypeError) = {
+ assert(errorContainer == null, "Cannot set ambiguous error twice for identifier")
+ errorContainer = tree
+ }
var defSym: Symbol = tree.symbol // the directly found symbol
var pre: Type = NoPrefix // the prefix type of defSym, if a class member
@@ -3882,7 +3968,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
ambiguousError(
"it is imported twice in the same scope by\n"+imports.head + "\nand "+imports1.head)
}
- while (!imports1.isEmpty &&
+ while (errorContainer == null && !imports1.isEmpty &&
(!imports.head.isExplicitImport(name) ||
imports1.head.depth == imports.head.depth)) {
var impSym1 = imports1.head.importedSymbol(name)
@@ -3916,74 +4002,49 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (inaccessibleSym eq NoSymbol) {
// Avoiding some spurious error messages: see SI-2388.
if (reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME)) ()
- else {
- // This laborious determination arrived at to keep the tests working.
- val calcSimilar = (
- name.length > 2 && (
- startingIdentContext.reportGeneralErrors
- || startingIdentContext.enclClassOrMethod.reportGeneralErrors
- )
- )
- // avoid calculating if we're in "silent" mode.
- // name length check to limit unhelpful suggestions for e.g. "x" and "b1"
- val similar = {
- if (!calcSimilar) ""
- else {
- val allowed = (
- startingIdentContext.enclosingContextChain
- flatMap (ctx => ctx.scope.toList ++ ctx.imports.flatMap(_.allImportedSymbols))
- filter (sym => sym.isTerm == name.isTermName)
- filterNot (sym => sym.isPackage || sym.isSynthetic || sym.hasMeaninglessName)
- )
- val allowedStrings = (
- allowed.map("" + _.name).distinct.sorted
- filterNot (s => (s contains '$') || (s contains ' '))
- )
- similarString("" + name, allowedStrings)
- }
- }
- error(tree.pos, "not found: "+decodeWithKind(name, context.owner) + similar)
- }
- }
- else new AccessError(
- tree, inaccessibleSym, context.enclClass.owner.thisType,
- inaccessibleExplanation
- ).emit()
+ else identError(SymbolNotFoundError(tree, name, context.owner, startingIdentContext))
+ } else
+ identError(InferErrorGen.AccessError(
+ tree, inaccessibleSym, context.enclClass.owner.thisType, context.enclClass.owner,
+ inaccessibleExplanation
+ ))
defSym = context.owner.newErrorSymbol(name)
}
}
}
- if (defSym.owner.isPackageClass)
- pre = defSym.owner.thisType
+ if (errorContainer != null) {
+ ErrorUtils.issueTypeError(errorContainer)
+ setError(tree)
+ } else {
+ if (defSym.owner.isPackageClass)
+ pre = defSym.owner.thisType
- // Inferring classOf type parameter from expected type.
- if (defSym.isThisSym) {
- typed1(This(defSym.owner) setPos tree.pos, mode, pt)
- }
- // Inferring classOf type parameter from expected type. Otherwise an
- // actual call to the stubbed classOf method is generated, returning null.
- else if (isPredefMemberNamed(defSym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty)
- typedClassOf(tree, TypeTree(pt.typeArgs.head))
- else {
- val tree1 = (
- if (qual == EmptyTree) tree
- // atPos necessary because qualifier might come from startContext
- else atPos(tree.pos)(Select(qual, name))
- )
- 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
+ // Inferring classOf type parameter from expected type.
+ if (defSym.isThisSym) {
+ typed1(This(defSym.owner) setPos tree.pos, mode, pt)
+ }
+ // Inferring classOf type parameter from expected type. Otherwise an
+ // actual call to the stubbed classOf method is generated, returning null.
+ else if (isPredefMemberNamed(defSym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty)
+ typedClassOf(tree, TypeTree(pt.typeArgs.head))
+ else {
+ val tree1 = (
+ if (qual == EmptyTree) tree
+ // atPos necessary because qualifier might come from startContext
+ else atPos(tree.pos)(Select(qual, name))
+ )
+ 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)
}
}
}
def typedCompoundTypeTree(templ: Template) = {
val parents1 = templ.parents mapConserve (typedType(_, mode))
- if (parents1 exists (_.tpe.isError)) tree setType ErrorType
+ if (parents1 exists (_.isErrorTyped)) tree setType ErrorType
else {
- val decls = new Scope
+ val decls = newScope
//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)
@@ -3993,10 +4054,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = {
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
- if (tpt1.tpe.isError) {
- setError(tree)
+ if (tpt1.isErrorTyped) {
+ tpt1
} else if (!tpt1.hasSymbol) {
- errorTree(tree, tpt1.tpe+" does not take type parameters")
+ AppliedTypeNoParametersError(tree, tpt1.tpe)
} else {
val tparams = tpt1.symbol.typeParams
if (sameLength(tparams, args)) {
@@ -4028,16 +4089,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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, "")
+ checkBounds(result, 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) setPos(result.pos)
else result
} else if (tparams.isEmpty) {
- errorTree(tree, tpt1.tpe+" does not take type parameters")
+ AppliedTypeNoParametersError(tree, tpt1.tpe)
} else {
//Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}")
if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info)//debug
- errorTree(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length)
+ AppliedTypeWrongNumberOfArgsError(tree, tpt1, tparams)
}
}
}
@@ -4084,8 +4145,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val typer1 = newTyper(context.makeNewScope(tree, context.owner))
for (useCase <- comment.useCases) {
typer1.silent(_.typedUseCase(useCase)) match {
- case ex: TypeError =>
- unit.warning(useCase.pos, ex.msg)
+ case SilentTypeError(err) =>
+ unit.warning(useCase.pos, err.errMsg)
case _ =>
}
for (useCaseSym <- useCase.defined) {
@@ -4100,17 +4161,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
typedAnnotated(constr, typed(arg, mode, pt))
case tree @ Block(_, _) =>
- newTyper(context.makeNewScope(tree, context.owner))
- .typedBlock(tree, mode, pt)
+ typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ _.typedBlock(tree, mode, pt)
+ }
case Alternative(alts) =>
val alts1 = alts mapConserve (alt => typed(alt, mode | ALTmode, pt))
treeCopy.Alternative(tree, alts1) setType pt
case Star(elem) =>
- checkStarPatOK(tree.pos, mode)
- val elem1 = typed(elem, mode, pt)
- treeCopy.Star(tree, elem1) setType makeFullyDefined(pt)
+ if ((mode & STARmode) == 0 && !isPastTyper)
+ StarPatternWithVarargParametersError(tree)
+ treeCopy.Star(tree, typed(elem, mode, pt)) setType makeFullyDefined(pt)
case Bind(name, body) =>
typedBind(name, body)
@@ -4127,8 +4189,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case tree @ Function(_, _) =>
if (tree.symbol == NoSymbol)
tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos)
-
- newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(tree, mode, pt)
+ typerWithLocalContext(context.makeNewScope(tree, tree.symbol))(_.typedFunction(tree, mode, pt))
case Assign(lhs, rhs) =>
typedAssign(lhs, rhs)
@@ -4167,17 +4228,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(expr, Function(List(), EmptyTree)) =>
typedEta(checkDead(typed1(expr, mode, pt)))
- case Typed(expr, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
- val expr0 = typed(expr, onlyStickyModes(mode), WildcardType)
+ case Typed(expr0, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
+ val expr = typed(expr0, onlyStickyModes(mode), WildcardType)
def subArrayType(pt: Type) =
if (isValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
else {
val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
newExistentialType(List(tparam), arrayType(tparam.tpe))
}
- val (expr1, baseClass) = expr0.tpe.typeSymbol match {
- case ArrayClass => (adapt(expr0, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
- case _ => (adapt(expr0, onlyStickyModes(mode), seqType(pt)), SeqClass)
+
+ val (expr1, baseClass) = expr.tpe.typeSymbol match {
+ case ArrayClass => (adapt(expr, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
+ case _ => (adapt(expr, onlyStickyModes(mode), seqType(pt)), SeqClass)
}
expr1.tpe.baseType(baseClass) match {
case TypeRef(_, _, List(elemtp)) =>
@@ -4189,11 +4251,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(expr, tpt) =>
val tpt1 = typedType(tpt, mode)
val expr1 = typed(expr, onlyStickyModes(mode), tpt1.tpe.deconst)
- 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
+ val ownType = if (isPatternMode) inferTypedPattern(tpt1, tpt1.tpe, pt) else tpt1.tpe
+ 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)
@@ -4245,12 +4304,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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)
- 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)
+ MultiDimensionalArrayError(tree)
+ else {
+ val newArrayApp = atPos(tree.pos) {
+ val manif = getManifestTree(tree, manifType, false)
+ new ApplyToImplicitArgs(Select(manif, if (level == 1) "newArray" else "newArray"+level), args)
+ }
+ typed(newArrayApp, mode, pt)
}
- typed(newArrayApp, mode, pt)
case tree1 =>
tree1
}
@@ -4281,18 +4342,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val tree1 = // temporarily use `filter` and an alternative for `withFilter`
if (name == nme.withFilter)
silent(_ => typedSelect(qual1, name)) match {
- case result1: Tree =>
- result1
- case ex1: TypeError =>
+ case SilentResultValue(result) =>
+ result
+ case _ =>
silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
- case result2: Tree =>
+ case SilentResultValue(result2) =>
unit.deprecationWarning(
tree.pos, "`withFilter' method does not yet exist on "+qual1.tpe.widen+
", using `filter' method instead")
result2
- case ex2: TypeError =>
- reportTypeError(tree.pos, ex1)
- setError(tree)
+ case SilentTypeError(err) =>
+ WithFilterError(tree, err)
}
}
else
@@ -4325,8 +4385,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case SelectFromTypeTree(qual, selector) =>
val qual1 = typedType(qual, mode)
- if (qual1.tpe.isVolatile) error(tree.pos, "illegal type selection from volatile type "+qual.tpe)
- typedSelect(qual1, selector)
+ if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual)
+ else typedSelect(qual1, selector)
case CompoundTypeTree(templ) =>
typedCompoundTypeTree(templ)
@@ -4340,7 +4400,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
case etpt @ ExistentialTypeTree(_, _) =>
- newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt, mode)
+ typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ _.typedExistentialTypeTree(etpt, mode)
+ }
case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
case tpt @ TypeTree() =>
@@ -4390,7 +4452,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
ptLine("typing %s: pt = %s".format(ptTree(tree), pt),
"undetparams" -> context.undetparams,
"implicitsEnabled" -> context.implicitsEnabled,
- "silent" -> !context.reportGeneralErrors,
+ "silent" -> context.bufferErrors,
"context.owner" -> context.owner
)
)
@@ -4410,16 +4472,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
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 (!isPastTyper) signalDone(context.asInstanceOf[analyzer.Context], tree, result)
result
} catch {
case ex: TypeError =>
tree.tpe = null
+ // The only problematic case are (recoverable) cyclic reference errors which can pop up almost anywhere.
printTyping("caught %s: while typing %s".format(ex, tree)) //DEBUG
- reportTypeError(tree.pos, ex)
+
+ reportTypeError(context, tree.pos, ex)
setError(tree)
case ex: Exception =>
if (settings.debug.value) // @M causes cyclic reference error
@@ -4441,6 +4502,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
+ def expandMacro(tree: Tree): Tree =
+ macroExpand(tree, context) match {
+ case Some(t: Tree) => t
+ case Some(t) => MacroExpandError(tree, t)
+ case None => setError(tree) // error already reported
+ }
+
def atOwner(owner: Symbol): Typer =
newTyper(context.make(context.tree, owner))
@@ -4524,22 +4592,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// 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
- 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) {
- // 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
- // AnyRef, but the AnyRef type alias is entered after the scala package is
- // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
- // yet defined )
- result setType(restpe)
- } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
- // during uncurry (after refchecks), all types are normalized
- result
+ ConstructorPrefixError(tree, restpe)
+ } else {
+ //@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) {
+ // 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
+ // AnyRef, but the AnyRef type alias is entered after the scala package is
+ // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
+ // yet defined )
+ result setType(restpe)
+ } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
+ // during uncurry (after refchecks), all types are normalized
+ result
+ }
}
}
@@ -4563,11 +4631,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
true, false, context)
}
- def getManifestTree(pos: Position, tp: Type, full: Boolean): Tree = {
+ def getManifestTree(tree: Tree, tp: Type, full: Boolean): Tree = {
val manifestOpt = findManifest(tp, full)
if (manifestOpt.tree.isEmpty) {
- error(pos, "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp)
- Literal(Constant(null))
+ MissingManifestError(tree, full, tp)
} else {
manifestOpt.tree
}
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index a1ec90ed3f..53c767be20 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -9,7 +9,30 @@ package util
object Position {
val tabInc = 8
+
+ /** Prints the message with the given position indication. */
+ def formatMessage(posIn: Position, msg: String, shortenFile: Boolean): String = {
+ val pos = (
+ if (posIn eq null) NoPosition
+ else if (posIn.isDefined) posIn.inUltimateSource(posIn.source)
+ else posIn
+ )
+ def file = pos.source.file
+ def prefix = if (shortenFile) file.name else file.path
+
+ pos match {
+ case FakePos(fmsg) => fmsg+" "+msg
+ case NoPosition => msg
+ case _ =>
+ List(
+ "%s:%s: %s".format(prefix, pos.line, msg),
+ pos.lineContent.stripLineEnd,
+ " " * (pos.column - 1) + "^"
+ ) mkString "\n"
+ }
+ }
}
+
/** The Position class and its subclasses represent positions of ASTs and symbols.
* Except for NoPosition and FakePos, every position refers to a SourceFile
* and to an offset in the sourcefile (its `point`). For batch compilation,
diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala
index 27239b9b9f..f7c27dceb5 100644
--- a/src/compiler/scala/tools/nsc/util/Statistics.scala
+++ b/src/compiler/scala/tools/nsc/util/Statistics.scala
@@ -20,7 +20,7 @@ class Statistics extends scala.reflect.internal.util.Statistics {
val typedSelectCount = new Counter
val typerNanos = new Timer
val classReadNanos = new Timer
-
+
val failedApplyNanos = new Timer
val failedOpEqNanos = new Timer
val failedSilentNanos = new Timer
@@ -48,6 +48,7 @@ class Statistics extends scala.reflect.internal.util.Statistics {
val subtypeImprovCount = new SubCounter(subtypeCount)
val subtypeETNanos = new Timer
val matchesPtNanos = new Timer
+ val isReferencedNanos = new Timer
val ctr1 = new Counter
val ctr2 = new Counter
val ctr3 = new Counter
@@ -137,6 +138,7 @@ abstract class StatisticsInfo {
inform("time spent in failed : "+showRelTyper(failedSilentNanos))
inform(" failed apply : "+showRelTyper(failedApplyNanos))
inform(" failed op= : "+showRelTyper(failedOpEqNanos))
+ inform("time spent ref scanning : "+showRelTyper(isReferencedNanos))
inform("micros by tree node : "+showCounts(microsByType))
inform("#visits by tree node : "+showCounts(visitsByType))
val average = new ClassCounts