diff options
author | aleksandar <aleksandar@lampmac14.epfl.ch> | 2012-01-30 14:01:12 +0100 |
---|---|---|
committer | aleksandar <aleksandar@lampmac14.epfl.ch> | 2012-01-30 14:01:12 +0100 |
commit | 5f4c97c448f161b3bab7ae3271e30620eb9bea76 (patch) | |
tree | 337ba5231b800c680869931af1184b3ed77a692b | |
parent | a70d338afaef9a42bf13334267d07a43ad10c5c0 (diff) | |
parent | 5e9dd4a05c25f463f29d0fbc2f1bec194bf7700b (diff) | |
download | scala-5f4c97c448f161b3bab7ae3271e30620eb9bea76.tar.gz scala-5f4c97c448f161b3bab7ae3271e30620eb9bea76.tar.bz2 scala-5f4c97c448f161b3bab7ae3271e30620eb9bea76.zip |
Merge branch 'master' into issue/5374
170 files changed, 8456 insertions, 6097 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 f7e276fdab..8114be20d5 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -14,9 +14,17 @@ import PartialFunction._ trait Definitions extends reflect.api.StandardDefinitions { self: SymbolTable => + /** Since both the value parameter types and the result type may + * require access to the type parameter symbols, we model polymorphic + * creation as a function from those symbols to (formal types, result type). + * The Option is to distinguish between nullary methods and empty-param-list + * methods. + */ + private type PolyMethodCreator = List[Symbol] => (Option[List[Type]], Type) + 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 +37,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 +219,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 } @@ -306,17 +319,10 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote") lazy val RemoteExceptionClass = getRequiredClass("java.rmi.RemoteException") - lazy val RepeatedParamClass = newCovariantPolyClass( - ScalaPackageClass, - tpnme.REPEATED_PARAM_CLASS_NAME, - tparam => seqType(tparam.typeConstructor) - ) - - lazy val JavaRepeatedParamClass = newCovariantPolyClass( - ScalaPackageClass, - tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, - tparam => arrayType(tparam.typeConstructor) - ) + lazy val ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS_NAME, COVARIANT)(_ => AnyClass.typeConstructor) + lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN_NAME, 0L)(_ => AnyClass.typeConstructor) + lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => arrayType(tparam.typeConstructor)) + lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => seqType(tparam.typeConstructor)) def isByNameParamType(tp: Type) = tp.typeSymbol == ByNameParamClass def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass @@ -345,15 +351,6 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => false } - lazy val ByNameParamClass = newCovariantPolyClass( - ScalaPackageClass, - tpnme.BYNAME_PARAM_CLASS_NAME, - tparam => AnyClass.typeConstructor - ) - lazy val EqualsPatternClass = { - val clazz = newClass(ScalaPackageClass, tpnme.EQUALS_PATTERN_NAME, Nil) - clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, new Scope, clazz)) - } lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy") // collections classes @@ -424,24 +421,27 @@ trait Definitions extends reflect.api.StandardDefinitions { * information into the toString method. */ def manifestToType(m: OptManifest[_]): Type = m match { - case x: AnyValManifest[_] => - getClassIfDefined("scala." + x).tpe case m: ClassManifest[_] => - val name = m.erasure.getName - if (name endsWith nme.MODULE_SUFFIX_STRING) - getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING).tpe - else { - val sym = getClassIfDefined(name) - val args = m.typeArguments - - if (sym eq NoSymbol) NoType - else if (args.isEmpty) sym.tpe - else appliedType(sym.typeConstructor, args map manifestToType) - } + val sym = manifestToSymbol(m) + val args = m.typeArguments + + if ((sym eq NoSymbol) || args.isEmpty) sym.tpe + else appliedType(sym.typeConstructor, args map manifestToType) case _ => NoType } + def manifestToSymbol(m: ClassManifest[_]): Symbol = m match { + case x: scala.reflect.AnyValManifest[_] => + getMember(ScalaPackageClass, newTypeName("" + x)) + case _ => + val name = m.erasure.getName + if (name endsWith nme.MODULE_SUFFIX_STRING) + getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING) + else + getClassIfDefined(name) + } + // The given symbol represents either String.+ or StringAdd.+ def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ def isArrowAssoc(sym: Symbol) = ArrowAssocClass.tpe.decls.toList contains sym @@ -589,6 +589,14 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => NoType } + /** To avoid unchecked warnings on polymorphic classes, translate + * a Foo[T] into a Foo[_] for use in the pattern matcher. + */ + def typeCaseType(clazz: Symbol) = clazz.tpe.normalize match { + case TypeRef(_, sym, args) if args.nonEmpty => newExistentialType(sym.typeParams, clazz.tpe) + case tp => tp + } + def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg)) def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg)) def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) @@ -610,7 +618,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() @@ -630,31 +638,40 @@ 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 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 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 = newT1NullaryMethod(AnyClass, nme.isInstanceOf_, FINAL)(_ => booltype) + lazy val Any_asInstanceOf = newT1NullaryMethod(AnyClass, nme.asInstanceOf_, FINAL)(_.typeConstructor) + + // 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_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype) + lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor) + lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => + (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor) + ) + 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_) @@ -665,8 +682,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") lazy val VolatileObjectRefClass = getRequiredClass("scala.runtime.VolatileObjectRef") @@ -811,39 +826,36 @@ trait Definitions extends reflect.api.StandardDefinitions { */ private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length) - private def newCovariantPolyClass(owner: Symbol, name: TypeName, parent: Symbol => Type): Symbol = { - val clazz = newClass(owner, name, List()) - val tparam = newTypeParam(clazz, 0) setFlag COVARIANT - val p = parent(tparam) -/* p.typeSymbol.initialize - println(p.typeSymbol + " flags: " + Flags.flagsToString(p.typeSymbol.flags)) - val parents = /*if (p.typeSymbol.isTrait) - List(definitions.AnyRefClass.tpe, p) - else*/ List(p) - println("creating " + name + " with parents " + parents) */ - clazz.setInfo( - polyType( - List(tparam), - ClassInfoType(List(AnyRefClass.tpe, p), new Scope, clazz))) - } - private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol = owner.newAliasType(name) setInfoAndEnter alias - - /** tcon receives the type parameter symbol as argument */ - private def newPolyMethod(owner: Symbol, name: TermName, tcon: Symbol => Type): Symbol = - newPolyMethodCon(owner, name, tparam => msym => tcon(tparam)) - - /** tcon receives the type parameter symbol and the method symbol as arguments */ - private def newPolyMethodCon(owner: Symbol, name: TermName, tcon: Symbol => Symbol => Type): Symbol = { - val msym = owner.info.decls enter owner.newMethod(name.encode) - val tparam = newTypeParam(msym, 0) - - msym setInfo polyType(List(tparam), tcon(tparam)(msym)) + + private def specialPolyClass(name: TypeName, flags: Long)(parentFn: Symbol => Type): Symbol = { + val clazz = newClass(ScalaPackageClass, name, Nil) + val tparam = clazz.newSyntheticTypeParam("T0", flags) + val parents = List(AnyRefClass.tpe, parentFn(tparam)) + + clazz setInfo polyType(List(tparam), ClassInfoType(parents, newScope, clazz)) } + + def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): Symbol = { + val msym = owner.newMethod(name.encode, NoPosition, flags) + val tparams = msym.newSyntheticTypeParams(typeParamCount) + val mtpe = createFn(tparams) match { + case (Some(formals), restpe) => MethodType(msym.newSyntheticValueParams(formals), restpe) + case (_, restpe) => NullaryMethodType(restpe) + } - private def newTypeParam(owner: Symbol, index: Int): Symbol = - owner.newTypeParameter(newTypeName("T" + index)) setInfo TypeBounds.empty + msym setInfoAndEnter polyType(tparams, mtpe) + } + + /** T1 means one type parameter. + */ + def newT1NullaryMethod(owner: Symbol, name: TermName, flags: Long)(createFn: Symbol => Type): Symbol = { + newPolyMethod(1, owner, name, flags)(tparams => (None, createFn(tparams.head))) + } + def newT1NoParamsMethod(owner: Symbol, name: TermName, flags: Long)(createFn: Symbol => Type): Symbol = { + newPolyMethod(1, owner, name, flags)(tparams => (Some(Nil), createFn(tparams.head))) + } lazy val boxedClassValues = boxedClass.values.toSet lazy val isUnbox = unboxMethod.values.toSet @@ -941,43 +953,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, @@ -990,8 +966,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 aba00088f9..b3069adfb4 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -291,6 +291,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val array_update : NameType = "array_update" val arraycopy: NameType = "arraycopy" val asInstanceOf_ : NameType = "asInstanceOf" + val asInstanceOf_Ob : NameType = "$asInstanceOf" val asTypeConstructor: NameType = "asTypeConstructor" val assert_ : NameType = "assert" val assume_ : NameType = "assume" @@ -336,6 +337,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val isDefinedAt: NameType = "isDefinedAt" val isEmpty: NameType = "isEmpty" val isInstanceOf_ : NameType = "isInstanceOf" + val isInstanceOf_Ob : NameType = "$isInstanceOf" val java: NameType = "java" val lang: NameType = "lang" val length: NameType = "length" diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index ace4d55b90..fb827b0658 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -33,12 +33,17 @@ abstract class SymbolTable extends api.Universe { def rootLoader: LazyType def log(msg: => AnyRef): Unit - def abort(msg: String): Nothing = throw new FatalError(msg) + def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg)) + + @deprecated("2.10.0", "Give us a reason") def abort(): Nothing = abort("unknown error") /** Override with final implementation for inlining. */ def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) + + /** Overridden when we know more about what was happening during a failure. */ + def supplementErrorMessage(msg: String): String = msg private[scala] def printResult[T](msg: String)(result: T) = { Console.err.println(msg + ": " + result) @@ -271,4 +276,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 0e729bc7ea..94d764067f 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 } @@ -237,6 +251,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def freshName() = { cnt += 1; nme.syntheticParamName(cnt) } mmap(argtypess)(tp => newValueParameter(freshName(), focusPos(owner.pos), SYNTHETIC) setInfo tp) } + + def newSyntheticTypeParam(): Symbol = newSyntheticTypeParam("T0", 0L) + def newSyntheticTypeParam(name: String, newFlags: Long): Symbol = newTypeParameter(newTypeName(name), NoPosition, newFlags) setInfo TypeBounds.empty + def newSyntheticTypeParams(num: Int): List[Symbol] = (0 until num).toList map (n => newSyntheticTypeParam("T" + n, 0L)) /** Create a new existential type skolem with this symbol its owner, * based on the given symbol and origin. @@ -336,7 +354,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 +363,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 +758,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 +766,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 +800,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 +809,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => ifs = ifs.prev } } - rawname = name + _rawname = name } } @@ -855,20 +877,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 +976,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => throw CyclicReference(this, tp) } } else { - rawflags |= LOCKED + _rawflags |= LOCKED // activeLocks += 1 // lockedSyms += this } @@ -963,7 +985,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 +1005,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 +1024,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 +1066,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 +1081,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 +1091,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 +1107,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } } + } /** Initialize the symbol */ final def initialize: this.type = { @@ -1094,6 +1117,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 +1125,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 +1237,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 +1264,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 +1450,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`. @@ -1804,6 +1832,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } + /** Remove any access boundary and clear flags PROTECTED | PRIVATE. + */ + def makePublic = this setPrivateWithin NoSymbol resetFlag AccessFlags + + /** The first parameter to the first argument list of this method, + * or NoSymbol if inapplicable. + */ + def firstParam = info.params match { + case p :: _ => p + case _ => NoSymbol + } + /** change name by appending $$<fully-qualified-name-of-class `base`> * Do the same for any accessed symbols or setters/getters */ @@ -1874,36 +1914,43 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (isTerm && (!isParameter || isParamAccessor)) "val" else "" + private case class SymbolKind(accurate: String, sanitized: String, abbreviation: String) + private def symbolKind: SymbolKind = { + val kind = + if (isInstanceOf[FreeVar]) ("free variable", "free variable", "FV") + else if (isPackage) ("package", "package", "PK") + else if (isPackageClass) ("package class", "package", "PKC") + else if (isPackageObject) ("package object", "package", "PKO") + else if (isPackageObjectClass) ("package object class", "package", "PKOC") + else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC") + else if (isRefinementClass) ("refinement class", "", "RC") + else if (isModule) ("module", "object", "MOD") + else if (isModuleClass) ("module class", "object", "MODC") + else if (isGetter) ("getter", if (isSourceMethod) "method" else "value", "GET") + else if (isSetter) ("setter", if (isSourceMethod) "method" else "value", "SET") + else if (isTerm && isLazy) ("lazy value", "lazy value", "LAZ") + else if (isVariable) ("field", "variable", "VAR") + else if (isTrait) ("trait", "trait", "TRT") + else if (isClass) ("class", "class", "CLS") + else if (isType) ("type", "type", "TPE") + else if (isClassConstructor) ("constructor", "constructor", "CTOR") + else if (isSourceMethod) ("method", "method", "METH") + else if (isTerm) ("value", "value", "VAL") + else ("", "", "???") + SymbolKind(kind._1, kind._2, kind._3) + } + /** Accurate string representation of symbols' kind, suitable for developers. */ final def accurateKindString: String = - if (isPackage) "package" - else if (isPackageClass) "package class" - else if (isPackageObject) "package object" - else if (isPackageObjectClass) "package object class" - else if (isRefinementClass) "refinement class" - else if (isModule) "module" - else if (isModuleClass) "module class" - else if (isGetter) "getter" - else if (isSetter) "setter" - else if (isVariable) "field" - else sanitizedKindString + symbolKind.accurate /** String representation of symbol's kind, suitable for the masses. */ private def sanitizedKindString: String = - if (isPackage || isPackageClass) "package" - else if (isModule || isModuleClass) "object" - else if (isAnonymousClass) "anonymous class" - else if (isRefinementClass) "" - else if (isTrait) "trait" - else if (isClass) "class" - else if (isType) "type" - else if (isInstanceOf[FreeVar]) "free variable" - else if (isTerm && isLazy) "lazy value" - else if (isVariable) "variable" - else if (isClassConstructor) "constructor" - else if (isSourceMethod) "method" - else if (isTerm) "value" - else "" + symbolKind.sanitized + + /** String representation of symbol's kind, suitable for the masses. */ + protected[scala] def abbreviatedKindString: String = + symbolKind.abbreviation final def kindString: String = if (settings.debug.value) accurateKindString @@ -1926,12 +1973,25 @@ trait Symbols extends api.Symbols { self: SymbolTable => * If !settings.debug translates expansions of operators back to operator symbol. * E.g. $eq => =. * If settings.uniqid, adds id. + * If settings.Yshowsymkinds, adds abbreviated symbol kind. */ def nameString: String = ( - if (settings.uniqid.value) decodedName + "#" + id - else "" + decodedName + if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + decodedName + else if (settings.uniqid.value && !settings.Yshowsymkinds.value) decodedName + "#" + id + else if (!settings.uniqid.value && settings.Yshowsymkinds.value) decodedName + "#" + abbreviatedKindString + else decodedName + "#" + id + "#" + abbreviatedKindString ) + def fullNameString: String = { + def recur(sym: Symbol): String = { + if (sym.isRoot || sym.isRootPackage || sym == NoSymbol) sym.nameString + else if (sym.owner.isEffectiveRoot) sym.nameString + else recur(sym.effectiveOwner.enclClass) + "." + sym.nameString + } + + recur(this) + } + /** If settings.uniqid is set, the symbol's id, else "" */ final def idString = if (settings.uniqid.value) "#"+id else "" @@ -2046,15 +2106,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 +2199,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 +2222,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 +2248,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 +2289,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 +2427,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 +2456,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 +2522,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } typeOfThisCache } - else thissym.tpe + else thisSym.tpe } /** Sets the self type of the class */ @@ -2479,7 +2542,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 +2553,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 +2586,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 @@ -2557,6 +2622,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => 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..63e4c9f1fa 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -27,10 +27,20 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => /** Turns a path into a String, introducing backquotes * as necessary. */ - def backquotedPath(t: Tree): String = t match { - case Select(qual, name) => "%s.%s".format(backquotedPath(qual), quotedName(name)) - case Ident(name) => quotedName(name) - case _ => t.toString + def backquotedPath(t: Tree): String = { + def suffix(t: Tree) = { + var suffix = "" + if (t.hasSymbol && settings.uniqid.value) suffix += ("#" + t.symbol.id) + if (t.hasSymbol && settings.Yshowsymkinds.value) suffix += ("#" + t.symbol.abbreviatedKindString) + suffix + } + + t match { + case Select(qual, name) if name.isTermName => "%s.%s".format(backquotedPath(qual), quotedName(name)) + suffix(t) + case Select(qual, name) if name.isTypeName => "%s#%s".format(backquotedPath(qual), quotedName(name)) + suffix(t) + case Ident(name) => quotedName(name) + suffix(t) + case _ => t.toString + } } class TreePrinter(out: PrintWriter) extends super.TreePrinter { @@ -397,7 +407,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..fab10f7896 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 @@ -1204,7 +1205,7 @@ trait Types extends api.Types { self: SymbolTable => if (settings.debug.value) sym.nameString + ".this." else if (sym.isAnonOrRefinementClass) "this." else if (sym.isOmittablePrefix) "" - else if (sym.isModuleClass) sym.fullName + "." + else if (sym.isModuleClass) sym.fullNameString + "." else sym.nameString + ".this." override def safeToString: String = if (sym.isRoot) "<root>" @@ -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/internal/settings/MutableSettings.scala b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala index 6980d28bfb..0092f73fe3 100644 --- a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala @@ -38,6 +38,7 @@ abstract class MutableSettings extends AbsSettings { def explaintypes: BooleanSetting def verbose: BooleanSetting def uniqid: BooleanSetting + def Yshowsymkinds: BooleanSetting def Xprintpos: BooleanSetting def Yrecursion: IntSetting def maxClassfileName: IntSetting 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 bc5d616ae3..b4bcc52a23 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -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 09a4bbe198..4808326902 100644 --- a/src/compiler/scala/reflect/runtime/Mirror.scala +++ b/src/compiler/scala/reflect/runtime/Mirror.scala @@ -51,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/Settings.scala b/src/compiler/scala/reflect/runtime/Settings.scala index 2a6cdea519..b4f0123114 100644 --- a/src/compiler/scala/reflect/runtime/Settings.scala +++ b/src/compiler/scala/reflect/runtime/Settings.scala @@ -28,6 +28,7 @@ class Settings extends internal.settings.MutableSettings { val explaintypes = new BooleanSetting(false) val verbose = new BooleanSetting(false) val uniqid = new BooleanSetting(false) + val Yshowsymkinds = new BooleanSetting(false) val Xprintpos = new BooleanSetting(false) val printtypes = new BooleanSetting(false) val Yrecursion = new IntSetting(0) 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..46d890c5d1 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)) @@ -123,15 +123,21 @@ trait ToolBoxes extends { self: Universe => applyMeth.invoke(result) } } - - def showAttributed(tree: Tree): String = { - val saved = settings.printtypes.value + + def showAttributed(tree: Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = { + val saved1 = settings.printtypes.value + val saved2 = settings.uniqid.value + val saved3 = settings.Yshowsymkinds.value try { - settings.printtypes.value = true - //settings.uniqid.value = true + settings.printtypes.value = printTypes + settings.uniqid.value = printIds + settings.uniqid.value = printKinds tree.toString - } finally - compiler.settings.printtypes.value = saved + } finally { + settings.printtypes.value = saved1 + settings.uniqid.value = saved2 + settings.Yshowsymkinds.value = saved3 + } } } 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/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index e805b4e75e..797ed7e047 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -13,7 +13,7 @@ import scala.tools.util.{ Profiling, PathResolver } import scala.collection.{ mutable, immutable } import io.{ SourceReader, AbstractFile, Path } import reporters.{ Reporter, ConsoleReporter } -import util.{ NoPosition, Exceptional, ClassPath, SourceFile, Statistics, StatisticsInfo, BatchSourceFile, ScriptSourceFile, ShowPickled, ScalaClassLoader, returning } +import util.{ NoPosition, Exceptional, ClassPath, SourceFile, NoSourceFile, Statistics, StatisticsInfo, BatchSourceFile, ScriptSourceFile, ShowPickled, ScalaClassLoader, returning } import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat } import settings.{ AestheticSettings } @@ -164,6 +164,23 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb if (opt.fatalWarnings) globalError(msg) else reporter.warning(NoPosition, msg) + // Getting in front of Predef's asserts to supplement with more info. + // This has the happy side effect of masking the one argument forms + // of assert and require (but for now I've reproduced them here, + // because there are a million to fix.) + @inline final def assert(assertion: Boolean, message: => Any) { + Predef.assert(assertion, supplementErrorMessage("" + message)) + } + @inline final def assert(assertion: Boolean) { + assert(assertion, "") + } + @inline final def require(requirement: Boolean, message: => Any) { + Predef.require(requirement, supplementErrorMessage("" + message)) + } + @inline final def require(requirement: Boolean) { + require(requirement, "") + } + // Needs to call error to make sure the compile fails. override def abort(msg: String): Nothing = { error(msg) @@ -375,10 +392,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } final def applyPhase(unit: CompilationUnit) { + if ((unit ne null) && unit.exists) + lastSeenSourceFile = unit.source + if (opt.echoFilenames) inform("[running phase " + name + " on " + unit + "]") - val unit0 = currentRun.currentUnit + val unit0 = currentUnit try { currentRun.currentUnit = unit if (!cancelled(unit)) { @@ -387,7 +407,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } currentRun.advanceUnit } finally { - //assert(currentRun.currentUnit == unit) + //assert(currentUnit == unit) currentRun.currentUnit = unit0 } } @@ -615,7 +635,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. @@ -781,9 +801,40 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb curRun = null } + /** There are common error conditions where when the exception hits + * here, currentRun.currentUnit is null. This robs us of the knowledge + * of what file was being compiled when it broke. Since I really + * really want to know, this hack. + */ + private var lastSeenSourceFile: SourceFile = NoSourceFile + /** The currently active run */ - def currentRun: Run = curRun + def currentRun: Run = curRun + def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit + def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile + + /** Don't want to introduce new errors trying to report errors, + * so swallow exceptions. + */ + override def supplementErrorMessage(errorMessage: String): String = try { + """| + | while compiling: %s + | current phase: %s + | library version: %s + | compiler version: %s + | reconstructed args: %s + | + |%s""".stripMargin.format( + currentSource.path, + phase, + scala.util.Properties.versionString, + Properties.versionString, + settings.recreateArgs.mkString(" "), + if (opt.debug) "Current unit body:\n" + currentUnit.body + "\n" + errorMessage else errorMessage + ) + } + catch { case x: Exception => errorMessage } /** The id of the currently active run */ @@ -798,10 +849,40 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** A Run is a single execution of the compiler on a sets of units */ class Run { + /** Have been running into too many init order issues with Run + * during erroneous conditions. Moved all these vals up to the + * top of the file so at least they're not trivially null. + */ var isDefined = false + /** The currently compiled unit; set from GlobalPhase */ + var currentUnit: CompilationUnit = NoCompilationUnit + + /** 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 + /** To be initialized from firstPhase. */ private var terminalPhase: Phase = NoPhase + private val unitbuf = new mutable.ListBuffer[CompilationUnit] + val compiledFiles = new mutable.HashSet[String] + + /** A map from compiled top-level symbols to their source files */ + val symSource = new mutable.HashMap[Symbol, AbstractFile] + + /** A map from compiled top-level symbols to their picklers */ + val symData = new mutable.HashMap[Symbol, PickleBuffer] + + private var phasec: Int = 0 // phases completed + private var unitc: Int = 0 // units completed this phase + private var _unitbufSize = 0 + + def size = _unitbufSize + override def toString = "scalac Run for:\n " + compiledFiles.toList.sorted.mkString("\n ") + // Calculate where to stop based on settings -Ystop-before or -Ystop-after. // Slightly complicated logic due to wanting -Ystop-before:parser to fail rather // than mysteriously running to completion. @@ -895,16 +976,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb // --------------- Miscellania ------------------------------- - /** The currently compiled unit; set from GlobalPhase */ - var currentUnit: CompilationUnit = _ - - /** 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. * @@ -936,9 +1007,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } def cancel() { reporter.cancelled = true } - - private var phasec: Int = 0 // phases completed - private var unitc: Int = 0 // units completed this phase + private def currentProgress = (phasec * size) + unitc private def totalProgress = (phaseDescriptors.size - 1) * size // -1: drops terminal phase private def refreshProgress() = if (size > 0) progress(currentProgress, totalProgress) @@ -977,11 +1046,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb // ----------- Units and top-level classes and objects -------- - private val unitbuf = new mutable.ListBuffer[CompilationUnit] - val compiledFiles = new mutable.HashSet[String] - - private var _unitbufSize = 0 - def size = _unitbufSize /** add unit to be compiled in this run */ private def addUnit(unit: CompilationUnit) { @@ -1005,12 +1069,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb */ def units: Iterator[CompilationUnit] = unitbuf.iterator - /** A map from compiled top-level symbols to their source files */ - val symSource = new mutable.HashMap[Symbol, AbstractFile] - - /** A map from compiled top-level symbols to their picklers */ - val symData = new mutable.HashMap[Symbol, PickleBuffer] - def registerPickle(sym: Symbol): Unit = { // Convert all names to the type name: objects don't store pickled data if (opt.showPhase && (opt.showNames exists (x => findNamedMember(x.toTypeName, sym) != NoSymbol))) { @@ -1114,6 +1172,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Compile list of units, starting with phase `fromPhase` */ def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { + try compileUnitsInternal(units, fromPhase) + catch { case ex => + globalError(supplementErrorMessage("uncaught exception during compilation: " + ex.getClass.getName)) + throw ex + } + } + + private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) { units foreach addUnit if (opt.profileAll) { inform("starting CPU profiling on compilation run") 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..c80b07c44d 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) } @@ -225,7 +223,7 @@ trait Trees extends reflect.internal.Trees { self: Global => try unit.body = transform(unit.body) catch { case ex: Exception => - println("unhandled exception while transforming "+unit) + println(supplementErrorMessage("unhandled exception while transforming "+unit)) throw ex } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index a2a577a7ab..4478fb6128 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -468,7 +468,7 @@ trait Scanners extends ScannersCommon { nextChar() getOperatorRest() } else { - syntaxError("illegal character") + syntaxError("illegal character '" + ("" + '\\' + 'u' + "%04x".format(ch: Int)) + "'") nextChar() } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index b5ec0ceffb..e310611e68 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -24,7 +24,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse import global._ informProgress("parsing " + unit) unit.body = - if (unit.source.file.name.endsWith(".java")) new JavaUnitParser(unit).parse() + if (unit.isJava) new JavaUnitParser(unit).parse() else if (reporter.incompleteHandled) new UnitParser(unit).parse() else new UnitParser(unit).smartParse() diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 15b4c8c708..3d650ef753 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -179,7 +179,7 @@ abstract class GenICode extends SubComponent { } private def genThrow(expr: Tree, ctx: Context): (Context, TypeKind) = { - require(expr.tpe <:< ThrowableClass.tpe) + require(expr.tpe <:< ThrowableClass.tpe, expr.tpe) val thrownKind = toTypeKind(expr.tpe) val ctx1 = genLoad(expr, ctx, thrownKind) @@ -480,7 +480,7 @@ abstract class GenICode extends SubComponent { */ private def msil_genLoadZeroOfNonEnumValuetype(ctx: Context, kind: TypeKind, pos: Position, leaveAddressOnStackInstead: Boolean) { val REFERENCE(clssym) = kind - assert(loaders.clrTypes.isNonEnumValuetype(clssym)) + assert(loaders.clrTypes.isNonEnumValuetype(clssym), clssym) val local = ctx.makeLocal(pos, clssym.tpe, "tmp") ctx.method.addLocal(local) ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(local), pos) @@ -1064,7 +1064,7 @@ abstract class GenICode extends SubComponent { var default: BasicBlock = afterCtx.bb for (caze @ CaseDef(pat, guard, body) <- cases) { - assert(guard == EmptyTree) + assert(guard == EmptyTree, guard) val tmpCtx = ctx1.newBlock pat match { case Literal(value) => @@ -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/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 229bbceb36..f5be82a776 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -199,7 +199,7 @@ abstract class CopyPropagation { m foreachBlock { b => in(b) = lattice.bottom out(b) = lattice.bottom - assert(out.contains(b)) + assert(out.contains(b), out) log("Added point: " + b) } m.exh foreach { e => 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/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 494eb4d50b..b51cf1228c 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -211,7 +211,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { var start = 0 while (true) { val index = path.indexOf(separator, start) - assert(index < 0 || start < index) + assert(index < 0 || start < index, ((path, directory, start, index))) val name = path.substring(start, if (index < 0) length else index) file = getFile(file, name, if (index < 0) directory else true) if ((file eq null) || index < 0) return file 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 6806ca03ba..107ffc35c6 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -140,6 +140,7 @@ trait ScalaSettings extends AbsScalaSettings val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.") val Xshowtrees = BooleanSetting ("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs.") val Yshowsyms = BooleanSetting ("-Yshow-syms", "Print the AST symbol hierarchy after each phase.") + val Yshowsymkinds = BooleanSetting ("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.") val skip = PhasesSetting ("-Yskip", "Skip") val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "") val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "") 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..ac6dca4422 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -392,7 +392,7 @@ abstract class ClassfileParser { } def getBytes(indices: List[Int]): Array[Byte] = { - assert(!indices.isEmpty) + assert(!indices.isEmpty, indices) var value = values(indices.head).asInstanceOf[Array[Byte]] if (value eq null) { val bytesBuffer = ArrayBuffer.empty[Byte] @@ -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) @@ -679,7 +679,7 @@ abstract class ClassfileParser { var index = 0 val end = sig.length def accept(ch: Char) { - assert(sig(index) == ch) + assert(sig(index) == ch, (sig(index), ch)) index += 1 } def subName(isDelimiter: Char => Boolean): Name = { @@ -736,7 +736,7 @@ abstract class ClassfileParser { } } accept('>') - assert(xs.length > 0) + assert(xs.length > 0, tp) newExistentialType(existentials.toList, typeRef(pre, classSym, xs.toList)) } else if (classSym.isMonomorphicType) { tp @@ -750,7 +750,7 @@ abstract class ClassfileParser { res } case tp => - assert(sig(index) != '<') + assert(sig(index) != '<', tp) tp } @@ -776,7 +776,7 @@ abstract class ClassfileParser { appliedType(definitions.ArrayClass.tpe, List(elemtp)) case '(' => // we need a method symbol. given in line 486 by calling getType(methodSym, ..) - assert(sym ne null) + assert(sym ne null, sig) val paramtypes = new ListBuffer[Type]() while (sig(index) != ')') { paramtypes += objToAny(sig2type(tparams, skiptvs)) @@ -809,7 +809,7 @@ abstract class ClassfileParser { var tparams = classTParams val newTParams = new ListBuffer[Symbol]() if (sig(index) == '<') { - assert(sym != null) + assert(sym != null, sig) index += 1 val start = index while (sig(index) != '>') { @@ -974,18 +974,18 @@ abstract class ClassfileParser { def parseScalaSigBytes: Option[ScalaSigBytes] = { val tag = in.nextByte.toChar - assert(tag == STRING_TAG) + assert(tag == STRING_TAG, tag) Some(ScalaSigBytes(pool getBytes in.nextChar)) } def parseScalaLongSigBytes: Option[ScalaSigBytes] = { val tag = in.nextByte.toChar - assert(tag == ARRAY_TAG) + assert(tag == ARRAY_TAG, tag) val stringCount = in.nextChar val entries = for (i <- 0 until stringCount) yield { val stag = in.nextByte.toChar - assert(stag == STRING_TAG) + assert(stag == STRING_TAG, stag) in.nextChar.toInt } Some(ScalaSigBytes(pool.getBytes(entries.toList))) @@ -1208,7 +1208,12 @@ abstract class ClassfileParser { atPhase(currentRun.typerPhase)(getMember(sym, innerName.toTypeName)) else getMember(sym, innerName.toTypeName) - assert(s ne NoSymbol, sym + "." + innerName + " linkedModule: " + sym.companionModule + sym.companionModule.info.members) + + assert(s ne NoSymbol, + "" + ((externalName, outerName, innerName, sym.fullLocationString)) + " / " + + " while parsing " + ((in.file, busy)) + + sym + "." + innerName + " linkedModule: " + sym.companionModule + sym.companionModule.info.members + ) s case None => diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 3c97122c9c..7d42dabc08 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -434,7 +434,7 @@ abstract class ICodeReader extends ClassfileParser { val padding = if ((pc + size) % 4 != 0) 4 - ((pc + size) % 4) else 0 size += padding in.bp += padding - assert((pc + size % 4) != 0) + assert((pc + size % 4) != 0, pc) /* var byte1 = in.nextByte; size += 1; while (byte1 == 0) { byte1 = in.nextByte; size += 1; } val default = byte1 << 24 | in.nextByte << 16 | in.nextByte << 8 | in.nextByte; @@ -454,7 +454,7 @@ abstract class ICodeReader extends ClassfileParser { val padding = if ((pc + size) % 4 != 0) 4 - ((pc + size) % 4) else 0 size += padding in.bp += padding - assert((pc + size % 4) != 0) + assert((pc + size % 4) != 0, pc) val default = pc + in.nextInt; size += 4 val npairs = in.nextInt; size += 4 var tags: List[List[Int]] = Nil @@ -988,7 +988,7 @@ abstract class ICodeReader extends ClassfileParser { def enterParam(idx: Int, kind: TypeKind) = { val sym = method.symbol.newVariable(newTermName("par" + idx)).setInfo(kind.toType) val l = new Local(sym, kind, true) - assert(!locals.isDefinedAt(idx)) + assert(!locals.isDefinedAt(idx), locals(idx)) locals += (idx -> List((l, kind))) l } 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..e01bbccf13 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -77,31 +77,57 @@ 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 + + // !!! Why does forcing the impl's info here lead to a crash? + // See test case pos/trait-force-info.scala for a minimization. + // It crashes like this: + // + // [log lazyvals] trait ContextTrees.implClass == class ContextTrees$class + // error: java.lang.AssertionError: assertion failed: (scala.tools.nsc.typechecker.Contexts$NoContext$,scala.tools.nsc.typechecker.Contexts,NoContext$,trait Contexts in package typechecker) / while parsing (/scala/trunk/build/pack/lib/scala-compiler.jar(scala/tools/nsc/interactive/ContextTrees$class.class),Some(class ContextTrees$class))trait Contexts.NoContext$ linkedModule: <none>List() + + 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 +145,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) @@ -159,7 +185,7 @@ abstract class AddInterfaces extends InfoTransform { ) def implType(tp: Type): Type = tp match { case ClassInfoType(parents, decls, _) => - assert(phase == implClassPhase) + assert(phase == implClassPhase, tp) ClassInfoType( ObjectClass.tpe +: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) :+ iface.tpe, implDecls(sym, decls), 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..fe479a5375 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) { @@ -797,7 +797,7 @@ abstract class Erasure extends AddInterfaces // && (bridge.paramss.nonEmpty && bridge.paramss.head.nonEmpty && bridge.paramss.head.tail.isEmpty) // does the first argument list has exactly one argument -- for user-defined unapplies we can't be sure && !(atPhase(phase.next)(member.tpe <:< other.tpe))) { // no static guarantees (TODO: is the subtype test ever true?) import CODE._ - val typeTest = gen.mkIsInstanceOf(REF(bridge.paramss.head.head), member.tpe.params.head.tpe, any = true, wrapInApply = true) // any = true since we're before erasure (?), wrapInapply is true since we're after uncurry + val typeTest = gen.mkIsInstanceOf(REF(bridge.firstParam), member.tpe.params.head.tpe, any = true, wrapInApply = true) // any = true since we're before erasure (?), wrapInapply is true since we're after uncurry // println("unapp type test: "+ typeTest) IF (typeTest) THEN bridgingCall ELSE REF(NoneModule) } else bridgingCall diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 14f3dc16fa..7f7f7e7b65 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -427,7 +427,7 @@ abstract class ExplicitOuter extends InfoTransform } val t = atPos(tree.pos) { - val context = MatrixContext(currentRun.currentUnit, transform, localTyper, currentOwner, tree.tpe) + val context = MatrixContext(currentUnit, transform, localTyper, currentOwner, tree.tpe) val t_untyped = handlePattern(nselector, ncases, checkExhaustive, context) /* if @switch annotation is present, verify the resulting tree is a Match */ @@ -506,7 +506,7 @@ abstract class ExplicitOuter extends InfoTransform val outerVal = atPos(tree.pos)(qual match { // it's a call between constructors of same class case _: This => - assert(outerParam != NoSymbol) + assert(outerParam != NoSymbol, tree) outerValue case _ => gen.mkAttributedQualifier(qual.tpe.prefix match { 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..b3b7596f9a 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 = _ @@ -1053,7 +1053,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { else accessedRef match { case Literal(_) => accessedRef case _ => - val init = Assign(accessedRef, Ident(sym.paramss.head.head)) + val init = Assign(accessedRef, Ident(sym.firstParam)) val getter = sym.getter(clazz) if (!needsInitFlag(getter)) init 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..6ee09d064f --- /dev/null +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -0,0 +1,1056 @@ +/* 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, (found, req)) + + 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) = { + /*** Disabled pending investigation of performance impact. + + // 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) + } + } + */ + val similar = "" + 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..740acbd10f 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? */ @@ -552,7 +585,7 @@ trait Contexts { self: Analyzer => debuglog("collect local implicits " + scope.toList)//DEBUG collectImplicits(scope.toList, NoPrefix) } else if (imports != nextOuter.imports) { - assert(imports.tail == nextOuter.imports) + assert(imports.tail == nextOuter.imports, (imports, nextOuter.imports)) collectImplicitImports(imports.head) } else if (owner.isPackageClass) { // the corresponding package object may contain implicit members. 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 7f9e56a926..c63ae90ef6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -97,8 +97,6 @@ trait Macros { self: Analyzer => override def defaultReflectiveClassLoader() = libraryClassLoader } - class MacroExpandError(val msg: String) extends Exception(msg) - /** 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. @@ -127,7 +125,7 @@ trait Macros { self: Analyzer => * Or, if that fails, and the macro overrides a method return * tree that calls this method instead of the macro. */ - def macroExpand(tree: Tree): Any = { + def macroExpand(tree: Tree, context: Context): Option[Any] = { val macroDef = tree.symbol macroImpl(macroDef) match { case Some((receiver, rmeth)) => @@ -139,41 +137,55 @@ trait Macros { self: Analyzer => } val rawArgs: Seq[Any] = rawArgss.flatten try { - mirror.invoke(receiver, rmeth, rawArgs: _*) + 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 - throw new MacroExpandError("exception during macro expansion: " + msg) + 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() = throw new MacroExpandError("macro implementation not found: " + macroDef.name) - def fallBackToOverridden(tree: Tree): Tree = { + 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 :: others => - return Select(qual, name) setPos tree.pos setSymbol first + case first :: _ => + Some(Select(qual, name) setPos tree.pos setSymbol first) case _ => trace("macro is not overridden: ")(tree) notFound() } case Apply(fn, args) => - Apply(fallBackToOverridden(fn), args) setPos tree.pos + fallBackToOverridden(fn) match { + case Some(fn1) => Some(Apply(fn1, args) setPos tree.pos) + case _ => None + } case TypeApply(fn, args) => - TypeApply(fallBackToOverridden(fn), args) setPos tree.pos + fallBackToOverridden(fn) match { + case Some(fn1) => Some(TypeApply(fn1, args) setPos tree.pos) + case _ => None + } case _ => trace("unexpected tree in fallback: ")(tree) notFound() } } - val tree1 = fallBackToOverridden(tree) - trace("falling back to ")(tree1) - currentRun.macroExpansionFailed = true - tree1 + 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..0c32ff32c0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -17,6 +17,139 @@ trait MethodSynthesis { import global._ import definitions._ + import CODE._ + + object synthesisUtil { + type M[T] = Manifest[T] + type CM[T] = ClassManifest[T] + + def ValOrDefDef(sym: Symbol, body: Tree) = + if (sym.isLazy) ValDef(sym, body) + else DefDef(sym, body) + + def applyTypeInternal(manifests: List[M[_]]): Type = { + val symbols = manifests map manifestToSymbol + val container :: args = symbols + val tparams = container.typeConstructor.typeParams + + // Conservative at present - if manifests were more usable this could do a lot more. + require(symbols forall (_ ne NoSymbol), "Must find all manifests: " + symbols) + require(container.owner.isPackageClass, "Container must be a top-level class in a package: " + container) + require(tparams.size == args.size, "Arguments must match type constructor arity: " + tparams + ", " + args) + + typeRef(container.typeConstructor.prefix, container, args map (_.tpe)) + } + + def companionType[T](implicit m: M[T]) = + getRequiredModule(m.erasure.getName).tpe + + // Use these like `applyType[List, Int]` or `applyType[Map, Int, String]` + def applyType[CC](implicit m1: M[CC]): Type = + applyTypeInternal(List(m1)) + + def applyType[CC[X1], X1](implicit m1: M[CC[_]], m2: M[X1]): Type = + applyTypeInternal(List(m1, m2)) + + def applyType[CC[X1, X2], X1, X2](implicit m1: M[CC[_,_]], m2: M[X1], m3: M[X2]): Type = + applyTypeInternal(List(m1, m2, m3)) + + def applyType[CC[X1, X2, X3], X1, X2, X3](implicit m1: M[CC[_,_,_]], m2: M[X1], m3: M[X2], m4: M[X3]): Type = + applyTypeInternal(List(m1, m2, m3, m4)) + + def newMethodType[F](owner: Symbol)(implicit m: Manifest[F]): Type = { + val fnSymbol = manifestToSymbol(m) + assert(fnSymbol isSubClass FunctionClass(m.typeArguments.size - 1), (owner, m)) + val symbols = m.typeArguments map (m => manifestToSymbol(m)) + val formals = symbols.init map (_.typeConstructor) + val params = owner newSyntheticValueParams formals + + MethodType(params, symbols.last.typeConstructor) + } + } + import synthesisUtil._ + + class ClassMethodSynthesis(val clazz: Symbol, localTyper: Typer) { + private def isOverride(name: TermName) = + clazzMember(name).alternatives exists (sym => !sym.isDeferred && (sym.owner != clazz)) + + def newMethodFlags(name: TermName) = { + val overrideFlag = if (isOverride(name)) OVERRIDE else 0L + overrideFlag | SYNTHETIC + } + def newMethodFlags(method: Symbol) = { + val overrideFlag = if (isOverride(method.name)) OVERRIDE else 0L + (method.flags | overrideFlag | SYNTHETIC) & ~DEFERRED + } + + private def finishMethod(method: Symbol, f: Symbol => Tree): Tree = + logResult("finishMethod")(localTyper typed ValOrDefDef(method, f(method))) + + private def createInternal(name: Name, f: Symbol => Tree, info: Type): Tree = { + val m = clazz.newMethod(name.toTermName, clazz.pos.focus, newMethodFlags(name)) + finishMethod(m setInfoAndEnter info, f) + } + private def createInternal(name: Name, f: Symbol => Tree, infoFn: Symbol => Type): Tree = { + val m = clazz.newMethod(name.toTermName, clazz.pos.focus, newMethodFlags(name)) + finishMethod(m setInfoAndEnter infoFn(m), f) + } + private def cloneInternal(original: Symbol, f: Symbol => Tree, name: Name): Tree = { + val m = original.cloneSymbol(clazz, newMethodFlags(original)) setPos clazz.pos.focus + m.name = name + finishMethod(clazz.info.decls enter m, f) + } + + private def cloneInternal(original: Symbol, f: Symbol => Tree): Tree = + cloneInternal(original, f, original.name) + + def clazzMember(name: Name) = clazz.info nonPrivateMember name + def typeInClazz(sym: Symbol) = clazz.thisType memberType sym + + /** Function argument takes the newly created method symbol of + * the same type as `name` in clazz, and returns the tree to be + * added to the template. + */ + def overrideMethod(name: Name)(f: Symbol => Tree): Tree = + overrideMethod(clazzMember(name))(f) + + def overrideMethod(original: Symbol)(f: Symbol => Tree): Tree = + cloneInternal(original, sym => f(sym setFlag OVERRIDE)) + + def deriveMethod(original: Symbol, nameFn: Name => Name)(f: Symbol => Tree): Tree = + cloneInternal(original, f, nameFn(original.name)) + + def createMethod(name: Name, paramTypes: List[Type], returnType: Type)(f: Symbol => Tree): Tree = + createInternal(name, f, (m: Symbol) => MethodType(m newSyntheticValueParams paramTypes, returnType)) + + def createMethod(name: Name, returnType: Type)(f: Symbol => Tree): Tree = + createInternal(name, f, NullaryMethodType(returnType)) + + def createMethod(original: Symbol)(f: Symbol => Tree): Tree = + createInternal(original.name, f, original.info) + + def forwardMethod(original: Symbol, newMethod: Symbol)(transformArgs: List[Tree] => List[Tree]): Tree = + createMethod(original)(m => gen.mkMethodCall(newMethod, transformArgs(m.paramss.head map Ident))) + + def createSwitchMethod(name: Name, range: Seq[Int], returnType: Type)(f: Int => Tree) = { + createMethod(name, List(IntClass.tpe), returnType) { m => + val arg0 = Ident(m.firstParam) + val default = DEFAULT ==> THROW(IndexOutOfBoundsExceptionClass, arg0) + val cases = range.map(num => CASE(LIT(num)) ==> f(num)).toList :+ default + + Match(arg0, cases) + } + } + + // def foo() = constant + def constantMethod(name: Name, value: Any): Tree = { + val constant = Constant(value) + createMethod(name, Nil, constant.tpe)(_ => Literal(constant)) + } + // def foo = constant + def constantNullary(name: Name, value: Any): Tree = { + val constant = Constant(value) + createMethod(name, constant.tpe)(_ => Literal(constant)) + } + } /** There are two key methods in here. * @@ -32,10 +165,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 +178,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 +322,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 +390,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 +438,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 e04d89047b..0ff2b418f4 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 @@ -832,7 +838,7 @@ trait Namers extends MethodSynthesis { val parents = typer.parentTypes(templ) map checkParent enterSelf(templ.self) - val decls = new Scope + val decls = newScope val templateNamer = newNamer(context.make(templ, clazz, decls)) templateNamer enterSyms templ.body @@ -918,7 +924,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) @@ -994,7 +1000,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 } } @@ -1262,7 +1268,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) @@ -1276,7 +1282,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) @@ -1290,7 +1296,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) @@ -1337,43 +1343,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? @@ -1391,7 +1397,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) @@ -1456,14 +1462,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) } @@ -1476,8 +1482,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") @@ -1506,7 +1510,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..44579400ff 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -81,7 +81,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => // we don't transform after typers // (that would require much more sophistication when generating trees, // and the only place that emits Matches after typers is for exception handling anyway) - assert(phase.id <= currentRun.typerPhase.id) + assert(phase.id <= currentRun.typerPhase.id, phase) val scrutType = repeatedToSeq(elimAnonymousClass(scrut.tpe.widen)) @@ -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 @@ -876,7 +876,7 @@ defined class Foo */ private val reusedBy = new collection.mutable.HashSet[Test] var reuses: Option[Test] = None def registerReuseBy(later: Test): Unit = { - assert(later.reuses.isEmpty) + assert(later.reuses.isEmpty, later.reuses) reusedBy += later later.reuses = Some(this) } @@ -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) @@ -1253,7 +1239,7 @@ defined class Foo */ case d : DefTree if (d.symbol != NoSymbol) && ((d.symbol.owner == NoSymbol) || (d.symbol.owner == origOwner)) => // don't indiscriminately change existing owners! (see e.g., pos/t3440, pos/t3534, pos/unapplyContexts2) // println("def: "+ (d, d.symbol.ownerChain, currentOwner.ownerChain)) if(d.symbol.isLazy) { // for lazy val's accessor -- is there no tree?? - assert(d.symbol.lazyAccessor != NoSymbol && d.symbol.lazyAccessor.owner == d.symbol.owner) + assert(d.symbol.lazyAccessor != NoSymbol && d.symbol.lazyAccessor.owner == d.symbol.owner, d.symbol.lazyAccessor) d.symbol.lazyAccessor.owner = currentOwner } if(d.symbol.moduleClass ne NoSymbol) @@ -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..a99d09173e 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) { @@ -1490,7 +1491,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R def checkSuper(mix: Name) = // term should have been eliminated by super accessors - assert(!(qual.symbol.isTrait && sym.isTerm && mix == tpnme.EMPTY)) + assert(!(qual.symbol.isTrait && sym.isTerm && mix == tpnme.EMPTY), (qual.symbol, sym, mix)) transformCaseApply(tree, qual match { @@ -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..0ab09b4fec 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 @@ -444,7 +453,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT if (referencingClass.isSubClass(sym.owner.enclClass) || referencingClass.thisSym.isSubClass(sym.owner.enclClass) || referencingClass.enclosingPackageClass == sym.owner.enclosingPackageClass) { - assert(referencingClass.isClass) + assert(referencingClass.isClass, referencingClass) referencingClass } else if(referencingClass.owner.enclClass != NoSymbol) hostForAccessorOf(sym, referencingClass.owner.enclClass) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 4e986dc5aa..4ea21b1c44 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -36,158 +36,13 @@ trait SyntheticMethods extends ast.TreeDSL { import definitions._ import CODE._ - private object util { - private type CM[T] = ClassManifest[T] - - def ValOrDefDef(sym: Symbol, body: Tree) = - if (sym.isLazy) ValDef(sym, body) - else DefDef(sym, body) - - /** To avoid unchecked warnings on polymorphic classes. - */ - def clazzTypeToTest(clazz: Symbol) = clazz.tpe.normalize match { - case TypeRef(_, sym, args) if args.nonEmpty => newExistentialType(sym.typeParams, clazz.tpe) - case tp => tp - } - - def makeMethodPublic(method: Symbol): Symbol = ( - method setPrivateWithin NoSymbol resetFlag AccessFlags - ) - - def methodArg(method: Symbol, idx: Int): Tree = Ident(method.paramss.head(idx)) - - private def applyTypeInternal(manifests: List[CM[_]]): Type = { - val symbols = manifests map manifestToSymbol - val container :: args = symbols - val tparams = container.typeConstructor.typeParams - - // Overly conservative at present - if manifests were more usable - // this could do a lot more. - require(symbols forall (_ ne NoSymbol), "Must find all manifests: " + symbols) - require(container.owner.isPackageClass, "Container must be a top-level class in a package: " + container) - require(tparams.size == args.size, "Arguments must match type constructor arity: " + tparams + ", " + args) - require(args forall (_.typeConstructor.typeParams.isEmpty), "Arguments must be unparameterized: " + args) - - typeRef(container.typeConstructor.prefix, container, args map (_.tpe)) - } - - def manifestToSymbol(m: CM[_]): Symbol = m match { - case x: scala.reflect.AnyValManifest[_] => getMember(ScalaPackageClass, newTermName("" + x)) - case _ => getClassIfDefined(m.erasure.getName) - } - def companionType[T](implicit m: CM[T]) = - getRequiredModule(m.erasure.getName).tpe - - // Use these like `applyType[List, Int]` or `applyType[Map, Int, String]` - def applyType[M](implicit m1: CM[M]): Type = - applyTypeInternal(List(m1)) - - def applyType[M[X1], X1](implicit m1: CM[M[_]], m2: CM[X1]): Type = - applyTypeInternal(List(m1, m2)) - - def applyType[M[X1, X2], X1, X2](implicit m1: CM[M[_,_]], m2: CM[X1], m3: CM[X2]): Type = - applyTypeInternal(List(m1, m2, m3)) - - def applyType[M[X1, X2, X3], X1, X2, X3](implicit m1: CM[M[_,_,_]], m2: CM[X1], m3: CM[X2], m4: CM[X3]): Type = - applyTypeInternal(List(m1, m2, m3, m4)) - } - import util._ - - class MethodSynthesis(val clazz: Symbol, localTyper: Typer) { - private def isOverride(method: Symbol) = - clazzMember(method.name).alternatives exists (sym => (sym != method) && !sym.isDeferred) - - private def setMethodFlags(method: Symbol): Symbol = { - val overrideFlag = if (isOverride(method)) OVERRIDE else 0L - - method setFlag (overrideFlag | SYNTHETIC) resetFlag DEFERRED - } - - private def finishMethod(method: Symbol, f: Symbol => Tree): Tree = { - setMethodFlags(method) - clazz.info.decls enter method - logResult("finishMethod")(localTyper typed ValOrDefDef(method, f(method))) - } - - private def createInternal(name: Name, f: Symbol => Tree, info: Type): Tree = { - val m = clazz.newMethod(name.toTermName, clazz.pos.focus) - m setInfo info - finishMethod(m, f) - } - private def createInternal(name: Name, f: Symbol => Tree, infoFn: Symbol => Type): Tree = { - val m = clazz.newMethod(name.toTermName, clazz.pos.focus) - m setInfo infoFn(m) - finishMethod(m, f) - } - private def cloneInternal(original: Symbol, f: Symbol => Tree, name: Name): Tree = { - val m = original.cloneSymbol(clazz) setPos clazz.pos.focus - m.name = name - finishMethod(m, f) - } - - private def cloneInternal(original: Symbol, f: Symbol => Tree): Tree = - cloneInternal(original, f, original.name) - - def clazzMember(name: Name) = clazz.info nonPrivateMember name match { - case NoSymbol => log("In " + clazz + ", " + name + " not found: " + clazz.info) ; NoSymbol - case sym => sym - } - def typeInClazz(sym: Symbol) = clazz.thisType memberType sym - - /** Function argument takes the newly created method symbol of - * the same type as `name` in clazz, and returns the tree to be - * added to the template. - */ - def overrideMethod(name: Name)(f: Symbol => Tree): Tree = - overrideMethod(clazzMember(name))(f) - - def overrideMethod(original: Symbol)(f: Symbol => Tree): Tree = - cloneInternal(original, sym => f(sym setFlag OVERRIDE)) - - def deriveMethod(original: Symbol, nameFn: Name => Name)(f: Symbol => Tree): Tree = - cloneInternal(original, f, nameFn(original.name)) - - def createMethod(name: Name, paramTypes: List[Type], returnType: Type)(f: Symbol => Tree): Tree = - createInternal(name, f, (m: Symbol) => MethodType(m newSyntheticValueParams paramTypes, returnType)) - - def createMethod(name: Name, returnType: Type)(f: Symbol => Tree): Tree = - createInternal(name, f, NullaryMethodType(returnType)) - - def createMethod(original: Symbol)(f: Symbol => Tree): Tree = - createInternal(original.name, f, original.info) - - def forwardMethod(original: Symbol, newMethod: Symbol)(transformArgs: List[Tree] => List[Tree]): Tree = - createMethod(original)(m => gen.mkMethodCall(newMethod, transformArgs(m.paramss.head map Ident))) - - def createSwitchMethod(name: Name, range: Seq[Int], returnType: Type)(f: Int => Tree) = { - createMethod(name, List(IntClass.tpe), returnType) { m => - val arg0 = methodArg(m, 0) - val default = DEFAULT ==> THROW(IndexOutOfBoundsExceptionClass, arg0) - val cases = range.map(num => CASE(LIT(num)) ==> f(num)).toList :+ default - - Match(arg0, cases) - } - } - - // def foo() = constant - def constantMethod(name: Name, value: Any): Tree = { - val constant = Constant(value) - createMethod(name, Nil, constant.tpe)(_ => Literal(constant)) - } - // def foo = constant - def constantNullary(name: Name, value: Any): Tree = { - val constant = Constant(value) - createMethod(name, constant.tpe)(_ => Literal(constant)) - } - } - /** Add the synthetic methods to case classes. */ def addSyntheticMethods(templ: Template, clazz0: Symbol, context: Context): Template = { if (phase.erasedTypes) return templ - val synthesizer = new MethodSynthesis( + val synthesizer = new ClassMethodSynthesis( clazz0, newTyper( if (reporter.hasErrors) context makeSilent false else context ) ) @@ -212,11 +67,12 @@ trait SyntheticMethods extends ast.TreeDSL { // like Manifests and Arrays which are not robust and infer things // which they shouldn't. val accessorLub = ( - if (opt.experimental) + if (opt.experimental) { global.weakLub(accessors map (_.tpe.finalResultType))._1 match { case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents) case tp => tp } + } else AnyClass.tpe ) @@ -258,11 +114,10 @@ trait SyntheticMethods extends ast.TreeDSL { /** The canEqual method for case classes. * def canEqual(that: Any) = that.isInstanceOf[This] */ - def canEqualMethod: Tree = { - createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m => - methodArg(m, 0) IS_OBJ clazzTypeToTest(clazz) - ) - } + def canEqualMethod: Tree = ( + createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m => + Ident(m.firstParam) IS_OBJ typeCaseType(clazz)) + ) /** The equality method for case classes. * 0 args: @@ -276,8 +131,8 @@ trait SyntheticMethods extends ast.TreeDSL { * } */ def equalsClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m => - val arg0 = methodArg(m, 0) - val thatTest = gen.mkIsInstanceOf(arg0, clazzTypeToTest(clazz), true, false) + val arg0 = Ident(m.firstParam) + val thatTest = gen.mkIsInstanceOf(arg0, typeCaseType(clazz), true, false) val thatCast = gen.mkCast(arg0, clazz.tpe) def argsBody: Tree = { @@ -331,7 +186,7 @@ trait SyntheticMethods extends ast.TreeDSL { Object_hashCode -> (() => constantMethod(nme.hashCode_, clazz.name.decode.hashCode)), Object_toString -> (() => constantMethod(nme.toString_, clazz.name.decode)) // Not needed, as reference equality is the default. - // Object_equals -> (() => createMethod(Object_equals)(m => This(clazz) ANY_EQ methodArg(m, 0))) + // Object_equals -> (() => createMethod(Object_equals)(m => This(clazz) ANY_EQ Ident(m.firstParam))) ) /** If you serialize a singleton and then deserialize it twice, @@ -381,7 +236,7 @@ trait SyntheticMethods extends ast.TreeDSL { for (ddef @ DefDef(_, _, _, _, _, _) <- templ.body ; if isRewrite(ddef.symbol)) { val original = ddef.symbol val newAcc = deriveMethod(ddef.symbol, name => context.unit.freshTermName(name + "$")) { newAcc => - makeMethodPublic(newAcc) + newAcc.makePublic newAcc resetFlag (ACCESSOR | PARAMACCESSOR) ddef.rhs.duplicate } diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index b0500776fe..ed263cbbef 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -142,11 +142,11 @@ abstract class TreeCheckers extends Analyzer { result } def runWithUnit[T](unit: CompilationUnit)(body: => Unit): Unit = { - val unit0 = currentRun.currentUnit + val unit0 = currentUnit currentRun.currentUnit = unit body currentRun.advanceUnit - assertFn(currentRun.currentUnit == unit, "currentUnit is " + currentRun.currentUnit + ", but unit is " + unit) + assertFn(currentUnit == unit, "currentUnit is " + currentUnit + ", but unit is " + unit) currentRun.currentUnit = unit0 } def check(unit: CompilationUnit) { diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index fe3ceafa2d..4f4087a953 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -39,8 +39,6 @@ trait TypeDiagnostics { import definitions._ import global.typer.{ infer, context } - private def currentUnit = currentRun.currentUnit - /** The common situation of making sure nothing is erroneous could be * nicer if Symbols, Types, and Trees all implemented some common interface * in which isErroneous and similar would be placed. @@ -93,37 +91,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 +98,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 +118,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 +151,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 +367,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 +387,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 +400,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 +415,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 +435,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 216ad6cd4c..770b55d6ab 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) + assert(context.undetparams.isEmpty, context.undetparams) newTyper(context.makeConstructorContext) } else this + @inline + final def withCondConstrTyper[T](inConstr: Boolean)(f: Typer => T): T = + if (inConstr) { + assert(context.undetparams.isEmpty, context.undetparams) + 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,12 +862,12 @@ 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) } } def insertApply(): Tree = { - assert(!inHKMode(mode)) //@M + assert(!inHKMode(mode), modeString(mode)) //@M val qual = adaptToName(tree, nme.apply) match { case id @ Ident(_) => val pre = if (id.symbol.owner.isPackageClass) id.symbol.owner.thisType @@ -922,7 +948,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { applyPossible) insertApply() else if (!context.undetparams.isEmpty && !inPolyMode(mode)) { // (9) - assert(!inHKMode(mode)) //@M + assert(!inHKMode(mode), modeString(mode)) //@M if (inExprModeButNot(mode, FUNmode) && pt.typeSymbol == UnitClass) instantiateExpectingUnit(tree, mode) else @@ -960,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) @@ -977,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 } } } @@ -986,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) } } } @@ -1027,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()))) @@ -1053,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) @@ -1083,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) @@ -1099,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 @@ -1162,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 } @@ -1201,19 +1239,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { }) val outercontext = context.outer - assert(clazz != NoSymbol) + assert(clazz != NoSymbol, templ) val cscope = outercontext.makeNewScope(constr, outercontext.owner) 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) @@ -1223,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) @@ -1256,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)) } @@ -1276,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 && @@ -1311,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) /* @@ -1331,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, @@ -1348,6 +1388,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case _ => newinfo } } + FinitaryError(tparam) } } } @@ -1360,11 +1401,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // attributes(cdef) val clazz = cdef.symbol val typedMods = removeAnnotations(cdef.mods) - assert(clazz != NoSymbol) + assert(clazz != NoSymbol, cdef) 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)) @@ -1397,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 @@ -1516,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) { @@ -1569,18 +1611,19 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { (call, List()) } val (superConstr, superArgs) = decompose(rhs) - assert(superConstr.symbol ne null)//debug + assert(superConstr.symbol ne null, superConstr)//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 _ => () } } @@ -1613,6 +1656,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } } + pending.foreach(ErrorUtils.issueTypeError) } /** Check if a structurally defined method violates implementation restrictions. @@ -1661,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))) @@ -1711,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) @@ -1723,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 @@ -1738,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 @@ -1783,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 } @@ -1906,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 @@ -1952,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) @@ -1968,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) { @@ -1980,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) @@ -1991,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 @@ -2005,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 } } @@ -2025,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 @@ -2041,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) @@ -2059,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(_, _) => @@ -2074,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 } } @@ -2121,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) @@ -2168,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) } @@ -2244,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) { @@ -2308,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 @@ -2329,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 => @@ -2337,7 +2387,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { || tupledTree.symbol == null || checkValidAdaptation(tupledTree, args) ) - case ex => + case _ => context.undetparams = savedUndetparams None } @@ -2352,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 }" @@ -2380,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 @@ -2397,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)) } } } @@ -2466,13 +2516,12 @@ 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) doTypedApply(tree, fun, args, mode, pt) } else { - assert(!inPatternMode(mode)) // this case cannot arise for patterns + assert(!inPatternMode(mode), modeString(mode)) // this case cannot arise for patterns val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt) val strictTargs = map2(lenientTargs, tparams)((targ, tparam) => if (targ == WildcardType) tparam.tpe else targ) //@M TODO: should probably be .tpeHK @@ -2488,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" @@ -2509,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 { @@ -2522,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) } @@ -2542,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)) @@ -2553,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)) { @@ -2567,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)) } } @@ -2587,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 } @@ -2604,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)) } @@ -2619,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) @@ -2643,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) @@ -2669,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 @@ -2685,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)) @@ -2703,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 @@ -2715,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) @@ -2781,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) @@ -2791,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? @@ -2890,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 _ => @@ -2907,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) } } } @@ -2977,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) @@ -2989,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 @@ -3012,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(_, _) => @@ -3020,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] @@ -3036,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 @@ -3110,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 @@ -3149,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) @@ -3176,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 { @@ -3203,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) = { @@ -3273,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. @@ -3297,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>> @@ -3321,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 { @@ -3369,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() } } @@ -3393,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. @@ -3419,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]) = { @@ -3451,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 { @@ -3481,7 +3561,7 @@ 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) @@ -3489,30 +3569,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { else res } 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( @@ -3553,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) @@ -3596,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 @@ -3618,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 } } @@ -3659,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) } @@ -3691,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) @@ -3700,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 && @@ -3736,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 } @@ -3753,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 @@ -3761,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 } @@ -3775,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 @@ -3896,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) @@ -3930,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) @@ -4007,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)) { @@ -4042,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) } } } @@ -4098,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) { @@ -4114,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) @@ -4141,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) @@ -4181,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)) => @@ -4203,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) @@ -4259,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 } @@ -4295,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 @@ -4339,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) @@ -4354,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() => @@ -4366,7 +4414,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // whatever type to tree; we just have to survive until a real error message is issued. tree setType AnyClass.tpe case Import(expr, selectors) => - assert(forInteractive) // should not happen in normal circumstances. + assert(forInteractive, "!forInteractive") // should not happen in normal circumstances. tree setType tree.symbol.tpe case _ => abort("unexpected tree: " + tree.getClass + "\n" + tree)//debug @@ -4404,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 ) ) @@ -4424,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 @@ -4455,14 +4502,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - def expandMacro(tree: Tree): Tree = try { - macroExpand(tree) match { - case t: Tree => t - case t => errorTree(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass) + 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 } - } catch { - case ex: MacroExpandError => errorTree(tree, ex.msg) - } def atOwner(owner: Symbol): Typer = newTyper(context.make(context.tree, owner)) @@ -4547,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 + } } } @@ -4586,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/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index a7cd89621c..19b8632ed7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -25,7 +25,7 @@ trait Unapplies extends ast.TreeDSL /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { - assert(ufn.isMethod) + assert(ufn.isMethod, ufn) //Console.println("utl "+ufntpe+" "+ufntpe.typeSymbol) ufn.name match { case nme.unapply => unapplyTypeListFromReturnType(ufntpe) 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/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala index 4405b3457b..e1ae96da8c 100644 --- a/src/compiler/scala/tools/nsc/util/SourceFile.scala +++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala @@ -34,7 +34,7 @@ abstract class SourceFile { * For regular source files, simply return the argument. */ def positionInUltimateSource(position: Position) = position - override def toString(): String = file.name /* + ":" + content.length */ + override def toString() = file.name def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString def path = file.path @@ -61,7 +61,7 @@ object NoSourceFile extends SourceFile { def length = -1 def offsetToLine(offset: Int) = -1 def lineToOffset(index : Int) = -1 - override def toString = "NoSourceFile" + override def toString = "<no source file>" } object NoFile extends VirtualFile("<no file>", "<no file>") diff --git a/src/detach/plugin/scala/tools/detach/Detach.scala b/src/detach/plugin/scala/tools/detach/Detach.scala index e9cd474b82..fee2c5a273 100644 --- a/src/detach/plugin/scala/tools/detach/Detach.scala +++ b/src/detach/plugin/scala/tools/detach/Detach.scala @@ -735,7 +735,7 @@ abstract class Detach extends PluginComponent iface.sourceFile = clazz.sourceFile iface setFlag (ABSTRACT | TRAIT | INTERFACE) // Java interface val iparents = List(ObjectClass.tpe, RemoteClass.tpe, ScalaObjectClass.tpe) - iface setInfo ClassInfoType(iparents, new Scope, iface) + iface setInfo ClassInfoType(iparents, newScope, iface) // methods must throw RemoteException iface addAnnotation remoteAnnotationInfo @@ -749,7 +749,7 @@ abstract class Detach extends PluginComponent // Variant 2: un-/exportObject //val cparents = List(ObjectClass.tpe, iface.tpe, // UnreferencedClass.tpe, ScalaObjectClass.tpe) - iclaz setInfo ClassInfoType(cparents, new Scope, iclaz) + iclaz setInfo ClassInfoType(cparents, newScope, iclaz) val proxy = (iface, iclaz, new mutable.HashMap[Symbol, Symbol]) proxies(clazz) = proxy proxy diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 6d84b4276b..02298ef096 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -151,8 +151,9 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] with GenSeqLike[A, Repr] def next(): Repr = { if (!hasNext) Iterator.empty.next - - val result = (self.newBuilder ++= elms.toList).result + + val forcedElms = new mutable.ArrayBuffer[A](elms.size) ++= elms + val result = (self.newBuilder ++= forcedElms).result var i = idxs.length - 2 while(i >= 0 && idxs(i) >= idxs(i+1)) i -= 1 diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 55ce8fa822..9cde20f1df 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -111,7 +111,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { // TODO: add HashMap2, HashMap3, ... - class HashMap1[A,+B](private[HashMap] var key: A, private[HashMap] var hash: Int, private[collection] var value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { + class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { override def size = 1 private[collection] def getKey = key @@ -176,13 +176,14 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def iterator: Iterator[(A,B)] = Iterator(ensurePair) override def foreach[U](f: ((A, B)) => U): Unit = f(ensurePair) + // this method may be called multiple times in a multithreaded environment, but that's ok private[HashMap] def ensurePair: (A,B) = if (kv ne null) kv else { kv = (key, value); kv } protected override def merge0[B1 >: B](that: HashMap[A, B1], level: Int, merger: Merger[B1]): HashMap[A, B1] = { that.updated0(key, hash, level, value, kv, merger) } } - private[collection] class HashMapCollision1[A, +B](private[HashMap] var hash: Int, var kvs: ListMap[A, B @uV]) + private[collection] class HashMapCollision1[A, +B](private[collection] val hash: Int, val kvs: ListMap[A, B @uV]) extends HashMap[A, B @uV] { override def size = kvs.size @@ -227,9 +228,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } class HashTrieMap[A, +B]( - private[HashMap] var bitmap: Int, - private[collection] var elems: Array[HashMap[A, B @uV]], - private[HashMap] var size0: Int + private[collection] val bitmap: Int, + private[collection] val elems: Array[HashMap[A, B @uV]], + private[collection] val size0: Int ) extends HashMap[A, B @uV] { /* diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 8cb19d4f31..79d2fb71cc 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -105,7 +105,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { // TODO: add HashSet2, HashSet3, ... - class HashSet1[A](private[HashSet] var key: A, private[HashSet] var hash: Int) extends HashSet[A] { + class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends HashSet[A] { override def size = 1 override def get0(key: A, hash: Int, level: Int): Boolean = @@ -131,7 +131,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def foreach[U](f: A => U): Unit = f(key) } - private[immutable] class HashSetCollision1[A](private[HashSet] var hash: Int, var ks: ListSet[A]) + private[immutable] class HashSetCollision1[A](private[HashSet] val hash: Int, val ks: ListSet[A]) extends HashSet[A] { override def size = ks.size @@ -178,7 +178,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } - class HashTrieSet[A](private var bitmap: Int, private[collection] var elems: Array[HashSet[A]], private var size0: Int) + class HashTrieSet[A](private val bitmap: Int, private[collection] val elems: Array[HashSet[A]], private val size0: Int) extends HashSet[A] { override def size = size0 diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index c92c0268b6..7537558f0b 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -286,18 +286,36 @@ extends collection.AbstractSeq[Int] object Range { private[immutable] val MAX_PRINT = 512 // some arbitrary value - /** Counts in "Long arithmetic" so we can recognize overflow. + /** Counts the number of range elements. + * @pre step != 0 + * If the size of the range exceeds Int.MaxValue, the + * result will be negative. */ - def count(start: Int, end: Int, step: Int): Int = - count(start, end, step, false) - def count(start: Int, end: Int, step: Int, isInclusive: Boolean): Int = { - // faster path for the common counting range - if (start >= 0 && end > start && end < scala.Int.MaxValue && step == 1) - (end - start) + ( if (isInclusive) 1 else 0 ) - else - NumericRange.count[Long](start, end, step, isInclusive) + if (step == 0) + throw new IllegalArgumentException("step cannot be 0.") + + val isEmpty = ( + if (start == end) !isInclusive + else if (start < end) step < 0 + else step > 0 + ) + if (isEmpty) 0 + else { + // Counts with Longs so we can recognize too-large ranges. + val gap: Long = end.toLong - start.toLong + val jumps: Long = gap / step + // Whether the size of this range is one larger than the + // number of full-sized jumps. + val hasStub = isInclusive || (gap % step != 0) + val result: Long = jumps + ( if (hasStub) 1 else 0 ) + + if (result > scala.Int.MaxValue) -1 + else result.toInt + } } + def count(start: Int, end: Int, step: Int): Int = + count(start, end, step, false) class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { // override def par = new ParRange(this) diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index e6587f9615..2eb2f8eb09 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -929,13 +929,19 @@ self => /** A specialized, extra-lazy implementation of a stream iterator, so it can * iterate as lazily as it traverses the tail. */ -final class StreamIterator[+A](self: Stream[A]) extends AbstractIterator[A] with Iterator[A] { +final class StreamIterator[+A] private() extends AbstractIterator[A] with Iterator[A] { + def this(self: Stream[A]) { + this() + these = new LazyCell(self) + } + // A call-by-need cell. class LazyCell(st: => Stream[A]) { lazy val v = st } - private var these = new LazyCell(self) + private var these: LazyCell = _ + def hasNext: Boolean = these.v.nonEmpty def next(): A = if (isEmpty) Iterator.empty.next diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 90b64c17f9..390bd72ab5 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -895,7 +895,8 @@ self: ParIterableLike[T, Repr, Sequential] => @volatile var result: R1 = null.asInstanceOf[R1] def map(r: R): R1 def leaf(prevr: Option[R1]) = { - result = map(executeAndWaitResult(inner)) + val initialResult = executeAndWaitResult(inner) + result = map(initialResult) } private[parallel] override def signalAbort() { inner.signalAbort diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala index 873291fb2d..b705909cad 100644 --- a/src/library/scala/collection/parallel/Tasks.scala +++ b/src/library/scala/collection/parallel/Tasks.scala @@ -88,7 +88,7 @@ trait Tasks { if (this.throwable == null && that.throwable == null && (this.result == null || that.result == null)) { println("This: " + this + ", thr=" + this.throwable + "; merged with " + that + ", thr=" + that.throwable) } else if (this.throwable != null || that.throwable != null) { - println("merging this thr: " + this.throwable + " with " + that + ", thr=" + that.throwable) + println("merging this: " + this + " with thr: " + this.throwable + " with " + that + ", thr=" + that.throwable) } } @@ -118,7 +118,7 @@ trait Tasks { /** Try to cancel the task. * @return `true` if cancellation is successful. */ - def tryCancel: Boolean + def tryCancel(): Boolean /** If the task has been cancelled successfully, those syncing on it may * automatically be notified, depending on the implementation. If they * aren't, this release method should be called after processing the @@ -161,32 +161,39 @@ trait AdaptiveWorkStealingTasks extends Tasks { def split: Seq[TaskImpl[R, Tp]] - def compute() = if (body.shouldSplitFurther) internal else body.tryLeaf(None) + def compute() = if (body.shouldSplitFurther) { + internal() + release() + } else { + body.tryLeaf(None) + release() + } def internal() = { var last = spawnSubtasks() - + last.body.tryLeaf(None) + last.release() body.result = last.body.result body.throwable = last.body.throwable - + while (last.next != null) { // val lastresult = Option(last.body.result) val beforelast = last last = last.next - if (last.tryCancel) { + if (last.tryCancel()) { // println("Done with " + beforelast.body + ", next direct is " + last.body) last.body.tryLeaf(Some(body.result)) - last.release + last.release() } else { // println("Done with " + beforelast.body + ", next sync is " + last.body) - last.sync + last.sync() } // println("Merging " + body + " with " + last.body) body.tryMerge(last.body.repr) } } - + def spawnSubtasks() = { var last: TaskImpl[R, Tp] = null var head: TaskImpl[R, Tp] = this @@ -196,7 +203,7 @@ trait AdaptiveWorkStealingTasks extends Tasks { for (t <- subtasks.tail.reverse) { t.next = last last = t - t.start + t.start() } } while (head.body.shouldSplitFurther); head.next = last @@ -230,12 +237,12 @@ trait ThreadPoolTasks extends Tasks { // utb: var future: Future[_] = null @volatile var owned = false @volatile var completed = false - + def start() = synchronized { // debuglog("Starting " + body) // utb: future = executor.submit(this) executor.synchronized { - incrTasks + incrTasks() executor.submit(this) } } @@ -249,9 +256,9 @@ trait ThreadPoolTasks extends Tasks { //assert(executor.getCorePoolSize == (coresize + 1)) } } - if (!completed) this.wait + while (!completed) this.wait } - def tryCancel = synchronized { + def tryCancel() = synchronized { // utb: future.cancel(false) if (!owned) { // debuglog("Cancelling " + body) @@ -259,7 +266,7 @@ trait ThreadPoolTasks extends Tasks { true } else false } - def run = { + def run() = { // utb: compute var isOkToRun = false synchronized { @@ -270,17 +277,17 @@ trait ThreadPoolTasks extends Tasks { } if (isOkToRun) { // debuglog("Running body of " + body) - compute - release + compute() } else { // just skip // debuglog("skipping body of " + body) } } - override def release = synchronized { + override def release() = synchronized { + //println("releasing: " + this + ", body: " + this.body) completed = true executor.synchronized { - decrTasks + decrTasks() } this.notifyAll } @@ -305,10 +312,10 @@ trait ThreadPoolTasks extends Tasks { val t = newTaskImpl(task) // debuglog("-----------> Executing without wait: " + task) - t.start + t.start() () => { - t.sync + t.sync() t.body.forwardThrowable t.body.result } @@ -318,9 +325,9 @@ trait ThreadPoolTasks extends Tasks { val t = newTaskImpl(task) // debuglog("-----------> Executing with wait: " + task) - t.start - - t.sync + t.start() + + t.sync() t.body.forwardThrowable t.body.result } @@ -369,7 +376,7 @@ trait FutureThreadPoolTasks extends Tasks { def sync() = future.get def tryCancel = false def run = { - compute + compute() } } diff --git a/src/library/scala/collection/parallel/immutable/ParHashMap.scala b/src/library/scala/collection/parallel/immutable/ParHashMap.scala index 1fec522a93..e785932933 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashMap.scala @@ -304,14 +304,21 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has evaluateCombiners(trie) trie.asInstanceOf[HashMap[K, Repr]] } - private def evaluateCombiners(trie: HashMap[K, Combiner[V, Repr]]): Unit = trie match { + private def evaluateCombiners(trie: HashMap[K, Combiner[V, Repr]]): HashMap[K, Repr] = trie match { case hm1: HashMap.HashMap1[_, _] => - hm1.asInstanceOf[HashMap.HashMap1[K, Repr]].value = hm1.value.result - hm1.kv = null + val evaledvalue = hm1.value.result + new HashMap.HashMap1[K, Repr](hm1.key, hm1.hash, evaledvalue, null) case hmc: HashMap.HashMapCollision1[_, _] => - hmc.asInstanceOf[HashMap.HashMapCollision1[K, Repr]].kvs = hmc.kvs map { p => (p._1, p._2.result) } - case htm: HashMap.HashTrieMap[_, _] => - for (hm <- htm.elems) evaluateCombiners(hm) + val evaledkvs = hmc.kvs map { p => (p._1, p._2.result) } + new HashMap.HashMapCollision1[K, Repr](hmc.hash, evaledkvs) + case htm: HashMap.HashTrieMap[k, v] => + var i = 0 + while (i < htm.elems.length) { + htm.elems(i) = evaluateCombiners(htm.elems(i)).asInstanceOf[HashMap[k, v]] + i += 1 + } + htm.asInstanceOf[HashMap[K, Repr]] + case empty => empty.asInstanceOf[HashMap[K, Repr]] } def split = { val fp = howmany / 2 diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index addc366072..f152629c50 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -117,7 +117,7 @@ package parallel { /** Composite throwable - thrown when multiple exceptions are thrown at the same time. */ final case class CompositeThrowable( val throwables: Set[Throwable] - ) extends Throwable( + ) extends Exception( "Multiple exceptions thrown during a parallel computation: " + throwables.map(t => t + "\n" + t.getStackTrace.take(10).++("...").mkString("\n")).mkString("\n\n") ) diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 361e02cb16..8a53afaa62 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -309,7 +309,7 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def byteValue = intValue.toByte /** Converts this BigInt to a <tt>short</tt>. - * If the BigInt is too big to fit in a byte, only the low-order 16 bits are returned. + * If the BigInt is too big to fit in a short, only the low-order 16 bits are returned. * Note that this conversion can lose information about the overall magnitude of the * BigInt value as well as return a result with the opposite sign. */ @@ -323,7 +323,7 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo def charValue = intValue.toChar /** Converts this BigInt to an <tt>int</tt>. - * If the BigInt is too big to fit in a char, only the low-order 32 bits + * If the BigInt is too big to fit in a int, only the low-order 32 bits * are returned. Note that this conversion can lose information about the * overall magnitude of the BigInt value as well as return a result with * the opposite sign. @@ -331,7 +331,7 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo def intValue = this.bigInteger.intValue /** Converts this BigInt to a <tt>long</tt>. - * If the BigInt is too big to fit in a char, only the low-order 64 bits + * If the BigInt is too big to fit in a long, only the low-order 64 bits * are returned. Note that this conversion can lose information about the * overall magnitude of the BigInt value as well as return a result with * the opposite sign. diff --git a/src/library/scala/reflect/api/Names.scala b/src/library/scala/reflect/api/Names.scala index e226d2265a..9498f0af36 100755 --- a/src/library/scala/reflect/api/Names.scala +++ b/src/library/scala/reflect/api/Names.scala @@ -1,32 +1,59 @@ package scala.reflect package api +/** A trait that manages names. + * A name is a string in one of two name universes: terms and types. + * The same string can be a name in both universes. + * Two names are equal if they represent the same string and they are + * members of the same universe. + * + * Names are interned. That is, for two names `name11 and `name2`, + * `name1 == name2` implies `name1 eq name2`. + */ trait Names { - + + /** The abstract type of names */ type Name >: Null <: AbsName + + /** The abstract type of names representing terms */ type TypeName <: Name + + /** The abstract type of names representing types */ type TermName <: Name abstract class AbsName { + /** Is this name a term name? */ def isTermName: Boolean + + /** Is this name a type name? */ def isTypeName: Boolean + + /** Returns a term name that represents the same string as this name */ def toTermName: TermName + + /** Returns a type name that represents the same string as this name */ def toTypeName: TypeName - /** Replace all occurrences of $op_names in this name by corresponding operator symbols. + /** Replaces all occurrences of $op_names in this name by corresponding operator symbols. * Example: `foo_+=` becomes `foo_$plus$eq`. */ def decode: String - /** Replace all occurrences of operator symbols in this name by corresponding $op_names. + /** Replaces all occurrences of operator symbols in this name by corresponding $op_names. * Example: `foo_$plus$eq` becomes `foo_+=` */ def encode: Name } + /** Create a new term name. + */ def newTermName(s: String): TermName + + /** Creates a new type name. + */ def newTypeName(s: String): TypeName def EmptyTermName: TermName = newTermName("") + def EmptyTypeName: TypeName = EmptyTermName.toTypeName } diff --git a/src/library/scala/reflect/api/StandardDefinitions.scala b/src/library/scala/reflect/api/StandardDefinitions.scala index 6b480ab83d..08071660a2 100755 --- a/src/library/scala/reflect/api/StandardDefinitions.scala +++ b/src/library/scala/reflect/api/StandardDefinitions.scala @@ -12,9 +12,7 @@ trait StandardDefinitions { self: Universe => abstract class AbsDefinitions { // outer packages and their classes - // Under consideration - // def RootPackage: Symbol - + def RootPackage: Symbol def RootClass: Symbol def EmptyPackage: Symbol def EmptyPackageClass: Symbol diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala index 8b4b170847..01c1a0f2ae 100755 --- a/src/library/scala/reflect/api/Symbols.scala +++ b/src/library/scala/reflect/api/Symbols.scala @@ -15,7 +15,14 @@ trait Symbols { self: Universe => */ def hasModifier(mod: Modifier.Value): Boolean - /** The owner of this symbol. + /** The owner of this symbol. This is the symbol + * that directly contains the current symbol's definition. + * The `NoSymbol` symbol does not have an owner, and calling this method + * on one causes an internal error. + * The owner of the Scala root class [[scala.reflect.api.mirror.RootClass]] + * and the Scala root object [[scala.reflect.api.mirror.RootPackage]] is `NoSymbol`. + * Every other symbol has a chain of owners that ends in + * [[scala.reflect.api.mirror.RootClass]]. */ def owner: Symbol @@ -74,23 +81,6 @@ trait Symbols { self: Universe => */ def annotations: List[self.AnnotationInfo] - /** The type of the symbol - */ - def tpe: Type - - /** The info of the symbol. This is like tpe, except for class symbols where the `info` - * describes the contents of the class whereas the `tpe` is a reference to the class. - */ - def info: Type - - /** If this symbol is a class or trait, its self type, otherwise the type of the symbol itself - */ - def typeOfThis: Type - - /** The type `C.this`, where `C` is the current class. - */ - def thisType: Type - /** For a class: the module or case class factory with the same name in the same package. * For all others: NoSymbol */ @@ -114,20 +104,43 @@ trait Symbols { self: Universe => /** The top-level class containing this symbol. */ def toplevelClass: Symbol - /** The next enclosing class */ + /** The next enclosing class, or `NoSymbol` if none exists */ def enclClass : Symbol - /** The next enclosing method */ + /** The next enclosing method, or `NoSymbol` if none exists */ def enclMethod : Symbol + /** Does this symbol represent the definition of term? + * Note that every symbol is either a term or a type. + * So for every symbol `sym`, either `sym.isTerm` is true + * or `sym.isType` is true. + */ def isTerm : Boolean + + /** Does this symbol represent the definition of type? + * Note that every symbol is either a term or a type. + * So for every symbol `sym`, either `sym.isTerm` is true + * or `sym.isType` is true. + */ def isType : Boolean + + /** Does this symbol represent the definition of class? + * If yes, `isType` is also guaranteed to be true. + */ def isClass : Boolean + + /** Does this symbol represent the definition of a type alias? + * If yes, `isType` is also guaranteed to be true. + */ def isAliasType : Boolean + + /** Does this symbol represent the definition of an abstract type? + * If yes, `isType` is also guaranteed to be true. + */ def isAbstractType : Boolean /** The type signature of this symbol. - * Note if symbol is a member of a class, one almost always is interested + * Note if the symbol is a member of a class, one almost always is interested * in `typeSigIn` with a site type instead. */ def typeSig: Type @@ -136,22 +149,44 @@ trait Symbols { self: Universe => */ def typeSigIn(site: Type): Type - /** The type constructor corresponding to this type symbol. - */ - def asTypeConstructor: Type // needed by LiftCode - - /** A type reference that refers to this type symbol + /** A type reference that refers to this type symbol * Note if symbol is a member of a class, one almost always is interested * in `asTypeIn` with a site type instead. + * + * Example: Given a class declaration `class C[T] { ... } `, that generates a symbol + * `C`. Then `C.asType` is the type `C[T]`. + * + * By contrast, `C.typeSig` would be a type signature of form + * `PolyType(ClassInfoType(...))` that describes type parameters, value + * parameters, parent types, and members of `C`. */ def asType: Type - /** A type reference that refers to this type symbol seen as a member of given type `site`. + /** A type reference that refers to this type symbol seen + * as a member of given type `site`. */ def asTypeIn(site: Type): Type + /** The type constructor corresponding to this type symbol. + * This is different from `asType` in that type parameters + * are part of results of `asType`, but not of `asTypeConstructor`. + * + * Example: Given a class declaration `class C[T] { ... } `, that generates a symbol + * `C`. Then `C.asType` is the type `C[T]`, but `C.asTypeCponstructor` is `C`. + */ + def asTypeConstructor: Type // needed by LiftCode + + /** If this symbol is a class or trait, its self type, otherwise the type + * of the symbol itself. + */ + def typeOfThis: Type + + /** If this symbol is a class, the type `C.this`, otherwise `NoPrefix`. + */ + def thisType: Type + /** A fresh symbol with given name `name`, position `pos` and flags `flags` that has - * the current symbol as its owner. + * the current symbol as its owner. */ def newNestedSymbol(name: Name, pos: Position, flags: Long): Symbol // needed by LiftCode diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index 2394925657..03b043c188 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -8,9 +8,8 @@ package api import scala.collection.mutable.ListBuffer -//import scala.tools.nsc.util.{ FreshNameCreator, HashSet, SourceFile } - -trait Trees /*extends reflect.generic.Trees*/ { self: Universe => +// Syncnote: Trees are currently not thread-safe. +trait Trees { self: Universe => private[scala] var nodeCount = 0 @@ -549,7 +548,7 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe => Select(qualifier, sym.name) setSymbol sym /** Identifier <name> */ - case class Ident(name: Name) extends RefTree { } + case class Ident(name: Name) extends RefTree def Ident(name: String): Ident = Ident(newTermName(name)) diff --git a/src/library/scala/reflect/api/Types.scala b/src/library/scala/reflect/api/Types.scala index 4b959649fd..6185a788ae 100755 --- a/src/library/scala/reflect/api/Types.scala +++ b/src/library/scala/reflect/api/Types.scala @@ -20,7 +20,7 @@ trait Types { self: Universe => /** The collection of declarations in this type */ - def allDeclarations: Iterable[Symbol] + def declarations: Iterable[Symbol] /** The member with given name, either directly declared or inherited, * an OverloadedSymbol if several exist, NoSymbol if none exist. @@ -36,7 +36,7 @@ trait Types { self: Universe => * Members appear in the linearization order of their owners. * Members with the same owner appear in reverse order of their declarations. */ - def allMembers: Iterable[Symbol] + def members: Iterable[Symbol] /** An iterable containing all non-private members of this type (directly declared or inherited) * Members appear in the linearization order of their owners. @@ -125,19 +125,23 @@ trait Types { self: Universe => /** Does this type contain a reference to given symbol? */ def contains(sym: Symbol): Boolean - } - /** This class declares methods that are visible in a `SingleType`. - */ - trait AbsSingletonType extends AbsType { + /** If this is a compound type, the list of its parent types; + * otherwise the empty list + */ + def parents: List[Type] - /** The type underlying a singleton type */ + /** If this is a singleton type, returns the type underlying it; + * otherwise returns this type itself. + */ def underlying: Type - /** Widen from singleton type to its underlying non-singleton - * base type by applying one or more `underlying` dereferences, - * identity for all other types. + /** If this is a singleton type, widen it to its nearest underlying non-singleton + * base type by applying one or more `underlying` dereferences. + * If this is not a singlecon type, returns this type itself. * + * Example: + * * class Outer { class C ; val x: C } * val o: Outer * <o.x.type>.widen = o.C @@ -145,19 +149,6 @@ trait Types { self: Universe => def widen: Type } - /** This class declares methods that are visible in a `CompoundType` (i.e. - * a class/trait/object template or refined type of the form - * {{{ - * P_1 with ... with P_m { D_1; ...; D_n } - * }}} - * P_n - */ - trait AbsCompoundType extends AbsType { - - /** The list of parent types of this compound type */ - def parents: List[Type] - } - /** The type of Scala types, and also Scala type signatures. * (No difference is internally made between the two). */ @@ -293,7 +284,7 @@ trait Types { self: Universe => /** A subtype of Type representing refined types as well as `ClassInfo` signatures. */ - type CompoundType <: /*AbsCompoundType with*/ Type + type CompoundType <: Type /** The `RefinedType` type defines types of any of the forms on the left, * with their RefinedType representations to the right. diff --git a/src/partest-alternative/README b/src/partest-alternative/README deleted file mode 100644 index c7673fe2f8..0000000000 --- a/src/partest-alternative/README +++ /dev/null @@ -1,50 +0,0 @@ -If you're looking for something to read, I suggest running ../test/partest -with no arguments, which at this moment prints this: - -Usage: partest [<options>] [<test> <test> ...] - <test>: a path to a test designator, typically a .scala file or a directory. - Examples: files/pos/test1.scala, files/res/bug785 - - Test categories: - --all run all tests (default, unless no options given) - --pos Compile files that are expected to build - --neg Compile files that are expected to fail - --run Test JVM backend - --jvm Test JVM backend - --res Run resident compiler scenarii - --buildmanager Run Build Manager scenarii - --scalacheck Run Scalacheck tests - --script Run script files - --shootout Run shootout tests - --scalap Run scalap tests - - Test "smart" categories: - --grep run all tests with a source file containing <expr> - --failed run all tests which failed on the last run - - Specifying paths and additional flags, ~ means repository root: - --rootdir path from ~ to partest (default: test) - --builddir path from ~ to test build (default: build/pack) - --srcdir path from --rootdir to sources (default: files) - --javaopts flags to java on all runs (overrides JAVA_OPTS) - --scalacopts flags to scalac on all tests (overrides SCALAC_OPTS) - --pack alias for --builddir build/pack - --quick alias for --builddir build/quick - - Options influencing output: - --trace show the individual steps taken by each test - --show-diff show diff between log and check file - --show-log show log on failures - --dry-run do not run tests, only show their traces. - --terse be less verbose (almost silent except for failures) - --verbose be more verbose (additive with --trace) - --debug maximum debugging output - --ansi print output in color - - Other options: - --timeout Timeout in seconds - --cleanup delete all stale files and dirs before run - --nocleanup do not delete any logfiles or object dirs - --stats collect and print statistics about the tests - --validate examine test filesystem for inconsistencies - --version print version diff --git a/src/partest-alternative/scala/tools/partest/Actions.scala b/src/partest-alternative/scala/tools/partest/Actions.scala deleted file mode 100644 index 9a64edeadc..0000000000 --- a/src/partest-alternative/scala/tools/partest/Actions.scala +++ /dev/null @@ -1,189 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest - -import util._ -import nsc.io._ -import scala.sys.process._ - -trait Actions { - partest: Universe => - - class TestSequence(val actions: List[TestStep]) extends AbsTestSequence { - } - - implicit def createSequence(xs: List[TestStep]) = new TestSequence(xs) - - trait ExecSupport { - self: TestEntity => - - def execEnv: Map[String, String] = { - val map = assembleEnvironment() - val cwd = execCwd.toList map ("CWD" -> _.path) - - map ++ cwd - } - def execCwd = if (commandFile.isFile) Some(sourcesDir) else None - - def runExec(args: List[String]): Boolean = { - val cmd = fromArgs(args) - - if (isVerbose) { - trace("runExec: " + execEnv.mkString("ENV(", "\n", "\n)")) - execCwd foreach (x => trace("CWD(" + x + ")")) - } - - trace("runExec: " + cmd) - isDryRun || execAndLog(cmd) - } - - /** Exec a process to run a command. Assumes 0 exit value is success. - * Of necessity, also treats no available exit value as success. - */ - protected def execAndLog(cmd: String) = (cmd #> logFile.jfile !) == 0 - } - - trait ScriptableTest { - self: TestEntity => - - /** Translates a line from a .cmds file into a teststep. - */ - def customTestStep(line: String): TestStep = { - trace("customTestStep: " + line) - val (cmd, rest) = line span (x => !Character.isWhitespace(x)) - def qualify(name: String) = sourcesDir / name path - val args = toArgs(rest) map qualify - def fail: TestStep = (_: TestEntity) => error("Parse error: did not understand '%s'" format line) - - val f: TestEntity => Boolean = cmd match { - case "scalac" => _ scalac args - case "javac" => _ javac args - case "scala" => _ runScala args - case _ => fail - } - f - } - } - - trait CompilableTest extends CompileExecSupport { - self: TestEntity => - - def sourceFiles = location.walk collect { case f: File if isJavaOrScala(f) => f } toList - def allSources = sourceFiles map (_.path) - def scalaSources = sourceFiles filter isScala map (_.path) - def javaSources = sourceFiles filter isJava map (_.path) - - /** If there are mixed java and scala files, the standard compilation - * sequence is: - * - * scalac with all files - * javac with only java files - * scalac with only scala files - * - * This should be expanded to encompass other strategies so we know how - * well they're working or not working - notably, it would be very useful - * to know exactly when and how two-pass compilation fails. - */ - def compile() = { - trace("compile: " + sourceFiles) - - def compileJava() = javac(javaSources) - def compileScala() = scalac(scalaSources) - def compileAll() = scalac(allSources) - def compileMixed() = compileAll() && compileJava() && compileScala() - - if (scalaSources.nonEmpty && javaSources.nonEmpty) compileMixed() - else compileScala() - } - } - - trait DiffableTest { - self: TestEntity => - - def checkFile: File = withExtension("check").toFile - def checkFileRequired = - returning(checkFile.isFile)(res => if (!res) warnAndLog("A checkFile at '%s' is mandatory.\n" format checkFile.path)) - - lazy val sourceFileNames = sourceFiles map (_.name) - - /** Given the difficulty of verifying that any selective approach works - * everywhere, the algorithm now is to look for the name of any known - * source file for this test, and if seen, remove all the non-whitespace - * preceding it. (Paths with whitespace don't work anyway.) This should - * wipe out all slashes, backslashes, C:\, cygwin/windows differences, - * and whatever else makes a simple diff not simple. - * - * The log and check file are both transformed, which I don't think is - * correct -- only the log should be -- but doing it this way until I - * can clarify martin's comments in #3283. - */ - def normalizePaths(s: String) = - sourceFileNames.foldLeft(s)((res, name) => res.replaceAll("""\S+\Q%s\E""" format name, name)) - - /** The default cleanup normalizes paths relative to sourcesDir, - * absorbs line terminator differences by going to lines and back, - * and trims leading or trailing whitespace. - */ - def diffCleanup(f: File) = safeLines(f) map normalizePaths mkString "\n" trim - - /** diffFiles requires actual Files as arguments but the output we want - * is the post-processed versions of log/check, so we resort to tempfiles. - */ - lazy val diffOutput = { - if (!checkFile.exists) "" else { - val input = diffCleanup(checkFile) - val output = diffCleanup(logFile) - def asFile(s: String) = returning(File.makeTemp("partest-diff"))(_ writeAll s) - - if (input == output) "" - else diffFiles(asFile(input), asFile(output)) - } - } - private def checkTraceName = tracePath(checkFile) - private def logTraceName = tracePath(logFile) - private def isDiffConfirmed = checkFile.exists && (diffOutput == "") - - private def sendTraceMsg() { - def result = - if (isDryRun) "" - else if (isDiffConfirmed) " [passed]" - else if (checkFile.exists) " [failed]" - else " [unchecked]" - - trace("diff %s %s%s".format(checkTraceName, logTraceName, result)) - } - - /** If optional is true, a missing check file is considered - * a successful diff. Necessary since many categories use - * checkfiles in an ad hoc manner. - */ - def runDiff() = { - sendTraceMsg() - - def updateCheck = ( - isUpdateCheck && { - val formatStr = "** diff %s %s: " + ( - if (checkFile.exists) "failed, updating '%s' and marking as passed." - else if (diffOutput == "") "not creating checkFile at '%s' as there is no output." - else "was unchecked, creating '%s' for future tests." - ) + "\n" - - normal(formatStr.format(checkTraceName, logTraceName, checkFile.path)) - if (diffOutput != "") normal(diffOutput) - - checkFile.writeAll(diffCleanup(logFile), "\n") - true - } - ) - - isDryRun || isDiffConfirmed || (updateCheck || !checkFile.exists) - } - } -} diff --git a/src/partest-alternative/scala/tools/partest/Alarms.scala b/src/partest-alternative/scala/tools/partest/Alarms.scala deleted file mode 100644 index ef30d13705..0000000000 --- a/src/partest-alternative/scala/tools/partest/Alarms.scala +++ /dev/null @@ -1,86 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools -package partest - -import java.util.{ Timer, TimerTask } - -trait Alarms { - self: Universe => - - def interruptMeIn[T](debugMsg: String, seconds: Int)(body: => T): Option[T] = { - val thisThread = currentThread - val alarm = new SimpleAlarm(seconds * 1000) set thisThread.interrupt() - debug("interruptMeIn(%d) '%s'".format(seconds, debugMsg)) - - try { Some(body) } - catch { case _: InterruptedException => debug("Received interrupted exception.") ; None } - finally { debug("Cancelling interruptMeIn '%s'" format debugMsg) ; alarm.cancel() ; Thread.interrupted() } - } - - case class AlarmerAction(secs: Int, action: () => Unit) extends Runnable { - override def run() = action() - } - - /** Set any number of alarms up with tuples of the form: - * seconds to alarm -> Function0[Unit] to execute - */ - class Alarmer(alarms: AlarmerAction*) { - import java.util.concurrent._ - - val exec = Executors.newSingleThreadScheduledExecutor() - alarms foreach (x => exec.schedule(x, x.secs, TimeUnit.SECONDS)) - exec.shutdown() - - def cancelAll() = exec.shutdownNow() - } - - class SimpleAlarm(timeout: Long) { - private val alarm = new Timer - - /** Start a timer, running the given body if it goes off. - */ - def set(body: => Unit) = returning(new TimerTask { def run() = body })(alarm.schedule(_, timeout)) - - /** Cancel the timer. - */ - def cancel() = alarm.cancel() - } - - trait TestAlarms { - test: TestEntity => - - private def warning1 = AlarmerAction(testWarning, () => warning( - """|I've been waiting %s seconds for this to complete: - | %s - |It may be stuck, or if not, it should be broken into smaller tests. - |""".stripMargin.format(testWarning, test)) - ) - private def warning2 = AlarmerAction(testWarning * 2, () => warning( - """|Now I've been waiting %s seconds for this to complete: - | %s - |If partest seems hung it would be a good place to look. - |""".stripMargin.format(testWarning * 2, test)) - ) - - def startAlarms(onTimeout: => Unit) = - if (isNoAlarms) new Alarmer() // for alarm debugging - else new Alarmer(Seq(warning1, warning2, AlarmerAction(testTimeout, () => onTimeout)): _*) - } - - // Thread.setDefaultUncaughtExceptionHandler(new UncaughtException) - // class UncaughtException extends Thread.UncaughtExceptionHandler { - // def uncaughtException(t: Thread, e: Throwable) { - // Console.println("Uncaught in %s: %s".format(t, e)) - // } - // } - // - // lazy val logger = File("/tmp/partest.log").bufferedWriter() - // def flog(msg: String) = logger synchronized { - // logger write (msg + "\n") - // logger.flush() - // } -} diff --git a/src/partest-alternative/scala/tools/partest/BuildContributors.scala b/src/partest-alternative/scala/tools/partest/BuildContributors.scala deleted file mode 100644 index 85ca895103..0000000000 --- a/src/partest-alternative/scala/tools/partest/BuildContributors.scala +++ /dev/null @@ -1,102 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import nsc.io._ -import nsc.util.ClassPath - -trait BuildContributors { - universe: Universe => - - /** A trait mixed into types which contribute a portion of the values. - * The basic mechanism is the TestBuild, TestCategory, and TestEntity - * can each contribute to each value. They are assembled at the last - * moment by the ContributorAssembler (presently the TestEntity.) - */ - trait BuildContributor { - def javaFlags: List[String] - def scalacFlags: List[String] - def classpathPaths: List[Path] - def buildProperties: List[(String, Any)] - def buildEnvironment: Map[String, String] - } - - trait ContributorAssembler { - def contributors: List[BuildContributor] - def assemble[T](what: BuildContributor => List[T]): List[T] = contributors flatMap what - - /** !!! This will need work if we want to achieve real composability, - * but it can wait for the demand. - */ - def assembleScalacArgs(args: List[String]) = assemble(_.scalacFlags) ++ args - def assembleJavaArgs(args: List[String]) = assemble(_.javaFlags) ++ args - def assembleProperties() = assemble(_.buildProperties) - def assembleClasspaths(paths: List[Path]) = assemble(_.classpathPaths) ++ paths - def assembleEnvironment() = assemble(_.buildEnvironment.toList).toMap - - def createClasspathString() = ClassPath fromPaths (assembleClasspaths(Nil) : _*) - def createPropertyString() = assembleProperties() map { case (k, v) => "-D%s=%s".format(k, v.toString) } - } - - trait BuildContribution extends BuildContributor { - self: TestBuild => - - /** The base classpath and system properties. - * !!! TODO - this should adjust itself depending on the build - * being tested, because pack and quick at least need different jars. - */ - def classpathPaths = List[Path](library, compiler, partest, fjbg) ++ forkJoinPath - def buildProperties = List( - "scala.home" -> testBuildDir, - "partest.lib" -> library, // used in jvm/inner - "java.awt.headless" -> true, - "user.language" -> "en", - "user.country" -> "US", - "partest.debug" -> isDebug, - "partest.verbose" -> isVerbose - // Disabled because there are no natives tests. - // "java.library.path" -> srcLibDir - ) - def javaFlags: List[String] = toArgs(javaOpts) - def scalacFlags: List[String] = toArgs(scalacOpts) - - /** We put the build being tested's /bin directory in the front of the - * path so the scripts and such written to execute "scala" will use this - * build and not whatever happens to be on their path. - */ - private def modifiedPath = ClassPath.join(scalaBin.path, Properties.envOrElse("PATH", "")) - def buildEnvironment = Map("PATH" -> modifiedPath) - } - - trait CategoryContribution extends BuildContributor { - self: DirBasedCategory => - - /** Category-wide classpath additions placed in <category>/lib. */ - private def libContents = root / "lib" ifDirectory (_.list.toList) - - def classpathPaths = libContents getOrElse Nil - def buildProperties = Nil - def javaFlags = Nil - def scalacFlags = Nil - def buildEnvironment = Map() - } - - trait TestContribution extends BuildContributor with ContributorAssembler { - self: TestEntity => - - def jarsInTestDir = location.walk collect { case f: File if f hasExtension "jar" => f } toList - - def contributors = List(build, category, self) - def javaFlags = safeArgs(javaOptsFile) - def scalacFlags = safeArgs(scalaOptsFile) - def classpathPaths = jarsInTestDir :+ outDir - def buildProperties = List( - "partest.output" -> outDir.toAbsolute, // used in jvm/inner - "partest.cwd" -> outDir.parent.toAbsolute // used in shootout tests - ) - def buildEnvironment = Map("JAVA_OPTS" -> fromArgs(assembleJavaArgs(Nil))) - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/Categories.scala b/src/partest-alternative/scala/tools/partest/Categories.scala deleted file mode 100644 index c517a3f931..0000000000 --- a/src/partest-alternative/scala/tools/partest/Categories.scala +++ /dev/null @@ -1,70 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest - -import nsc.Settings -import nsc.io._ -import nsc.util.{ ClassPath } - -trait Categories { - self: Universe => - - trait TestCategory extends AbsTestCategory { - def kind: String - def startMessage: String = "Executing test group" - def testSequence: TestSequence - - class TestSettings(entity: TestEntity, error: String => Unit) extends Settings(error) { - def this(entity: TestEntity) = this(entity, Console println _) - - deprecation.value = false - encoding.value = "ISO-8859-1" - classpath.value = entity.testClasspath - outdir.value = entity.outDir.path - } - - def createSettings(entity: TestEntity): TestSettings = new TestSettings(entity) - def createTest(location: Path): TestEntity = - if (location.isFile) TestFile(this, location.toFile) - else if (location.isDirectory) TestDirectory(this, location.toDirectory) - else error("Failed to create test at '%s'" format location) - - /** Category test identification. - */ - def denotesTestFile(p: Path) = p.isFile && (p hasExtension "scala") - def denotesTestDir(p: Path) = p.isDirectory && !ignorePath(p) - def denotesTest(p: Path) = denotesTestDir(p) || denotesTestFile(p) - - /** This should verify that all necessary files are present. - * By default it delegates to denotesTest. - */ - def denotesValidTest(p: Path) = denotesTest(p) - } - - abstract class DirBasedCategory(val kind: String) extends TestCategory with CategoryContribution { - lazy val root = Directory(src / kind).normalize - def enumerate = root.list filter denotesTest map createTest toList - - /** Standard actions. These can be overridden either on the - * Category level or by individual tests. - */ - def compile: TestStep = (_: TestEntity).compile() - def checkFileRequired: TestStep = (_: TestEntity).checkFileRequired - def diff: TestStep = (_: TestEntity).diff() - def run: TestStep = (_: TestEntity).run() - def exec: TestStep = (_: TestEntity).exec() - - /** Combinators. - */ - def not(f: TestStep): TestStep = !f(_: TestEntity) - - override def toString = kind - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/Compilable.scala b/src/partest-alternative/scala/tools/partest/Compilable.scala deleted file mode 100644 index 65b5d5da0e..0000000000 --- a/src/partest-alternative/scala/tools/partest/Compilable.scala +++ /dev/null @@ -1,106 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import scala.tools.nsc.io._ -import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError } -import scala.tools.nsc.util.{ ClassPath } -import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter } - -trait PartestCompilation { - self: Universe => - - trait CompileExecSupport extends ExecSupport { - self: TestEntity => - - def javacpArg = "-classpath " + testClasspath - def scalacpArg = "-usejavacp" - - /** Not used, requires tools.jar. - */ - // def javacInternal(args: List[String]) = { - // import com.sun.tools.javac.Main - // Main.compile(args.toArray, logWriter) - // } - - def javac(args: List[String]): Boolean = { - val allArgString = fromArgs(javacpArg :: javacOpts :: args) - - // javac -d outdir -classpath <basepath> <files> - val cmd = "%s -d %s %s".format(javacCmd, outDir, allArgString) - def traceMsg = - if (isVerbose) cmd - else "%s -d %s %s".format(tracePath(Path(javacCmd)), tracePath(outDir), fromArgs(args)) - - trace(traceMsg) - - isDryRun || execAndLog(cmd) - } - - def scalac(args: List[String]): Boolean = { - val allArgs = assembleScalacArgs(args) - val (global, files) = newGlobal(allArgs) - def nonFileArgs = if (isVerbose) global.settings.recreateArgs else assembleScalacArgs(Nil) - def traceArgs = fromArgs(nonFileArgs ++ (files map tracePath)) - def traceMsg = "scalac " + traceArgs - - trace(traceMsg) - isDryRun || global.partestCompile(files, true) - } - - /** Actually running the test, post compilation. - * Normally args will be List("Test", "jvm"), main class and arg to it. - */ - def runScala(args: List[String]): Boolean = { - val scalaRunnerClass = "scala.tools.nsc.MainGenericRunner" - - // java $JAVA_OPTS <javaopts> -classpath <cp> - val javaCmdAndOptions = javaCmd +: assembleJavaArgs(List(javacpArg)) - // MainGenericRunner -usejavacp <scalacopts> Test jvm - val scalaCmdAndOptions = List(scalaRunnerClass, scalacpArg) ++ assembleScalacArgs(args) - // Assembled - val cmd = fromArgs(javaCmdAndOptions ++ createPropertyString() ++ scalaCmdAndOptions) - - def traceMsg = if (isVerbose) cmd else fromArgs(javaCmd :: args) - trace("runScala: " + traceMsg) - - isDryRun || execAndLog(cmd) - } - - def newReporter(settings: Settings) = new ConsoleReporter(settings, Console.in, logWriter) - - class PartestGlobal(settings: Settings, val creporter: ConsoleReporter) extends Global(settings, creporter) { - def partestCompile(files: List[String], printSummary: Boolean): Boolean = { - try { new Run compile files } - catch { - case FatalError(msg) => creporter.error(null, "fatal error: " + msg) - case ae: AssertionError => creporter.error(null, ""+ae) - case te: TypeError => creporter.error(null, ""+te) - case ex => - creporter.error(null, ""+ex) - throw ex - } - - if (printSummary) - creporter.printSummary - - creporter.flush() - !creporter.hasErrors - } - } - - def newGlobal(args: List[String]): (PartestGlobal, List[String]) = { - val settings = category createSettings self - val command = new CompilerCommand(args, settings) - val reporter = newReporter(settings) - - if (!command.ok) - debug("Error parsing arguments: '%s'".format(args mkString ", ")) - - (new PartestGlobal(command.settings, reporter), command.files) - } - } -} diff --git a/src/partest-alternative/scala/tools/partest/Config.scala b/src/partest-alternative/scala/tools/partest/Config.scala deleted file mode 100644 index ee1852f6ed..0000000000 --- a/src/partest-alternative/scala/tools/partest/Config.scala +++ /dev/null @@ -1,115 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import io._ -import nsc.io._ -import Properties._ - -trait Config { - universe: Universe => - - lazy val src = absolutize(srcDir).toDirectory - lazy val build = new TestBuild() - - def javaHomeEnv = envOrElse("JAVA_HOME", null) - def javaCmd = envOrElse("JAVACMD", "java") - def javacCmd = Option(javaHomeEnv) map (x => Path(x) / "bin" / "javac" path) getOrElse "javac" - - /** Values related to actors. The timeouts are in seconds. On a dry - * run we only allocate one worker so the output isn't interspersed. - */ - def workerTimeout = 3600 // 1 hour, probably overly generous - def numWorkers = if (isDryRun) 1 else propOrElse("partest.actors", "8").toInt - def expectedErrors = propOrElse("partest.errors", "0").toInt - def poolSize = (wrapAccessControl(propOrNone("actors.corePoolSize")) getOrElse "16").toInt - - def allScalaFiles = src.deepFiles filter (_ hasExtension "scala") - def allObjDirs = src.deepDirs filter (_ hasExtension "obj") - def allLogFiles = src.deepFiles filter (_ hasExtension "log") - def allClassFiles = src.deepFiles filter (_ hasExtension "class") - - class TestBuild() extends BuildContribution { - import nsc.util.ClassPath - - /** Scala core libs. - */ - val library = pathForComponent("library") - val compiler = pathForComponent("compiler") - val partest = pathForComponent("partest") - val scalap = pathForComponent("scalap", "%s.jar") - - /** Scala supplementary libs - these are not all needed for all build targets, - * and some of them are copied inside other jars in later targets. However quick - * for instance cannot be run without some of these. - */ - val fjbg = pathForLibrary("fjbg") - val msil = pathForLibrary("msil") - val forkjoin = pathForLibrary("forkjoin") - val scalacheck = pathForLibrary("scalacheck") - - /** Other interesting paths. - */ - val scalaBin = testBuildDir / "bin" - - /** A hack for now to get quick running. - */ - def needsForkJoin = { - val loader = nsc.util.ScalaClassLoader.fromURLs(List(library.toURL)) - val fjMarker = "scala.concurrent.forkjoin.ForkJoinTask" - val clazz = loader.tryToLoadClass(fjMarker) - - if (clazz.isDefined) debug("Loaded ForkJoinTask OK, don't need jar.") - else debug("Could not load ForkJoinTask, putting jar on classpath.") - - clazz.isEmpty - } - lazy val forkJoinPath: List[Path] = if (needsForkJoin) List(forkjoin) else Nil - - /** Internal **/ - private def repo = partestDir.parent.normalize - - private def pathForComponent(what: String, jarFormat: String = "scala-%s.jar"): Path = { - def asDir = testBuildDir / "classes" / what - def asJar = testBuildDir / "lib" / jarFormat.format(what) - - if (asDir.isDirectory) asDir - else if (asJar.isFile) asJar - else "" - } - private def pathForLibrary(what: String) = File(repo / "lib" / (what + ".jar")) - } - - def printConfigBanner() = { - debug("Java VM started with arguments: '%s'" format fromArgs(Process.javaVmArguments)) - debug("System Properties:\n" + util.allPropertiesString()) - - normal(configBanner()) - } - - /** Treat an access control failure as None. */ - private def wrapAccessControl[T](body: => Option[T]): Option[T] = - try body catch { case _: java.security.AccessControlException => None } - - private def configBanner() = { - val javaBin = Path(javaHome) / "bin" - val javaInfoString = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo) - - List( - "Scala compiler classes in: " + testBuildDir, - "Scala version is: " + nsc.Properties.versionMsg, - "Scalac options are: " + universe.scalacOpts, - "Java binaries in: " + javaBin, - "Java runtime is: " + javaInfoString, - "Java runtime options: " + (Process.javaVmArguments mkString " "), - "Javac options are: " + universe.javacOpts, - "Java options are: " + universe.javaOpts, - "Source directory is: " + src, - "Selected categories: " + (selectedCategories mkString " "), - "" - ) mkString "\n" - } -} diff --git a/src/partest-alternative/scala/tools/partest/Dispatcher.scala b/src/partest-alternative/scala/tools/partest/Dispatcher.scala deleted file mode 100644 index 69efc353eb..0000000000 --- a/src/partest-alternative/scala/tools/partest/Dispatcher.scala +++ /dev/null @@ -1,162 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools -package partest - -import scala.tools.nsc.io._ -import scala.actors.{ Actor, TIMEOUT } -import scala.actors.Actor._ -import scala.collection.immutable -import scala.util.control.Exception.ultimately - -/** The machinery for concurrent execution of tests. Each Worker - * is given a bundle of tests, which it runs sequentially and then - * sends a report back to the dispatcher. - */ -trait Dispatcher { - partest: Universe => - - /** The public entry point. The given filter narrows down the list of - * tests to run. - */ - def runSelection(categories: List[TestCategory], filt: TestEntity => Boolean = _ => true): CombinedTestResults = { - // Setting scala.home informs tests where to obtain their jars. - setProp("scala.home", testBuildDir.path) - - val allTests = allCategories flatMap (_.enumerate) - val selected = allTests filter filt - val groups = selected groupBy (_.category) - val count = selected.size - - if (count == 0) return CombinedTestResults(0, 0, 0, Nil) - else if (count == allTests.size) verbose("Running all %d tests." format count) - else verbose("Running %d/%d tests: %s".format(count, allTests.size, toStringTrunc(selected map (_.label) mkString ", "))) - - allCategories collect { case x if groups contains x => runCategory(x, groups(x)) } reduceLeft (_ ++ _) - } - - private def parallelizeTests(tests: List[TestEntity]): immutable.Map[TestEntity, TestResult] = { - // propagate verbosity - if (isDebug) scala.actors.Debug.level = 3 - - // "If elected, I guarantee a slice of tests for every worker!" - val groups = tests grouped ((tests.size / numWorkers) + 1) toList - - // "Workers, line up for assignments!" - val workers = - for ((slice, workerNum) <- groups.zipWithIndex) yield { - returning(new Worker(workerNum)) { worker => - worker.start() - worker ! TestsToRun(slice) - } - } - - normal("Started %d workers with ~%d tests each.\n".format(groups.size, groups.head.size)) - - /** Listening for news from the proletariat. - */ - (workers map { w => - receiveWithin(workerTimeout * 1000) { - case ResultsOfRun(resultMap) => resultMap - case TIMEOUT => - warning("Worker %d timed out." format w.workerNum) - // mark all the worker's tests as having timed out - should be hard to miss - // immutable.Map[TestEntity, TestResult]() - groups(w.workerNum) map (x => (x -> new Timeout(x))) toMap - } - }) reduceLeft (_ ++ _) - } - - private def runCategory(category: TestCategory, tests: List[TestEntity]): CombinedTestResults = { - val kind = category.kind - normal("%s (%s tests in %s)\n".format(category.startMessage, tests.size, category)) - - val (milliSeconds, resultMap) = timed2(parallelizeTests(tests)) - val (passed, failed) = resultsToStatistics(resultMap mapValues (_.state)) - val failures = resultMap.values filterNot (_.passed) toList - - CombinedTestResults(passed, failed, milliSeconds, failures) - } - - /** A Worker is given a bundle of tests and runs them all sequentially. - */ - class Worker(val workerNum: Int) extends Actor { - def act() { - react { case TestsToRun(tests) => - val master = sender - runTests(tests)(results => master ! ResultsOfRun(results)) - } - } - - /** Runs the tests. Passes the result Map to onCompletion when done. - */ - private def runTests(tests: List[TestEntity])(onCompletion: immutable.Map[TestEntity, TestResult] => Unit) { - var results = new immutable.HashMap[TestEntity, TestResult] // maps tests to results - val numberOfTests = tests.size - val testIterator = tests.iterator - def processed = results.size - def isComplete = testIterator.isEmpty - - def atThreshold(num: Double) = { - require(num >= 0 && num <= 1.0) - ((processed - 1).toDouble / numberOfTests <= num) && (processed.toDouble / numberOfTests >= num) - } - - def extraMessage = { - // for now quiet for normal people - if (isVerbose || isTrace || isDebug) { - if (isComplete) "(#%d 100%%)" format workerNum - else if (isVerbose) "(#%d %d/%d)".format(workerNum, processed, numberOfTests) - else if (isTrace && atThreshold(0.5)) "(#%d 50%%)" format workerNum - else "" - } - else "" - } - - def countAndReport(result: TestResult) { - val TestResult(test, state) = result - // refuse to count an entity twice - if (results contains test) - return warning("Received duplicate result for %s: was %s, now %s".format(test, results(test), state)) - - // increment the counter for this result state - results += (test -> result) - - // show on screen - if (isDryRun) normal("\n") // blank line between dry run traces - else result show extraMessage - - // remove log if successful - if (result.passed) - test.deleteLog() - - // Respond to master if this Worker is complete - if (isComplete) - onCompletion(results) - } - - Actor.loopWhile(testIterator.hasNext) { - val parent = self - // pick a test and set some alarms - val test = testIterator.next - val alarmer = test startAlarms (parent ! new Timeout(test)) - - actor { - ultimately(alarmer.cancelAll()) { - // Calling isSuccess forces the lazy val "process" inside the test, running it. - val res = test.isSuccess - // Cancel the alarms and alert the media. - parent ! TestResult(test, res) - } - } - - react { - case x: TestResult => countAndReport(x) - } - } - } - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/Entities.scala b/src/partest-alternative/scala/tools/partest/Entities.scala deleted file mode 100644 index 301deb972b..0000000000 --- a/src/partest-alternative/scala/tools/partest/Entities.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools -package partest - -import nsc.io._ - -trait Entities { - self: Universe => - - abstract class TestEntity extends AbsTestEntity - with TestContribution - with TestHousekeeping - with TestAlarms - with EntityLogging - with CompilableTest - with ScriptableTest - with DiffableTest { - def location: Path - def category: TestCategory - - lazy val label = location.stripExtension - lazy val testClasspath = returning(createClasspathString())(x => vtrace("testClasspath: " + x)) - - /** Was this test successful? Calling this for the first time forces - * lazy val "process" which actually runs the test. - */ - def isSuccess = process - - /** Some standard files, which may or may not be present. - */ - def scalaOptsFile = withExtension("flags").toFile // opts to scalac - def javaOptsFile = withExtension("javaopts").toFile // opts to java (but not javac) - def commandFile = withExtension("cmds").toFile // sequence of commands to execute - def logFile = withExtension("log").toFile // collected output - - /** Some standard directories. - */ - def outDir = withExtension("obj").toDirectory // output dir, e.g. files/pos/t14.obj - def categoryDir = location.parent.normalize // category dir, e.g. files/pos/ - def sourcesDir = location ifDirectory (_.normalize) getOrElse categoryDir - - /** Standard arguments for run, exec, diff. - */ - def argumentsToRun = List("Test", "jvm") - def argumentsToExec = List(location.path) - - /** Using a .cmds file for a custom test sequence. - */ - def commandList = safeLines(commandFile) - def testSequence = - if (commandFile.isFile && commandList.nonEmpty) commandList map customTestStep - else category.testSequence - - def run() = runScala(argumentsToRun) - def exec() = runExec(argumentsToExec) - def diff() = runDiff() // checkFile, logFile - - /** The memoized result of the test run. - */ - private lazy val process = { - val outcome = runWrappers(testSequence.actions forall (f => f(this))) - - // an empty outcome means we've been interrupted and are shutting down. - outcome getOrElse false - } - } - - case class TestDirectory(category: TestCategory, location: Directory) extends TestEntity { } - case class TestFile(category: TestCategory, location: File) extends TestEntity { } -} diff --git a/src/partest-alternative/scala/tools/partest/Housekeeping.scala b/src/partest-alternative/scala/tools/partest/Housekeeping.scala deleted file mode 100644 index cfdecee9c7..0000000000 --- a/src/partest-alternative/scala/tools/partest/Housekeeping.scala +++ /dev/null @@ -1,187 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import scala.util.control.Exception.catching -import util._ -import nsc.io._ -import Process.runtime -import Properties._ - -/** An agglomeration of code which is low on thrills. Hopefully - * it operates so quietly in the background that you never have to - * look at this file. - */ -trait Housekeeping { - self: Universe => - - /** Orderly shutdown on ctrl-C. */ - @volatile private var _shuttingDown = false - protected def setShuttingDown() = { - /** Whatever we want to do as shutdown begins goes here. */ - if (!_shuttingDown) { - warning("Received shutdown signal, partest is cleaning up...\n") - _shuttingDown = true - } - } - def isShuttingDown = _shuttingDown - - /** Execute some code with a shutdown hook in place. This is - * motivated by the desire not to leave the filesystem full of - * junk when someone ctrl-Cs a test run. - */ - def withShutdownHook[T](hook: => Unit)(body: => T): Option[T] = - /** Java doesn't like it if you keep adding and removing shutdown - * hooks after shutdown has begun, so we trap the failure. - */ - catching(classOf[IllegalStateException]) opt { - val t = new Thread() { - override def run() = { - setShuttingDown() - hook - } - } - runtime addShutdownHook t - - try body - finally runtime removeShutdownHook t - } - - /** Search for a directory, possibly given only a name, by starting - * at the current dir and walking upward looking for it at each level. - */ - protected def searchForDir(name: String): Directory = { - val result = Path(name) ifDirectory (x => x.normalize) orElse { - val cwd = Directory.Current getOrElse error("user.dir property not set") - val dirs = cwd :: cwd.parents map (_ / name) - - Path onlyDirs dirs map (_.normalize) headOption - } - - result getOrElse error("Fatal: could not find directory '%s'" format name) - } - - /** Paths we ignore for most purposes. - */ - def ignorePath(x: Path) = { - (x.name startsWith ".") || - (x.isDirectory && ((x.name == "lib") || x.hasExtension("obj", "svn"))) - } - /** Make a possibly relative path absolute using partestDir as the base. - */ - def absolutize(path: String) = Path(path) toAbsoluteWithRoot partestDir - - /** Go on a deleting binge. - */ - def cleanupAll() { - if (isNoCleanup) - return - - val (dirCount, fileCount) = (cleanupObjDirs(), cleanupLogs() + cleanupJunk()) - if (dirCount + fileCount > 0) - normal("Cleaned up %d directories and %d files.\n".format(dirCount, fileCount)) - } - - def cleanupObjDirs() = countTrue(allObjDirs collect { case x if x.exists => x.deleteRecursively() }) - def cleanupJunk() = countTrue(allClassFiles collect { case x if x.exists => x.delete() }) - def cleanupLogs() = countTrue(allLogFiles collect { case x if x.exists => x.delete() }) - - /** Look through every file in the partest directory and ask around - * to make sure someone knows him. Complain about strangers. - */ - def validateAll() { - def denotesTest(p: Path) = allCategories exists (_ denotesTest p) - def isMSILcheck(p: Path) = p.name endsWith "-msil.check" - - def analyzeCategory(cat: DirBasedCategory) = { - val allTests = cat.enumerate - val otherPaths = cat.root walkFilter (x => !ignorePath(x)) filterNot (cat denotesTest _) filterNot isMSILcheck toList - val count = otherPaths.size - - println("Validating %d non-test paths in %s.".format(count, cat.kind)) - - for (path <- otherPaths) { - (allTests find (_ acknowledges path)) match { - case Some(test) => if (isVerbose) println(" OK: '%s' is claimed by '%s'".format(path, test.label)) - case _ => println(">> Unknown path '%s'" format path) - } - } - } - - allCategories collect { case x: DirBasedCategory => analyzeCategory(x) } - } - - trait TestHousekeeping { - self: TestEntity => - - /** Calculating derived files. Given a test like - * files/run/foo.scala or files/run/foo/ - * This creates paths like foo.check, foo.flags, etc. - */ - def withExtension(extension: String) = categoryDir / "%s.%s".format(label, extension) - - /** True for a path if this test acknowledges it belongs to this test. - * Overridden by some categories. - */ - def acknowledges(path: Path): Boolean = { - val loc = location.normalize - val knownPaths = List(scalaOptsFile, javaOptsFile, commandFile, logFile, checkFile) ++ jarsInTestDir - def isContainedSource = location.isDirectory && isJavaOrScala(path) && (path.normalize startsWith loc) - - (knownPaths exists (_ isSame path)) || isContainedSource - } - - /** This test "responds to" this String. This could mean anything -- it's a - * way of specifying ad-hoc collections of tests to exercise only a subset of tests. - * At present it looks for the given String in all the test sources. - */ - def respondsToString(str: String) = containsString(str) - def containsString(str: String) = { - debug("Checking %s for \"%s\"".format(sourceFiles mkString ", ", str)) - sourceFiles map safeSlurp exists (_ contains str) - } - - def possiblyTimed[T](body: => T): T = { - if (isStats) timed(recordTestTiming(label, _))(body) - else body - } - - private def prepareForTestRun() = { - // make sure we have a clean slate - deleteLog(force = true) - if (outDir.exists) - outDir.deleteRecursively() - - // recreate object dir - outDir createDirectory true - } - def deleteOutDir() = outDir.deleteRecursively() - def deleteShutdownHook() = { debug("Shutdown hook deleting " + outDir) ; deleteOutDir() } - - protected def runWrappers[T](body: => T): Option[T] = { - prepareForTestRun() - - withShutdownHook(deleteShutdownHook()) { - loggingOutAndErr { - val result = possiblyTimed { body } - if (!isNoCleanup) - deleteOutDir() - - result - } - } - } - - override def toString = location.path - override def equals(other: Any) = other match { - case x: TestEntity => location.normalize == x.location.normalize - case _ => false - } - override def hashCode = location.normalize.hashCode - } - - private def countTrue(f: => Iterator[Boolean]) = f filter (_ == true) length -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/Partest.scala b/src/partest-alternative/scala/tools/partest/Partest.scala deleted file mode 100644 index 74a3a6a19b..0000000000 --- a/src/partest-alternative/scala/tools/partest/Partest.scala +++ /dev/null @@ -1,81 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import nsc.io._ -import nsc.util._ -import category.AllCategories - -/** Global object for a Partest run. It is completely configured by the list - * of arguments passed to the constructor (although there are a few properties - * and environment variables which can influence matters.) See PartestSpec.scala - * for the complete list. - */ -class Partest(args: List[String]) extends { - val parsed = PartestSpec(args: _*) -} with Universe with PartestSpec with cmd.Instance with AllCategories { - - if (parsed.propertyArgs.nonEmpty) - debug("Partest property args: " + fromArgs(parsed.propertyArgs)) - - debug("Partest created with args: " + fromArgs(args)) - - def helpMsg = PartestSpec.helpMsg - - // The abstract values from Universe. - lazy val testBuildDir = searchForDir(buildDir) - lazy val partestDir = searchForDir(rootDir) - lazy val allCategories = List(Pos, Neg, Run, Jvm, Res, Shootout, Scalap, Scalacheck, BuildManager, Script) - lazy val selectedCategories = if (isAllImplied) allCategories else specifiedCats - - def specifiedTests = parsed.residualArgs map (x => Path(x).normalize) - def specifiedKinds = testKinds filter (x => isSet(x) || (runSets contains x)) - def specifiedCats = specifiedKinds flatMap (x => allCategories find (_.kind == x)) - def isAllImplied = isAll || (specifiedTests.isEmpty && specifiedKinds.isEmpty) - - /** Assembles a filter based on command line options which restrict the test set - * --grep limits to only matching tests - * --failed limits to only recently failed tests (log file is present) - * --<category> limits to only the given tests and categories (but --all overrides) - * path/to/Test limits to only the given tests and categories - */ - lazy val filter = { - def indivFilter(test: TestEntity) = specifiedTests contains test.location.normalize - def categoryFilter(test: TestEntity) = specifiedCats contains test.category - def indivOrCat(test: TestEntity) = isAllImplied || indivFilter(test) || categoryFilter(test) // combines previous two - - def failedFilter(test: TestEntity) = !isFailed || (test.logFile exists) - def grepFilter(test: TestEntity) = grepExpr.isEmpty || (test containsString grepExpr.get) - def combinedFilter(x: TestEntity) = indivOrCat(x) && failedFilter(x) && grepFilter(x) // combines previous three - - combinedFilter _ - } - - def launchTestSuite() = { - def onTimeout() = { - warning("Partest test run timed out after " + timeout + " seconds.\n") - System.exit(-1) - } - val alarm = new Alarmer(AlarmerAction(timeout, () => onTimeout())) - - try runSelection(selectedCategories, filter) - finally alarm.cancelAll() - } -} - -object Partest { - def fromBuild(dir: String, args: String*): Partest = apply("--builddir" +: dir +: args: _*) - def apply(args: String*): Partest = new Partest(args.toList) - - // builds without partest jars won't actually work - def starr() = fromBuild("") - def locker() = fromBuild("build/locker") - def quick() = fromBuild("build/quick") - def pack() = fromBuild("build/pack") - def strap() = fromBuild("build/strap") - def dist() = fromBuild("dists/latest") -} - diff --git a/src/partest-alternative/scala/tools/partest/PartestSpec.scala b/src/partest-alternative/scala/tools/partest/PartestSpec.scala deleted file mode 100644 index 75d94bdb72..0000000000 --- a/src/partest-alternative/scala/tools/partest/PartestSpec.scala +++ /dev/null @@ -1,104 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools -package partest - -import nsc.io._ -import cmd._ - -/** This takes advantage of bits of scala goodness to fully define a command - * line program with a minimum of duplicated code. When the specification object - * is created, the vals are evaluated in order and each of them side effects - * a private accumulator. What emerges is a full list of the valid unary - * and binary arguments, as well as autogenerated help. - */ -trait PartestSpec extends Spec with Meta.StdOpts with Interpolation { - def referenceSpec = PartestSpec - def programInfo = Spec.Info("partest", "", "scala.tools.partest.Runner") - private val kind = new Spec.Accumulator[String]() - protected def testKinds = kind.get - - private implicit val tokenizeString = FromString.ArgumentsFromString // String => List[String] - - help(""" - |# Pro Tip! Instant bash completion: `partest --bash` (note backticks) - |Usage: partest [<options>] [<test> <test> ...] - | <test>: a path to a test designator, typically a .scala file or a directory. - | Examples: files/pos/test1.scala, files/res/bug785 - | - | Test categories:""".stripMargin) - - val isAll = ("all" / "run all tests (default, unless no options given)" --?) - (kind("pos") / "Compile files that are expected to build" --?) - (kind("neg") / "Compile files that are expected to fail" --?) - (kind("run") / "Test JVM backend" --?) - (kind("jvm") / "Test JVM backend" --?) - (kind("res") / "Run resident compiler scenarii" --?) - (kind("buildmanager") / "Run Build Manager scenarii" --?) - (kind("scalacheck") / "Run Scalacheck tests" --?) - (kind("script") / "Run script files" --?) - (kind("shootout") / "Run shootout tests" --?) - (kind("scalap") / "Run scalap tests" --?) - - heading ("""Test "smart" categories:""") - val grepExpr = "grep" / "run all tests with a source file containing <expr>" --| - val isFailed = "failed" / "run all tests which failed on the last run" --? - - heading ("Specifying paths and additional flags, ~ means repository root:") - - val rootDir = "rootdir" / "path from ~ to partest" defaultTo "test" - val buildDir = "builddir" / "path from ~ to test build" defaultTo "build/pack" - val srcDir = "srcdir" / "path from --rootdir to sources" defaultTo "files" - val javaOpts = "javaopts" / "flags to java on all runs" defaultToEnv "JAVA_OPTS" - val javacOpts = "javacopts" / "flags to javac on all runs" defaultToEnv "JAVAC_OPTS" - val scalacOpts = "scalacopts" / "flags to scalac on all tests" defaultToEnv "SCALAC_OPTS" - - "pack" / "" expandTo ("--builddir", "build/pack") - "quick" / "" expandTo ("--builddir", "build/quick") - - heading ("Options influencing output:") - val isTrace = "trace" / "show the individual steps taken by each test" --? - val isShowDiff = "show-diff" / "show diff between log and check file" --? - val isShowLog = "show-log" / "show log on failures" --? - val isDryRun = "dry-run" / "do not run tests, only show their traces." --? - val isTerse = "terse" / "be less verbose (almost silent except for failures)" --? - val isVerbose = "verbose" / "be more verbose (additive with --trace)" --? - val isDebug = "debug" / "maximum debugging output" --? - val isAnsi = "ansi" / "print output in color" --? - - heading ("Other options:") - val timeout = "timeout" / "Overall timeout in seconds" defaultTo 7200 - val testWarning = "test-warning" / "Test warning in seconds" defaultTo 90 - val testTimeout = "test-timeout" / "Test timeout in seconds" defaultTo 900 - val isCleanup = "cleanup" / "delete all stale files and dirs before run" --? - val isNoCleanup = "nocleanup" / "do not delete any logfiles or object dirs" --? - val isStats = "stats" / "collect and print statistics about the tests" --? - val isValidate = "validate" / "examine test filesystem for inconsistencies" --? - val isUpdateCheck = "update-check" / "overwrite checkFile if diff fails" --? - - "version" / "print version" --> runAndExit(println(Properties.versionMsg)) - - // no help for anything below this line - secret options - // mostly intended for property configuration. - val runSets = ("runsets" --^) getOrElse Nil - val isNoAlarms = "noalarms" --? - val isInsideAnt = "is-in-ant" --? -} - -object PartestSpec extends PartestSpec with Property { - lazy val propMapper = new PropertyMapper(PartestSpec) { - override def isPassThrough(key: String) = key == "partest.options" - } - - type ThisCommandLine = PartestCommandLine - class PartestCommandLine(args: List[String]) extends SpecCommandLine(args) { - override def errorFn(msg: String) = printAndExit("Error: " + msg) - - def propertyArgs = PartestSpec.propertyArgs - } - - override def creator(args: List[String]): PartestCommandLine = new PartestCommandLine(args) -} diff --git a/src/partest-alternative/scala/tools/partest/Properties.scala b/src/partest-alternative/scala/tools/partest/Properties.scala deleted file mode 100644 index 2d36f163c8..0000000000 --- a/src/partest-alternative/scala/tools/partest/Properties.scala +++ /dev/null @@ -1,17 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.tools -package partest - -/** Loads partest.properties from the jar. */ -object Properties extends scala.util.PropertiesTrait { - protected def propCategory = "partest" - protected def pickJarBasedOn = classOf[Application] -} diff --git a/src/partest-alternative/scala/tools/partest/Results.scala b/src/partest-alternative/scala/tools/partest/Results.scala deleted file mode 100644 index e0fceed17a..0000000000 --- a/src/partest-alternative/scala/tools/partest/Results.scala +++ /dev/null @@ -1,121 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import scala.collection.immutable - -trait Results { - self: Universe => - - /** A collection of tests for a Worker. - */ - case class TestsToRun(entities: List[TestEntity]) - - /** The response from a Worker who has been given TestsToRun. - */ - case class ResultsOfRun(results: immutable.Map[TestEntity, TestResult]) - - /** The result of a single test. (0: OK, 1: FAILED, 2: TIMEOUT) - */ - sealed abstract class TestResult(val state: Int, val description: String) { - def entity: TestEntity - - def passed = state == 0 - def colorize(s: String): String - def show(msg: String) = - if (!isShuttingDown) - showResult(colorize(description), msg) - - private def outputPrefix = if (isInsideAnt) "" else markNormal("partest: ") - private def name = src relativize entity.location // e.g. "neg/test.scala" - private def showResult(status: String, extraMsg: String) = - normal(outputPrefix + "[...]/%-40s [%s] %s\n".format(name, status, extraMsg)) - - override def equals(other: Any) = other match { - case x: TestResult => entity == x.entity - case _ => false - } - override def hashCode = entity.hashCode - override def toString = "%s [%s]".format(entity, description) - } - - class Success(val entity: TestEntity) extends TestResult(0, " OK ") { - def colorize(s: String) = markSuccess(s) - override def show(msg: String) = if (!isTerse) super.show(msg) - } - class Failure(val entity: TestEntity) extends TestResult(1, " FAILED ") { - def colorize(s: String) = markFailure(s) - - override def show(msg: String) = { - super.show(msg) - - if (isShowDiff || isTrace) - normal(entity.diffOutput) - - if (isShowLog || isTrace) - normal(toStringTrunc(entity.failureMessage(), 1600)) - } - override def toString = List(super.toString, toStringTrunc(entity.failureMessage(), 400)) mkString "\n" - } - class Timeout(val entity: TestEntity) extends TestResult(2, "TIME OUT") { - def colorize(s: String) = markFailure(s) - } - - object TestResult { - def apply(entity: TestEntity, success: Boolean) = - if (success) new Success(entity) - else new Failure(entity) - - def apply(entity: TestEntity, state: Int) = state match { - case 0 => new Success(entity) - case 1 => new Failure(entity) - case 2 => new Timeout(entity) - } - def unapply(x: Any) = x match { - case x: TestResult => Some((x.entity, x.state)) - case _ => None - } - } - - /** The combined results of any number of tests. - */ - case class CombinedTestResults( - passed: Int, - failed: Int, - elapsedMilliseconds: Long, - failures: List[TestResult] - ) { - // housekeeping - val elapsedSecs = elapsedMilliseconds / 1000 - val elapsedMins = elapsedSecs / 60 - val elapsedHrs = elapsedMins / 60 - val dispMins = elapsedMins - elapsedHrs * 60 - val dispSecs = elapsedSecs - elapsedMins * 60 - - def total = passed + failed - def hasFailures = failed > 0 - def exitCode = if (expectedErrors == failed) 0 else 1 - - def ++(x: CombinedTestResults) = CombinedTestResults( - passed + x.passed, - failed + x.failed, - elapsedMilliseconds + x.elapsedMilliseconds, - failures ::: x.failures - ) - - def elapsedString = "%02d:%02d:%02d".format(elapsedHrs, dispMins, dispSecs) - def failuresString = { - if (failures.isEmpty) "" - else "Summary of failures:" :: failures mkString ("\n", "\n", "") - } - - override def toString = - if (total == 0) "There were no tests to run." - else if (isDryRun) "%d tests would be run." format total - else if (hasFailures) "%d of %d tests failed (elapsed time: %s)".format(failed, total, elapsedString) + failuresString - else "All %d tests were successful (elapsed time: %s)".format(total, elapsedString) - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/Runner.scala b/src/partest-alternative/scala/tools/partest/Runner.scala deleted file mode 100644 index 7fe2c98d43..0000000000 --- a/src/partest-alternative/scala/tools/partest/Runner.scala +++ /dev/null @@ -1,36 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools -package partest - -import nsc.io._ - -object Runner { - def main(args: Array[String]) { - val runner = Partest(args: _*) - import runner._ - - if (args.isEmpty) return println(helpMsg) - if (isValidate) return validateAll() - - printConfigBanner() - - if (isCleanup) - cleanupAll() - - val result = launchTestSuite() - val exitCode = result.exitCode - val message = "\n" + result + "\n" - - if (exitCode == 0) success(message) - else failure(message) - - if (isStats) - showTestStatistics() - - System exit exitCode - } -} diff --git a/src/partest-alternative/scala/tools/partest/Statistics.scala b/src/partest-alternative/scala/tools/partest/Statistics.scala deleted file mode 100644 index e90377cfa7..0000000000 --- a/src/partest-alternative/scala/tools/partest/Statistics.scala +++ /dev/null @@ -1,46 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools -package partest - -import scala.collection.mutable - -trait Statistics { - /** Only collected when --stats is given. */ - lazy val testStatistics = new mutable.HashMap[String, Long] - - /** Given function and block of code, evaluates code block, - * calls function with milliseconds elapsed, and returns block result. - */ - def timed[T](f: Long => Unit)(body: => T): T = { - val start = System.currentTimeMillis - val result = body - val end = System.currentTimeMillis - - f(end - start) - result - } - /** Times body and returns both values. - */ - def timed2[T](body: => T): (Long, T) = { - var milliSeconds = 0L - val result = timed(x => milliSeconds = x)(body) - - (milliSeconds, result) - } - - def resultsToStatistics(results: Iterable[(_, Int)]): (Int, Int) = - (results partition (_._2 == 0)) match { - case (winners, losers) => (winners.size, losers.size) - } - - def recordTestTiming(name: String, milliseconds: Long) = - synchronized { testStatistics(name) = milliseconds } - - def showTestStatistics() { - testStatistics.toList sortBy (-_._2) foreach { case (k, v) => println("%s: %.2f seconds".format(k, (v.toDouble / 1000))) } - } -} diff --git a/src/partest-alternative/scala/tools/partest/Universe.scala b/src/partest-alternative/scala/tools/partest/Universe.scala deleted file mode 100644 index 3dd79e4791..0000000000 --- a/src/partest-alternative/scala/tools/partest/Universe.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest - -import nsc.io._ -import category.AllCategories -import io.Logging - -/** The high level view of the partest infrastructure. - */ -abstract class Universe - extends Entities - with BuildContributors - with Logging - with Dispatcher - with Statistics - with Housekeeping - with Results - with PartestCompilation - with PartestSpec - with Config - with Alarms - with Actions - with Categories { - - /** The abstract values from which all else is derived. */ - def partestDir: Directory - def testBuildDir: Directory - def allCategories: List[TestCategory] - def selectedCategories: List[TestCategory] - - /** Some plausibly abstract types. */ - type TestBuild <: BuildContributor // e.g. quick, pack - type TestCategory <: AbsTestCategory // e.g. pos, neg, run - type TestEntity <: AbsTestEntity // e.g. files/pos/test25.scala - type TestSequence <: AbsTestSequence // e.g. compile, run, diff - - /** Although TestStep isn't much more than Function1 right now, - * it exists this way so it can become more capable. - */ - implicit def f1ToTestStep(f: TestEntity => Boolean): TestStep = - new TestStep { def apply(test: TestEntity) = f(test) } - - abstract class TestStep extends (TestEntity => Boolean) { - def apply(test: TestEntity): Boolean - } - - /** An umbrella category of tests, such as "pos" or "run". - */ - trait AbsTestCategory extends BuildContributor { - type TestSettings - - def kind: String - def testSequence: TestSequence - def denotesTest(location: Path): Boolean - - def createTest(location: Path): TestEntity - def createSettings(entity: TestEntity): TestSettings - def enumerate: List[TestEntity] - } - - /** A single test. It may involve multiple files, but only a - * single path is used to designate it. - */ - trait AbsTestEntity extends BuildContributor { - def category: TestCategory - def location: Path - def onException(x: Throwable): Unit - def testClasspath: String - - /** Most tests will use the sequence defined by the category, - * but the test can override and define a custom sequence. - */ - def testSequence: TestSequence - - /** True if this test recognizes the given path as a piece of it. - * For validation purposes. - */ - def acknowledges(path: Path): Boolean - } - - /** Every TestEntity is partly characterized by a series of actions - * which are applied to the TestEntity in the given order. The test - * passes if all those actions return true, fails otherwise. - */ - trait AbsTestSequence { - def actions: List[TestStep] - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/ant/JavaTask.scala b/src/partest-alternative/scala/tools/partest/ant/JavaTask.scala deleted file mode 100644 index f8c0133dc1..0000000000 --- a/src/partest-alternative/scala/tools/partest/ant/JavaTask.scala +++ /dev/null @@ -1,57 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest -package ant - -import org.apache.tools.ant.Task -import org.apache.tools.ant.taskdefs.Java -import org.apache.tools.ant.types.Environment - -import scala.tools.nsc.io._ -import scala.tools.nsc.util.ClassPath -import cmd.Spec._ - -class JavaTask extends Java { - override def getTaskName() = "partest" - private val scalaRunnerClass = "scala.tools.nsc.MainGenericRunner" - private val partestRunnerClass = "scala.tools.partest.Runner" - def defaultJvmArgs = "-Xms64M -Xmx768M -Xss768K -XX:MaxPermSize=96M" - - protected def rootDir = prop("partest.rootdir") getOrElse (baseDir / "test").path - protected def partestJVMArgs = prop("partest.jvm.args") getOrElse defaultJvmArgs - protected def runnerArgs = List("-usejavacp", partestRunnerClass, "--javaopts", partestJVMArgs) - - private def baseDir = Directory(getProject.getBaseDir) - private def prop(s: String) = Option(getProject getProperty s) - private def jvmline(s: String) = returning(createJvmarg())(_ setLine s) - private def addArg(s: String) = returning(createArg())(_ setValue s) - - private def newKeyValue(key: String, value: String) = - returning(new Environment.Variable)(x => { x setKey key ; x setValue value }) - - def setDefaults() { - setFork(true) - setFailonerror(true) - getProject.setSystemProperties() - setClassname(scalaRunnerClass) - addSysproperty(newKeyValue("partest.is-in-ant", "true")) - jvmline(partestJVMArgs) - runnerArgs foreach addArg - - // do we want basedir or rootDir to be the cwd? - // setDir(Path(rootDir).jfile) - } - - override def init() = { - super.init() - setDefaults() - } -} - diff --git a/src/partest-alternative/scala/tools/partest/antlib.xml b/src/partest-alternative/scala/tools/partest/antlib.xml deleted file mode 100644 index af36f11368..0000000000 --- a/src/partest-alternative/scala/tools/partest/antlib.xml +++ /dev/null @@ -1,3 +0,0 @@ -<antlib> - <taskdef name="partest" classname="scala.tools.partest.ant.JavaTask"/> -</antlib> diff --git a/src/partest-alternative/scala/tools/partest/category/AllCategories.scala b/src/partest-alternative/scala/tools/partest/category/AllCategories.scala deleted file mode 100644 index 1c3f4c9899..0000000000 --- a/src/partest-alternative/scala/tools/partest/category/AllCategories.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest -package category - -trait AllCategories extends Compiler with Analysis with Runner { - self: Universe => - - object Pos extends DirBasedCategory("pos") { lazy val testSequence: TestSequence = List(compile) } - object Neg extends DirBasedCategory("neg") { lazy val testSequence: TestSequence = List(checkFileRequired, not(compile), diff) } - object Run extends DirBasedCategory("run") { lazy val testSequence: TestSequence = List(compile, run, diff) } - object Jvm extends DirBasedCategory("jvm") { lazy val testSequence: TestSequence = List(compile, run, diff) } -} diff --git a/src/partest-alternative/scala/tools/partest/category/Analysis.scala b/src/partest-alternative/scala/tools/partest/category/Analysis.scala deleted file mode 100644 index 944f8c691f..0000000000 --- a/src/partest-alternative/scala/tools/partest/category/Analysis.scala +++ /dev/null @@ -1,64 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest -package category - -import java.lang.{ ClassLoader => JavaClassLoader } -import java.net.URL -import nsc.util.ScalaClassLoader -import nsc.io._ - -class PartestClassLoader(urls: Array[URL], parent: JavaClassLoader) extends ScalaClassLoader.URLClassLoader(urls, parent) { - def this(urls: Array[URL]) = this(urls, null) - def bytes(path: String) = findBytesForClassName(path) - def singleton(path: String) = tryToInitializeClass(path).get getField "MODULE$" get null - - /** Calls a method in an object via reflection. - */ - def apply[T](className: String, methodName: String)(args: Any*): T = { - def fail = error("Reflection failed on %s.%s".format(className, methodName)) - val clazz = tryToLoadClass(className) getOrElse fail - val obj = singleton(className) - val m = clazz.getMethods find (x => x.getName == methodName && x.getParameterTypes.size == args.size) getOrElse fail - - m.invoke(obj, args map (_.asInstanceOf[AnyRef]): _*).asInstanceOf[T] - } -} - -trait Analysis { - self: Universe => - - object Scalap extends DirBasedCategory("scalap") { - val testSequence: TestSequence = List(checkFileRequired, compile, run, diff) - override def denotesTest(p: Path) = p.isDirectory && (p.toDirectory.files exists (_.name == "result.test")) - override def createTest(location: Path) = new ScalapTest(location) - - class ScalapTest(val location: Path) extends TestEntity { - val category = Scalap - val scalapMain = "scala.tools.scalap.Main$" - val scalapMethod = "decompileScala" - - override def classpathPaths = super.classpathPaths :+ build.scalap - override def checkFile = File(location / "result.test") - - private def runnerURLs = build.classpathPaths ::: classpathPaths map (_.toURL) - private def createClassLoader = new PartestClassLoader(runnerURLs.toArray, this.getClass.getClassLoader) - - val isPackageObject = containsString("package object") - val suffix = if (isPackageObject) ".package" else "" - val className = location.name.capitalize + suffix - - override def run() = loggingResult { - def loader = createClassLoader - def bytes = loader.bytes(className) - - trace("scalap %s".format(className)) - if (isDryRun) "" - else loader[String](scalapMain, scalapMethod)(bytes, isPackageObject) - } - } - } -} diff --git a/src/partest-alternative/scala/tools/partest/category/Compiler.scala b/src/partest-alternative/scala/tools/partest/category/Compiler.scala deleted file mode 100644 index 6b65072856..0000000000 --- a/src/partest-alternative/scala/tools/partest/category/Compiler.scala +++ /dev/null @@ -1,140 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest -package category - -import nsc.io._ -import nsc.reporters._ -import nsc.{ Settings, CompilerCommand } -import scala.tools.nsc.interactive.RefinedBuildManager -import util.copyPath - -trait Compiler { - self: Universe => - - /** Resident Compiler. - * $SCALAC -d dir.obj -Xresident -sourcepath . "$@" - */ - object Res extends DirBasedCategory("res") { - lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff) - - override def denotesTest(p: Path) = p.isDirectory && resFile(p).isFile - override def createTest(location: Path) = new ResidentTest(location.toDirectory) - - override def createSettings(entity: TestEntity): TestSettings = - returning(super.createSettings(entity)) { settings => - settings.resident.value = true - settings.sourcepath.value = entity.sourcesDir.path - } - - class ResidentTest(val location: Directory) extends TestEntity { - val category = Res - override def sourcesDir = categoryDir - - override def acknowledges(p: Path) = - super.acknowledges(p) || (resFile(location) isSame p) - - private def residentCompilerCommands = safeLines(resFile(location)) - private def compileResident(global: PartestGlobal, lines: List[String]) = { - def printPrompt = global inform "nsc> " - val results = - lines map { line => - printPrompt - trace("compile " + line) - isDryRun || global.partestCompile(toArgs(line) map (categoryDir / _ path), false) - } - - printPrompt - - /** Note - some res tests are really "neg" style tests, so we can't - * use the return value of the compile. The diff catches failures. - */ - true // results forall (_ == true) - } - - override def compile() = compileResident(newGlobal(Nil)._1, residentCompilerCommands) - } - private[Res] def resFile(p: Path) = p.toFile addExtension "res" - } - - object BuildManager extends DirBasedCategory("buildmanager") { - lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff) - override def denotesTest(p: Path) = p.isDirectory && testFile(p).isFile - override def createTest(location: Path) = new BuildManagerTest(location.toDirectory) - - override def createSettings(entity: TestEntity): TestSettings = - returning[TestSettings](super.createSettings(entity)) { settings => - settings.Ybuildmanagerdebug.value = true - settings.sourcepath.value = entity.sourcesDir.path - } - - class PartestBuildManager(settings: Settings, val reporter: ConsoleReporter) extends RefinedBuildManager(settings) { - def errorFn(msg: String) = Console println msg - - override protected def newCompiler(newSettings: Settings) = - new BuilderGlobal(newSettings, reporter) - - private def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] = - fs flatMap (s => Option(AbstractFile getFile (Path(settings.sourcepath.value) / s path))) toSet - - def buildManagerCompile(line: String): Boolean = { - val prompt = "builder > " - reporter printMessage (prompt + line) - val command = new CompilerCommand(toArgs(line), settings) - val files = filesToSet(settings.sourcepath.value, command.files) - - update(files, Set.empty) - true - } - } - - private[BuildManager] def testFile(p: Path) = (p / p.name addExtension "test").toFile - - class BuildManagerTest(val location: Directory) extends TestEntity { - val category = BuildManager - - override def sourcesDir = outDir - override def sourceFiles = Path onlyFiles (location walkFilter (_ != changesDir) filter isJavaOrScala toList) - override def checkFile = File(location / location.name addExtension "check") - - override def acknowledges(p: Path) = super.acknowledges(p) || (p isSame testFile(location)) - - def buildManagerCommands = safeLines(testFile(location)) - def changesDir = Directory(location / (location.name + ".changes")) - - override def compile() = { - val settings = createSettings(this) - val pbm = new PartestBuildManager(settings, newReporter(settings)) - - // copy files - for (source <- sourceFiles) { - val target = outDir / (location.normalize relativize source) - copyPath(source, target.toFile) - } - - def runUpdate(line: String) = { - val Array(srcName, replacement) = line split "=>" - copyPath(File(changesDir / replacement), File(outDir / srcName)) - } - - def sendCommand(line: String): Boolean = { - val compileRegex = """^>>compile (.*)$""".r - val updateRegex = """^>>update\s+(.*)""".r - trace("send: " + (line drop 2)) - - isDryRun || (line match { - case compileRegex(xs) => pbm.buildManagerCompile(xs) - case updateRegex(line) => runUpdate(line) - }) - } - - // send each line to the build manager - buildManagerCommands forall sendCommand - } - } - } -} - diff --git a/src/partest-alternative/scala/tools/partest/category/Runner.scala b/src/partest-alternative/scala/tools/partest/category/Runner.scala deleted file mode 100644 index add1c55feb..0000000000 --- a/src/partest-alternative/scala/tools/partest/category/Runner.scala +++ /dev/null @@ -1,108 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest -package category - -import nsc.io._ - -trait Runner { - self: Universe => - - /** Shootout. - */ - object Shootout extends DirBasedCategory("shootout") { - lazy val testSequence: TestSequence = List(compile, run, diff) - - override def denotesTest(p: Path) = isScala(p) && runner(p).isFile - override def createTest(location: Path) = new ShootoutTest(location.toFile) - - class ShootoutTest(val location: File) extends TestEntity { - val category = Shootout - // The files in shootout are very free form, so acknowledge anything close. - override def acknowledges(p: Path) = - (p.parent.normalize isSame Shootout.root) && (p.name startsWith label) - - private def generated = File(outDir / "test.scala") - private def runnerFile = runner(location) - override def sourceFiles = List(generated) - - override def compile() = { - trace("generate %s from %s, %s".format(tracePath(generated), tracePath(location), tracePath(runnerFile))) - // generate source file (even on dry run, we need the path) - generated.writeAll(location.slurp(), runnerFile.slurp()) - - // compile generated file - super.compile() - } - } - - private[Shootout] def runner(p: Path) = p addExtension "runner" toFile - } - - object Scalacheck extends DirBasedCategory("scalacheck") { - lazy val testSequence: TestSequence = List(compile, run) - override def createTest(location: Path) = new ScalacheckTest(location) - - class ScalacheckTest(val location: Path) extends TestEntity { - val category = Scalacheck - - import build.{ scalacheck, forkjoin } - import org.scalacheck.Properties - import org.scalacheck.Test.{ checkProperties, defaultParams, Result } - - override def classpathPaths = super.classpathPaths ::: List(scalacheck, forkjoin) - private def arrayURLs = Array(scalacheck, outDir) map (_.toURL) - - /** For reasons I'm not entirely clear on, I've written all this - * to avoid a source dependency on scalacheck. - */ - class ScalacheckClassLoader extends PartestClassLoader(arrayURLs, this.getClass.getClassLoader) { - type ScalacheckResult = { def passed: Boolean } - - def propCallback(name: String, passed: Int, discarded: Int): Unit = () - def testCallback(name: String, result: AnyRef): Unit = () - - val test = singleton("Test$") - val params = apply[AnyRef]("org.scalacheck.Test$", "defaultParams")() - val result = apply[Seq[(String, AnyRef)]]("org.scalacheck.Test$", "checkProperties")(test, params, propCallback _, testCallback _) - - def allResults() = - for ((prop, res) <- result) yield { - ScalacheckTest.this.trace("%s: %s".format(prop, res)) - res.asInstanceOf[ScalacheckResult].passed - } - - def check() = allResults forall (_ == true) - } - - override def run() = { - trace("scalacheck runs via classloader with: %s".format(arrayURLs mkString ", ")) - isDryRun || (new ScalacheckClassLoader check) - } - } - } - - object Script extends DirBasedCategory("script") { - val testSequence: TestSequence = List(exec, diff) - override def createTest(location: Path) = new ScriptTest(location) - - class ScriptTest(val location: Path) extends TestEntity { - val category = Script - val scriptFile = if (location.isDirectory) location / (label + ".scala") else location - val argsFile = withExtension("args").toFile - def batFile = scriptFile changeExtension "bat" - def script = if (Properties.isWin) batFile else scriptFile - - override def acknowledges(p: Path) = super.acknowledges(p) || (List(argsFile, batFile) exists (_ isSame p)) - override def execCwd = Some(sourcesDir) - override def argumentsToExec = script.path :: safeArgs(argsFile) - } - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/io/ANSIWriter.scala b/src/partest-alternative/scala/tools/partest/io/ANSIWriter.scala deleted file mode 100644 index 59216cf03b..0000000000 --- a/src/partest-alternative/scala/tools/partest/io/ANSIWriter.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools -package partest -package io - -import java.io.{ Writer, PrintWriter, OutputStream, OutputStreamWriter } - -object ANSIWriter { - val NONE = 0 - val SOME = 1 - val MANY = 2 - - def apply(isAnsi: Boolean) = if (isAnsi) MANY else NONE -} -import ANSIWriter._ - -class ANSIWriter(writer: Writer) extends PrintWriter(writer, true) { - def this(out: OutputStream) = this(new OutputStreamWriter(out)) - def colorful: Int = NONE - - protected val manyColors = List( - Console.BOLD + Console.BLACK, - Console.BOLD + Console.GREEN, - Console.BOLD + Console.RED, - Console.BOLD + Console.YELLOW, - Console.RESET - ) - protected val someColors = List( - Console.BOLD + Console.BLACK, - Console.RESET, - Console.BOLD + Console.BLACK, - Console.BOLD + Console.BLACK, - Console.RESET - ) - protected val noColors = List("", "", "", "", "") - - lazy val List(_outline, _success, _failure, _warning, _default) = colorful match { - case NONE => noColors - case SOME => someColors - case MANY => manyColors - case _ => noColors - } - - private def wrprint(msg: String): Unit = synchronized { - print(msg) - flush() - } - - def outline(msg: String) = wrprint(_outline + msg + _default) - def success(msg: String) = wrprint(_success + msg + _default) - def failure(msg: String) = wrprint(_failure + msg + _default) - def warning(msg: String) = wrprint(_warning + msg + _default) - def normal(msg: String) = wrprint(_default + msg) -} diff --git a/src/partest-alternative/scala/tools/partest/io/Diff.java b/src/partest-alternative/scala/tools/partest/io/Diff.java deleted file mode 100644 index 69428d7e7a..0000000000 --- a/src/partest-alternative/scala/tools/partest/io/Diff.java +++ /dev/null @@ -1,873 +0,0 @@ - -package scala.tools.partest.io; - -import java.util.Hashtable; - -/** A class to compare IndexedSeqs of objects. The result of comparison - is a list of <code>change</code> objects which form an - edit script. The objects compared are traditionally lines - of text from two files. Comparison options such as "ignore - whitespace" are implemented by modifying the <code>equals</code> - and <code>hashcode</code> methods for the objects compared. -<p> - The basic algorithm is described in: </br> - "An O(ND) Difference Algorithm and its Variations", Eugene Myers, - Algorithmica Vol. 1 No. 2, 1986, p 251. -<p> - This class outputs different results from GNU diff 1.15 on some - inputs. Our results are actually better (smaller change list, smaller - total size of changes), but it would be nice to know why. Perhaps - there is a memory overwrite bug in GNU diff 1.15. - - @author Stuart D. Gathman, translated from GNU diff 1.15 - Copyright (C) 2000 Business Management Systems, Inc. -<p> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -<p> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -<p> - You should have received a copy of the <a href=COPYING.txt> - GNU General Public License</a> - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -public class Diff { - - /** Prepare to find differences between two arrays. Each element of - the arrays is translated to an "equivalence number" based on - the result of <code>equals</code>. The original Object arrays - are no longer needed for computing the differences. They will - be needed again later to print the results of the comparison as - an edit script, if desired. - */ - public Diff(Object[] a,Object[] b) { - Hashtable h = new Hashtable(a.length + b.length); - filevec[0] = new file_data(a,h); - filevec[1] = new file_data(b,h); - } - - /** 1 more than the maximum equivalence value used for this or its - sibling file. */ - private int equiv_max = 1; - - /** When set to true, the comparison uses a heuristic to speed it up. - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - public boolean heuristic = false; - - /** When set to true, the algorithm returns a guarranteed minimal - set of changes. This makes things slower, sometimes much slower. */ - public boolean no_discards = false; - - private int[] xvec, yvec; /* IndexedSeqs being compared. */ - private int[] fdiag; /* IndexedSeq, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the forward - search of the edit matrix. */ - private int[] bdiag; /* IndexedSeq, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the backward - search of the edit matrix. */ - private int fdiagoff, bdiagoff; - private final file_data[] filevec = new file_data[2]; - private int cost; - - /** Find the midpoint of the shortest edit script for a specified - portion of the two files. - - We scan from the beginnings of the files, and simultaneously from the ends, - doing a breadth-first search through the space of edit-sequence. - When the two searches meet, we have found the midpoint of the shortest - edit sequence. - - The value returned is the number of the diagonal on which the midpoint lies. - The diagonal number equals the number of inserted lines minus the number - of deleted lines (counting only lines before the midpoint). - The edit cost is stored into COST; this is the total number of - lines inserted or deleted (counting only lines before the midpoint). - - This function assumes that the first lines of the specified portions - of the two files do not match, and likewise that the last lines do not - match. The caller must trim matching lines from the beginning and end - of the portions it is going to specify. - - Note that if we return the "wrong" diagonal value, or if - the value of bdiag at that diagonal is "wrong", - the worst this can do is cause suboptimal diff output. - It cannot cause incorrect diff output. */ - - private int diag (int xoff, int xlim, int yoff, int ylim) { - final int[] fd = fdiag; // Give the compiler a chance. - final int[] bd = bdiag; // Additional help for the compiler. - final int[] xv = xvec; // Still more help for the compiler. - final int[] yv = yvec; // And more and more . . . - final int dmin = xoff - ylim; // Minimum valid diagonal. - final int dmax = xlim - yoff; // Maximum valid diagonal. - final int fmid = xoff - yoff; // Center diagonal of top-down search. - final int bmid = xlim - ylim; // Center diagonal of bottom-up search. - int fmin = fmid, fmax = fmid; // Limits of top-down search. - int bmin = bmid, bmax = bmid; // Limits of bottom-up search. - /* True if southeast corner is on an odd - diagonal with respect to the northwest. */ - final boolean odd = (fmid - bmid & 1) != 0; - - fd[fdiagoff + fmid] = xoff; - bd[bdiagoff + bmid] = xlim; - - for (int c = 1;; ++c) - { - int d; /* Active diagonal. */ - boolean big_snake = false; - - /* Extend the top-down search by an edit step in each diagonal. */ - if (fmin > dmin) - fd[fdiagoff + --fmin - 1] = -1; - else - ++fmin; - if (fmax < dmax) - fd[fdiagoff + ++fmax + 1] = -1; - else - --fmax; - for (d = fmax; d >= fmin; d -= 2) - { - int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1]; - - if (tlo >= thi) - x = tlo + 1; - else - x = thi; - oldx = x; - y = x - d; - while (x < xlim && y < ylim && xv[x] == yv[y]) { - ++x; ++y; - } - if (x - oldx > 20) - big_snake = true; - fd[fdiagoff + d] = x; - if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c - 1; - return d; - } - } - - /* Similar extend the bottom-up search. */ - if (bmin > dmin) - bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE; - else - ++bmin; - if (bmax < dmax) - bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE; - else - --bmax; - for (d = bmax; d >= bmin; d -= 2) - { - int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1]; - - if (tlo < thi) - x = tlo; - else - x = thi - 1; - oldx = x; - y = x - d; - while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) { - --x; --y; - } - if (oldx - x > 20) - big_snake = true; - bd[bdiagoff + d] = x; - if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c; - return d; - } - } - - /* Heuristic: check occasionally for a diagonal that has made - lots of progress compared with the edit distance. - If we have any such, find the one that has made the most - progress and return it as if it had succeeded. - - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - - if (c > 200 && big_snake && heuristic) - { - int best = 0; - int bestpos = -1; - - for (d = fmax; d >= fmin; d -= 2) - { - int dd = d - fmid; - if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if (fd[fdiagoff + d] * 2 - dd > best - && fd[fdiagoff + d] - xoff > 20 - && fd[fdiagoff + d] - d - yoff > 20) - { - int k; - int x = fd[fdiagoff + d]; - - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - for (k = 1; k <= 20; k++) - if (xvec[x - k] != yvec[x - d - k]) - break; - - if (k == 21) - { - best = fd[fdiagoff + d] * 2 - dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - - best = 0; - for (d = bmax; d >= bmin; d -= 2) - { - int dd = d - bmid; - if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if ((xlim - bd[bdiagoff + d]) * 2 + dd > best - && xlim - bd[bdiagoff + d] > 20 - && ylim - (bd[bdiagoff + d] - d) > 20) - { - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - int k; - int x = bd[bdiagoff + d]; - - for (k = 0; k < 20; k++) - if (xvec[x + k] != yvec[x - d + k]) - break; - if (k == 20) - { - best = (xlim - bd[bdiagoff + d]) * 2 + dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - } - } - } - - /** Compare in detail contiguous subsequences of the two files - which are known, as a whole, to match each other. - - The results are recorded in the IndexedSeqs filevec[N].changed_flag, by - storing a 1 in the element for each line that is an insertion or deletion. - - The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. - - Note that XLIM, YLIM are exclusive bounds. - All line numbers are origin-0 and discarded lines are not counted. */ - - private void compareseq (int xoff, int xlim, int yoff, int ylim) { - /* Slide down the bottom initial diagonal. */ - while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) { - ++xoff; ++yoff; - } - /* Slide up the top initial diagonal. */ - while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) { - --xlim; --ylim; - } - - /* Handle simple cases. */ - if (xoff == xlim) - while (yoff < ylim) - filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true; - else if (yoff == ylim) - while (xoff < xlim) - filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true; - else - { - /* Find a point of correspondence in the middle of the files. */ - - int d = diag (xoff, xlim, yoff, ylim); - int c = cost; - int f = fdiag[fdiagoff + d]; - int b = bdiag[bdiagoff + d]; - - if (c == 1) - { - /* This should be impossible, because it implies that - one of the two subsequences is empty, - and that case was handled above without calling `diag'. - Let's verify that this is true. */ - throw new IllegalArgumentException("Empty subsequence"); - } - else - { - /* Use that point to split this problem into two subproblems. */ - compareseq (xoff, b, yoff, b - d); - /* This used to use f instead of b, - but that is incorrect! - It is not necessarily the case that diagonal d - has a snake from b to f. */ - compareseq (b, xlim, b - d, ylim); - } - } - } - - /** Discard lines from one file that have no matches in the other file. - */ - - private void discard_confusing_lines() { - filevec[0].discard_confusing_lines(filevec[1]); - filevec[1].discard_confusing_lines(filevec[0]); - } - - private boolean inhibit = false; - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - */ - - private void shift_boundaries() { - if (inhibit) - return; - filevec[0].shift_boundaries(filevec[1]); - filevec[1].shift_boundaries(filevec[0]); - } - - public interface ScriptBuilder { - /** Scan the tables of which lines are inserted and deleted, - producing an edit script. - @param changed0 true for lines in first file which do not match 2nd - @param len0 number of lines in first file - @param changed1 true for lines in 2nd file which do not match 1st - @param len1 number of lines in 2nd file - @return a linked list of changes - or null - */ - public change build_script( - boolean[] changed0,int len0, - boolean[] changed1,int len1 - ); - } - - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in reverse order. */ - - static class ReverseScript implements ScriptBuilder { - public change build_script( - final boolean[] changed0,int len0, - final boolean[] changed1,int len1) - { - change script = null; - int i0 = 0, i1 = 0; - while (i0 < len0 || i1 < len1) { - if (changed0[1+i0] || changed1[1+i1]) { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[1+i0]) ++i0; - while (changed1[1+i1]) ++i1; - - /* Record this change. */ - script = new change(line0, line1, i0 - line0, i1 - line1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0++; i1++; - } - - return script; - } - } - - static class ForwardScript implements ScriptBuilder { - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in forward order. */ - public change build_script( - final boolean[] changed0,int len0, - final boolean[] changed1,int len1) - { - change script = null; - int i0 = len0, i1 = len1; - - while (i0 >= 0 || i1 >= 0) - { - if (changed0[i0] || changed1[i1]) - { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[i0]) --i0; - while (changed1[i1]) --i1; - - /* Record this change. */ - script = new change(i0, i1, line0 - i0, line1 - i1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0--; i1--; - } - - return script; - } - } - - /** Standard ScriptBuilders. */ - public final static ScriptBuilder - forwardScript = new ForwardScript(), - reverseScript = new ReverseScript(); - - /* Report the differences of two files. DEPTH is the current directory - depth. */ - public final change diff_2(final boolean reverse) { - return diff(reverse ? reverseScript : forwardScript); - } - - /** Get the results of comparison as an edit script. The script - is described by a list of changes. The standard ScriptBuilder - implementations provide for forward and reverse edit scripts. - Alternate implementations could, for instance, list common elements - instead of differences. - @param bld an object to build the script from change flags - @return the head of a list of changes - */ - public change diff(final ScriptBuilder bld) { - - /* Some lines are obviously insertions or deletions - because they don't match anything. Detect them now, - and avoid even thinking about them in the main comparison algorithm. */ - - discard_confusing_lines (); - - /* Now do the main comparison algorithm, considering just the - undiscarded lines. */ - - xvec = filevec[0].undiscarded; - yvec = filevec[1].undiscarded; - - int diags = - filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3; - fdiag = new int[diags]; - fdiagoff = filevec[1].nondiscarded_lines + 1; - bdiag = new int[diags]; - bdiagoff = filevec[1].nondiscarded_lines + 1; - - compareseq (0, filevec[0].nondiscarded_lines, - 0, filevec[1].nondiscarded_lines); - fdiag = null; - bdiag = null; - - /* Modify the results slightly to make them prettier - in cases where that can validly be done. */ - - shift_boundaries (); - - /* Get the results of comparison in the form of a chain - of `struct change's -- an edit script. */ - return bld.build_script( - filevec[0].changed_flag, - filevec[0].buffered_lines, - filevec[1].changed_flag, - filevec[1].buffered_lines - ); - - } - - /** The result of comparison is an "edit script": a chain of change objects. - Each change represents one place where some lines are deleted - and some are inserted. - - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - - public static class change { - /** Previous or next edit command. */ - public change link; - /** # lines of file 1 changed here. */ - public final int inserted; - /** # lines of file 0 changed here. */ - public final int deleted; - /** Line number of 1st deleted line. */ - public final int line0; - /** Line number of 1st inserted line. */ - public final int line1; - - /** Cons an additional entry onto the front of an edit script OLD. - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - public change(int line0, int line1, int deleted, int inserted, change old) { - this.line0 = line0; - this.line1 = line1; - this.inserted = inserted; - this.deleted = deleted; - this.link = old; - //System.err.println(line0+","+line1+","+inserted+","+deleted); - } - } - - /** Data on one input file being compared. - */ - - class file_data { - - /** Allocate changed array for the results of comparison. */ - void clear() { - /* Allocate a flag for each line of each file, saying whether that line - is an insertion or deletion. - Allocate an extra element, always zero, at each end of each IndexedSeq. - */ - changed_flag = new boolean[buffered_lines + 2]; - } - - /** Return equiv_count[I] as the number of lines in this file - that fall in equivalence class I. - @return the array of equivalence class counts. - */ - int[] equivCount() { - int[] equiv_count = new int[equiv_max]; - for (int i = 0; i < buffered_lines; ++i) - ++equiv_count[equivs[i]]; - return equiv_count; - } - - /** Discard lines that have no matches in another file. - - A line which is discarded will not be considered by the actual - comparison algorithm; it will be as if that line were not in the file. - The file's `realindexes' table maps virtual line numbers - (which don't count the discarded lines) into real line numbers; - this is how the actual comparison algorithm produces results - that are comprehensible when the discarded lines are counted. -<p> - When we discard a line, we also mark it as a deletion or insertion - so that it will be printed in the output. - @param f the other file - */ - void discard_confusing_lines(file_data f) { - clear(); - /* Set up table of which lines are going to be discarded. */ - final byte[] discarded = discardable(f.equivCount()); - - /* Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - filterDiscards(discarded); - - /* Actually discard the lines. */ - discard(discarded); - } - - /** Mark to be discarded each line that matches no line of another file. - If a line matches many lines, mark it as provisionally discardable. - @see equivCount() - @param counts The count of each equivalence number for the other file. - @return 0=nondiscardable, 1=discardable or 2=provisionally discardable - for each line - */ - - private byte[] discardable(final int[] counts) { - final int end = buffered_lines; - final byte[] discards = new byte[end]; - final int[] equivs = this.equivs; - int many = 5; - int tem = end / 64; - - /* Multiply MANY by approximate square root of number of lines. - That is the threshold for provisionally discardable lines. */ - while ((tem = tem >> 2) > 0) - many *= 2; - - for (int i = 0; i < end; i++) - { - int nmatch; - if (equivs[i] == 0) - continue; - nmatch = counts[equivs[i]]; - if (nmatch == 0) - discards[i] = 1; - else if (nmatch > many) - discards[i] = 2; - } - return discards; - } - - /** Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - - private void filterDiscards(final byte[] discards) { - final int end = buffered_lines; - - for (int i = 0; i < end; i++) - { - /* Cancel provisional discards not in middle of run of discards. */ - if (discards[i] == 2) - discards[i] = 0; - else if (discards[i] != 0) - { - /* We have found a nonprovisional discard. */ - int j; - int length; - int provisional = 0; - - /* Find end of this run of discardable lines. - Count how many are provisionally discardable. */ - for (j = i; j < end; j++) - { - if (discards[j] == 0) - break; - if (discards[j] == 2) - ++provisional; - } - - /* Cancel provisional discards at end, and shrink the run. */ - while (j > i && discards[j - 1] == 2) { - discards[--j] = 0; --provisional; - } - - /* Now we have the length of a run of discardable lines - whose first and last are not provisional. */ - length = j - i; - - /* If 1/4 of the lines in the run are provisional, - cancel discarding of all provisional lines in the run. */ - if (provisional * 4 > length) - { - while (j > i) - if (discards[--j] == 2) - discards[j] = 0; - } - else - { - int consec; - int minimum = 1; - int tem = length / 4; - - /* MINIMUM is approximate square root of LENGTH/4. - A subrun of two or more provisionals can stand - when LENGTH is at least 16. - A subrun of 4 or more can stand when LENGTH >= 64. */ - while ((tem = tem >> 2) > 0) - minimum *= 2; - minimum++; - - /* Cancel any subrun of MINIMUM or more provisionals - within the larger run. */ - for (j = 0, consec = 0; j < length; j++) - if (discards[i + j] != 2) - consec = 0; - else if (minimum == ++consec) - /* Back up to start of subrun, to cancel it all. */ - j -= consec; - else if (minimum < consec) - discards[i + j] = 0; - - /* Scan from beginning of run - until we find 3 or more nonprovisionals in a row - or until the first nonprovisional at least 8 lines in. - Until that point, cancel any provisionals. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i + j] == 1) - break; - if (discards[i + j] == 2) { - consec = 0; discards[i + j] = 0; - } - else if (discards[i + j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - - /* I advances to the last line of the run. */ - i += length - 1; - - /* Same thing, from end. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i - j] == 1) - break; - if (discards[i - j] == 2) { - consec = 0; discards[i - j] = 0; - } - else if (discards[i - j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - } - } - } - } - - /** Actually discard the lines. - @param discards flags lines to be discarded - */ - private void discard(final byte[] discards) { - final int end = buffered_lines; - int j = 0; - for (int i = 0; i < end; ++i) - if (no_discards || discards[i] == 0) - { - undiscarded[j] = equivs[i]; - realindexes[j++] = i; - } - else - changed_flag[1+i] = true; - nondiscarded_lines = j; - } - - file_data(Object[] data,Hashtable h) { - buffered_lines = data.length; - - equivs = new int[buffered_lines]; - undiscarded = new int[buffered_lines]; - realindexes = new int[buffered_lines]; - - for (int i = 0; i < data.length; ++i) { - Integer ir = (Integer)h.get(data[i]); - if (ir == null) - h.put(data[i],new Integer(equivs[i] = equiv_max++)); - else - equivs[i] = ir.intValue(); - } - } - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - - We do something when a run of changed lines include a blank - line at one end and have an excluded blank line at the other. - We are free to choose which blank line is included. - `compareseq' always chooses the one at the beginning, - but usually it is cleaner to consider the following blank line - to be the "change". The only exception is if the preceding blank line - would join this change to other changes. - @param f the file being compared against - */ - - void shift_boundaries(file_data f) { - final boolean[] changed = changed_flag; - final boolean[] other_changed = f.changed_flag; - int i = 0; - int j = 0; - int i_end = buffered_lines; - int preceding = -1; - int other_preceding = -1; - - for (;;) - { - int start, end, other_start; - - /* Scan forwards to find beginning of another run of changes. - Also keep track of the corresponding point in the other file. */ - - while (i < i_end && !changed[1+i]) - { - while (other_changed[1+j++]) - /* Non-corresponding lines in the other file - will count as the preceding batch of changes. */ - other_preceding = j; - i++; - } - - if (i == i_end) - break; - - start = i; - other_start = j; - - for (;;) - { - /* Now find the end of this run of changes. */ - - while (i < i_end && changed[1+i]) i++; - end = i; - - /* If the first changed line matches the following unchanged one, - and this run does not follow right after a previous run, - and there are no lines deleted from the other file here, - then classify the first changed line as unchanged - and the following line as changed in its place. */ - - /* You might ask, how could this run follow right after another? - Only because the previous run was shifted here. */ - - if (end != i_end - && equivs[start] == equivs[end] - && !other_changed[1+j] - && end != i_end - && !((preceding >= 0 && start == preceding) - || (other_preceding >= 0 - && other_start == other_preceding))) - { - changed[1+end++] = true; - changed[1+start++] = false; - ++i; - /* Since one line-that-matches is now before this run - instead of after, we must advance in the other file - to keep in synch. */ - ++j; - } - else - break; - } - - preceding = i; - other_preceding = j; - } - } - - /** Number of elements (lines) in this file. */ - final int buffered_lines; - - /** IndexedSeq, indexed by line number, containing an equivalence code for - each line. It is this IndexedSeq that is actually compared with that - of another file to generate differences. */ - private final int[] equivs; - - /** IndexedSeq, like the previous one except that - the elements for discarded lines have been squeezed out. */ - final int[] undiscarded; - - /** IndexedSeq mapping virtual line numbers (not counting discarded lines) - to real ones (counting those lines). Both are origin-0. */ - final int[] realindexes; - - /** Total number of nondiscarded lines. */ - int nondiscarded_lines; - - /** Array, indexed by real origin-1 line number, - containing true for a line that is an insertion or a deletion. - The results of comparison are stored here. */ - boolean[] changed_flag; - - } -} diff --git a/src/partest-alternative/scala/tools/partest/io/DiffPrint.java b/src/partest-alternative/scala/tools/partest/io/DiffPrint.java deleted file mode 100644 index 273b6cba52..0000000000 --- a/src/partest-alternative/scala/tools/partest/io/DiffPrint.java +++ /dev/null @@ -1,606 +0,0 @@ - -package scala.tools.partest.io; - -import java.io.*; -import java.util.Vector; -import java.util.Date; -//import com.objectspace.jgl.predicates.UnaryPredicate; - -interface UnaryPredicate { - boolean execute(Object obj); -} - -/** A simple framework for printing change lists produced by <code>Diff</code>. - @see bmsi.util.Diff - @author Stuart D. Gathman - Copyright (C) 2000 Business Management Systems, Inc. -<p> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -<p> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -<p> - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -public class DiffPrint { - /** A Base class for printing edit scripts produced by Diff. - This class divides the change list into "hunks", and calls - <code>print_hunk</code> for each hunk. Various utility methods - are provided as well. - */ - public static abstract class Base { - protected Base(Object[] a,Object[] b, Writer w) { - outfile = new PrintWriter(w); - file0 = a; - file1 = b; - } - /** Set to ignore certain kinds of lines when printing - an edit script. For example, ignoring blank lines or comments. - */ - protected UnaryPredicate ignore = null; - - /** Set to the lines of the files being compared. - */ - protected Object[] file0, file1; - - /** Divide SCRIPT into pieces by calling HUNKFUN and - print each piece with PRINTFUN. - Both functions take one arg, an edit script. - - PRINTFUN takes a subscript which belongs together (with a null - link at the end) and prints it. */ - public void print_script(Diff.change script) { - Diff.change next = script; - - while (next != null) - { - Diff.change t, end; - - /* Find a set of changes that belong together. */ - t = next; - end = hunkfun(next); - - /* Disconnect them from the rest of the changes, - making them a hunk, and remember the rest for next iteration. */ - next = end.link; - end.link = null; - //if (DEBUG) - // debug_script(t); - - /* Print this hunk. */ - print_hunk(t); - - /* Reconnect the script so it will all be freed properly. */ - end.link = next; - } - outfile.flush(); - } - - /** Called with the tail of the script - and returns the last link that belongs together with the start - of the tail. */ - - protected Diff.change hunkfun(Diff.change hunk) { - return hunk; - } - - protected int first0, last0, first1, last1, deletes, inserts; - protected PrintWriter outfile; - - /** Look at a hunk of edit script and report the range of lines in each file - that it applies to. HUNK is the start of the hunk, which is a chain - of `struct change'. The first and last line numbers of file 0 are stored - in *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. - Note that these are internal line numbers that count from 0. - - If no lines from file 0 are deleted, then FIRST0 is LAST0+1. - - Also set *DELETES nonzero if any lines of file 0 are deleted - and set *INSERTS nonzero if any lines of file 1 are inserted. - If only ignorable lines are inserted or deleted, both are - set to 0. */ - - protected void analyze_hunk(Diff.change hunk) { - int f0, l0 = 0, f1, l1 = 0, show_from = 0, show_to = 0; - int i; - Diff.change next; - boolean nontrivial = (ignore == null); - - show_from = show_to = 0; - - f0 = hunk.line0; - f1 = hunk.line1; - - for (next = hunk; next != null; next = next.link) - { - l0 = next.line0 + next.deleted - 1; - l1 = next.line1 + next.inserted - 1; - show_from += next.deleted; - show_to += next.inserted; - for (i = next.line0; i <= l0 && ! nontrivial; i++) - if (!ignore.execute(file0[i])) - nontrivial = true; - for (i = next.line1; i <= l1 && ! nontrivial; i++) - if (!ignore.execute(file1[i])) - nontrivial = true; - } - - first0 = f0; - last0 = l0; - first1 = f1; - last1 = l1; - - /* If all inserted or deleted lines are ignorable, - tell the caller to ignore this hunk. */ - - if (!nontrivial) - show_from = show_to = 0; - - deletes = show_from; - inserts = show_to; - } - - /** Print the script header which identifies the files compared. */ - protected void print_header(String filea, String fileb) { } - - protected abstract void print_hunk(Diff.change hunk); - - protected void print_1_line(String pre,Object linbuf) { - outfile.println(pre + linbuf.toString()); - } - - /** Print a pair of line numbers with SEPCHAR, translated for file FILE. - If the two numbers are identical, print just one number. - - Args A and B are internal line numbers. - We print the translated (real) line numbers. */ - - protected void print_number_range (char sepchar, int a, int b) { - /* Note: we can have B < A in the case of a range of no lines. - In this case, we should print the line number before the range, - which is B. */ - if (++b > ++a) - outfile.print("" + a + sepchar + b); - else - outfile.print(b); - } - - public static char change_letter(int inserts, int deletes) { - if (inserts == 0) - return 'd'; - else if (deletes == 0) - return 'a'; - else - return 'c'; - } - } - - /** Print a change list in the standard diff format. - */ - public static class NormalPrint extends Base { - - public NormalPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - /** Print a hunk of a normal diff. - This is a contiguous portion of a complete edit script, - describing changes in consecutive lines. */ - - protected void print_hunk (Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - analyze_hunk(hunk); - if (deletes == 0 && inserts == 0) - return; - - /* Print out the line number header for this hunk */ - print_number_range (',', first0, last0); - outfile.print(change_letter(inserts, deletes)); - print_number_range (',', first1, last1); - outfile.println(); - - /* Print the lines that the first file has. */ - if (deletes != 0) - for (int i = first0; i <= last0; i++) - print_1_line ("< ", file0[i]); - - if (inserts != 0 && deletes != 0) - outfile.println("---"); - - /* Print the lines that the second file has. */ - if (inserts != 0) - for (int i = first1; i <= last1; i++) - print_1_line ("> ", file1[i]); - } - } - - /** Prints an edit script in a format suitable for input to <code>ed</code>. - The edit script must be generated with the reverse option to - be useful as actual <code>ed</code> input. - */ - public static class EdPrint extends Base { - - public EdPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - /** Print a hunk of an ed diff */ - protected void print_hunk(Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk); - if (deletes == 0 && inserts == 0) - return; - - /* Print out the line number header for this hunk */ - print_number_range (',', first0, last0); - outfile.println(change_letter(inserts, deletes)); - - /* Print new/changed lines from second file, if needed */ - if (inserts != 0) - { - boolean inserting = true; - for (int i = first1; i <= last1; i++) - { - /* Resume the insert, if we stopped. */ - if (! inserting) - outfile.println(i - first1 + first0 + "a"); - inserting = true; - - /* If the file's line is just a dot, it would confuse `ed'. - So output it with a double dot, and set the flag LEADING_DOT - so that we will output another ed-command later - to change the double dot into a single dot. */ - - if (".".equals(file1[i])) - { - outfile.println(".."); - outfile.println("."); - /* Now change that double dot to the desired single dot. */ - outfile.println(i - first1 + first0 + 1 + "s/^\\.\\././"); - inserting = false; - } - else - /* Line is not `.', so output it unmodified. */ - print_1_line ("", file1[i]); - } - - /* End insert mode, if we are still in it. */ - if (inserting) - outfile.println("."); - } - } - } - - /** Prints an edit script in context diff format. This and its - 'unified' variation is used for source code patches. - */ - public static class ContextPrint extends Base { - - protected int context = 3; - - public ContextPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - protected void print_context_label (String mark, File inf, String label) { - if (label != null) - outfile.println(mark + ' ' + label); - else if (inf.lastModified() > 0) - // FIXME: use DateFormat to get precise format needed. - outfile.println( - mark + ' ' + inf.getPath() + '\t' + new Date(inf.lastModified()) - ); - else - /* Don't pretend that standard input is ancient. */ - outfile.println(mark + ' ' + inf.getPath()); - } - - public void print_header(String filea,String fileb) { - print_context_label ("***", new File(filea), filea); - print_context_label ("---", new File(fileb), fileb); - } - - /** If function_regexp defined, search for start of function. */ - private String find_function(Object[] lines, int start) { - return null; - } - - protected void print_function(Object[] file,int start) { - String function = find_function (file0, first0); - if (function != null) { - outfile.print(" "); - outfile.print( - (function.length() < 40) ? function : function.substring(0,40) - ); - } - } - - protected void print_hunk(Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - - analyze_hunk (hunk); - - if (deletes == 0 && inserts == 0) - return; - - /* Include a context's width before and after. */ - - first0 = Math.max(first0 - context, 0); - first1 = Math.max(first1 - context, 0); - last0 = Math.min(last0 + context, file0.length - 1); - last1 = Math.min(last1 + context, file1.length - 1); - - - outfile.print("***************"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - print_function (file0, first0); - - outfile.println(); - outfile.print("*** "); - print_number_range (',', first0, last0); - outfile.println(" ****"); - - if (deletes != 0) { - Diff.change next = hunk; - - for (int i = first0; i <= last0; i++) { - /* Skip past changes that apply (in file 0) - only to lines before line I. */ - - while (next != null && next.line0 + next.deleted <= i) - next = next.link; - - /* Compute the marking for line I. */ - - String prefix = " "; - if (next != null && next.line0 <= i) - /* The change NEXT covers this line. - If lines were inserted here in file 1, this is "changed". - Otherwise it is "deleted". */ - prefix = (next.inserted > 0) ? "!" : "-"; - - print_1_line (prefix, file0[i]); - } - } - - outfile.print("--- "); - print_number_range (',', first1, last1); - outfile.println(" ----"); - - if (inserts != 0) { - Diff.change next = hunk; - - for (int i = first1; i <= last1; i++) { - /* Skip past changes that apply (in file 1) - only to lines before line I. */ - - while (next != null && next.line1 + next.inserted <= i) - next = next.link; - - /* Compute the marking for line I. */ - - String prefix = " "; - if (next != null && next.line1 <= i) - /* The change NEXT covers this line. - If lines were deleted here in file 0, this is "changed". - Otherwise it is "inserted". */ - prefix = (next.deleted > 0) ? "!" : "+"; - - print_1_line (prefix, file1[i]); - } - } - } - } - - /** Prints an edit script in context diff format. This and its - 'unified' variation is used for source code patches. - */ - public static class UnifiedPrint extends ContextPrint { - - public UnifiedPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - public void print_header(String filea,String fileb) { - print_context_label ("---", new File(filea), filea); - print_context_label ("+++", new File(fileb), fileb); - } - - private void print_number_range (int a, int b) { - //translate_range (file, a, b, &trans_a, &trans_b); - - /* Note: we can have B < A in the case of a range of no lines. - In this case, we should print the line number before the range, - which is B. */ - if (b < a) - outfile.print(b + ",0"); - else - super.print_number_range(',',a,b); - } - - protected void print_hunk(Diff.change hunk) { - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk); - - if (deletes == 0 && inserts == 0) - return; - - /* Include a context's width before and after. */ - - first0 = Math.max(first0 - context, 0); - first1 = Math.max(first1 - context, 0); - last0 = Math.min(last0 + context, file0.length - 1); - last1 = Math.min(last1 + context, file1.length - 1); - - - - outfile.print("@@ -"); - print_number_range (first0, last0); - outfile.print(" +"); - print_number_range (first1, last1); - outfile.print(" @@"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - print_function(file0,first0); - - outfile.println(); - - Diff.change next = hunk; - int i = first0; - int j = first1; - - while (i <= last0 || j <= last1) { - - /* If the line isn't a difference, output the context from file 0. */ - - if (next == null || i < next.line0) { - outfile.print(' '); - print_1_line ("", file0[i++]); - j++; - } - else { - /* For each difference, first output the deleted part. */ - - int k = next.deleted; - while (k-- > 0) { - outfile.print('-'); - print_1_line ("", file0[i++]); - } - - /* Then output the inserted part. */ - - k = next.inserted; - while (k-- > 0) { - outfile.print('+'); - print_1_line ("", file1[j++]); - } - - /* We're done with this hunk, so on to the next! */ - - next = next.link; - } - } - } - } - - - /** Read a text file into an array of String. This provides basic diff - functionality. A more advanced diff utility will use specialized - objects to represent the text lines, with options to, for example, - convert sequences of whitespace to a single space for comparison - purposes. - */ - static String[] slurp(String file) throws IOException { - BufferedReader rdr = new BufferedReader(new FileReader(file)); - Vector s = new Vector(); - for (;;) { - String line = rdr.readLine(); - if (line == null) break; - s.addElement(line); - } - String[] a = new String[s.size()]; - s.copyInto(a); - return a; - } - - public static void main(String[] argv) throws IOException { - String filea = argv[argv.length - 2]; - String fileb = argv[argv.length - 1]; - String[] a = slurp(filea); - String[] b = slurp(fileb); - Diff d = new Diff(a,b); - char style = 'n'; - for (int i = 0; i < argv.length - 2; ++i) { - String f = argv[i]; - if (f.startsWith("-")) { - for (int j = 1; j < f.length(); ++j) { - switch (f.charAt(j)) { - case 'e': // Ed style - style = 'e'; break; - case 'c': // Context diff - style = 'c'; break; - case 'u': - style = 'u'; break; - } - } - } - } - boolean reverse = style == 'e'; - Diff.change script = d.diff_2(reverse); - if (script == null) - System.err.println("No differences"); - else { - Base p; - Writer w = new OutputStreamWriter(System.out); - switch (style) { - case 'e': - p = new EdPrint(a,b,w); break; - case 'c': - p = new ContextPrint(a,b,w); break; - case 'u': - p = new UnifiedPrint(a,b,w); break; - default: - p = new NormalPrint(a,b,w); - } - p.print_header(filea,fileb); - p.print_script(script); - } - } - - public static void doDiff(String[] argv, Writer w) throws IOException { - String filea = argv[argv.length - 2]; - String fileb = argv[argv.length - 1]; - String[] a = slurp(filea); - String[] b = slurp(fileb); - Diff d = new Diff(a,b); - char style = 'n'; - for (int i = 0; i < argv.length - 2; ++i) { - String f = argv[i]; - if (f.startsWith("-")) { - for (int j = 1; j < f.length(); ++j) { - switch (f.charAt(j)) { - case 'e': // Ed style - style = 'e'; break; - case 'c': // Context diff - style = 'c'; break; - case 'u': - style = 'u'; break; - } - } - } - } - boolean reverse = style == 'e'; - Diff.change script = d.diff_2(reverse); - if (script == null) - w.write("No differences\n"); - else { - Base p; - switch (style) { - case 'e': - p = new EdPrint(a,b,w); break; - case 'c': - p = new ContextPrint(a,b,w); break; - case 'u': - p = new UnifiedPrint(a,b,w); break; - default: - p = new NormalPrint(a,b,w); - } - p.print_header(filea,fileb); - p.print_script(script); - } - } - -} diff --git a/src/partest-alternative/scala/tools/partest/io/JUnitReport.scala b/src/partest-alternative/scala/tools/partest/io/JUnitReport.scala deleted file mode 100644 index ddb3bc23fd..0000000000 --- a/src/partest-alternative/scala/tools/partest/io/JUnitReport.scala +++ /dev/null @@ -1,38 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest -package io - -/** This is disabled for the moment but I can fix it up if anyone - * is using it. - */ -class JUnitReport { - // create JUnit Report xml files if directory was specified - // def junitReport(dir: Directory) = { - // dir.mkdir() - // val report = testReport(set.kind, results, succs, fails) - // XML.save("%s/%s.xml".format(d.toAbsolute.path, set.kind), report) - // } - - // def oneResult(res: (TestEntity, Int)) = - // <testcase name={res._1.path}>{ - // res._2 match { - // case 0 => scala.xml.NodeSeq.Empty - // case 1 => <failure message="Test failed"/> - // case 2 => <failure message="Test timed out"/> - // } - // }</testcase> - // - // def testReport(kind: String, results: Iterable[(TestEntity, Int)], succs: Int, fails: Int) = { - // <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}> - // <properties/> - // { - // results.map(oneResult(_)) - // } - // </testsuite> - // } - // -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/io/Logging.scala b/src/partest-alternative/scala/tools/partest/io/Logging.scala deleted file mode 100644 index 52239ffb2c..0000000000 --- a/src/partest-alternative/scala/tools/partest/io/Logging.scala +++ /dev/null @@ -1,137 +0,0 @@ -package scala.tools -package partest -package io - -import java.io.{ StringWriter, PrintWriter, Writer } -import scala.tools.nsc.io._ -import scala.util.control.ControlThrowable - -trait Logging { - universe: Universe => - - class PartestANSIWriter extends ANSIWriter(Console.out) { - override def colorful: Int = ANSIWriter(universe.isAnsi) - private def printIf(cond: Boolean, msg: String) = - if (cond) { outline("debug: ") ; println(msg) } - - val verbose = printIf(isVerbose || isDebug, _: String) - val debug = printIf(isDebug, _: String) - } - - lazy val NestUI = new PartestANSIWriter() - - import NestUI.{ _outline, _success, _failure, _warning, _default } - - def markOutline(msg: String) = _outline + msg + _default - def markSuccess(msg: String) = _success + msg + _default - def markFailure(msg: String) = _failure + msg + _default - def markWarning(msg: String) = _warning + msg + _default - def markNormal(msg: String) = _default + msg - - def outline(msg: String) = NestUI outline msg - def success(msg: String) = NestUI success msg - def failure(msg: String) = NestUI failure msg - def warning(msg: String) = NestUI warning msg - def normal(msg: String) = NestUI normal msg - - def verbose(msg: String) = NestUI verbose msg - def debug(msg: String) = NestUI debug msg - - trait EntityLogging { - self: TestEntity => - - lazy val logWriter = new LogWriter(logFile) - - /** Redirect stdout and stderr to logFile, run body, return result. - */ - def loggingOutAndErr[T](body: => T): T = { - val log = logFile.printStream(append = true) - - try Console.withOut(log) { - Console.withErr(log) { - body - } - } - finally log.close() - } - - /** What to print in a failure summary. - */ - def failureMessage() = if (diffOutput != "") diffOutput else safeSlurp(logFile) - - /** For tracing. Outputs a line describing the next action. tracePath - * is a path wrapper which prints name or full path depending on verbosity. - */ - def trace(msg: String) = if (isTrace || isDryRun) System.err.println(">> [%s] %s".format(label, msg)) - - def tracePath(path: Path): String = if (isVerbose) path.path else path.name - def tracePath(path: String): String = tracePath(Path(path)) - - /** v == verbose. - */ - def vtrace(msg: String) = if (isVerbose) trace(msg) - - /** Run body, writes result to logFile. Any throwable is - * caught, stringified, and written to the log. - */ - def loggingResult(body: => String) = - try returning(true)(_ => logFile writeAll body) - catch { - case x: ControlThrowable => throw x - case x: InterruptedException => debug(this + " received interrupt, failing.\n") ; false - case x: Throwable => logException(x) - } - - def throwableToString(x: Throwable): String = { - val w = new StringWriter - x.printStackTrace(new PrintWriter(w)) - w.toString - } - - def warnAndLog(str: String) = { - warning(toStringTrunc(str, 800)) - logWriter append str - } - - def warnAndLogException(msg: String, ex: Throwable) = - warnAndLog(msg + throwableToString(ex)) - - def deleteLog(force: Boolean = false) = - if (universe.isNoCleanup && !force) debug("Not cleaning up " + logFile) - else logFile.deleteIfExists() - - def onException(x: Throwable) { logException(x) } - def logException(x: Throwable) = { - val msg = throwableToString(x) - if (!isTerse) - normal(msg) - - logWriter append msg - false - } - } - - /** A writer which doesn't create the file until a write comes in. - */ - class LazilyCreatedWriter(log: File) extends Writer { - @volatile private var isCreated = false - private lazy val underlying = { - isCreated = true - log.bufferedWriter() - } - - def flush() = if (isCreated) underlying.flush() - def close() = if (isCreated) underlying.close() - def write(chars: Array[Char], off: Int, len: Int) = { - underlying.write(chars, off, len) - underlying.flush() - } - } - - class LogWriter(log: File) extends PrintWriter(new LazilyCreatedWriter(log), true) { - override def print(s: String) = { - super.print(s) - flush() - } - } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/package.scala b/src/partest-alternative/scala/tools/partest/package.scala deleted file mode 100644 index 9c515aa2f4..0000000000 --- a/src/partest-alternative/scala/tools/partest/package.scala +++ /dev/null @@ -1,45 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools - -import nsc.io.{ File, Path, Process, Directory } -import java.nio.charset.CharacterCodingException - -package object partest { - /** The CharacterCodingExceptions are thrown at least on windows trying - * to read a file like script/utf-8.scala - */ - private[partest] def safeSlurp(f: File) = - try if (f.exists) f.slurp() else "" - catch { case _: CharacterCodingException => "" } - - private[partest] def safeLines(f: File) = safeSlurp(f) split """\r\n|\r|\n""" toList - private[partest] def safeArgs(f: File) = toArgs(safeSlurp(f)) - private[partest] def isJava(f: Path) = f.isFile && (f hasExtension "java") - private[partest] def isScala(f: Path) = f.isFile && (f hasExtension "scala") - private[partest] def isJavaOrScala(f: Path) = isJava(f) || isScala(f) - - private[partest] def toArgs(line: String) = cmd toArgs line - private[partest] def fromArgs(args: List[String]) = cmd fromArgs args - - /** Strings, argument lists, etc. */ - - private[partest] def fromAnyArgs(args: List[Any]) = args mkString " " // separate to avoid accidents - private[partest] def toStringTrunc(x: Any, max: Int = 240) = { - val s = x.toString - if (s.length < max) s - else (s take max) + " [...]" - } - private[partest] def setProp(k: String, v: String) = scala.util.Properties.setProp(k, v) - - /** Pretty self explanatory. */ - def printAndExit(msg: String): Unit = { - println(msg) - exit(1) - } - - /** Apply a function and return the passed value */ - def returning[T](x: T)(f: T => Unit): T = { f(x) ; x } -}
\ No newline at end of file diff --git a/src/partest-alternative/scala/tools/partest/util/package.scala b/src/partest-alternative/scala/tools/partest/util/package.scala deleted file mode 100644 index c34d641db1..0000000000 --- a/src/partest-alternative/scala/tools/partest/util/package.scala +++ /dev/null @@ -1,61 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2011 LAMP/EPFL - */ - -package scala.tools -package partest - -import java.util.{ Timer, TimerTask } -import java.io.StringWriter -import nsc.io._ - -/** Misc code still looking for a good home. - */ -package object util { - - def allPropertiesString() = javaHashtableToString(System.getProperties) - - private def javaHashtableToString(table: java.util.Hashtable[_,_]) = { - import collection.JavaConversions._ - (table.toList map { case (k, v) => "%s -> %s\n".format(k, v) }).sorted mkString - } - - def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] = - fs flatMap (x => Option(AbstractFile getFile (Path(pre) / x).path)) toSet - - /** Copies one Path to another Path, trying to be sensible when one or the - * other is a Directory. Returns true if it believes it succeeded. - */ - def copyPath(from: Path, to: Path): Boolean = { - if (!to.parent.isDirectory) - to.parent.createDirectory(force = true) - - def copyDir = { - val sub = to / from.name createDirectory true - from.toDirectory.list forall (x => copyPath(x, sub)) - } - (from.isDirectory, to.isDirectory) match { - case (true, true) => copyDir - case (true, false) => false - case (false, true) => from.toFile copyTo (to / from.name) - case (false, false) => from.toFile copyTo to - } - } - - /** - * Compares two files using a Java implementation of the GNU diff - * available at http://www.bmsi.com/java/#diff. - * - * @param f1 the first file to be compared - * @param f2 the second file to be compared - * @return the text difference between the compared files - */ - def diffFiles(f1: File, f2: File): String = { - val diffWriter = new StringWriter - val args = Array(f1.toAbsolute.path, f2.toAbsolute.path) - - io.DiffPrint.doDiff(args, diffWriter) - val result = diffWriter.toString - if (result == "No differences") "" else result - } -} diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index a08100a33f..a90a61a9aa 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -281,6 +281,26 @@ class PartestTask extends Task with CompilationPathProperty { } } getOrElse sys.error("Provided classpath does not contain a Scala library.") + val scalaCompiler = { + (classpath.list map { fs => new File(fs) }) find { f => + f.getName match { + case "scala-compiler.jar" => true + case "compiler" if (f.getParentFile.getName == "classes") => true + case _ => false + } + } + } getOrElse sys.error("Provided classpath does not contain a Scala compiler.") + + val scalaPartest = { + (classpath.list map { fs => new File(fs) }) find { f => + f.getName match { + case "scala-partest.jar" => true + case "partest" if (f.getParentFile.getName == "classes") => true + case _ => false + } + } + } getOrElse sys.error("Provided classpath does not contain a Scala partest.") + def scalacArgsFlat: Option[Seq[String]] = scalacArgs map (_ flatMap { a => val parts = a.getParts if(parts eq null) Seq[String]() else parts.toSeq @@ -294,6 +314,8 @@ class PartestTask extends Task with CompilationPathProperty { antFileManager.failed = runFailed antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*) antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath + antFileManager.LATEST_COMP = scalaCompiler.getAbsolutePath + antFileManager.LATEST_PARTEST = scalaPartest.getAbsolutePath javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath) javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath) @@ -361,18 +383,18 @@ class PartestTask extends Task with CompilationPathProperty { private def oneResult(res: (String, Int)) = <testcase name={res._1}>{ - res._2 match { - case 0 => scala.xml.NodeSeq.Empty + res._2 match { + case 0 => scala.xml.NodeSeq.Empty case 1 => <failure message="Test failed"/> case 2 => <failure message="Test timed out"/> - } - }</testcase> + } + }</testcase> private def testReport(kind: String, results: Iterable[(String, Int)], succs: Int, fails: Int) = <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}> - <properties/> - { - results.map(oneResult(_)) - } + <properties/> + { + results.map(oneResult(_)) + } </testsuite> } diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala index 002e454b7b..4795e5551a 100644 --- a/src/partest/scala/tools/partest/nest/AntRunner.scala +++ b/src/partest/scala/tools/partest/nest/AntRunner.scala @@ -20,6 +20,8 @@ class AntRunner extends DirectRunner { var JAVAC_CMD: String = "javac" var CLASSPATH: String = _ var LATEST_LIB: String = _ + var LATEST_COMP: String = _ + var LATEST_PARTEST: String = _ val testRootPath: String = "test" val testRootDir: Directory = Directory(testRootPath) } diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 68688ff949..6604bc551d 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -26,7 +26,7 @@ class TestSettings(cp: String, error: String => Unit) extends Settings(error) { deprecation.value = true nowarnings.value = false - encoding.value = "ISO-8859-1" + encoding.value = "UTF-8" classpath.value = cp } @@ -111,6 +111,7 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { try { NestUI.verbose("compiling "+toCompile) + NestUI.verbose("with classpath: "+global.classPath.toString) try new global.Run compile toCompile catch { case FatalError(msg) => diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala index b9b371d6cb..3d72227b04 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala @@ -157,9 +157,13 @@ class ConsoleFileManager extends FileManager { } LATEST_LIB = latestLibFile.getAbsolutePath + LATEST_COMP = latestCompFile.getAbsolutePath + LATEST_PARTEST = latestPartestFile.getAbsolutePath } var LATEST_LIB: String = "" + var LATEST_COMP: String = "" + var LATEST_PARTEST: String = "" var latestFile: File = _ var latestLibFile: File = _ diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala index 78184664c2..d3d50ca58c 100644 --- a/src/partest/scala/tools/partest/nest/DirectRunner.scala +++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala @@ -52,8 +52,15 @@ trait DirectRunner { val kindFiles = onlyValidTestPaths(_kindFiles) val groupSize = (kindFiles.length / numActors) + 1 - val consFM = new ConsoleFileManager - import consFM.{ latestCompFile, latestLibFile, latestPartestFile } + // @partest maintainer: we cannot create a fresh file manager here + // since the FM must respect --buildpath and --classpath from the command line + // for example, see how it's done in ReflectiveRunner + //val consFM = new ConsoleFileManager + //import consFM.{ latestCompFile, latestLibFile, latestPartestFile } + val latestCompFile = new File(fileManager.LATEST_COMP); + val latestLibFile = new File(fileManager.LATEST_LIB); + val latestPartestFile = new File(fileManager.LATEST_PARTEST); + val scalacheckURL = PathSettings.scalaCheck.toURL val scalaCheckParentClassLoader = ScalaClassLoader.fromURLs( List(scalacheckURL, latestCompFile.toURI.toURL, latestLibFile.toURI.toURL, latestPartestFile.toURI.toURL) diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 780f7a35e5..a4a94fe93e 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -60,6 +60,8 @@ trait FileManager extends FileUtil { var CLASSPATH: String var LATEST_LIB: String + var LATEST_COMP: String + var LATEST_PARTEST: String var showDiff = false var updateCheck = false diff --git a/src/partest/scala/tools/partest/nest/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala index 0c176e4b06..4c6f417df5 100644 --- a/src/partest/scala/tools/partest/nest/SBTRunner.scala +++ b/src/partest/scala/tools/partest/nest/SBTRunner.scala @@ -7,16 +7,18 @@ import scala.util.Properties.setProp object SBTRunner extends DirectRunner { - + val fileManager = new FileManager { var JAVACMD: String = "java" var JAVAC_CMD: String = "javac" var CLASSPATH: String = _ var LATEST_LIB: String = _ + var LATEST_COMP: String = _ + var LATEST_PARTEST: String = _ val testRootPath: String = "test" val testRootDir: Directory = Directory(testRootPath) } - + def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String):java.util.HashMap[String,Int] = { def convert(scalaM:scala.collection.immutable.Map[String,Int]):java.util.HashMap[String,Int] = { val javaM = new java.util.HashMap[String,Int]() @@ -25,9 +27,9 @@ object SBTRunner extends DirectRunner { } def failedOnlyIfRequired(files:List[File]):List[File]={ - if (fileManager.failed) files filter (x => fileManager.logFileExists(x, kind)) else files + if (fileManager.failed) files filter (x => fileManager.logFileExists(x, kind)) else files } - convert(runTestsForFiles(failedOnlyIfRequired(kindFiles.toList), kind)) + convert(runTestsForFiles(failedOnlyIfRequired(kindFiles.toList), kind)) } case class CommandLineOptions(classpath: Option[String] = None, @@ -38,7 +40,7 @@ object SBTRunner extends DirectRunner { def mainReflect(args: Array[String]): java.util.Map[String,Int] = { setProp("partest.debug", "true") setProperties() - + val Argument = new scala.util.matching.Regex("-(.*)") def parseArgs(args: Seq[String], data: CommandLineOptions): CommandLineOptions = args match { case Seq("--failed", rest @ _*) => parseArgs(rest, data.copy(justFailedTests = true)) @@ -50,10 +52,14 @@ object SBTRunner extends DirectRunner { } val config = parseArgs(args, CommandLineOptions()) fileManager.SCALAC_OPTS = config.scalacOptions - fileManager.CLASSPATH = config.classpath getOrElse error("No classpath set") + fileManager.CLASSPATH = config.classpath getOrElse sys.error("No classpath set") // Find scala library jar file... val lib: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-library.*\\.jar")).headOption - fileManager.LATEST_LIB = lib getOrElse error("No scala-library found! Classpath = " + fileManager.CLASSPATH) + fileManager.LATEST_LIB = lib getOrElse sys.error("No scala-library found! Classpath = " + fileManager.CLASSPATH) + val comp: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-compiler.*\\.jar")).headOption + fileManager.LATEST_COMP = comp getOrElse sys.error("No scala-compiler found! Classpath = " + fileManager.CLASSPATH) + val partest: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-partest.*\\.jar")).headOption + fileManager.LATEST_PARTEST = partest getOrElse sys.error("No scala-partest found! Classpath = " + fileManager.CLASSPATH) // TODO - Do something useful here!!! fileManager.JAVAC_CMD = "javac" fileManager.failed = config.justFailedTests @@ -63,7 +69,7 @@ object SBTRunner extends DirectRunner { val runs = config.tests.filterNot(_._2.isEmpty) // This next bit uses java maps... import collection.JavaConverters._ - (for { + (for { (testType, files) <- runs (path, result) <- reflectiveRunTestsForFiles(files,testType).asScala } yield (path, result)).seq asJava @@ -80,4 +86,3 @@ object SBTRunner extends DirectRunner { if(!failures.isEmpty) sys.exit(1) } } - diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala index 9c61097cb0..3e5fe35f9e 100644 --- a/src/partest/scala/tools/partest/nest/TestFile.scala +++ b/src/partest/scala/tools/partest/nest/TestFile.scala @@ -12,6 +12,7 @@ import java.io.{ File => JFile } import scala.tools.nsc.Settings import scala.tools.nsc.util.ClassPath import scala.tools.nsc.io._ +import scala.util.Properties.{ propIsSet, propOrElse, setProp } trait TestFileCommon { def file: JFile @@ -61,6 +62,10 @@ case class SpecializedTestFile(file: JFile, fileManager: FileManager) extends Te super.defineSettings(settings, setOutDir) && { // add the instrumented library version to classpath settings.classpath prepend PathSettings.srcSpecLib.toString + // @partest maintainer: if we use a custom Scala build (specified via --classpath) + // then the classes provided by it will come earlier than instrumented.jar in the resulting classpath + // this entire classpath business needs a thorough solution + if (propIsSet("java.class.path")) setProp("java.class.path", PathSettings.srcSpecLib.toString + ";" + propOrElse("java.class.path", "")) true } } diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala index f74182e81c..952d99c318 100644 --- a/src/partest/scala/tools/partest/nest/Worker.scala +++ b/src/partest/scala/tools/partest/nest/Worker.scala @@ -53,6 +53,8 @@ class ScalaCheckFileManager(val origmanager: FileManager) extends FileManager { var CLASSPATH: String = join(origmanager.CLASSPATH, PathSettings.scalaCheck.path) var LATEST_LIB: String = origmanager.LATEST_LIB + var LATEST_COMP: String = origmanager.LATEST_COMP + var LATEST_PARTEST: String = origmanager.LATEST_PARTEST } object Output { diff --git a/test/files/buildmanager/t2790/t2790.check b/test/files/buildmanager/t2790/t2790.check index 4e41db4e49..13d61dac42 100644 --- a/test/files/buildmanager/t2790/t2790.check +++ b/test/files/buildmanager/t2790/t2790.check @@ -9,6 +9,5 @@ compiling Set(B.scala) B.scala:2: error: type mismatch; found : Int(5) required: String -Error occurred in an application involving default arguments. val y = A.x(5) ^ diff --git a/test/files/neg/nopredefs.check b/test/files/neg/nopredefs.check index e6c1af78a0..0a0ab34482 100644 --- a/test/files/neg/nopredefs.check +++ b/test/files/neg/nopredefs.check @@ -1,4 +1,4 @@ -nopredefs.scala:5: error: not found: value Set (similar: Seq) +nopredefs.scala:5: error: not found: value Set val y = Set(3) ^ one error found diff --git a/test/files/neg/sensitive2.check b/test/files/neg/sensitive2.check new file mode 100644 index 0000000000..19152fe188 --- /dev/null +++ b/test/files/neg/sensitive2.check @@ -0,0 +1,10 @@ +sensitive2.scala:6: error: type mismatch; + found : String("abc") + required: Test.Foo[_] +Note that implicit conversions are not applicable because they are ambiguous: + both method foo1 in object Test of type [A](a: A)Test.Foo[A] + and method foo2 in object Test of type (a: Any)Test.Foo[String] + are possible conversion functions from String("abc") to Test.Foo[_] + val a: Foo[_] = "abc" + ^ +one error found diff --git a/test/files/neg/sensitive2.scala b/test/files/neg/sensitive2.scala new file mode 100644 index 0000000000..92b91bef20 --- /dev/null +++ b/test/files/neg/sensitive2.scala @@ -0,0 +1,8 @@ +object Test { + class Foo[A](z: A) + implicit def foo1[A](a: A): Foo[A] = new Foo(a) + implicit def foo2(a: Any): Foo[String] = new Foo("123") + + val a: Foo[_] = "abc" + +}
\ No newline at end of file diff --git a/test/files/neg/suggest-similar.check b/test/files/neg/suggest-similar.check index 0a858aaf2e..057aa8b250 100644 --- a/test/files/neg/suggest-similar.check +++ b/test/files/neg/suggest-similar.check @@ -1,10 +1,10 @@ -suggest-similar.scala:8: error: not found: value flippitx (similar: flippity) +suggest-similar.scala:8: error: not found: value flippitx flippitx = 123 ^ -suggest-similar.scala:9: error: not found: value identiyt (similar: identity) +suggest-similar.scala:9: error: not found: value identiyt Nil map identiyt ^ -suggest-similar.scala:10: error: not found: type Bingus (similar: Dingus) +suggest-similar.scala:10: error: not found: type Bingus new Bingus ^ three errors found diff --git a/test/files/neg/t1878.check b/test/files/neg/t1878.check index f3a6701d41..128741a022 100644 --- a/test/files/neg/t1878.check +++ b/test/files/neg/t1878.check @@ -6,10 +6,13 @@ t1878.scala:3: error: scrutinee is incompatible with pattern type; required: String val err1 = "" match { case Seq(f @ _*, ',') => f } ^ +t1878.scala:3: error: not found: value f + val err1 = "" match { case Seq(f @ _*, ',') => f } + ^ t1878.scala:9: error: _* may only come last val List(List(_*, arg2), _) = List(List(1,2,3), List(4,5,6)) ^ t1878.scala:13: error: _* may only come last case <p> { _* } </p> => ^ -four errors found +5 errors found diff --git a/test/files/neg/t2641.check b/test/files/neg/t2641.check index 2056a1b9ab..9e2f02ac47 100644 --- a/test/files/neg/t2641.check +++ b/test/files/neg/t2641.check @@ -1,4 +1,4 @@ -t2641.scala:18: error: illegal cyclic reference involving trait ManagedSeq +t2641.scala:18: error: wrong number of type arguments for ManagedSeq, should be 2 with TraversableViewLike[A, ManagedSeqStrict[A], ManagedSeq[A]] ^ t2641.scala:16: error: illegal inheritance; @@ -13,23 +13,7 @@ t2641.scala:16: error: illegal inheritance; self-type ManagedSeq does not conform to ScalaObject's selftype ScalaObject extends ManagedSeqStrict[A] ^ -t2641.scala:24: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = typer - trait Transformed[+B] extends ManagedSeq[B, Coll] with super.Transformed[B] - ^ -t2641.scala:26: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = namer - trait Sliced extends Transformed[A] with super.Sliced { - ^ -t2641.scala:26: error: illegal inheritance; superclass Any - is not a subclass of the superclass ManagedSeqStrict - of the mixin trait Transformed - trait Sliced extends Transformed[A] with super.Sliced { - ^ -t2641.scala:26: error: illegal inheritance; superclass Any - is not a subclass of the superclass Object - of the mixin trait Sliced - trait Sliced extends Transformed[A] with super.Sliced { - ^ t2641.scala:27: error: value managedIterator is not a member of ManagedSeq override def managedIterator = self.managedIterator slice (from, until) ^ -9 errors found +5 errors found diff --git a/test/files/neg/t2870.check b/test/files/neg/t2870.check index ab962d48c8..99522eca65 100644 --- a/test/files/neg/t2870.check +++ b/test/files/neg/t2870.check @@ -1,4 +1,4 @@ -t2870.scala:1: error: not found: type Jar (similar: Jars) +t2870.scala:1: error: not found: type Jar class Jars(jar: Jar) ^ t2870.scala:4: error: encountered unrecoverable cycle resolving import. diff --git a/test/files/neg/t2918.check b/test/files/neg/t2918.check index 263beab518..aae3045e8a 100644 --- a/test/files/neg/t2918.check +++ b/test/files/neg/t2918.check @@ -1,10 +1,10 @@ t2918.scala:2: error: illegal cyclic reference involving type A - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x ^ t2918.scala:2: error: cyclic aliasing or subtyping involving type A - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x ^ t2918.scala:2: error: A does not take type parameters - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x ^ three errors found diff --git a/test/files/neg/t2918.scala b/test/files/neg/t2918.scala index 03477ccfbf..ff2be39ae0 100755 --- a/test/files/neg/t2918.scala +++ b/test/files/neg/t2918.scala @@ -1,3 +1,3 @@ object Test { - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x } diff --git a/test/files/neg/t3015.check b/test/files/neg/t3015.check index 0b394e23d6..53221b7ca0 100644 --- a/test/files/neg/t3015.check +++ b/test/files/neg/t3015.check @@ -3,9 +3,4 @@ t3015.scala:7: error: scrutinee is incompatible with pattern type; required: String val b(foo) = "foo" ^ -t3015.scala:7: error: type mismatch; - found : String with _$1(in object Test) where type +_$1(in object Test) - required: (some other)_$1(in object Test) where type +(some other)_$1(in object Test) - val b(foo) = "foo" - ^ -two errors found +one error found diff --git a/test/files/neg/t3854.check b/test/files/neg/t3854.check new file mode 100644 index 0000000000..c478481a6f --- /dev/null +++ b/test/files/neg/t3854.check @@ -0,0 +1,5 @@ +t3854.scala:1: error: class Bar needs to be abstract, since method foo in trait Foo of type [G[_]](implicit n: N[G,F])X[F] is not defined +(Note that N[G,F] does not match M[G]) +class Bar[F[_]] extends Foo[F] { + ^ +one error found diff --git a/test/files/neg/t3854.scala b/test/files/neg/t3854.scala new file mode 100644 index 0000000000..e8db76c0a5 --- /dev/null +++ b/test/files/neg/t3854.scala @@ -0,0 +1,15 @@ +class Bar[F[_]] extends Foo[F] { + def foo[G[_[_], _]](implicit M: M[G]): X[({type λ[α] = G[F, α] })#λ] = null +} +// vim: set ts=4 sw=4 et: + +trait M[F[_[_], _]] +trait N[F[_], G[_]] + +trait X[F[_]] { + def apply[A]: F[A] +} + +trait Foo[F[_]] { + def foo[G[_]](implicit n: N[G, F]): X[F] +} diff --git a/test/files/neg/t4515.check b/test/files/neg/t4515.check new file mode 100644 index 0000000000..ce5350b35f --- /dev/null +++ b/test/files/neg/t4515.check @@ -0,0 +1,6 @@ +t4515.scala:37: error: type mismatch; + found : _0(in value $anonfun) where type _0(in value $anonfun) + required: (some other)_0(in value $anonfun) where type +(some other)_0(in value $anonfun) + handler.onEvent(target, ctx.getEvent, node, ctx) + ^ +one error found diff --git a/test/files/neg/t4515.scala b/test/files/neg/t4515.scala new file mode 100644 index 0000000000..63049f201d --- /dev/null +++ b/test/files/neg/t4515.scala @@ -0,0 +1,41 @@ +import scala.collection.mutable.HashMap + +object Main { + trait Target { } + + trait PushEventContext[EventType] { + def getEvent: EventType + } + trait PushNode[EventType] { } + trait DerivedPushNode[EventType] extends PushNode[EventType] { } + + trait HandlerBase[EventType] { + def onEvent(target: Target, + event: EventType, + node: PushNode[EventType], + ctx: PushEventContext[EventType]): Unit + } + val handlers = new HashMap[DerivedPushNode[_], HandlerBase[_]] + + object TimerPushService { + private val INSTANCE: TimerPushService = new TimerPushService + def get: TimerPushService = INSTANCE + } + + class TimerPushService { + def add[EventType](node: DerivedPushNode[EventType], + context: PushEventContext[EventType]): Unit = {} + + def pollEvents[EventType](node: DerivedPushNode[EventType]): List[PushEventContext[EventType]] = + Nil + } + + def onTimer(target: Target) { + val pushService = TimerPushService.get + for ((node, handler) <- handlers) { + for (ctx <- pushService.pollEvents(node)) { + handler.onEvent(target, ctx.getEvent, node, ctx) + } + } + } +}
\ No newline at end of file diff --git a/test/files/neg/t649.check b/test/files/neg/t649.check index 5a270d4751..a6670886b5 100644 --- a/test/files/neg/t649.check +++ b/test/files/neg/t649.check @@ -1,4 +1,4 @@ t649.scala:3: error: overloaded method foo needs result type def foo[A] = foo[A] - ^ + ^ one error found diff --git a/test/files/pos/t3999b.scala b/test/files/pos/t3999b.scala new file mode 100644 index 0000000000..d3fe108479 --- /dev/null +++ b/test/files/pos/t3999b.scala @@ -0,0 +1,20 @@ +object `package` { + trait Score { def toString : String } + trait Test[+T <: Score] { def apply(s : String) : T } + + case class FT(f : Float) extends Score + implicit object FT extends Test[FT] { def apply(s : String) : FT = new FT(s.toFloat) } + + case class IT(i : Int) extends Score + implicit object IT extends Test[IT] { def apply(s : String) : IT = new IT(s.toInt) } +} + +class TT[+T <: Score](implicit val tb : Test[T]) { + def read(s : String) : T = tb(s) +} + +object Tester { + val tt = new TT[FT] + val r = tt.read("1.0") + r.toString +}
\ No newline at end of file diff --git a/test/files/pos/trait-force-info.flags b/test/files/pos/trait-force-info.flags new file mode 100644 index 0000000000..eb4d19bcb9 --- /dev/null +++ b/test/files/pos/trait-force-info.flags @@ -0,0 +1 @@ +-optimise
\ No newline at end of file diff --git a/test/files/pos/trait-force-info.scala b/test/files/pos/trait-force-info.scala new file mode 100644 index 0000000000..e01d225c84 --- /dev/null +++ b/test/files/pos/trait-force-info.scala @@ -0,0 +1,18 @@ +/** This does NOT crash unless it's in the interactive package. + */ + +package scala.tools.nsc +package interactive + +trait MyContextTrees { + val self: Global + val NoContext = self.analyzer.NoContext +} +// +// error: java.lang.AssertionError: assertion failed: trait Contexts.NoContext$ linkedModule: <none>List() +// at scala.Predef$.assert(Predef.scala:160) +// at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.innerSymbol$1(ClassfileParser.scala:1211) +// at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.classSymbol(ClassfileParser.scala:1223) +// at scala.tools.nsc.symtab.classfile.ClassfileParser.classNameToSymbol(ClassfileParser.scala:489) +// at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:757) +// at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:789) diff --git a/test/files/run/macro-range/macro_range_1.scala b/test/files/run/macro-range/macro_range_1.scala index 15a018fcff..fdfe7169ad 100644 --- a/test/files/run/macro-range/macro_range_1.scala +++ b/test/files/run/macro-range/macro_range_1.scala @@ -29,12 +29,13 @@ abstract class Utils { } } def makeApply(fn: Tree, args: List[Tree]): Tree = fn match { - case Function(vparams, body) => + case Function(vparams, body) => new TreeSubstituter(vparams map (_.symbol), args) transform body case Block(stats, expr) => Block(stats, makeApply(expr, args)) - case _ => - println("no beta on "+fn+" "+fn.getClass) + case _ => + // todo. read the compiler config and print if -Ydebug is set + //println("no beta on "+fn+" "+fn.getClass) Apply(fn, args) } def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = { @@ -48,7 +49,8 @@ abstract class Utils { class Range(val from: Int, val to: Int) extends RangeDefault { override def macro foreach(f: Int => Unit): Unit = { - println("macro-expand, _this = "+ _this) + // todo. read the compiler config and print if -Ydebug is set + //println("macro-expand, _this = "+ _this) import _context._ object utils extends Utils { val context: _context.type = _context @@ -71,12 +73,15 @@ class Range(val from: Int, val to: Int) extends RangeDefault { val body = Block( List(makeApply(f, List(iref))), Assign(iref, makeBinop(iref, "$plus", Literal(Constant(1))))) - tools.nsc.util.trace("generated: ")( + val generated = Block( List( ValDef(Modifiers(Set(Modifier.mutable)), iname, TypeTree(), lo), ValDef(Modifiers(), hname, TypeTree(), hi)), - makeWhile(labelname, cond, body))) + makeWhile(labelname, cond, body)) + // todo. read the compiler config and print if -Ydebug is set + //tools.nsc.util.trace("generated: ")(generated) + generated case _ => Apply( Select( diff --git a/test/files/run/macro-range/macro_range_2.scala b/test/files/run/macro-range/macro_range_2.scala index 15a018fcff..fdfe7169ad 100644 --- a/test/files/run/macro-range/macro_range_2.scala +++ b/test/files/run/macro-range/macro_range_2.scala @@ -29,12 +29,13 @@ abstract class Utils { } } def makeApply(fn: Tree, args: List[Tree]): Tree = fn match { - case Function(vparams, body) => + case Function(vparams, body) => new TreeSubstituter(vparams map (_.symbol), args) transform body case Block(stats, expr) => Block(stats, makeApply(expr, args)) - case _ => - println("no beta on "+fn+" "+fn.getClass) + case _ => + // todo. read the compiler config and print if -Ydebug is set + //println("no beta on "+fn+" "+fn.getClass) Apply(fn, args) } def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = { @@ -48,7 +49,8 @@ abstract class Utils { class Range(val from: Int, val to: Int) extends RangeDefault { override def macro foreach(f: Int => Unit): Unit = { - println("macro-expand, _this = "+ _this) + // todo. read the compiler config and print if -Ydebug is set + //println("macro-expand, _this = "+ _this) import _context._ object utils extends Utils { val context: _context.type = _context @@ -71,12 +73,15 @@ class Range(val from: Int, val to: Int) extends RangeDefault { val body = Block( List(makeApply(f, List(iref))), Assign(iref, makeBinop(iref, "$plus", Literal(Constant(1))))) - tools.nsc.util.trace("generated: ")( + val generated = Block( List( ValDef(Modifiers(Set(Modifier.mutable)), iname, TypeTree(), lo), ValDef(Modifiers(), hname, TypeTree(), hi)), - makeWhile(labelname, cond, body))) + makeWhile(labelname, cond, body)) + // todo. read the compiler config and print if -Ydebug is set + //tools.nsc.util.trace("generated: ")(generated) + generated case _ => Apply( Select( diff --git a/test/files/run/range-unit.check b/test/files/run/range-unit.check new file mode 100644 index 0000000000..3daf91cd64 --- /dev/null +++ b/test/files/run/range-unit.check @@ -0,0 +1,4178 @@ +>>> Range.inclusive <<< + +start end step length/first/last +----------------------------------------- +0 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 0 -1 1/0/0 +0 0 1 1/0/0 +0 0 -2 1/0/0 +0 0 2 1/0/0 +0 0 -3 1/0/0 +0 0 3 1/0/0 +0 0 17 1/0/0 +0 0 127 1/0/0 +0 0 MIN+1 1/0/0 +0 0 MAX 1/0/0 +0 0 MIN 1/0/0 +0 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 -1 -1 2/0/-1 +0 -1 1 0 +0 -1 -2 1/0/0 +0 -1 2 0 +0 -1 -3 1/0/0 +0 -1 3 0 +0 -1 17 0 +0 -1 127 0 +0 -1 MIN+1 1/0/0 +0 -1 MAX 0 +0 -1 MIN 1/0/0 +0 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 1 -1 0 +0 1 1 2/0/1 +0 1 -2 0 +0 1 2 1/0/0 +0 1 -3 0 +0 1 3 1/0/0 +0 1 17 1/0/0 +0 1 127 1/0/0 +0 1 MIN+1 0 +0 1 MAX 1/0/0 +0 1 MIN 0 +0 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 3 -1 0 +0 3 1 4/0/3 +0 3 -2 0 +0 3 2 2/0/2 +0 3 -3 0 +0 3 3 2/0/3 +0 3 17 1/0/0 +0 3 127 1/0/0 +0 3 MIN+1 0 +0 3 MAX 1/0/0 +0 3 MIN 0 +0 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN+1 -1 --- + java.lang.IllegalArgumentException: 0 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +0 MIN+1 1 0 +0 MIN+1 -2 1073741824/0/MIN+2 +0 MIN+1 2 0 +0 MIN+1 -3 715827883/0/MIN+2 +0 MIN+1 3 0 +0 MIN+1 17 0 +0 MIN+1 127 0 +0 MIN+1 MIN+1 2/0/MIN+1 +0 MIN+1 MAX 0 +0 MIN+1 MIN 1/0/0 +0 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MAX -1 0 +0 MAX 1 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX -2 0 +0 MAX 2 1073741824/0/MAX-1 +0 MAX -3 0 +0 MAX 3 715827883/0/MAX-1 +0 MAX 17 126322568/0/MAX-8 +0 MAX 127 16909321/0/MAX-7 +0 MAX MIN+1 0 +0 MAX MAX 2/0/MAX +0 MAX MIN 0 +0 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN -1 --- + java.lang.IllegalArgumentException: 0 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +0 MIN 1 0 +0 MIN -2 1073741825/0/MIN +0 MIN 2 0 +0 MIN -3 715827883/0/MIN+2 +0 MIN 3 0 +0 MIN 17 0 +0 MIN 127 0 +0 MIN MIN+1 2/0/MIN+1 +0 MIN MAX 0 +0 MIN MIN 2/0/MIN + +start end step length/first/last +----------------------------------------- +-1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 0 -1 0 +-1 0 1 2/-1/0 +-1 0 -2 0 +-1 0 2 1/-1/-1 +-1 0 -3 0 +-1 0 3 1/-1/-1 +-1 0 17 1/-1/-1 +-1 0 127 1/-1/-1 +-1 0 MIN+1 0 +-1 0 MAX 1/-1/-1 +-1 0 MIN 0 +-1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 -1 -1 1/-1/-1 +-1 -1 1 1/-1/-1 +-1 -1 -2 1/-1/-1 +-1 -1 2 1/-1/-1 +-1 -1 -3 1/-1/-1 +-1 -1 3 1/-1/-1 +-1 -1 17 1/-1/-1 +-1 -1 127 1/-1/-1 +-1 -1 MIN+1 1/-1/-1 +-1 -1 MAX 1/-1/-1 +-1 -1 MIN 1/-1/-1 +-1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 1 -1 0 +-1 1 1 3/-1/1 +-1 1 -2 0 +-1 1 2 2/-1/1 +-1 1 -3 0 +-1 1 3 1/-1/-1 +-1 1 17 1/-1/-1 +-1 1 127 1/-1/-1 +-1 1 MIN+1 0 +-1 1 MAX 1/-1/-1 +-1 1 MIN 0 +-1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 3 -1 0 +-1 3 1 5/-1/3 +-1 3 -2 0 +-1 3 2 3/-1/3 +-1 3 -3 0 +-1 3 3 2/-1/2 +-1 3 17 1/-1/-1 +-1 3 127 1/-1/-1 +-1 3 MIN+1 0 +-1 3 MAX 1/-1/-1 +-1 3 MIN 0 +-1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN+1 -1 MAX/-1/MIN+1 +-1 MIN+1 1 0 +-1 MIN+1 -2 1073741824/-1/MIN+1 +-1 MIN+1 2 0 +-1 MIN+1 -3 715827883/-1/MIN+1 +-1 MIN+1 3 0 +-1 MIN+1 17 0 +-1 MIN+1 127 0 +-1 MIN+1 MIN+1 1/-1/-1 +-1 MIN+1 MAX 0 +-1 MIN+1 MIN 1/-1/-1 +-1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MAX -1 0 +-1 MAX 1 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -2 0 +-1 MAX 2 1073741825/-1/MAX +-1 MAX -3 0 +-1 MAX 3 715827883/-1/MAX-2 +-1 MAX 17 126322568/-1/MAX-9 +-1 MAX 127 16909321/-1/MAX-8 +-1 MAX MIN+1 0 +-1 MAX MAX 2/-1/MAX-1 +-1 MAX MIN 0 +-1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN -1 --- + java.lang.IllegalArgumentException: -1 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +-1 MIN 1 0 +-1 MIN -2 1073741824/-1/MIN+1 +-1 MIN 2 0 +-1 MIN -3 715827883/-1/MIN+1 +-1 MIN 3 0 +-1 MIN 17 0 +-1 MIN 127 0 +-1 MIN MIN+1 2/-1/MIN +-1 MIN MAX 0 +-1 MIN MIN 1/-1/-1 + +start end step length/first/last +----------------------------------------- +1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 0 -1 2/1/0 +1 0 1 0 +1 0 -2 1/1/1 +1 0 2 0 +1 0 -3 1/1/1 +1 0 3 0 +1 0 17 0 +1 0 127 0 +1 0 MIN+1 1/1/1 +1 0 MAX 0 +1 0 MIN 1/1/1 +1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 -1 -1 3/1/-1 +1 -1 1 0 +1 -1 -2 2/1/-1 +1 -1 2 0 +1 -1 -3 1/1/1 +1 -1 3 0 +1 -1 17 0 +1 -1 127 0 +1 -1 MIN+1 1/1/1 +1 -1 MAX 0 +1 -1 MIN 1/1/1 +1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 1 -1 1/1/1 +1 1 1 1/1/1 +1 1 -2 1/1/1 +1 1 2 1/1/1 +1 1 -3 1/1/1 +1 1 3 1/1/1 +1 1 17 1/1/1 +1 1 127 1/1/1 +1 1 MIN+1 1/1/1 +1 1 MAX 1/1/1 +1 1 MIN 1/1/1 +1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 3 -1 0 +1 3 1 3/1/3 +1 3 -2 0 +1 3 2 2/1/3 +1 3 -3 0 +1 3 3 1/1/1 +1 3 17 1/1/1 +1 3 127 1/1/1 +1 3 MIN+1 0 +1 3 MAX 1/1/1 +1 3 MIN 0 +1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN+1 -1 --- + java.lang.IllegalArgumentException: 1 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN+1 1 0 +1 MIN+1 -2 1073741825/1/MIN+1 +1 MIN+1 2 0 +1 MIN+1 -3 715827883/1/MIN+3 +1 MIN+1 3 0 +1 MIN+1 17 0 +1 MIN+1 127 0 +1 MIN+1 MIN+1 2/1/MIN+2 +1 MIN+1 MAX 0 +1 MIN+1 MIN 2/1/MIN+1 +1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MAX -1 0 +1 MAX 1 MAX/1/MAX +1 MAX -2 0 +1 MAX 2 1073741824/1/MAX +1 MAX -3 0 +1 MAX 3 715827883/1/MAX +1 MAX 17 126322568/1/MAX-7 +1 MAX 127 16909321/1/MAX-6 +1 MAX MIN+1 0 +1 MAX MAX 1/1/1 +1 MAX MIN 0 +1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN -1 --- + java.lang.IllegalArgumentException: 1 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN 1 0 +1 MIN -2 1073741825/1/MIN+1 +1 MIN 2 0 +1 MIN -3 715827884/1/MIN +1 MIN 3 0 +1 MIN 17 0 +1 MIN 127 0 +1 MIN MIN+1 2/1/MIN+2 +1 MIN MAX 0 +1 MIN MIN 2/1/MIN+1 + +start end step length/first/last +----------------------------------------- +3 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 0 -1 4/3/0 +3 0 1 0 +3 0 -2 2/3/1 +3 0 2 0 +3 0 -3 2/3/0 +3 0 3 0 +3 0 17 0 +3 0 127 0 +3 0 MIN+1 1/3/3 +3 0 MAX 0 +3 0 MIN 1/3/3 +3 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 -1 -1 5/3/-1 +3 -1 1 0 +3 -1 -2 3/3/-1 +3 -1 2 0 +3 -1 -3 2/3/0 +3 -1 3 0 +3 -1 17 0 +3 -1 127 0 +3 -1 MIN+1 1/3/3 +3 -1 MAX 0 +3 -1 MIN 1/3/3 +3 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 1 -1 3/3/1 +3 1 1 0 +3 1 -2 2/3/1 +3 1 2 0 +3 1 -3 1/3/3 +3 1 3 0 +3 1 17 0 +3 1 127 0 +3 1 MIN+1 1/3/3 +3 1 MAX 0 +3 1 MIN 1/3/3 +3 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 3 -1 1/3/3 +3 3 1 1/3/3 +3 3 -2 1/3/3 +3 3 2 1/3/3 +3 3 -3 1/3/3 +3 3 3 1/3/3 +3 3 17 1/3/3 +3 3 127 1/3/3 +3 3 MIN+1 1/3/3 +3 3 MAX 1/3/3 +3 3 MIN 1/3/3 +3 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN+1 -1 --- + java.lang.IllegalArgumentException: 3 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN+1 1 0 +3 MIN+1 -2 1073741826/3/MIN+1 +3 MIN+1 2 0 +3 MIN+1 -3 715827884/3/MIN+2 +3 MIN+1 3 0 +3 MIN+1 17 0 +3 MIN+1 127 0 +3 MIN+1 MIN+1 2/3/MIN+4 +3 MIN+1 MAX 0 +3 MIN+1 MIN 2/3/MIN+3 +3 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MAX -1 0 +3 MAX 1 MAX-2/3/MAX +3 MAX -2 0 +3 MAX 2 1073741823/3/MAX +3 MAX -3 0 +3 MAX 3 715827882/3/MAX-1 +3 MAX 17 126322568/3/MAX-5 +3 MAX 127 16909321/3/MAX-4 +3 MAX MIN+1 0 +3 MAX MAX 1/3/3 +3 MAX MIN 0 +3 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN -1 --- + java.lang.IllegalArgumentException: 3 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN 1 0 +3 MIN -2 1073741826/3/MIN+1 +3 MIN 2 0 +3 MIN -3 715827884/3/MIN+2 +3 MIN 3 0 +3 MIN 17 0 +3 MIN 127 0 +3 MIN MIN+1 2/3/MIN+4 +3 MIN MAX 0 +3 MIN MIN 2/3/MIN+3 + +start end step length/first/last +----------------------------------------- +MIN+1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 0 -1 0 +MIN+1 0 1 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 -2 0 +MIN+1 0 2 1073741824/MIN+1/-1 +MIN+1 0 -3 0 +MIN+1 0 3 715827883/MIN+1/-1 +MIN+1 0 17 126322568/MIN+1/-8 +MIN+1 0 127 16909321/MIN+1/-7 +MIN+1 0 MIN+1 0 +MIN+1 0 MAX 2/MIN+1/0 +MIN+1 0 MIN 0 +MIN+1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 -1 -1 0 +MIN+1 -1 1 MAX/MIN+1/-1 +MIN+1 -1 -2 0 +MIN+1 -1 2 1073741824/MIN+1/-1 +MIN+1 -1 -3 0 +MIN+1 -1 3 715827883/MIN+1/-1 +MIN+1 -1 17 126322568/MIN+1/-8 +MIN+1 -1 127 16909321/MIN+1/-7 +MIN+1 -1 MIN+1 0 +MIN+1 -1 MAX 1/MIN+1/MIN+1 +MIN+1 -1 MIN 0 +MIN+1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 1 -1 0 +MIN+1 1 1 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -2 0 +MIN+1 1 2 1073741825/MIN+1/1 +MIN+1 1 -3 0 +MIN+1 1 3 715827883/MIN+1/-1 +MIN+1 1 17 126322568/MIN+1/-8 +MIN+1 1 127 16909321/MIN+1/-7 +MIN+1 1 MIN+1 0 +MIN+1 1 MAX 2/MIN+1/0 +MIN+1 1 MIN 0 +MIN+1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 3 -1 0 +MIN+1 3 1 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -2 0 +MIN+1 3 2 1073741826/MIN+1/3 +MIN+1 3 -3 0 +MIN+1 3 3 715827884/MIN+1/2 +MIN+1 3 17 126322568/MIN+1/-8 +MIN+1 3 127 16909321/MIN+1/-7 +MIN+1 3 MIN+1 0 +MIN+1 3 MAX 2/MIN+1/0 +MIN+1 3 MIN 0 +MIN+1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN+1 -1 1/MIN+1/MIN+1 +MIN+1 MIN+1 1 1/MIN+1/MIN+1 +MIN+1 MIN+1 -2 1/MIN+1/MIN+1 +MIN+1 MIN+1 2 1/MIN+1/MIN+1 +MIN+1 MIN+1 -3 1/MIN+1/MIN+1 +MIN+1 MIN+1 3 1/MIN+1/MIN+1 +MIN+1 MIN+1 17 1/MIN+1/MIN+1 +MIN+1 MIN+1 127 1/MIN+1/MIN+1 +MIN+1 MIN+1 MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN+1 MAX 1/MIN+1/MIN+1 +MIN+1 MIN+1 MIN 1/MIN+1/MIN+1 +MIN+1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MAX -1 0 +MIN+1 MAX 1 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -2 0 +MIN+1 MAX 2 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 2: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -3 0 +MIN+1 MAX 3 1431655765/MIN+1/MAX-2 +MIN+1 MAX 17 252645135/MIN+1/MAX-16 +MIN+1 MAX 127 33818641/MIN+1/MAX-14 +MIN+1 MAX MIN+1 0 +MIN+1 MAX MAX 3/MIN+1/MAX +MIN+1 MAX MIN 0 +MIN+1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN -1 2/MIN+1/MIN +MIN+1 MIN 1 0 +MIN+1 MIN -2 1/MIN+1/MIN+1 +MIN+1 MIN 2 0 +MIN+1 MIN -3 1/MIN+1/MIN+1 +MIN+1 MIN 3 0 +MIN+1 MIN 17 0 +MIN+1 MIN 127 0 +MIN+1 MIN MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN MAX 0 +MIN+1 MIN MIN 1/MIN+1/MIN+1 + +start end step length/first/last +----------------------------------------- +MAX 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 0 -1 --- + java.lang.IllegalArgumentException: 2147483647 to 0 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX 0 1 0 +MAX 0 -2 1073741824/MAX/1 +MAX 0 2 0 +MAX 0 -3 715827883/MAX/1 +MAX 0 3 0 +MAX 0 17 0 +MAX 0 127 0 +MAX 0 MIN+1 2/MAX/0 +MAX 0 MAX 0 +MAX 0 MIN 1/MAX/MAX +MAX -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX -1 -1 --- + java.lang.IllegalArgumentException: 2147483647 to -1 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX -1 1 0 +MAX -1 -2 1073741825/MAX/-1 +MAX -1 2 0 +MAX -1 -3 715827883/MAX/1 +MAX -1 3 0 +MAX -1 17 0 +MAX -1 127 0 +MAX -1 MIN+1 2/MAX/0 +MAX -1 MAX 0 +MAX -1 MIN 2/MAX/-1 +MAX 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 1 -1 MAX/MAX/1 +MAX 1 1 0 +MAX 1 -2 1073741824/MAX/1 +MAX 1 2 0 +MAX 1 -3 715827883/MAX/1 +MAX 1 3 0 +MAX 1 17 0 +MAX 1 127 0 +MAX 1 MIN+1 1/MAX/MAX +MAX 1 MAX 0 +MAX 1 MIN 1/MAX/MAX +MAX 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 3 -1 MAX-2/MAX/3 +MAX 3 1 0 +MAX 3 -2 1073741823/MAX/3 +MAX 3 2 0 +MAX 3 -3 715827882/MAX/4 +MAX 3 3 0 +MAX 3 17 0 +MAX 3 127 0 +MAX 3 MIN+1 1/MAX/MAX +MAX 3 MAX 0 +MAX 3 MIN 1/MAX/MAX +MAX MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN+1 -1 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN+1 1 0 +MAX MIN+1 -2 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483647 by -2: seqs cannot contain more than Int.MaxValue elements. +MAX MIN+1 2 0 +MAX MIN+1 -3 1431655765/MAX/MIN+3 +MAX MIN+1 3 0 +MAX MIN+1 17 0 +MAX MIN+1 127 0 +MAX MIN+1 MIN+1 3/MAX/MIN+1 +MAX MIN+1 MAX 0 +MAX MIN+1 MIN 2/MAX/-1 +MAX MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MAX -1 1/MAX/MAX +MAX MAX 1 1/MAX/MAX +MAX MAX -2 1/MAX/MAX +MAX MAX 2 1/MAX/MAX +MAX MAX -3 1/MAX/MAX +MAX MAX 3 1/MAX/MAX +MAX MAX 17 1/MAX/MAX +MAX MAX 127 1/MAX/MAX +MAX MAX MIN+1 1/MAX/MAX +MAX MAX MAX 1/MAX/MAX +MAX MAX MIN 1/MAX/MAX +MAX MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN -1 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 1 0 +MAX MIN -2 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483648 by -2: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 2 0 +MAX MIN -3 1431655766/MAX/MIN +MAX MIN 3 0 +MAX MIN 17 0 +MAX MIN 127 0 +MAX MIN MIN+1 3/MAX/MIN+1 +MAX MIN MAX 0 +MAX MIN MIN 2/MAX/-1 + +start end step length/first/last +----------------------------------------- +MIN 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 0 -1 0 +MIN 0 1 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -2 0 +MIN 0 2 1073741825/MIN/0 +MIN 0 -3 0 +MIN 0 3 715827883/MIN/-2 +MIN 0 17 126322568/MIN/-9 +MIN 0 127 16909321/MIN/-8 +MIN 0 MIN+1 0 +MIN 0 MAX 2/MIN/-1 +MIN 0 MIN 0 +MIN -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN -1 -1 0 +MIN -1 1 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 -2 0 +MIN -1 2 1073741824/MIN/-2 +MIN -1 -3 0 +MIN -1 3 715827883/MIN/-2 +MIN -1 17 126322568/MIN/-9 +MIN -1 127 16909321/MIN/-8 +MIN -1 MIN+1 0 +MIN -1 MAX 2/MIN/-1 +MIN -1 MIN 0 +MIN 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 1 -1 0 +MIN 1 1 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -2 0 +MIN 1 2 1073741825/MIN/0 +MIN 1 -3 0 +MIN 1 3 715827884/MIN/1 +MIN 1 17 126322568/MIN/-9 +MIN 1 127 16909321/MIN/-8 +MIN 1 MIN+1 0 +MIN 1 MAX 2/MIN/-1 +MIN 1 MIN 0 +MIN 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 3 -1 0 +MIN 3 1 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -2 0 +MIN 3 2 1073741826/MIN/2 +MIN 3 -3 0 +MIN 3 3 715827884/MIN/1 +MIN 3 17 126322568/MIN/-9 +MIN 3 127 16909321/MIN/-8 +MIN 3 MIN+1 0 +MIN 3 MAX 2/MIN/-1 +MIN 3 MIN 0 +MIN MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN+1 -1 0 +MIN MIN+1 1 2/MIN/MIN+1 +MIN MIN+1 -2 0 +MIN MIN+1 2 1/MIN/MIN +MIN MIN+1 -3 0 +MIN MIN+1 3 1/MIN/MIN +MIN MIN+1 17 1/MIN/MIN +MIN MIN+1 127 1/MIN/MIN +MIN MIN+1 MIN+1 0 +MIN MIN+1 MAX 1/MIN/MIN +MIN MIN+1 MIN 0 +MIN MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MAX -1 0 +MIN MAX 1 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -2 0 +MIN MAX 2 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 2: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -3 0 +MIN MAX 3 1431655766/MIN/MAX +MIN MAX 17 252645136/MIN/MAX +MIN MAX 127 33818641/MIN/MAX-15 +MIN MAX MIN+1 0 +MIN MAX MAX 3/MIN/MAX-1 +MIN MAX MIN 0 +MIN MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN -1 1/MIN/MIN +MIN MIN 1 1/MIN/MIN +MIN MIN -2 1/MIN/MIN +MIN MIN 2 1/MIN/MIN +MIN MIN -3 1/MIN/MIN +MIN MIN 3 1/MIN/MIN +MIN MIN 17 1/MIN/MIN +MIN MIN 127 1/MIN/MIN +MIN MIN MIN+1 1/MIN/MIN +MIN MIN MAX 1/MIN/MIN +MIN MIN MIN 1/MIN/MIN + +>>> Range.apply <<< + +start end step length/first/last +----------------------------------------- +0 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 0 -1 0 +0 0 1 0 +0 0 -2 0 +0 0 2 0 +0 0 -3 0 +0 0 3 0 +0 0 17 0 +0 0 127 0 +0 0 MIN+1 0 +0 0 MAX 0 +0 0 MIN 0 +0 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 -1 -1 1/0/0 +0 -1 1 0 +0 -1 -2 1/0/0 +0 -1 2 0 +0 -1 -3 1/0/0 +0 -1 3 0 +0 -1 17 0 +0 -1 127 0 +0 -1 MIN+1 1/0/0 +0 -1 MAX 0 +0 -1 MIN 1/0/0 +0 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 1 -1 0 +0 1 1 1/0/0 +0 1 -2 0 +0 1 2 1/0/0 +0 1 -3 0 +0 1 3 1/0/0 +0 1 17 1/0/0 +0 1 127 1/0/0 +0 1 MIN+1 0 +0 1 MAX 1/0/0 +0 1 MIN 0 +0 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 3 -1 0 +0 3 1 3/0/2 +0 3 -2 0 +0 3 2 2/0/2 +0 3 -3 0 +0 3 3 1/0/0 +0 3 17 1/0/0 +0 3 127 1/0/0 +0 3 MIN+1 0 +0 3 MAX 1/0/0 +0 3 MIN 0 +0 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN+1 -1 MAX/0/MIN+2 +0 MIN+1 1 0 +0 MIN+1 -2 1073741824/0/MIN+2 +0 MIN+1 2 0 +0 MIN+1 -3 715827883/0/MIN+2 +0 MIN+1 3 0 +0 MIN+1 17 0 +0 MIN+1 127 0 +0 MIN+1 MIN+1 1/0/0 +0 MIN+1 MAX 0 +0 MIN+1 MIN 1/0/0 +0 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MAX -1 0 +0 MAX 1 MAX/0/MAX-1 +0 MAX -2 0 +0 MAX 2 1073741824/0/MAX-1 +0 MAX -3 0 +0 MAX 3 715827883/0/MAX-1 +0 MAX 17 126322568/0/MAX-8 +0 MAX 127 16909321/0/MAX-7 +0 MAX MIN+1 0 +0 MAX MAX 1/0/0 +0 MAX MIN 0 +0 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN -1 --- + java.lang.IllegalArgumentException: 0 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +0 MIN 1 0 +0 MIN -2 1073741824/0/MIN+2 +0 MIN 2 0 +0 MIN -3 715827883/0/MIN+2 +0 MIN 3 0 +0 MIN 17 0 +0 MIN 127 0 +0 MIN MIN+1 2/0/MIN+1 +0 MIN MAX 0 +0 MIN MIN 1/0/0 + +start end step length/first/last +----------------------------------------- +-1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 0 -1 0 +-1 0 1 1/-1/-1 +-1 0 -2 0 +-1 0 2 1/-1/-1 +-1 0 -3 0 +-1 0 3 1/-1/-1 +-1 0 17 1/-1/-1 +-1 0 127 1/-1/-1 +-1 0 MIN+1 0 +-1 0 MAX 1/-1/-1 +-1 0 MIN 0 +-1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 -1 -1 0 +-1 -1 1 0 +-1 -1 -2 0 +-1 -1 2 0 +-1 -1 -3 0 +-1 -1 3 0 +-1 -1 17 0 +-1 -1 127 0 +-1 -1 MIN+1 0 +-1 -1 MAX 0 +-1 -1 MIN 0 +-1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 1 -1 0 +-1 1 1 2/-1/0 +-1 1 -2 0 +-1 1 2 1/-1/-1 +-1 1 -3 0 +-1 1 3 1/-1/-1 +-1 1 17 1/-1/-1 +-1 1 127 1/-1/-1 +-1 1 MIN+1 0 +-1 1 MAX 1/-1/-1 +-1 1 MIN 0 +-1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 3 -1 0 +-1 3 1 4/-1/2 +-1 3 -2 0 +-1 3 2 2/-1/1 +-1 3 -3 0 +-1 3 3 2/-1/2 +-1 3 17 1/-1/-1 +-1 3 127 1/-1/-1 +-1 3 MIN+1 0 +-1 3 MAX 1/-1/-1 +-1 3 MIN 0 +-1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN+1 -1 MAX-1/-1/MIN+2 +-1 MIN+1 1 0 +-1 MIN+1 -2 1073741823/-1/MIN+3 +-1 MIN+1 2 0 +-1 MIN+1 -3 715827882/-1/MIN+4 +-1 MIN+1 3 0 +-1 MIN+1 17 0 +-1 MIN+1 127 0 +-1 MIN+1 MIN+1 1/-1/-1 +-1 MIN+1 MAX 0 +-1 MIN+1 MIN 1/-1/-1 +-1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MAX -1 0 +-1 MAX 1 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -2 0 +-1 MAX 2 1073741824/-1/MAX-2 +-1 MAX -3 0 +-1 MAX 3 715827883/-1/MAX-2 +-1 MAX 17 126322568/-1/MAX-9 +-1 MAX 127 16909321/-1/MAX-8 +-1 MAX MIN+1 0 +-1 MAX MAX 2/-1/MAX-1 +-1 MAX MIN 0 +-1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN -1 MAX/-1/MIN+1 +-1 MIN 1 0 +-1 MIN -2 1073741824/-1/MIN+1 +-1 MIN 2 0 +-1 MIN -3 715827883/-1/MIN+1 +-1 MIN 3 0 +-1 MIN 17 0 +-1 MIN 127 0 +-1 MIN MIN+1 1/-1/-1 +-1 MIN MAX 0 +-1 MIN MIN 1/-1/-1 + +start end step length/first/last +----------------------------------------- +1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 0 -1 1/1/1 +1 0 1 0 +1 0 -2 1/1/1 +1 0 2 0 +1 0 -3 1/1/1 +1 0 3 0 +1 0 17 0 +1 0 127 0 +1 0 MIN+1 1/1/1 +1 0 MAX 0 +1 0 MIN 1/1/1 +1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 -1 -1 2/1/0 +1 -1 1 0 +1 -1 -2 1/1/1 +1 -1 2 0 +1 -1 -3 1/1/1 +1 -1 3 0 +1 -1 17 0 +1 -1 127 0 +1 -1 MIN+1 1/1/1 +1 -1 MAX 0 +1 -1 MIN 1/1/1 +1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 1 -1 0 +1 1 1 0 +1 1 -2 0 +1 1 2 0 +1 1 -3 0 +1 1 3 0 +1 1 17 0 +1 1 127 0 +1 1 MIN+1 0 +1 1 MAX 0 +1 1 MIN 0 +1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 3 -1 0 +1 3 1 2/1/2 +1 3 -2 0 +1 3 2 1/1/1 +1 3 -3 0 +1 3 3 1/1/1 +1 3 17 1/1/1 +1 3 127 1/1/1 +1 3 MIN+1 0 +1 3 MAX 1/1/1 +1 3 MIN 0 +1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN+1 -1 --- + java.lang.IllegalArgumentException: 1 until -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN+1 1 0 +1 MIN+1 -2 1073741824/1/MIN+3 +1 MIN+1 2 0 +1 MIN+1 -3 715827883/1/MIN+3 +1 MIN+1 3 0 +1 MIN+1 17 0 +1 MIN+1 127 0 +1 MIN+1 MIN+1 2/1/MIN+2 +1 MIN+1 MAX 0 +1 MIN+1 MIN 1/1/1 +1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MAX -1 0 +1 MAX 1 MAX-1/1/MAX-1 +1 MAX -2 0 +1 MAX 2 1073741823/1/MAX-2 +1 MAX -3 0 +1 MAX 3 715827882/1/MAX-3 +1 MAX 17 126322568/1/MAX-7 +1 MAX 127 16909321/1/MAX-6 +1 MAX MIN+1 0 +1 MAX MAX 1/1/1 +1 MAX MIN 0 +1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN -1 --- + java.lang.IllegalArgumentException: 1 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN 1 0 +1 MIN -2 1073741825/1/MIN+1 +1 MIN 2 0 +1 MIN -3 715827883/1/MIN+3 +1 MIN 3 0 +1 MIN 17 0 +1 MIN 127 0 +1 MIN MIN+1 2/1/MIN+2 +1 MIN MAX 0 +1 MIN MIN 2/1/MIN+1 + +start end step length/first/last +----------------------------------------- +3 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 0 -1 3/3/1 +3 0 1 0 +3 0 -2 2/3/1 +3 0 2 0 +3 0 -3 1/3/3 +3 0 3 0 +3 0 17 0 +3 0 127 0 +3 0 MIN+1 1/3/3 +3 0 MAX 0 +3 0 MIN 1/3/3 +3 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 -1 -1 4/3/0 +3 -1 1 0 +3 -1 -2 2/3/1 +3 -1 2 0 +3 -1 -3 2/3/0 +3 -1 3 0 +3 -1 17 0 +3 -1 127 0 +3 -1 MIN+1 1/3/3 +3 -1 MAX 0 +3 -1 MIN 1/3/3 +3 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 1 -1 2/3/2 +3 1 1 0 +3 1 -2 1/3/3 +3 1 2 0 +3 1 -3 1/3/3 +3 1 3 0 +3 1 17 0 +3 1 127 0 +3 1 MIN+1 1/3/3 +3 1 MAX 0 +3 1 MIN 1/3/3 +3 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 3 -1 0 +3 3 1 0 +3 3 -2 0 +3 3 2 0 +3 3 -3 0 +3 3 3 0 +3 3 17 0 +3 3 127 0 +3 3 MIN+1 0 +3 3 MAX 0 +3 3 MIN 0 +3 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN+1 -1 --- + java.lang.IllegalArgumentException: 3 until -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN+1 1 0 +3 MIN+1 -2 1073741825/3/MIN+3 +3 MIN+1 2 0 +3 MIN+1 -3 715827884/3/MIN+2 +3 MIN+1 3 0 +3 MIN+1 17 0 +3 MIN+1 127 0 +3 MIN+1 MIN+1 2/3/MIN+4 +3 MIN+1 MAX 0 +3 MIN+1 MIN 2/3/MIN+3 +3 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MAX -1 0 +3 MAX 1 MAX-3/3/MAX-1 +3 MAX -2 0 +3 MAX 2 1073741822/3/MAX-2 +3 MAX -3 0 +3 MAX 3 715827882/3/MAX-1 +3 MAX 17 126322568/3/MAX-5 +3 MAX 127 16909321/3/MAX-4 +3 MAX MIN+1 0 +3 MAX MAX 1/3/3 +3 MAX MIN 0 +3 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN -1 --- + java.lang.IllegalArgumentException: 3 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN 1 0 +3 MIN -2 1073741826/3/MIN+1 +3 MIN 2 0 +3 MIN -3 715827884/3/MIN+2 +3 MIN 3 0 +3 MIN 17 0 +3 MIN 127 0 +3 MIN MIN+1 2/3/MIN+4 +3 MIN MAX 0 +3 MIN MIN 2/3/MIN+3 + +start end step length/first/last +----------------------------------------- +MIN+1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 0 -1 0 +MIN+1 0 1 MAX/MIN+1/-1 +MIN+1 0 -2 0 +MIN+1 0 2 1073741824/MIN+1/-1 +MIN+1 0 -3 0 +MIN+1 0 3 715827883/MIN+1/-1 +MIN+1 0 17 126322568/MIN+1/-8 +MIN+1 0 127 16909321/MIN+1/-7 +MIN+1 0 MIN+1 0 +MIN+1 0 MAX 1/MIN+1/MIN+1 +MIN+1 0 MIN 0 +MIN+1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 -1 -1 0 +MIN+1 -1 1 MAX-1/MIN+1/-2 +MIN+1 -1 -2 0 +MIN+1 -1 2 1073741823/MIN+1/-3 +MIN+1 -1 -3 0 +MIN+1 -1 3 715827882/MIN+1/-4 +MIN+1 -1 17 126322568/MIN+1/-8 +MIN+1 -1 127 16909321/MIN+1/-7 +MIN+1 -1 MIN+1 0 +MIN+1 -1 MAX 1/MIN+1/MIN+1 +MIN+1 -1 MIN 0 +MIN+1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 1 -1 0 +MIN+1 1 1 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -2 0 +MIN+1 1 2 1073741824/MIN+1/-1 +MIN+1 1 -3 0 +MIN+1 1 3 715827883/MIN+1/-1 +MIN+1 1 17 126322568/MIN+1/-8 +MIN+1 1 127 16909321/MIN+1/-7 +MIN+1 1 MIN+1 0 +MIN+1 1 MAX 2/MIN+1/0 +MIN+1 1 MIN 0 +MIN+1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 3 -1 0 +MIN+1 3 1 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -2 0 +MIN+1 3 2 1073741825/MIN+1/1 +MIN+1 3 -3 0 +MIN+1 3 3 715827884/MIN+1/2 +MIN+1 3 17 126322568/MIN+1/-8 +MIN+1 3 127 16909321/MIN+1/-7 +MIN+1 3 MIN+1 0 +MIN+1 3 MAX 2/MIN+1/0 +MIN+1 3 MIN 0 +MIN+1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN+1 -1 0 +MIN+1 MIN+1 1 0 +MIN+1 MIN+1 -2 0 +MIN+1 MIN+1 2 0 +MIN+1 MIN+1 -3 0 +MIN+1 MIN+1 3 0 +MIN+1 MIN+1 17 0 +MIN+1 MIN+1 127 0 +MIN+1 MIN+1 MIN+1 0 +MIN+1 MIN+1 MAX 0 +MIN+1 MIN+1 MIN 0 +MIN+1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MAX -1 0 +MIN+1 MAX 1 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -2 0 +MIN+1 MAX 2 MAX/MIN+1/MAX-2 +MIN+1 MAX -3 0 +MIN+1 MAX 3 1431655765/MIN+1/MAX-2 +MIN+1 MAX 17 252645135/MIN+1/MAX-16 +MIN+1 MAX 127 33818641/MIN+1/MAX-14 +MIN+1 MAX MIN+1 0 +MIN+1 MAX MAX 2/MIN+1/0 +MIN+1 MAX MIN 0 +MIN+1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN -1 1/MIN+1/MIN+1 +MIN+1 MIN 1 0 +MIN+1 MIN -2 1/MIN+1/MIN+1 +MIN+1 MIN 2 0 +MIN+1 MIN -3 1/MIN+1/MIN+1 +MIN+1 MIN 3 0 +MIN+1 MIN 17 0 +MIN+1 MIN 127 0 +MIN+1 MIN MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN MAX 0 +MIN+1 MIN MIN 1/MIN+1/MIN+1 + +start end step length/first/last +----------------------------------------- +MAX 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 0 -1 MAX/MAX/1 +MAX 0 1 0 +MAX 0 -2 1073741824/MAX/1 +MAX 0 2 0 +MAX 0 -3 715827883/MAX/1 +MAX 0 3 0 +MAX 0 17 0 +MAX 0 127 0 +MAX 0 MIN+1 1/MAX/MAX +MAX 0 MAX 0 +MAX 0 MIN 1/MAX/MAX +MAX -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX -1 -1 --- + java.lang.IllegalArgumentException: 2147483647 until -1 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX -1 1 0 +MAX -1 -2 1073741824/MAX/1 +MAX -1 2 0 +MAX -1 -3 715827883/MAX/1 +MAX -1 3 0 +MAX -1 17 0 +MAX -1 127 0 +MAX -1 MIN+1 2/MAX/0 +MAX -1 MAX 0 +MAX -1 MIN 1/MAX/MAX +MAX 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 1 -1 MAX-1/MAX/2 +MAX 1 1 0 +MAX 1 -2 1073741823/MAX/3 +MAX 1 2 0 +MAX 1 -3 715827882/MAX/4 +MAX 1 3 0 +MAX 1 17 0 +MAX 1 127 0 +MAX 1 MIN+1 1/MAX/MAX +MAX 1 MAX 0 +MAX 1 MIN 1/MAX/MAX +MAX 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 3 -1 MAX-3/MAX/4 +MAX 3 1 0 +MAX 3 -2 1073741822/MAX/5 +MAX 3 2 0 +MAX 3 -3 715827882/MAX/4 +MAX 3 3 0 +MAX 3 17 0 +MAX 3 127 0 +MAX 3 MIN+1 1/MAX/MAX +MAX 3 MAX 0 +MAX 3 MIN 1/MAX/MAX +MAX MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN+1 -1 --- + java.lang.IllegalArgumentException: 2147483647 until -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN+1 1 0 +MAX MIN+1 -2 MAX/MAX/MIN+3 +MAX MIN+1 2 0 +MAX MIN+1 -3 1431655765/MAX/MIN+3 +MAX MIN+1 3 0 +MAX MIN+1 17 0 +MAX MIN+1 127 0 +MAX MIN+1 MIN+1 2/MAX/0 +MAX MIN+1 MAX 0 +MAX MIN+1 MIN 2/MAX/-1 +MAX MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MAX -1 0 +MAX MAX 1 0 +MAX MAX -2 0 +MAX MAX 2 0 +MAX MAX -3 0 +MAX MAX 3 0 +MAX MAX 17 0 +MAX MAX 127 0 +MAX MAX MIN+1 0 +MAX MAX MAX 0 +MAX MAX MIN 0 +MAX MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN -1 --- + java.lang.IllegalArgumentException: 2147483647 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 1 0 +MAX MIN -2 --- + java.lang.IllegalArgumentException: 2147483647 until -2147483648 by -2: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 2 0 +MAX MIN -3 1431655765/MAX/MIN+3 +MAX MIN 3 0 +MAX MIN 17 0 +MAX MIN 127 0 +MAX MIN MIN+1 3/MAX/MIN+1 +MAX MIN MAX 0 +MAX MIN MIN 2/MAX/-1 + +start end step length/first/last +----------------------------------------- +MIN 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 0 -1 0 +MIN 0 1 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -2 0 +MIN 0 2 1073741824/MIN/-2 +MIN 0 -3 0 +MIN 0 3 715827883/MIN/-2 +MIN 0 17 126322568/MIN/-9 +MIN 0 127 16909321/MIN/-8 +MIN 0 MIN+1 0 +MIN 0 MAX 2/MIN/-1 +MIN 0 MIN 0 +MIN -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN -1 -1 0 +MIN -1 1 MAX/MIN/-2 +MIN -1 -2 0 +MIN -1 2 1073741824/MIN/-2 +MIN -1 -3 0 +MIN -1 3 715827883/MIN/-2 +MIN -1 17 126322568/MIN/-9 +MIN -1 127 16909321/MIN/-8 +MIN -1 MIN+1 0 +MIN -1 MAX 1/MIN/MIN +MIN -1 MIN 0 +MIN 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 1 -1 0 +MIN 1 1 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -2 0 +MIN 1 2 1073741825/MIN/0 +MIN 1 -3 0 +MIN 1 3 715827883/MIN/-2 +MIN 1 17 126322568/MIN/-9 +MIN 1 127 16909321/MIN/-8 +MIN 1 MIN+1 0 +MIN 1 MAX 2/MIN/-1 +MIN 1 MIN 0 +MIN 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 3 -1 0 +MIN 3 1 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -2 0 +MIN 3 2 1073741826/MIN/2 +MIN 3 -3 0 +MIN 3 3 715827884/MIN/1 +MIN 3 17 126322568/MIN/-9 +MIN 3 127 16909321/MIN/-8 +MIN 3 MIN+1 0 +MIN 3 MAX 2/MIN/-1 +MIN 3 MIN 0 +MIN MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN+1 -1 0 +MIN MIN+1 1 1/MIN/MIN +MIN MIN+1 -2 0 +MIN MIN+1 2 1/MIN/MIN +MIN MIN+1 -3 0 +MIN MIN+1 3 1/MIN/MIN +MIN MIN+1 17 1/MIN/MIN +MIN MIN+1 127 1/MIN/MIN +MIN MIN+1 MIN+1 0 +MIN MIN+1 MAX 1/MIN/MIN +MIN MIN+1 MIN 0 +MIN MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MAX -1 0 +MIN MAX 1 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -2 0 +MIN MAX 2 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 2: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -3 0 +MIN MAX 3 1431655765/MIN/MAX-3 +MIN MAX 17 252645135/MIN/MAX-17 +MIN MAX 127 33818641/MIN/MAX-15 +MIN MAX MIN+1 0 +MIN MAX MAX 3/MIN/MAX-1 +MIN MAX MIN 0 +MIN MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN -1 0 +MIN MIN 1 0 +MIN MIN -2 0 +MIN MIN 2 0 +MIN MIN -3 0 +MIN MIN 3 0 +MIN MIN 17 0 +MIN MIN 127 0 +MIN MIN MIN+1 0 +MIN MIN MAX 0 +MIN MIN MIN 0 + +>>> start to end <<< + +start end step length/first/last +----------------------------------------- +0 0 0 1/0/0 +0 0 -1 1/0/0 +0 0 1 1/0/0 +0 0 -2 1/0/0 +0 0 2 1/0/0 +0 0 -3 1/0/0 +0 0 3 1/0/0 +0 0 17 1/0/0 +0 0 127 1/0/0 +0 0 MIN+1 1/0/0 +0 0 MAX 1/0/0 +0 0 MIN 1/0/0 +0 -1 0 0 +0 -1 -1 0 +0 -1 1 0 +0 -1 -2 0 +0 -1 2 0 +0 -1 -3 0 +0 -1 3 0 +0 -1 17 0 +0 -1 127 0 +0 -1 MIN+1 0 +0 -1 MAX 0 +0 -1 MIN 0 +0 1 0 2/0/1 +0 1 -1 2/0/1 +0 1 1 2/0/1 +0 1 -2 2/0/1 +0 1 2 2/0/1 +0 1 -3 2/0/1 +0 1 3 2/0/1 +0 1 17 2/0/1 +0 1 127 2/0/1 +0 1 MIN+1 2/0/1 +0 1 MAX 2/0/1 +0 1 MIN 2/0/1 +0 3 0 4/0/3 +0 3 -1 4/0/3 +0 3 1 4/0/3 +0 3 -2 4/0/3 +0 3 2 4/0/3 +0 3 -3 4/0/3 +0 3 3 4/0/3 +0 3 17 4/0/3 +0 3 127 4/0/3 +0 3 MIN+1 4/0/3 +0 3 MAX 4/0/3 +0 3 MIN 4/0/3 +0 MIN+1 0 0 +0 MIN+1 -1 0 +0 MIN+1 1 0 +0 MIN+1 -2 0 +0 MIN+1 2 0 +0 MIN+1 -3 0 +0 MIN+1 3 0 +0 MIN+1 17 0 +0 MIN+1 127 0 +0 MIN+1 MIN+1 0 +0 MIN+1 MAX 0 +0 MIN+1 MIN 0 +0 MAX 0 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX -1 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX 1 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX -2 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX 2 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX -3 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX 3 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX 17 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX 127 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX MIN+1 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX MAX --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX MIN --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MIN 0 0 +0 MIN -1 0 +0 MIN 1 0 +0 MIN -2 0 +0 MIN 2 0 +0 MIN -3 0 +0 MIN 3 0 +0 MIN 17 0 +0 MIN 127 0 +0 MIN MIN+1 0 +0 MIN MAX 0 +0 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +-1 0 0 2/-1/0 +-1 0 -1 2/-1/0 +-1 0 1 2/-1/0 +-1 0 -2 2/-1/0 +-1 0 2 2/-1/0 +-1 0 -3 2/-1/0 +-1 0 3 2/-1/0 +-1 0 17 2/-1/0 +-1 0 127 2/-1/0 +-1 0 MIN+1 2/-1/0 +-1 0 MAX 2/-1/0 +-1 0 MIN 2/-1/0 +-1 -1 0 1/-1/-1 +-1 -1 -1 1/-1/-1 +-1 -1 1 1/-1/-1 +-1 -1 -2 1/-1/-1 +-1 -1 2 1/-1/-1 +-1 -1 -3 1/-1/-1 +-1 -1 3 1/-1/-1 +-1 -1 17 1/-1/-1 +-1 -1 127 1/-1/-1 +-1 -1 MIN+1 1/-1/-1 +-1 -1 MAX 1/-1/-1 +-1 -1 MIN 1/-1/-1 +-1 1 0 3/-1/1 +-1 1 -1 3/-1/1 +-1 1 1 3/-1/1 +-1 1 -2 3/-1/1 +-1 1 2 3/-1/1 +-1 1 -3 3/-1/1 +-1 1 3 3/-1/1 +-1 1 17 3/-1/1 +-1 1 127 3/-1/1 +-1 1 MIN+1 3/-1/1 +-1 1 MAX 3/-1/1 +-1 1 MIN 3/-1/1 +-1 3 0 5/-1/3 +-1 3 -1 5/-1/3 +-1 3 1 5/-1/3 +-1 3 -2 5/-1/3 +-1 3 2 5/-1/3 +-1 3 -3 5/-1/3 +-1 3 3 5/-1/3 +-1 3 17 5/-1/3 +-1 3 127 5/-1/3 +-1 3 MIN+1 5/-1/3 +-1 3 MAX 5/-1/3 +-1 3 MIN 5/-1/3 +-1 MIN+1 0 0 +-1 MIN+1 -1 0 +-1 MIN+1 1 0 +-1 MIN+1 -2 0 +-1 MIN+1 2 0 +-1 MIN+1 -3 0 +-1 MIN+1 3 0 +-1 MIN+1 17 0 +-1 MIN+1 127 0 +-1 MIN+1 MIN+1 0 +-1 MIN+1 MAX 0 +-1 MIN+1 MIN 0 +-1 MAX 0 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -1 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 1 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -2 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 2 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -3 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 3 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 17 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 127 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX MIN+1 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX MAX --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX MIN --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MIN 0 0 +-1 MIN -1 0 +-1 MIN 1 0 +-1 MIN -2 0 +-1 MIN 2 0 +-1 MIN -3 0 +-1 MIN 3 0 +-1 MIN 17 0 +-1 MIN 127 0 +-1 MIN MIN+1 0 +-1 MIN MAX 0 +-1 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +1 0 0 0 +1 0 -1 0 +1 0 1 0 +1 0 -2 0 +1 0 2 0 +1 0 -3 0 +1 0 3 0 +1 0 17 0 +1 0 127 0 +1 0 MIN+1 0 +1 0 MAX 0 +1 0 MIN 0 +1 -1 0 0 +1 -1 -1 0 +1 -1 1 0 +1 -1 -2 0 +1 -1 2 0 +1 -1 -3 0 +1 -1 3 0 +1 -1 17 0 +1 -1 127 0 +1 -1 MIN+1 0 +1 -1 MAX 0 +1 -1 MIN 0 +1 1 0 1/1/1 +1 1 -1 1/1/1 +1 1 1 1/1/1 +1 1 -2 1/1/1 +1 1 2 1/1/1 +1 1 -3 1/1/1 +1 1 3 1/1/1 +1 1 17 1/1/1 +1 1 127 1/1/1 +1 1 MIN+1 1/1/1 +1 1 MAX 1/1/1 +1 1 MIN 1/1/1 +1 3 0 3/1/3 +1 3 -1 3/1/3 +1 3 1 3/1/3 +1 3 -2 3/1/3 +1 3 2 3/1/3 +1 3 -3 3/1/3 +1 3 3 3/1/3 +1 3 17 3/1/3 +1 3 127 3/1/3 +1 3 MIN+1 3/1/3 +1 3 MAX 3/1/3 +1 3 MIN 3/1/3 +1 MIN+1 0 0 +1 MIN+1 -1 0 +1 MIN+1 1 0 +1 MIN+1 -2 0 +1 MIN+1 2 0 +1 MIN+1 -3 0 +1 MIN+1 3 0 +1 MIN+1 17 0 +1 MIN+1 127 0 +1 MIN+1 MIN+1 0 +1 MIN+1 MAX 0 +1 MIN+1 MIN 0 +1 MAX 0 MAX/1/MAX +1 MAX -1 MAX/1/MAX +1 MAX 1 MAX/1/MAX +1 MAX -2 MAX/1/MAX +1 MAX 2 MAX/1/MAX +1 MAX -3 MAX/1/MAX +1 MAX 3 MAX/1/MAX +1 MAX 17 MAX/1/MAX +1 MAX 127 MAX/1/MAX +1 MAX MIN+1 MAX/1/MAX +1 MAX MAX MAX/1/MAX +1 MAX MIN MAX/1/MAX +1 MIN 0 0 +1 MIN -1 0 +1 MIN 1 0 +1 MIN -2 0 +1 MIN 2 0 +1 MIN -3 0 +1 MIN 3 0 +1 MIN 17 0 +1 MIN 127 0 +1 MIN MIN+1 0 +1 MIN MAX 0 +1 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +3 0 0 0 +3 0 -1 0 +3 0 1 0 +3 0 -2 0 +3 0 2 0 +3 0 -3 0 +3 0 3 0 +3 0 17 0 +3 0 127 0 +3 0 MIN+1 0 +3 0 MAX 0 +3 0 MIN 0 +3 -1 0 0 +3 -1 -1 0 +3 -1 1 0 +3 -1 -2 0 +3 -1 2 0 +3 -1 -3 0 +3 -1 3 0 +3 -1 17 0 +3 -1 127 0 +3 -1 MIN+1 0 +3 -1 MAX 0 +3 -1 MIN 0 +3 1 0 0 +3 1 -1 0 +3 1 1 0 +3 1 -2 0 +3 1 2 0 +3 1 -3 0 +3 1 3 0 +3 1 17 0 +3 1 127 0 +3 1 MIN+1 0 +3 1 MAX 0 +3 1 MIN 0 +3 3 0 1/3/3 +3 3 -1 1/3/3 +3 3 1 1/3/3 +3 3 -2 1/3/3 +3 3 2 1/3/3 +3 3 -3 1/3/3 +3 3 3 1/3/3 +3 3 17 1/3/3 +3 3 127 1/3/3 +3 3 MIN+1 1/3/3 +3 3 MAX 1/3/3 +3 3 MIN 1/3/3 +3 MIN+1 0 0 +3 MIN+1 -1 0 +3 MIN+1 1 0 +3 MIN+1 -2 0 +3 MIN+1 2 0 +3 MIN+1 -3 0 +3 MIN+1 3 0 +3 MIN+1 17 0 +3 MIN+1 127 0 +3 MIN+1 MIN+1 0 +3 MIN+1 MAX 0 +3 MIN+1 MIN 0 +3 MAX 0 MAX-2/3/MAX +3 MAX -1 MAX-2/3/MAX +3 MAX 1 MAX-2/3/MAX +3 MAX -2 MAX-2/3/MAX +3 MAX 2 MAX-2/3/MAX +3 MAX -3 MAX-2/3/MAX +3 MAX 3 MAX-2/3/MAX +3 MAX 17 MAX-2/3/MAX +3 MAX 127 MAX-2/3/MAX +3 MAX MIN+1 MAX-2/3/MAX +3 MAX MAX MAX-2/3/MAX +3 MAX MIN MAX-2/3/MAX +3 MIN 0 0 +3 MIN -1 0 +3 MIN 1 0 +3 MIN -2 0 +3 MIN 2 0 +3 MIN -3 0 +3 MIN 3 0 +3 MIN 17 0 +3 MIN 127 0 +3 MIN MIN+1 0 +3 MIN MAX 0 +3 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +MIN+1 0 0 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 -1 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 1 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 -2 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 2 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 -3 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 3 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 17 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 127 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 MAX --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 MIN --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 -1 0 MAX/MIN+1/-1 +MIN+1 -1 -1 MAX/MIN+1/-1 +MIN+1 -1 1 MAX/MIN+1/-1 +MIN+1 -1 -2 MAX/MIN+1/-1 +MIN+1 -1 2 MAX/MIN+1/-1 +MIN+1 -1 -3 MAX/MIN+1/-1 +MIN+1 -1 3 MAX/MIN+1/-1 +MIN+1 -1 17 MAX/MIN+1/-1 +MIN+1 -1 127 MAX/MIN+1/-1 +MIN+1 -1 MIN+1 MAX/MIN+1/-1 +MIN+1 -1 MAX MAX/MIN+1/-1 +MIN+1 -1 MIN MAX/MIN+1/-1 +MIN+1 1 0 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -1 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 1 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -2 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 2 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -3 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 3 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 17 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 127 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 MAX --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 MIN --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 0 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -1 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 1 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -2 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 2 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -3 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 3 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 17 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 127 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 MAX --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 MIN --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MIN+1 0 1/MIN+1/MIN+1 +MIN+1 MIN+1 -1 1/MIN+1/MIN+1 +MIN+1 MIN+1 1 1/MIN+1/MIN+1 +MIN+1 MIN+1 -2 1/MIN+1/MIN+1 +MIN+1 MIN+1 2 1/MIN+1/MIN+1 +MIN+1 MIN+1 -3 1/MIN+1/MIN+1 +MIN+1 MIN+1 3 1/MIN+1/MIN+1 +MIN+1 MIN+1 17 1/MIN+1/MIN+1 +MIN+1 MIN+1 127 1/MIN+1/MIN+1 +MIN+1 MIN+1 MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN+1 MAX 1/MIN+1/MIN+1 +MIN+1 MIN+1 MIN 1/MIN+1/MIN+1 +MIN+1 MAX 0 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -1 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 1 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -2 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 2 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -3 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 3 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 17 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 127 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX MAX --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX MIN --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MIN 0 0 +MIN+1 MIN -1 0 +MIN+1 MIN 1 0 +MIN+1 MIN -2 0 +MIN+1 MIN 2 0 +MIN+1 MIN -3 0 +MIN+1 MIN 3 0 +MIN+1 MIN 17 0 +MIN+1 MIN 127 0 +MIN+1 MIN MIN+1 0 +MIN+1 MIN MAX 0 +MIN+1 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +MAX 0 0 0 +MAX 0 -1 0 +MAX 0 1 0 +MAX 0 -2 0 +MAX 0 2 0 +MAX 0 -3 0 +MAX 0 3 0 +MAX 0 17 0 +MAX 0 127 0 +MAX 0 MIN+1 0 +MAX 0 MAX 0 +MAX 0 MIN 0 +MAX -1 0 0 +MAX -1 -1 0 +MAX -1 1 0 +MAX -1 -2 0 +MAX -1 2 0 +MAX -1 -3 0 +MAX -1 3 0 +MAX -1 17 0 +MAX -1 127 0 +MAX -1 MIN+1 0 +MAX -1 MAX 0 +MAX -1 MIN 0 +MAX 1 0 0 +MAX 1 -1 0 +MAX 1 1 0 +MAX 1 -2 0 +MAX 1 2 0 +MAX 1 -3 0 +MAX 1 3 0 +MAX 1 17 0 +MAX 1 127 0 +MAX 1 MIN+1 0 +MAX 1 MAX 0 +MAX 1 MIN 0 +MAX 3 0 0 +MAX 3 -1 0 +MAX 3 1 0 +MAX 3 -2 0 +MAX 3 2 0 +MAX 3 -3 0 +MAX 3 3 0 +MAX 3 17 0 +MAX 3 127 0 +MAX 3 MIN+1 0 +MAX 3 MAX 0 +MAX 3 MIN 0 +MAX MIN+1 0 0 +MAX MIN+1 -1 0 +MAX MIN+1 1 0 +MAX MIN+1 -2 0 +MAX MIN+1 2 0 +MAX MIN+1 -3 0 +MAX MIN+1 3 0 +MAX MIN+1 17 0 +MAX MIN+1 127 0 +MAX MIN+1 MIN+1 0 +MAX MIN+1 MAX 0 +MAX MIN+1 MIN 0 +MAX MAX 0 1/MAX/MAX +MAX MAX -1 1/MAX/MAX +MAX MAX 1 1/MAX/MAX +MAX MAX -2 1/MAX/MAX +MAX MAX 2 1/MAX/MAX +MAX MAX -3 1/MAX/MAX +MAX MAX 3 1/MAX/MAX +MAX MAX 17 1/MAX/MAX +MAX MAX 127 1/MAX/MAX +MAX MAX MIN+1 1/MAX/MAX +MAX MAX MAX 1/MAX/MAX +MAX MAX MIN 1/MAX/MAX +MAX MIN 0 0 +MAX MIN -1 0 +MAX MIN 1 0 +MAX MIN -2 0 +MAX MIN 2 0 +MAX MIN -3 0 +MAX MIN 3 0 +MAX MIN 17 0 +MAX MIN 127 0 +MAX MIN MIN+1 0 +MAX MIN MAX 0 +MAX MIN MIN 0 + +start end step length/first/last +----------------------------------------- +MIN 0 0 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -1 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 1 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -2 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 2 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -3 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 3 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 17 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 127 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 MAX --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 MIN --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 0 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 -1 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 1 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 -2 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 2 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 -3 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 3 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 17 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 127 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 MAX --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 MIN --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 0 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -1 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 1 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -2 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 2 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -3 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 3 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 17 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 127 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 MAX --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 MIN --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 0 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -1 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 1 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -2 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 2 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -3 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 3 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 17 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 127 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 MAX --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 MIN --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MIN+1 0 2/MIN/MIN+1 +MIN MIN+1 -1 2/MIN/MIN+1 +MIN MIN+1 1 2/MIN/MIN+1 +MIN MIN+1 -2 2/MIN/MIN+1 +MIN MIN+1 2 2/MIN/MIN+1 +MIN MIN+1 -3 2/MIN/MIN+1 +MIN MIN+1 3 2/MIN/MIN+1 +MIN MIN+1 17 2/MIN/MIN+1 +MIN MIN+1 127 2/MIN/MIN+1 +MIN MIN+1 MIN+1 2/MIN/MIN+1 +MIN MIN+1 MAX 2/MIN/MIN+1 +MIN MIN+1 MIN 2/MIN/MIN+1 +MIN MAX 0 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -1 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 1 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -2 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 2 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -3 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 3 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 17 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 127 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX MAX --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX MIN --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MIN 0 1/MIN/MIN +MIN MIN -1 1/MIN/MIN +MIN MIN 1 1/MIN/MIN +MIN MIN -2 1/MIN/MIN +MIN MIN 2 1/MIN/MIN +MIN MIN -3 1/MIN/MIN +MIN MIN 3 1/MIN/MIN +MIN MIN 17 1/MIN/MIN +MIN MIN 127 1/MIN/MIN +MIN MIN MIN+1 1/MIN/MIN +MIN MIN MAX 1/MIN/MIN +MIN MIN MIN 1/MIN/MIN + +>>> start to end by step <<< + +start end step length/first/last +----------------------------------------- +0 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 0 -1 1/0/0 +0 0 1 1/0/0 +0 0 -2 1/0/0 +0 0 2 1/0/0 +0 0 -3 1/0/0 +0 0 3 1/0/0 +0 0 17 1/0/0 +0 0 127 1/0/0 +0 0 MIN+1 1/0/0 +0 0 MAX 1/0/0 +0 0 MIN 1/0/0 +0 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 -1 -1 2/0/-1 +0 -1 1 0 +0 -1 -2 1/0/0 +0 -1 2 0 +0 -1 -3 1/0/0 +0 -1 3 0 +0 -1 17 0 +0 -1 127 0 +0 -1 MIN+1 1/0/0 +0 -1 MAX 0 +0 -1 MIN 1/0/0 +0 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 1 -1 0 +0 1 1 2/0/1 +0 1 -2 0 +0 1 2 1/0/0 +0 1 -3 0 +0 1 3 1/0/0 +0 1 17 1/0/0 +0 1 127 1/0/0 +0 1 MIN+1 0 +0 1 MAX 1/0/0 +0 1 MIN 0 +0 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 3 -1 0 +0 3 1 4/0/3 +0 3 -2 0 +0 3 2 2/0/2 +0 3 -3 0 +0 3 3 2/0/3 +0 3 17 1/0/0 +0 3 127 1/0/0 +0 3 MIN+1 0 +0 3 MAX 1/0/0 +0 3 MIN 0 +0 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN+1 -1 --- + java.lang.IllegalArgumentException: 0 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +0 MIN+1 1 0 +0 MIN+1 -2 1073741824/0/MIN+2 +0 MIN+1 2 0 +0 MIN+1 -3 715827883/0/MIN+2 +0 MIN+1 3 0 +0 MIN+1 17 0 +0 MIN+1 127 0 +0 MIN+1 MIN+1 2/0/MIN+1 +0 MIN+1 MAX 0 +0 MIN+1 MIN 1/0/0 +0 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MAX -1 0 +0 MAX 1 --- + java.lang.IllegalArgumentException: 0 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +0 MAX -2 0 +0 MAX 2 1073741824/0/MAX-1 +0 MAX -3 0 +0 MAX 3 715827883/0/MAX-1 +0 MAX 17 126322568/0/MAX-8 +0 MAX 127 16909321/0/MAX-7 +0 MAX MIN+1 0 +0 MAX MAX 2/0/MAX +0 MAX MIN 0 +0 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN -1 --- + java.lang.IllegalArgumentException: 0 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +0 MIN 1 0 +0 MIN -2 1073741825/0/MIN +0 MIN 2 0 +0 MIN -3 715827883/0/MIN+2 +0 MIN 3 0 +0 MIN 17 0 +0 MIN 127 0 +0 MIN MIN+1 2/0/MIN+1 +0 MIN MAX 0 +0 MIN MIN 2/0/MIN + +start end step length/first/last +----------------------------------------- +-1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 0 -1 0 +-1 0 1 2/-1/0 +-1 0 -2 0 +-1 0 2 1/-1/-1 +-1 0 -3 0 +-1 0 3 1/-1/-1 +-1 0 17 1/-1/-1 +-1 0 127 1/-1/-1 +-1 0 MIN+1 0 +-1 0 MAX 1/-1/-1 +-1 0 MIN 0 +-1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 -1 -1 1/-1/-1 +-1 -1 1 1/-1/-1 +-1 -1 -2 1/-1/-1 +-1 -1 2 1/-1/-1 +-1 -1 -3 1/-1/-1 +-1 -1 3 1/-1/-1 +-1 -1 17 1/-1/-1 +-1 -1 127 1/-1/-1 +-1 -1 MIN+1 1/-1/-1 +-1 -1 MAX 1/-1/-1 +-1 -1 MIN 1/-1/-1 +-1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 1 -1 0 +-1 1 1 3/-1/1 +-1 1 -2 0 +-1 1 2 2/-1/1 +-1 1 -3 0 +-1 1 3 1/-1/-1 +-1 1 17 1/-1/-1 +-1 1 127 1/-1/-1 +-1 1 MIN+1 0 +-1 1 MAX 1/-1/-1 +-1 1 MIN 0 +-1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 3 -1 0 +-1 3 1 5/-1/3 +-1 3 -2 0 +-1 3 2 3/-1/3 +-1 3 -3 0 +-1 3 3 2/-1/2 +-1 3 17 1/-1/-1 +-1 3 127 1/-1/-1 +-1 3 MIN+1 0 +-1 3 MAX 1/-1/-1 +-1 3 MIN 0 +-1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN+1 -1 MAX/-1/MIN+1 +-1 MIN+1 1 0 +-1 MIN+1 -2 1073741824/-1/MIN+1 +-1 MIN+1 2 0 +-1 MIN+1 -3 715827883/-1/MIN+1 +-1 MIN+1 3 0 +-1 MIN+1 17 0 +-1 MIN+1 127 0 +-1 MIN+1 MIN+1 1/-1/-1 +-1 MIN+1 MAX 0 +-1 MIN+1 MIN 1/-1/-1 +-1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MAX -1 0 +-1 MAX 1 --- + java.lang.IllegalArgumentException: -1 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -2 0 +-1 MAX 2 1073741825/-1/MAX +-1 MAX -3 0 +-1 MAX 3 715827883/-1/MAX-2 +-1 MAX 17 126322568/-1/MAX-9 +-1 MAX 127 16909321/-1/MAX-8 +-1 MAX MIN+1 0 +-1 MAX MAX 2/-1/MAX-1 +-1 MAX MIN 0 +-1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN -1 --- + java.lang.IllegalArgumentException: -1 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +-1 MIN 1 0 +-1 MIN -2 1073741824/-1/MIN+1 +-1 MIN 2 0 +-1 MIN -3 715827883/-1/MIN+1 +-1 MIN 3 0 +-1 MIN 17 0 +-1 MIN 127 0 +-1 MIN MIN+1 2/-1/MIN +-1 MIN MAX 0 +-1 MIN MIN 1/-1/-1 + +start end step length/first/last +----------------------------------------- +1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 0 -1 2/1/0 +1 0 1 0 +1 0 -2 1/1/1 +1 0 2 0 +1 0 -3 1/1/1 +1 0 3 0 +1 0 17 0 +1 0 127 0 +1 0 MIN+1 1/1/1 +1 0 MAX 0 +1 0 MIN 1/1/1 +1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 -1 -1 3/1/-1 +1 -1 1 0 +1 -1 -2 2/1/-1 +1 -1 2 0 +1 -1 -3 1/1/1 +1 -1 3 0 +1 -1 17 0 +1 -1 127 0 +1 -1 MIN+1 1/1/1 +1 -1 MAX 0 +1 -1 MIN 1/1/1 +1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 1 -1 1/1/1 +1 1 1 1/1/1 +1 1 -2 1/1/1 +1 1 2 1/1/1 +1 1 -3 1/1/1 +1 1 3 1/1/1 +1 1 17 1/1/1 +1 1 127 1/1/1 +1 1 MIN+1 1/1/1 +1 1 MAX 1/1/1 +1 1 MIN 1/1/1 +1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 3 -1 0 +1 3 1 3/1/3 +1 3 -2 0 +1 3 2 2/1/3 +1 3 -3 0 +1 3 3 1/1/1 +1 3 17 1/1/1 +1 3 127 1/1/1 +1 3 MIN+1 0 +1 3 MAX 1/1/1 +1 3 MIN 0 +1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN+1 -1 --- + java.lang.IllegalArgumentException: 1 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN+1 1 0 +1 MIN+1 -2 1073741825/1/MIN+1 +1 MIN+1 2 0 +1 MIN+1 -3 715827883/1/MIN+3 +1 MIN+1 3 0 +1 MIN+1 17 0 +1 MIN+1 127 0 +1 MIN+1 MIN+1 2/1/MIN+2 +1 MIN+1 MAX 0 +1 MIN+1 MIN 2/1/MIN+1 +1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MAX -1 0 +1 MAX 1 MAX/1/MAX +1 MAX -2 0 +1 MAX 2 1073741824/1/MAX +1 MAX -3 0 +1 MAX 3 715827883/1/MAX +1 MAX 17 126322568/1/MAX-7 +1 MAX 127 16909321/1/MAX-6 +1 MAX MIN+1 0 +1 MAX MAX 1/1/1 +1 MAX MIN 0 +1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN -1 --- + java.lang.IllegalArgumentException: 1 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN 1 0 +1 MIN -2 1073741825/1/MIN+1 +1 MIN 2 0 +1 MIN -3 715827884/1/MIN +1 MIN 3 0 +1 MIN 17 0 +1 MIN 127 0 +1 MIN MIN+1 2/1/MIN+2 +1 MIN MAX 0 +1 MIN MIN 2/1/MIN+1 + +start end step length/first/last +----------------------------------------- +3 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 0 -1 4/3/0 +3 0 1 0 +3 0 -2 2/3/1 +3 0 2 0 +3 0 -3 2/3/0 +3 0 3 0 +3 0 17 0 +3 0 127 0 +3 0 MIN+1 1/3/3 +3 0 MAX 0 +3 0 MIN 1/3/3 +3 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 -1 -1 5/3/-1 +3 -1 1 0 +3 -1 -2 3/3/-1 +3 -1 2 0 +3 -1 -3 2/3/0 +3 -1 3 0 +3 -1 17 0 +3 -1 127 0 +3 -1 MIN+1 1/3/3 +3 -1 MAX 0 +3 -1 MIN 1/3/3 +3 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 1 -1 3/3/1 +3 1 1 0 +3 1 -2 2/3/1 +3 1 2 0 +3 1 -3 1/3/3 +3 1 3 0 +3 1 17 0 +3 1 127 0 +3 1 MIN+1 1/3/3 +3 1 MAX 0 +3 1 MIN 1/3/3 +3 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 3 -1 1/3/3 +3 3 1 1/3/3 +3 3 -2 1/3/3 +3 3 2 1/3/3 +3 3 -3 1/3/3 +3 3 3 1/3/3 +3 3 17 1/3/3 +3 3 127 1/3/3 +3 3 MIN+1 1/3/3 +3 3 MAX 1/3/3 +3 3 MIN 1/3/3 +3 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN+1 -1 --- + java.lang.IllegalArgumentException: 3 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN+1 1 0 +3 MIN+1 -2 1073741826/3/MIN+1 +3 MIN+1 2 0 +3 MIN+1 -3 715827884/3/MIN+2 +3 MIN+1 3 0 +3 MIN+1 17 0 +3 MIN+1 127 0 +3 MIN+1 MIN+1 2/3/MIN+4 +3 MIN+1 MAX 0 +3 MIN+1 MIN 2/3/MIN+3 +3 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MAX -1 0 +3 MAX 1 MAX-2/3/MAX +3 MAX -2 0 +3 MAX 2 1073741823/3/MAX +3 MAX -3 0 +3 MAX 3 715827882/3/MAX-1 +3 MAX 17 126322568/3/MAX-5 +3 MAX 127 16909321/3/MAX-4 +3 MAX MIN+1 0 +3 MAX MAX 1/3/3 +3 MAX MIN 0 +3 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN -1 --- + java.lang.IllegalArgumentException: 3 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN 1 0 +3 MIN -2 1073741826/3/MIN+1 +3 MIN 2 0 +3 MIN -3 715827884/3/MIN+2 +3 MIN 3 0 +3 MIN 17 0 +3 MIN 127 0 +3 MIN MIN+1 2/3/MIN+4 +3 MIN MAX 0 +3 MIN MIN 2/3/MIN+3 + +start end step length/first/last +----------------------------------------- +MIN+1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 0 -1 0 +MIN+1 0 1 --- + java.lang.IllegalArgumentException: -2147483647 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 0 -2 0 +MIN+1 0 2 1073741824/MIN+1/-1 +MIN+1 0 -3 0 +MIN+1 0 3 715827883/MIN+1/-1 +MIN+1 0 17 126322568/MIN+1/-8 +MIN+1 0 127 16909321/MIN+1/-7 +MIN+1 0 MIN+1 0 +MIN+1 0 MAX 2/MIN+1/0 +MIN+1 0 MIN 0 +MIN+1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 -1 -1 0 +MIN+1 -1 1 MAX/MIN+1/-1 +MIN+1 -1 -2 0 +MIN+1 -1 2 1073741824/MIN+1/-1 +MIN+1 -1 -3 0 +MIN+1 -1 3 715827883/MIN+1/-1 +MIN+1 -1 17 126322568/MIN+1/-8 +MIN+1 -1 127 16909321/MIN+1/-7 +MIN+1 -1 MIN+1 0 +MIN+1 -1 MAX 1/MIN+1/MIN+1 +MIN+1 -1 MIN 0 +MIN+1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 1 -1 0 +MIN+1 1 1 --- + java.lang.IllegalArgumentException: -2147483647 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -2 0 +MIN+1 1 2 1073741825/MIN+1/1 +MIN+1 1 -3 0 +MIN+1 1 3 715827883/MIN+1/-1 +MIN+1 1 17 126322568/MIN+1/-8 +MIN+1 1 127 16909321/MIN+1/-7 +MIN+1 1 MIN+1 0 +MIN+1 1 MAX 2/MIN+1/0 +MIN+1 1 MIN 0 +MIN+1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 3 -1 0 +MIN+1 3 1 --- + java.lang.IllegalArgumentException: -2147483647 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -2 0 +MIN+1 3 2 1073741826/MIN+1/3 +MIN+1 3 -3 0 +MIN+1 3 3 715827884/MIN+1/2 +MIN+1 3 17 126322568/MIN+1/-8 +MIN+1 3 127 16909321/MIN+1/-7 +MIN+1 3 MIN+1 0 +MIN+1 3 MAX 2/MIN+1/0 +MIN+1 3 MIN 0 +MIN+1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN+1 -1 1/MIN+1/MIN+1 +MIN+1 MIN+1 1 1/MIN+1/MIN+1 +MIN+1 MIN+1 -2 1/MIN+1/MIN+1 +MIN+1 MIN+1 2 1/MIN+1/MIN+1 +MIN+1 MIN+1 -3 1/MIN+1/MIN+1 +MIN+1 MIN+1 3 1/MIN+1/MIN+1 +MIN+1 MIN+1 17 1/MIN+1/MIN+1 +MIN+1 MIN+1 127 1/MIN+1/MIN+1 +MIN+1 MIN+1 MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN+1 MAX 1/MIN+1/MIN+1 +MIN+1 MIN+1 MIN 1/MIN+1/MIN+1 +MIN+1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MAX -1 0 +MIN+1 MAX 1 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -2 0 +MIN+1 MAX 2 --- + java.lang.IllegalArgumentException: -2147483647 to 2147483647 by 2: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -3 0 +MIN+1 MAX 3 1431655765/MIN+1/MAX-2 +MIN+1 MAX 17 252645135/MIN+1/MAX-16 +MIN+1 MAX 127 33818641/MIN+1/MAX-14 +MIN+1 MAX MIN+1 0 +MIN+1 MAX MAX 3/MIN+1/MAX +MIN+1 MAX MIN 0 +MIN+1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN -1 2/MIN+1/MIN +MIN+1 MIN 1 0 +MIN+1 MIN -2 1/MIN+1/MIN+1 +MIN+1 MIN 2 0 +MIN+1 MIN -3 1/MIN+1/MIN+1 +MIN+1 MIN 3 0 +MIN+1 MIN 17 0 +MIN+1 MIN 127 0 +MIN+1 MIN MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN MAX 0 +MIN+1 MIN MIN 1/MIN+1/MIN+1 + +start end step length/first/last +----------------------------------------- +MAX 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 0 -1 --- + java.lang.IllegalArgumentException: 2147483647 to 0 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX 0 1 0 +MAX 0 -2 1073741824/MAX/1 +MAX 0 2 0 +MAX 0 -3 715827883/MAX/1 +MAX 0 3 0 +MAX 0 17 0 +MAX 0 127 0 +MAX 0 MIN+1 2/MAX/0 +MAX 0 MAX 0 +MAX 0 MIN 1/MAX/MAX +MAX -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX -1 -1 --- + java.lang.IllegalArgumentException: 2147483647 to -1 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX -1 1 0 +MAX -1 -2 1073741825/MAX/-1 +MAX -1 2 0 +MAX -1 -3 715827883/MAX/1 +MAX -1 3 0 +MAX -1 17 0 +MAX -1 127 0 +MAX -1 MIN+1 2/MAX/0 +MAX -1 MAX 0 +MAX -1 MIN 2/MAX/-1 +MAX 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 1 -1 MAX/MAX/1 +MAX 1 1 0 +MAX 1 -2 1073741824/MAX/1 +MAX 1 2 0 +MAX 1 -3 715827883/MAX/1 +MAX 1 3 0 +MAX 1 17 0 +MAX 1 127 0 +MAX 1 MIN+1 1/MAX/MAX +MAX 1 MAX 0 +MAX 1 MIN 1/MAX/MAX +MAX 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 3 -1 MAX-2/MAX/3 +MAX 3 1 0 +MAX 3 -2 1073741823/MAX/3 +MAX 3 2 0 +MAX 3 -3 715827882/MAX/4 +MAX 3 3 0 +MAX 3 17 0 +MAX 3 127 0 +MAX 3 MIN+1 1/MAX/MAX +MAX 3 MAX 0 +MAX 3 MIN 1/MAX/MAX +MAX MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN+1 -1 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN+1 1 0 +MAX MIN+1 -2 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483647 by -2: seqs cannot contain more than Int.MaxValue elements. +MAX MIN+1 2 0 +MAX MIN+1 -3 1431655765/MAX/MIN+3 +MAX MIN+1 3 0 +MAX MIN+1 17 0 +MAX MIN+1 127 0 +MAX MIN+1 MIN+1 3/MAX/MIN+1 +MAX MIN+1 MAX 0 +MAX MIN+1 MIN 2/MAX/-1 +MAX MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MAX -1 1/MAX/MAX +MAX MAX 1 1/MAX/MAX +MAX MAX -2 1/MAX/MAX +MAX MAX 2 1/MAX/MAX +MAX MAX -3 1/MAX/MAX +MAX MAX 3 1/MAX/MAX +MAX MAX 17 1/MAX/MAX +MAX MAX 127 1/MAX/MAX +MAX MAX MIN+1 1/MAX/MAX +MAX MAX MAX 1/MAX/MAX +MAX MAX MIN 1/MAX/MAX +MAX MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN -1 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 1 0 +MAX MIN -2 --- + java.lang.IllegalArgumentException: 2147483647 to -2147483648 by -2: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 2 0 +MAX MIN -3 1431655766/MAX/MIN +MAX MIN 3 0 +MAX MIN 17 0 +MAX MIN 127 0 +MAX MIN MIN+1 3/MAX/MIN+1 +MAX MIN MAX 0 +MAX MIN MIN 2/MAX/-1 + +start end step length/first/last +----------------------------------------- +MIN 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 0 -1 0 +MIN 0 1 --- + java.lang.IllegalArgumentException: -2147483648 to 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -2 0 +MIN 0 2 1073741825/MIN/0 +MIN 0 -3 0 +MIN 0 3 715827883/MIN/-2 +MIN 0 17 126322568/MIN/-9 +MIN 0 127 16909321/MIN/-8 +MIN 0 MIN+1 0 +MIN 0 MAX 2/MIN/-1 +MIN 0 MIN 0 +MIN -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN -1 -1 0 +MIN -1 1 --- + java.lang.IllegalArgumentException: -2147483648 to -1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 -2 0 +MIN -1 2 1073741824/MIN/-2 +MIN -1 -3 0 +MIN -1 3 715827883/MIN/-2 +MIN -1 17 126322568/MIN/-9 +MIN -1 127 16909321/MIN/-8 +MIN -1 MIN+1 0 +MIN -1 MAX 2/MIN/-1 +MIN -1 MIN 0 +MIN 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 1 -1 0 +MIN 1 1 --- + java.lang.IllegalArgumentException: -2147483648 to 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -2 0 +MIN 1 2 1073741825/MIN/0 +MIN 1 -3 0 +MIN 1 3 715827884/MIN/1 +MIN 1 17 126322568/MIN/-9 +MIN 1 127 16909321/MIN/-8 +MIN 1 MIN+1 0 +MIN 1 MAX 2/MIN/-1 +MIN 1 MIN 0 +MIN 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 3 -1 0 +MIN 3 1 --- + java.lang.IllegalArgumentException: -2147483648 to 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -2 0 +MIN 3 2 1073741826/MIN/2 +MIN 3 -3 0 +MIN 3 3 715827884/MIN/1 +MIN 3 17 126322568/MIN/-9 +MIN 3 127 16909321/MIN/-8 +MIN 3 MIN+1 0 +MIN 3 MAX 2/MIN/-1 +MIN 3 MIN 0 +MIN MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN+1 -1 0 +MIN MIN+1 1 2/MIN/MIN+1 +MIN MIN+1 -2 0 +MIN MIN+1 2 1/MIN/MIN +MIN MIN+1 -3 0 +MIN MIN+1 3 1/MIN/MIN +MIN MIN+1 17 1/MIN/MIN +MIN MIN+1 127 1/MIN/MIN +MIN MIN+1 MIN+1 0 +MIN MIN+1 MAX 1/MIN/MIN +MIN MIN+1 MIN 0 +MIN MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MAX -1 0 +MIN MAX 1 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -2 0 +MIN MAX 2 --- + java.lang.IllegalArgumentException: -2147483648 to 2147483647 by 2: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -3 0 +MIN MAX 3 1431655766/MIN/MAX +MIN MAX 17 252645136/MIN/MAX +MIN MAX 127 33818641/MIN/MAX-15 +MIN MAX MIN+1 0 +MIN MAX MAX 3/MIN/MAX-1 +MIN MAX MIN 0 +MIN MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN -1 1/MIN/MIN +MIN MIN 1 1/MIN/MIN +MIN MIN -2 1/MIN/MIN +MIN MIN 2 1/MIN/MIN +MIN MIN -3 1/MIN/MIN +MIN MIN 3 1/MIN/MIN +MIN MIN 17 1/MIN/MIN +MIN MIN 127 1/MIN/MIN +MIN MIN MIN+1 1/MIN/MIN +MIN MIN MAX 1/MIN/MIN +MIN MIN MIN 1/MIN/MIN + +>>> start until end <<< + +start end step length/first/last +----------------------------------------- +0 0 0 0 +0 0 -1 0 +0 0 1 0 +0 0 -2 0 +0 0 2 0 +0 0 -3 0 +0 0 3 0 +0 0 17 0 +0 0 127 0 +0 0 MIN+1 0 +0 0 MAX 0 +0 0 MIN 0 +0 -1 0 0 +0 -1 -1 0 +0 -1 1 0 +0 -1 -2 0 +0 -1 2 0 +0 -1 -3 0 +0 -1 3 0 +0 -1 17 0 +0 -1 127 0 +0 -1 MIN+1 0 +0 -1 MAX 0 +0 -1 MIN 0 +0 1 0 1/0/0 +0 1 -1 1/0/0 +0 1 1 1/0/0 +0 1 -2 1/0/0 +0 1 2 1/0/0 +0 1 -3 1/0/0 +0 1 3 1/0/0 +0 1 17 1/0/0 +0 1 127 1/0/0 +0 1 MIN+1 1/0/0 +0 1 MAX 1/0/0 +0 1 MIN 1/0/0 +0 3 0 3/0/2 +0 3 -1 3/0/2 +0 3 1 3/0/2 +0 3 -2 3/0/2 +0 3 2 3/0/2 +0 3 -3 3/0/2 +0 3 3 3/0/2 +0 3 17 3/0/2 +0 3 127 3/0/2 +0 3 MIN+1 3/0/2 +0 3 MAX 3/0/2 +0 3 MIN 3/0/2 +0 MIN+1 0 0 +0 MIN+1 -1 0 +0 MIN+1 1 0 +0 MIN+1 -2 0 +0 MIN+1 2 0 +0 MIN+1 -3 0 +0 MIN+1 3 0 +0 MIN+1 17 0 +0 MIN+1 127 0 +0 MIN+1 MIN+1 0 +0 MIN+1 MAX 0 +0 MIN+1 MIN 0 +0 MAX 0 MAX/0/MAX-1 +0 MAX -1 MAX/0/MAX-1 +0 MAX 1 MAX/0/MAX-1 +0 MAX -2 MAX/0/MAX-1 +0 MAX 2 MAX/0/MAX-1 +0 MAX -3 MAX/0/MAX-1 +0 MAX 3 MAX/0/MAX-1 +0 MAX 17 MAX/0/MAX-1 +0 MAX 127 MAX/0/MAX-1 +0 MAX MIN+1 MAX/0/MAX-1 +0 MAX MAX MAX/0/MAX-1 +0 MAX MIN MAX/0/MAX-1 +0 MIN 0 0 +0 MIN -1 0 +0 MIN 1 0 +0 MIN -2 0 +0 MIN 2 0 +0 MIN -3 0 +0 MIN 3 0 +0 MIN 17 0 +0 MIN 127 0 +0 MIN MIN+1 0 +0 MIN MAX 0 +0 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +-1 0 0 1/-1/-1 +-1 0 -1 1/-1/-1 +-1 0 1 1/-1/-1 +-1 0 -2 1/-1/-1 +-1 0 2 1/-1/-1 +-1 0 -3 1/-1/-1 +-1 0 3 1/-1/-1 +-1 0 17 1/-1/-1 +-1 0 127 1/-1/-1 +-1 0 MIN+1 1/-1/-1 +-1 0 MAX 1/-1/-1 +-1 0 MIN 1/-1/-1 +-1 -1 0 0 +-1 -1 -1 0 +-1 -1 1 0 +-1 -1 -2 0 +-1 -1 2 0 +-1 -1 -3 0 +-1 -1 3 0 +-1 -1 17 0 +-1 -1 127 0 +-1 -1 MIN+1 0 +-1 -1 MAX 0 +-1 -1 MIN 0 +-1 1 0 2/-1/0 +-1 1 -1 2/-1/0 +-1 1 1 2/-1/0 +-1 1 -2 2/-1/0 +-1 1 2 2/-1/0 +-1 1 -3 2/-1/0 +-1 1 3 2/-1/0 +-1 1 17 2/-1/0 +-1 1 127 2/-1/0 +-1 1 MIN+1 2/-1/0 +-1 1 MAX 2/-1/0 +-1 1 MIN 2/-1/0 +-1 3 0 4/-1/2 +-1 3 -1 4/-1/2 +-1 3 1 4/-1/2 +-1 3 -2 4/-1/2 +-1 3 2 4/-1/2 +-1 3 -3 4/-1/2 +-1 3 3 4/-1/2 +-1 3 17 4/-1/2 +-1 3 127 4/-1/2 +-1 3 MIN+1 4/-1/2 +-1 3 MAX 4/-1/2 +-1 3 MIN 4/-1/2 +-1 MIN+1 0 0 +-1 MIN+1 -1 0 +-1 MIN+1 1 0 +-1 MIN+1 -2 0 +-1 MIN+1 2 0 +-1 MIN+1 -3 0 +-1 MIN+1 3 0 +-1 MIN+1 17 0 +-1 MIN+1 127 0 +-1 MIN+1 MIN+1 0 +-1 MIN+1 MAX 0 +-1 MIN+1 MIN 0 +-1 MAX 0 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -1 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 1 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -2 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 2 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -3 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 3 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 17 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX 127 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX MIN+1 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX MAX --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX MIN --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MIN 0 0 +-1 MIN -1 0 +-1 MIN 1 0 +-1 MIN -2 0 +-1 MIN 2 0 +-1 MIN -3 0 +-1 MIN 3 0 +-1 MIN 17 0 +-1 MIN 127 0 +-1 MIN MIN+1 0 +-1 MIN MAX 0 +-1 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +1 0 0 0 +1 0 -1 0 +1 0 1 0 +1 0 -2 0 +1 0 2 0 +1 0 -3 0 +1 0 3 0 +1 0 17 0 +1 0 127 0 +1 0 MIN+1 0 +1 0 MAX 0 +1 0 MIN 0 +1 -1 0 0 +1 -1 -1 0 +1 -1 1 0 +1 -1 -2 0 +1 -1 2 0 +1 -1 -3 0 +1 -1 3 0 +1 -1 17 0 +1 -1 127 0 +1 -1 MIN+1 0 +1 -1 MAX 0 +1 -1 MIN 0 +1 1 0 0 +1 1 -1 0 +1 1 1 0 +1 1 -2 0 +1 1 2 0 +1 1 -3 0 +1 1 3 0 +1 1 17 0 +1 1 127 0 +1 1 MIN+1 0 +1 1 MAX 0 +1 1 MIN 0 +1 3 0 2/1/2 +1 3 -1 2/1/2 +1 3 1 2/1/2 +1 3 -2 2/1/2 +1 3 2 2/1/2 +1 3 -3 2/1/2 +1 3 3 2/1/2 +1 3 17 2/1/2 +1 3 127 2/1/2 +1 3 MIN+1 2/1/2 +1 3 MAX 2/1/2 +1 3 MIN 2/1/2 +1 MIN+1 0 0 +1 MIN+1 -1 0 +1 MIN+1 1 0 +1 MIN+1 -2 0 +1 MIN+1 2 0 +1 MIN+1 -3 0 +1 MIN+1 3 0 +1 MIN+1 17 0 +1 MIN+1 127 0 +1 MIN+1 MIN+1 0 +1 MIN+1 MAX 0 +1 MIN+1 MIN 0 +1 MAX 0 MAX-1/1/MAX-1 +1 MAX -1 MAX-1/1/MAX-1 +1 MAX 1 MAX-1/1/MAX-1 +1 MAX -2 MAX-1/1/MAX-1 +1 MAX 2 MAX-1/1/MAX-1 +1 MAX -3 MAX-1/1/MAX-1 +1 MAX 3 MAX-1/1/MAX-1 +1 MAX 17 MAX-1/1/MAX-1 +1 MAX 127 MAX-1/1/MAX-1 +1 MAX MIN+1 MAX-1/1/MAX-1 +1 MAX MAX MAX-1/1/MAX-1 +1 MAX MIN MAX-1/1/MAX-1 +1 MIN 0 0 +1 MIN -1 0 +1 MIN 1 0 +1 MIN -2 0 +1 MIN 2 0 +1 MIN -3 0 +1 MIN 3 0 +1 MIN 17 0 +1 MIN 127 0 +1 MIN MIN+1 0 +1 MIN MAX 0 +1 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +3 0 0 0 +3 0 -1 0 +3 0 1 0 +3 0 -2 0 +3 0 2 0 +3 0 -3 0 +3 0 3 0 +3 0 17 0 +3 0 127 0 +3 0 MIN+1 0 +3 0 MAX 0 +3 0 MIN 0 +3 -1 0 0 +3 -1 -1 0 +3 -1 1 0 +3 -1 -2 0 +3 -1 2 0 +3 -1 -3 0 +3 -1 3 0 +3 -1 17 0 +3 -1 127 0 +3 -1 MIN+1 0 +3 -1 MAX 0 +3 -1 MIN 0 +3 1 0 0 +3 1 -1 0 +3 1 1 0 +3 1 -2 0 +3 1 2 0 +3 1 -3 0 +3 1 3 0 +3 1 17 0 +3 1 127 0 +3 1 MIN+1 0 +3 1 MAX 0 +3 1 MIN 0 +3 3 0 0 +3 3 -1 0 +3 3 1 0 +3 3 -2 0 +3 3 2 0 +3 3 -3 0 +3 3 3 0 +3 3 17 0 +3 3 127 0 +3 3 MIN+1 0 +3 3 MAX 0 +3 3 MIN 0 +3 MIN+1 0 0 +3 MIN+1 -1 0 +3 MIN+1 1 0 +3 MIN+1 -2 0 +3 MIN+1 2 0 +3 MIN+1 -3 0 +3 MIN+1 3 0 +3 MIN+1 17 0 +3 MIN+1 127 0 +3 MIN+1 MIN+1 0 +3 MIN+1 MAX 0 +3 MIN+1 MIN 0 +3 MAX 0 MAX-3/3/MAX-1 +3 MAX -1 MAX-3/3/MAX-1 +3 MAX 1 MAX-3/3/MAX-1 +3 MAX -2 MAX-3/3/MAX-1 +3 MAX 2 MAX-3/3/MAX-1 +3 MAX -3 MAX-3/3/MAX-1 +3 MAX 3 MAX-3/3/MAX-1 +3 MAX 17 MAX-3/3/MAX-1 +3 MAX 127 MAX-3/3/MAX-1 +3 MAX MIN+1 MAX-3/3/MAX-1 +3 MAX MAX MAX-3/3/MAX-1 +3 MAX MIN MAX-3/3/MAX-1 +3 MIN 0 0 +3 MIN -1 0 +3 MIN 1 0 +3 MIN -2 0 +3 MIN 2 0 +3 MIN -3 0 +3 MIN 3 0 +3 MIN 17 0 +3 MIN 127 0 +3 MIN MIN+1 0 +3 MIN MAX 0 +3 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +MIN+1 0 0 MAX/MIN+1/-1 +MIN+1 0 -1 MAX/MIN+1/-1 +MIN+1 0 1 MAX/MIN+1/-1 +MIN+1 0 -2 MAX/MIN+1/-1 +MIN+1 0 2 MAX/MIN+1/-1 +MIN+1 0 -3 MAX/MIN+1/-1 +MIN+1 0 3 MAX/MIN+1/-1 +MIN+1 0 17 MAX/MIN+1/-1 +MIN+1 0 127 MAX/MIN+1/-1 +MIN+1 0 MIN+1 MAX/MIN+1/-1 +MIN+1 0 MAX MAX/MIN+1/-1 +MIN+1 0 MIN MAX/MIN+1/-1 +MIN+1 -1 0 MAX-1/MIN+1/-2 +MIN+1 -1 -1 MAX-1/MIN+1/-2 +MIN+1 -1 1 MAX-1/MIN+1/-2 +MIN+1 -1 -2 MAX-1/MIN+1/-2 +MIN+1 -1 2 MAX-1/MIN+1/-2 +MIN+1 -1 -3 MAX-1/MIN+1/-2 +MIN+1 -1 3 MAX-1/MIN+1/-2 +MIN+1 -1 17 MAX-1/MIN+1/-2 +MIN+1 -1 127 MAX-1/MIN+1/-2 +MIN+1 -1 MIN+1 MAX-1/MIN+1/-2 +MIN+1 -1 MAX MAX-1/MIN+1/-2 +MIN+1 -1 MIN MAX-1/MIN+1/-2 +MIN+1 1 0 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -1 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 1 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -2 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 2 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -3 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 3 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 17 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 127 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 MAX --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 MIN --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 0 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -1 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 1 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -2 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 2 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -3 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 3 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 17 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 127 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 MAX --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 MIN --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MIN+1 0 0 +MIN+1 MIN+1 -1 0 +MIN+1 MIN+1 1 0 +MIN+1 MIN+1 -2 0 +MIN+1 MIN+1 2 0 +MIN+1 MIN+1 -3 0 +MIN+1 MIN+1 3 0 +MIN+1 MIN+1 17 0 +MIN+1 MIN+1 127 0 +MIN+1 MIN+1 MIN+1 0 +MIN+1 MIN+1 MAX 0 +MIN+1 MIN+1 MIN 0 +MIN+1 MAX 0 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -1 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 1 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -2 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 2 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -3 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 3 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 17 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX 127 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX MIN+1 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX MAX --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX MIN --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MIN 0 0 +MIN+1 MIN -1 0 +MIN+1 MIN 1 0 +MIN+1 MIN -2 0 +MIN+1 MIN 2 0 +MIN+1 MIN -3 0 +MIN+1 MIN 3 0 +MIN+1 MIN 17 0 +MIN+1 MIN 127 0 +MIN+1 MIN MIN+1 0 +MIN+1 MIN MAX 0 +MIN+1 MIN MIN 0 + +start end step length/first/last +----------------------------------------- +MAX 0 0 0 +MAX 0 -1 0 +MAX 0 1 0 +MAX 0 -2 0 +MAX 0 2 0 +MAX 0 -3 0 +MAX 0 3 0 +MAX 0 17 0 +MAX 0 127 0 +MAX 0 MIN+1 0 +MAX 0 MAX 0 +MAX 0 MIN 0 +MAX -1 0 0 +MAX -1 -1 0 +MAX -1 1 0 +MAX -1 -2 0 +MAX -1 2 0 +MAX -1 -3 0 +MAX -1 3 0 +MAX -1 17 0 +MAX -1 127 0 +MAX -1 MIN+1 0 +MAX -1 MAX 0 +MAX -1 MIN 0 +MAX 1 0 0 +MAX 1 -1 0 +MAX 1 1 0 +MAX 1 -2 0 +MAX 1 2 0 +MAX 1 -3 0 +MAX 1 3 0 +MAX 1 17 0 +MAX 1 127 0 +MAX 1 MIN+1 0 +MAX 1 MAX 0 +MAX 1 MIN 0 +MAX 3 0 0 +MAX 3 -1 0 +MAX 3 1 0 +MAX 3 -2 0 +MAX 3 2 0 +MAX 3 -3 0 +MAX 3 3 0 +MAX 3 17 0 +MAX 3 127 0 +MAX 3 MIN+1 0 +MAX 3 MAX 0 +MAX 3 MIN 0 +MAX MIN+1 0 0 +MAX MIN+1 -1 0 +MAX MIN+1 1 0 +MAX MIN+1 -2 0 +MAX MIN+1 2 0 +MAX MIN+1 -3 0 +MAX MIN+1 3 0 +MAX MIN+1 17 0 +MAX MIN+1 127 0 +MAX MIN+1 MIN+1 0 +MAX MIN+1 MAX 0 +MAX MIN+1 MIN 0 +MAX MAX 0 0 +MAX MAX -1 0 +MAX MAX 1 0 +MAX MAX -2 0 +MAX MAX 2 0 +MAX MAX -3 0 +MAX MAX 3 0 +MAX MAX 17 0 +MAX MAX 127 0 +MAX MAX MIN+1 0 +MAX MAX MAX 0 +MAX MAX MIN 0 +MAX MIN 0 0 +MAX MIN -1 0 +MAX MIN 1 0 +MAX MIN -2 0 +MAX MIN 2 0 +MAX MIN -3 0 +MAX MIN 3 0 +MAX MIN 17 0 +MAX MIN 127 0 +MAX MIN MIN+1 0 +MAX MIN MAX 0 +MAX MIN MIN 0 + +start end step length/first/last +----------------------------------------- +MIN 0 0 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -1 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 1 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -2 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 2 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -3 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 3 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 17 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 127 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 MAX --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 MIN --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN -1 0 MAX/MIN/-2 +MIN -1 -1 MAX/MIN/-2 +MIN -1 1 MAX/MIN/-2 +MIN -1 -2 MAX/MIN/-2 +MIN -1 2 MAX/MIN/-2 +MIN -1 -3 MAX/MIN/-2 +MIN -1 3 MAX/MIN/-2 +MIN -1 17 MAX/MIN/-2 +MIN -1 127 MAX/MIN/-2 +MIN -1 MIN+1 MAX/MIN/-2 +MIN -1 MAX MAX/MIN/-2 +MIN -1 MIN MAX/MIN/-2 +MIN 1 0 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -1 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 1 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -2 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 2 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -3 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 3 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 17 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 127 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 MAX --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 MIN --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 0 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -1 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 1 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -2 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 2 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -3 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 3 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 17 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 127 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 MAX --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 MIN --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MIN+1 0 1/MIN/MIN +MIN MIN+1 -1 1/MIN/MIN +MIN MIN+1 1 1/MIN/MIN +MIN MIN+1 -2 1/MIN/MIN +MIN MIN+1 2 1/MIN/MIN +MIN MIN+1 -3 1/MIN/MIN +MIN MIN+1 3 1/MIN/MIN +MIN MIN+1 17 1/MIN/MIN +MIN MIN+1 127 1/MIN/MIN +MIN MIN+1 MIN+1 1/MIN/MIN +MIN MIN+1 MAX 1/MIN/MIN +MIN MIN+1 MIN 1/MIN/MIN +MIN MAX 0 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -1 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 1 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -2 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 2 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -3 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 3 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 17 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX 127 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX MIN+1 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX MAX --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX MIN --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MIN 0 0 +MIN MIN -1 0 +MIN MIN 1 0 +MIN MIN -2 0 +MIN MIN 2 0 +MIN MIN -3 0 +MIN MIN 3 0 +MIN MIN 17 0 +MIN MIN 127 0 +MIN MIN MIN+1 0 +MIN MIN MAX 0 +MIN MIN MIN 0 + +>>> start until end by step <<< + +start end step length/first/last +----------------------------------------- +0 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 0 -1 0 +0 0 1 0 +0 0 -2 0 +0 0 2 0 +0 0 -3 0 +0 0 3 0 +0 0 17 0 +0 0 127 0 +0 0 MIN+1 0 +0 0 MAX 0 +0 0 MIN 0 +0 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 -1 -1 1/0/0 +0 -1 1 0 +0 -1 -2 1/0/0 +0 -1 2 0 +0 -1 -3 1/0/0 +0 -1 3 0 +0 -1 17 0 +0 -1 127 0 +0 -1 MIN+1 1/0/0 +0 -1 MAX 0 +0 -1 MIN 1/0/0 +0 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 1 -1 0 +0 1 1 1/0/0 +0 1 -2 0 +0 1 2 1/0/0 +0 1 -3 0 +0 1 3 1/0/0 +0 1 17 1/0/0 +0 1 127 1/0/0 +0 1 MIN+1 0 +0 1 MAX 1/0/0 +0 1 MIN 0 +0 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 3 -1 0 +0 3 1 3/0/2 +0 3 -2 0 +0 3 2 2/0/2 +0 3 -3 0 +0 3 3 1/0/0 +0 3 17 1/0/0 +0 3 127 1/0/0 +0 3 MIN+1 0 +0 3 MAX 1/0/0 +0 3 MIN 0 +0 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN+1 -1 MAX/0/MIN+2 +0 MIN+1 1 0 +0 MIN+1 -2 1073741824/0/MIN+2 +0 MIN+1 2 0 +0 MIN+1 -3 715827883/0/MIN+2 +0 MIN+1 3 0 +0 MIN+1 17 0 +0 MIN+1 127 0 +0 MIN+1 MIN+1 1/0/0 +0 MIN+1 MAX 0 +0 MIN+1 MIN 1/0/0 +0 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MAX -1 0 +0 MAX 1 MAX/0/MAX-1 +0 MAX -2 0 +0 MAX 2 1073741824/0/MAX-1 +0 MAX -3 0 +0 MAX 3 715827883/0/MAX-1 +0 MAX 17 126322568/0/MAX-8 +0 MAX 127 16909321/0/MAX-7 +0 MAX MIN+1 0 +0 MAX MAX 1/0/0 +0 MAX MIN 0 +0 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +0 MIN -1 --- + java.lang.IllegalArgumentException: 0 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +0 MIN 1 0 +0 MIN -2 1073741824/0/MIN+2 +0 MIN 2 0 +0 MIN -3 715827883/0/MIN+2 +0 MIN 3 0 +0 MIN 17 0 +0 MIN 127 0 +0 MIN MIN+1 2/0/MIN+1 +0 MIN MAX 0 +0 MIN MIN 1/0/0 + +start end step length/first/last +----------------------------------------- +-1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 0 -1 0 +-1 0 1 1/-1/-1 +-1 0 -2 0 +-1 0 2 1/-1/-1 +-1 0 -3 0 +-1 0 3 1/-1/-1 +-1 0 17 1/-1/-1 +-1 0 127 1/-1/-1 +-1 0 MIN+1 0 +-1 0 MAX 1/-1/-1 +-1 0 MIN 0 +-1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 -1 -1 0 +-1 -1 1 0 +-1 -1 -2 0 +-1 -1 2 0 +-1 -1 -3 0 +-1 -1 3 0 +-1 -1 17 0 +-1 -1 127 0 +-1 -1 MIN+1 0 +-1 -1 MAX 0 +-1 -1 MIN 0 +-1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 1 -1 0 +-1 1 1 2/-1/0 +-1 1 -2 0 +-1 1 2 1/-1/-1 +-1 1 -3 0 +-1 1 3 1/-1/-1 +-1 1 17 1/-1/-1 +-1 1 127 1/-1/-1 +-1 1 MIN+1 0 +-1 1 MAX 1/-1/-1 +-1 1 MIN 0 +-1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 3 -1 0 +-1 3 1 4/-1/2 +-1 3 -2 0 +-1 3 2 2/-1/1 +-1 3 -3 0 +-1 3 3 2/-1/2 +-1 3 17 1/-1/-1 +-1 3 127 1/-1/-1 +-1 3 MIN+1 0 +-1 3 MAX 1/-1/-1 +-1 3 MIN 0 +-1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN+1 -1 MAX-1/-1/MIN+2 +-1 MIN+1 1 0 +-1 MIN+1 -2 1073741823/-1/MIN+3 +-1 MIN+1 2 0 +-1 MIN+1 -3 715827882/-1/MIN+4 +-1 MIN+1 3 0 +-1 MIN+1 17 0 +-1 MIN+1 127 0 +-1 MIN+1 MIN+1 1/-1/-1 +-1 MIN+1 MAX 0 +-1 MIN+1 MIN 1/-1/-1 +-1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MAX -1 0 +-1 MAX 1 --- + java.lang.IllegalArgumentException: -1 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +-1 MAX -2 0 +-1 MAX 2 1073741824/-1/MAX-2 +-1 MAX -3 0 +-1 MAX 3 715827883/-1/MAX-2 +-1 MAX 17 126322568/-1/MAX-9 +-1 MAX 127 16909321/-1/MAX-8 +-1 MAX MIN+1 0 +-1 MAX MAX 2/-1/MAX-1 +-1 MAX MIN 0 +-1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +-1 MIN -1 MAX/-1/MIN+1 +-1 MIN 1 0 +-1 MIN -2 1073741824/-1/MIN+1 +-1 MIN 2 0 +-1 MIN -3 715827883/-1/MIN+1 +-1 MIN 3 0 +-1 MIN 17 0 +-1 MIN 127 0 +-1 MIN MIN+1 1/-1/-1 +-1 MIN MAX 0 +-1 MIN MIN 1/-1/-1 + +start end step length/first/last +----------------------------------------- +1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 0 -1 1/1/1 +1 0 1 0 +1 0 -2 1/1/1 +1 0 2 0 +1 0 -3 1/1/1 +1 0 3 0 +1 0 17 0 +1 0 127 0 +1 0 MIN+1 1/1/1 +1 0 MAX 0 +1 0 MIN 1/1/1 +1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 -1 -1 2/1/0 +1 -1 1 0 +1 -1 -2 1/1/1 +1 -1 2 0 +1 -1 -3 1/1/1 +1 -1 3 0 +1 -1 17 0 +1 -1 127 0 +1 -1 MIN+1 1/1/1 +1 -1 MAX 0 +1 -1 MIN 1/1/1 +1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 1 -1 0 +1 1 1 0 +1 1 -2 0 +1 1 2 0 +1 1 -3 0 +1 1 3 0 +1 1 17 0 +1 1 127 0 +1 1 MIN+1 0 +1 1 MAX 0 +1 1 MIN 0 +1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 3 -1 0 +1 3 1 2/1/2 +1 3 -2 0 +1 3 2 1/1/1 +1 3 -3 0 +1 3 3 1/1/1 +1 3 17 1/1/1 +1 3 127 1/1/1 +1 3 MIN+1 0 +1 3 MAX 1/1/1 +1 3 MIN 0 +1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN+1 -1 --- + java.lang.IllegalArgumentException: 1 until -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN+1 1 0 +1 MIN+1 -2 1073741824/1/MIN+3 +1 MIN+1 2 0 +1 MIN+1 -3 715827883/1/MIN+3 +1 MIN+1 3 0 +1 MIN+1 17 0 +1 MIN+1 127 0 +1 MIN+1 MIN+1 2/1/MIN+2 +1 MIN+1 MAX 0 +1 MIN+1 MIN 1/1/1 +1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MAX -1 0 +1 MAX 1 MAX-1/1/MAX-1 +1 MAX -2 0 +1 MAX 2 1073741823/1/MAX-2 +1 MAX -3 0 +1 MAX 3 715827882/1/MAX-3 +1 MAX 17 126322568/1/MAX-7 +1 MAX 127 16909321/1/MAX-6 +1 MAX MIN+1 0 +1 MAX MAX 1/1/1 +1 MAX MIN 0 +1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +1 MIN -1 --- + java.lang.IllegalArgumentException: 1 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +1 MIN 1 0 +1 MIN -2 1073741825/1/MIN+1 +1 MIN 2 0 +1 MIN -3 715827883/1/MIN+3 +1 MIN 3 0 +1 MIN 17 0 +1 MIN 127 0 +1 MIN MIN+1 2/1/MIN+2 +1 MIN MAX 0 +1 MIN MIN 2/1/MIN+1 + +start end step length/first/last +----------------------------------------- +3 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 0 -1 3/3/1 +3 0 1 0 +3 0 -2 2/3/1 +3 0 2 0 +3 0 -3 1/3/3 +3 0 3 0 +3 0 17 0 +3 0 127 0 +3 0 MIN+1 1/3/3 +3 0 MAX 0 +3 0 MIN 1/3/3 +3 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 -1 -1 4/3/0 +3 -1 1 0 +3 -1 -2 2/3/1 +3 -1 2 0 +3 -1 -3 2/3/0 +3 -1 3 0 +3 -1 17 0 +3 -1 127 0 +3 -1 MIN+1 1/3/3 +3 -1 MAX 0 +3 -1 MIN 1/3/3 +3 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 1 -1 2/3/2 +3 1 1 0 +3 1 -2 1/3/3 +3 1 2 0 +3 1 -3 1/3/3 +3 1 3 0 +3 1 17 0 +3 1 127 0 +3 1 MIN+1 1/3/3 +3 1 MAX 0 +3 1 MIN 1/3/3 +3 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 3 -1 0 +3 3 1 0 +3 3 -2 0 +3 3 2 0 +3 3 -3 0 +3 3 3 0 +3 3 17 0 +3 3 127 0 +3 3 MIN+1 0 +3 3 MAX 0 +3 3 MIN 0 +3 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN+1 -1 --- + java.lang.IllegalArgumentException: 3 until -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN+1 1 0 +3 MIN+1 -2 1073741825/3/MIN+3 +3 MIN+1 2 0 +3 MIN+1 -3 715827884/3/MIN+2 +3 MIN+1 3 0 +3 MIN+1 17 0 +3 MIN+1 127 0 +3 MIN+1 MIN+1 2/3/MIN+4 +3 MIN+1 MAX 0 +3 MIN+1 MIN 2/3/MIN+3 +3 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MAX -1 0 +3 MAX 1 MAX-3/3/MAX-1 +3 MAX -2 0 +3 MAX 2 1073741822/3/MAX-2 +3 MAX -3 0 +3 MAX 3 715827882/3/MAX-1 +3 MAX 17 126322568/3/MAX-5 +3 MAX 127 16909321/3/MAX-4 +3 MAX MIN+1 0 +3 MAX MAX 1/3/3 +3 MAX MIN 0 +3 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +3 MIN -1 --- + java.lang.IllegalArgumentException: 3 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +3 MIN 1 0 +3 MIN -2 1073741826/3/MIN+1 +3 MIN 2 0 +3 MIN -3 715827884/3/MIN+2 +3 MIN 3 0 +3 MIN 17 0 +3 MIN 127 0 +3 MIN MIN+1 2/3/MIN+4 +3 MIN MAX 0 +3 MIN MIN 2/3/MIN+3 + +start end step length/first/last +----------------------------------------- +MIN+1 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 0 -1 0 +MIN+1 0 1 MAX/MIN+1/-1 +MIN+1 0 -2 0 +MIN+1 0 2 1073741824/MIN+1/-1 +MIN+1 0 -3 0 +MIN+1 0 3 715827883/MIN+1/-1 +MIN+1 0 17 126322568/MIN+1/-8 +MIN+1 0 127 16909321/MIN+1/-7 +MIN+1 0 MIN+1 0 +MIN+1 0 MAX 1/MIN+1/MIN+1 +MIN+1 0 MIN 0 +MIN+1 -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 -1 -1 0 +MIN+1 -1 1 MAX-1/MIN+1/-2 +MIN+1 -1 -2 0 +MIN+1 -1 2 1073741823/MIN+1/-3 +MIN+1 -1 -3 0 +MIN+1 -1 3 715827882/MIN+1/-4 +MIN+1 -1 17 126322568/MIN+1/-8 +MIN+1 -1 127 16909321/MIN+1/-7 +MIN+1 -1 MIN+1 0 +MIN+1 -1 MAX 1/MIN+1/MIN+1 +MIN+1 -1 MIN 0 +MIN+1 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 1 -1 0 +MIN+1 1 1 --- + java.lang.IllegalArgumentException: -2147483647 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 1 -2 0 +MIN+1 1 2 1073741824/MIN+1/-1 +MIN+1 1 -3 0 +MIN+1 1 3 715827883/MIN+1/-1 +MIN+1 1 17 126322568/MIN+1/-8 +MIN+1 1 127 16909321/MIN+1/-7 +MIN+1 1 MIN+1 0 +MIN+1 1 MAX 2/MIN+1/0 +MIN+1 1 MIN 0 +MIN+1 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 3 -1 0 +MIN+1 3 1 --- + java.lang.IllegalArgumentException: -2147483647 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 3 -2 0 +MIN+1 3 2 1073741825/MIN+1/1 +MIN+1 3 -3 0 +MIN+1 3 3 715827884/MIN+1/2 +MIN+1 3 17 126322568/MIN+1/-8 +MIN+1 3 127 16909321/MIN+1/-7 +MIN+1 3 MIN+1 0 +MIN+1 3 MAX 2/MIN+1/0 +MIN+1 3 MIN 0 +MIN+1 MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN+1 -1 0 +MIN+1 MIN+1 1 0 +MIN+1 MIN+1 -2 0 +MIN+1 MIN+1 2 0 +MIN+1 MIN+1 -3 0 +MIN+1 MIN+1 3 0 +MIN+1 MIN+1 17 0 +MIN+1 MIN+1 127 0 +MIN+1 MIN+1 MIN+1 0 +MIN+1 MIN+1 MAX 0 +MIN+1 MIN+1 MIN 0 +MIN+1 MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MAX -1 0 +MIN+1 MAX 1 --- + java.lang.IllegalArgumentException: -2147483647 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN+1 MAX -2 0 +MIN+1 MAX 2 MAX/MIN+1/MAX-2 +MIN+1 MAX -3 0 +MIN+1 MAX 3 1431655765/MIN+1/MAX-2 +MIN+1 MAX 17 252645135/MIN+1/MAX-16 +MIN+1 MAX 127 33818641/MIN+1/MAX-14 +MIN+1 MAX MIN+1 0 +MIN+1 MAX MAX 2/MIN+1/0 +MIN+1 MAX MIN 0 +MIN+1 MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN+1 MIN -1 1/MIN+1/MIN+1 +MIN+1 MIN 1 0 +MIN+1 MIN -2 1/MIN+1/MIN+1 +MIN+1 MIN 2 0 +MIN+1 MIN -3 1/MIN+1/MIN+1 +MIN+1 MIN 3 0 +MIN+1 MIN 17 0 +MIN+1 MIN 127 0 +MIN+1 MIN MIN+1 1/MIN+1/MIN+1 +MIN+1 MIN MAX 0 +MIN+1 MIN MIN 1/MIN+1/MIN+1 + +start end step length/first/last +----------------------------------------- +MAX 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 0 -1 MAX/MAX/1 +MAX 0 1 0 +MAX 0 -2 1073741824/MAX/1 +MAX 0 2 0 +MAX 0 -3 715827883/MAX/1 +MAX 0 3 0 +MAX 0 17 0 +MAX 0 127 0 +MAX 0 MIN+1 1/MAX/MAX +MAX 0 MAX 0 +MAX 0 MIN 1/MAX/MAX +MAX -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX -1 -1 --- + java.lang.IllegalArgumentException: 2147483647 until -1 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX -1 1 0 +MAX -1 -2 1073741824/MAX/1 +MAX -1 2 0 +MAX -1 -3 715827883/MAX/1 +MAX -1 3 0 +MAX -1 17 0 +MAX -1 127 0 +MAX -1 MIN+1 2/MAX/0 +MAX -1 MAX 0 +MAX -1 MIN 1/MAX/MAX +MAX 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 1 -1 MAX-1/MAX/2 +MAX 1 1 0 +MAX 1 -2 1073741823/MAX/3 +MAX 1 2 0 +MAX 1 -3 715827882/MAX/4 +MAX 1 3 0 +MAX 1 17 0 +MAX 1 127 0 +MAX 1 MIN+1 1/MAX/MAX +MAX 1 MAX 0 +MAX 1 MIN 1/MAX/MAX +MAX 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX 3 -1 MAX-3/MAX/4 +MAX 3 1 0 +MAX 3 -2 1073741822/MAX/5 +MAX 3 2 0 +MAX 3 -3 715827882/MAX/4 +MAX 3 3 0 +MAX 3 17 0 +MAX 3 127 0 +MAX 3 MIN+1 1/MAX/MAX +MAX 3 MAX 0 +MAX 3 MIN 1/MAX/MAX +MAX MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN+1 -1 --- + java.lang.IllegalArgumentException: 2147483647 until -2147483647 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN+1 1 0 +MAX MIN+1 -2 MAX/MAX/MIN+3 +MAX MIN+1 2 0 +MAX MIN+1 -3 1431655765/MAX/MIN+3 +MAX MIN+1 3 0 +MAX MIN+1 17 0 +MAX MIN+1 127 0 +MAX MIN+1 MIN+1 2/MAX/0 +MAX MIN+1 MAX 0 +MAX MIN+1 MIN 2/MAX/-1 +MAX MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MAX -1 0 +MAX MAX 1 0 +MAX MAX -2 0 +MAX MAX 2 0 +MAX MAX -3 0 +MAX MAX 3 0 +MAX MAX 17 0 +MAX MAX 127 0 +MAX MAX MIN+1 0 +MAX MAX MAX 0 +MAX MAX MIN 0 +MAX MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MAX MIN -1 --- + java.lang.IllegalArgumentException: 2147483647 until -2147483648 by -1: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 1 0 +MAX MIN -2 --- + java.lang.IllegalArgumentException: 2147483647 until -2147483648 by -2: seqs cannot contain more than Int.MaxValue elements. +MAX MIN 2 0 +MAX MIN -3 1431655765/MAX/MIN+3 +MAX MIN 3 0 +MAX MIN 17 0 +MAX MIN 127 0 +MAX MIN MIN+1 3/MAX/MIN+1 +MAX MIN MAX 0 +MAX MIN MIN 2/MAX/-1 + +start end step length/first/last +----------------------------------------- +MIN 0 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 0 -1 0 +MIN 0 1 --- + java.lang.IllegalArgumentException: -2147483648 until 0 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 0 -2 0 +MIN 0 2 1073741824/MIN/-2 +MIN 0 -3 0 +MIN 0 3 715827883/MIN/-2 +MIN 0 17 126322568/MIN/-9 +MIN 0 127 16909321/MIN/-8 +MIN 0 MIN+1 0 +MIN 0 MAX 2/MIN/-1 +MIN 0 MIN 0 +MIN -1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN -1 -1 0 +MIN -1 1 MAX/MIN/-2 +MIN -1 -2 0 +MIN -1 2 1073741824/MIN/-2 +MIN -1 -3 0 +MIN -1 3 715827883/MIN/-2 +MIN -1 17 126322568/MIN/-9 +MIN -1 127 16909321/MIN/-8 +MIN -1 MIN+1 0 +MIN -1 MAX 1/MIN/MIN +MIN -1 MIN 0 +MIN 1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 1 -1 0 +MIN 1 1 --- + java.lang.IllegalArgumentException: -2147483648 until 1 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 1 -2 0 +MIN 1 2 1073741825/MIN/0 +MIN 1 -3 0 +MIN 1 3 715827883/MIN/-2 +MIN 1 17 126322568/MIN/-9 +MIN 1 127 16909321/MIN/-8 +MIN 1 MIN+1 0 +MIN 1 MAX 2/MIN/-1 +MIN 1 MIN 0 +MIN 3 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN 3 -1 0 +MIN 3 1 --- + java.lang.IllegalArgumentException: -2147483648 until 3 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN 3 -2 0 +MIN 3 2 1073741826/MIN/2 +MIN 3 -3 0 +MIN 3 3 715827884/MIN/1 +MIN 3 17 126322568/MIN/-9 +MIN 3 127 16909321/MIN/-8 +MIN 3 MIN+1 0 +MIN 3 MAX 2/MIN/-1 +MIN 3 MIN 0 +MIN MIN+1 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN+1 -1 0 +MIN MIN+1 1 1/MIN/MIN +MIN MIN+1 -2 0 +MIN MIN+1 2 1/MIN/MIN +MIN MIN+1 -3 0 +MIN MIN+1 3 1/MIN/MIN +MIN MIN+1 17 1/MIN/MIN +MIN MIN+1 127 1/MIN/MIN +MIN MIN+1 MIN+1 0 +MIN MIN+1 MAX 1/MIN/MIN +MIN MIN+1 MIN 0 +MIN MAX 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MAX -1 0 +MIN MAX 1 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 1: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -2 0 +MIN MAX 2 --- + java.lang.IllegalArgumentException: -2147483648 until 2147483647 by 2: seqs cannot contain more than Int.MaxValue elements. +MIN MAX -3 0 +MIN MAX 3 1431655765/MIN/MAX-3 +MIN MAX 17 252645135/MIN/MAX-17 +MIN MAX 127 33818641/MIN/MAX-15 +MIN MAX MIN+1 0 +MIN MAX MAX 3/MIN/MAX-1 +MIN MAX MIN 0 +MIN MIN 0 --- + java.lang.IllegalArgumentException: step cannot be 0. +MIN MIN -1 0 +MIN MIN 1 0 +MIN MIN -2 0 +MIN MIN 2 0 +MIN MIN -3 0 +MIN MIN 3 0 +MIN MIN 17 0 +MIN MIN 127 0 +MIN MIN MIN+1 0 +MIN MIN MAX 0 +MIN MIN MIN 0 + diff --git a/test/files/run/range-unit.scala b/test/files/run/range-unit.scala new file mode 100644 index 0000000000..ece0d9806c --- /dev/null +++ b/test/files/run/range-unit.scala @@ -0,0 +1,55 @@ +import scala.collection.immutable.Range + +object Test { + // ha ha, I always forget math.abs(Int.MinValue) == Int.MinValue + val numbers = ( + ( (-3 to 3) ++ List(17, 127, Int.MaxValue, Int.MinValue + 1) + ).distinct.sortBy(n => (math.abs(n), n)) + ) :+ Int.MinValue + + // reducing output a little + val endpoints = numbers filterNot Set(-3, -2, 2, 17, 127) + + def num(n: Int) = { + val frommax = Int.MaxValue - n + val frommin = Int.MinValue - n + + if (n > 0) { + if (frommax == 0) "MAX" + else if (frommax < 1000) "MAX-" + frommax + else "" + n + } + else { + if (frommin == 0) "MIN" + else if (frommin > -1000) "MIN+" + (-frommin) + else "" + n + } + } + + def run[T](body: => Range): List[Any] = { + try { val r = body ; if (r.isEmpty) List(r.length) else List(num(r.length), num(r.head), num(r.last)) } + catch { case e: IllegalArgumentException => List("---\n " + e) } + } + + def runGroup(label: String, f: (Int, Int, Int) => Range) { + println(">>> " + label + " <<<\n") + for (start <- endpoints) { + val s = "%-7s %-7s %-7s %s".format("start", "end", "step", "length/first/last") + println(s + "\n" + ("-" * s.length)) + for (end <- endpoints ; step <- numbers) { + print("%-7s %-7s %-7s ".format(num(start), num(end), num(step))) + println(run(f(start, end, step)).mkString("/")) + } + println("") + } + } + + def main(args: Array[String]): Unit = { + runGroup("Range.inclusive", Range.inclusive(_, _, _)) + runGroup("Range.apply", Range.apply(_, _, _)) + runGroup("start to end", (x, y, _) => x to y) + runGroup("start to end by step", _ to _ by _) + runGroup("start until end", (x, y, _) => x until y) + runGroup("start until end by step", _ until _ by _) + } +} diff --git a/test/files/run/reflection-implClass.scala b/test/files/run/reflection-implClass.scala index b91f122a23..2b30e29bb3 100644 --- a/test/files/run/reflection-implClass.scala +++ b/test/files/run/reflection-implClass.scala @@ -8,19 +8,19 @@ object Test extends App with Outer { import scala.reflect.mirror - assert(mirror.classToSymbol(manifest[Foo].erasure).info.declaration(mirror.newTermName("bar")).info == - mirror.classToSymbol(manifest[Bar].erasure).info.declaration(mirror.newTermName("foo")).info) + assert(mirror.classToSymbol(manifest[Foo].erasure).typeSig.declaration(mirror.newTermName("bar")).typeSig == + mirror.classToSymbol(manifest[Bar].erasure).typeSig.declaration(mirror.newTermName("foo")).typeSig) val s1 = implClass(manifest[Foo].erasure) assert(s1 != mirror.NoSymbol) - assert(s1.info != mirror.NoType) - assert(s1.companionModule.info != mirror.NoType) - assert(s1.companionModule.info.declaration(mirror.newTermName("bar")) != mirror.NoSymbol) + assert(s1.typeSig != mirror.NoType) + assert(s1.companionModule.typeSig != mirror.NoType) + assert(s1.companionModule.typeSig.declaration(mirror.newTermName("bar")) != mirror.NoSymbol) val s2 = implClass(manifest[Bar].erasure) assert(s2 != mirror.NoSymbol) - assert(s2.info != mirror.NoType) - assert(s2.companionModule.info != mirror.NoType) - assert(s2.companionModule.info.declaration(mirror.newTermName("foo")) != mirror.NoSymbol) + assert(s2.typeSig != mirror.NoType) + assert(s2.companionModule.typeSig != mirror.NoType) + assert(s2.companionModule.typeSig.declaration(mirror.newTermName("foo")) != mirror.NoSymbol) def implClass(clazz: Class[_]) = { val implClass = Class.forName(clazz.getName + "$class") mirror.classToSymbol(implClass) diff --git a/test/files/run/si5262.check b/test/files/run/si5262.check new file mode 100644 index 0000000000..4c7a875de5 --- /dev/null +++ b/test/files/run/si5262.check @@ -0,0 +1,2 @@ +List(1, 2, 3, 4) +List(1, 2, null, 4)
\ No newline at end of file diff --git a/test/files/run/si5262.scala b/test/files/run/si5262.scala new file mode 100644 index 0000000000..fc4e57aa96 --- /dev/null +++ b/test/files/run/si5262.scala @@ -0,0 +1,26 @@ + + + + + + + +object Test { + + def serializationDeserialization(obj : Any) { + val bos = new java.io.ByteArrayOutputStream() + val out = new java.io.ObjectOutputStream(bos) + out.writeObject(obj) + + val arr = bos.toByteArray() + val in = new java.io.ObjectInputStream(new java.io.ByteArrayInputStream(arr)) + val o = in.readObject() + println(o) + } + + def main(args : Array[String]) { + serializationDeserialization(List(1,2,3,4)) + serializationDeserialization(List(1,2,null,4)) + } + +} diff --git a/test/files/run/si5375.check b/test/files/run/si5375.check new file mode 100644 index 0000000000..7d3002ffda --- /dev/null +++ b/test/files/run/si5375.check @@ -0,0 +1 @@ +Composite throwable
\ No newline at end of file diff --git a/test/files/run/si5375.scala b/test/files/run/si5375.scala new file mode 100644 index 0000000000..e4b329deae --- /dev/null +++ b/test/files/run/si5375.scala @@ -0,0 +1,19 @@ + + + +import collection.parallel.CompositeThrowable + + + +object Test { + + def main(args: Array[String]) { + val foos = (1 to 1000) toSeq; + try { + foos.par.map(i => if (i % 37 == 0) sys.error("i div 37") else i) + } catch { + case CompositeThrowable(thr) => println("Composite throwable") + } + } + +} diff --git a/test/files/run/t4835.check b/test/files/run/t4835.check new file mode 100644 index 0000000000..531c3d7bb6 --- /dev/null +++ b/test/files/run/t4835.check @@ -0,0 +1,7 @@ +-1 0 1 2 3 4 5 6 7 8 9
+-1 1 3 5 7 9 11 13 15 17 19
+1 1
+2 1 2
+2 1 A 2
+3 1 2 3
+3 1 A 2 B 3
diff --git a/test/files/run/t4835.scala b/test/files/run/t4835.scala new file mode 100644 index 0000000000..50d161be40 --- /dev/null +++ b/test/files/run/t4835.scala @@ -0,0 +1,38 @@ +/*
+ * Test case for SI-4835. This tests confirm that the fix
+ * doesn't break laziness. To test memory consumption,
+ * I need to confirm that OutOfMemoryError doesn't occur.
+ * I could create such tests. However, such tests consume
+ * too much time and memory.
+ */
+object Test {
+ private final val INFINITE = -1
+ def testStreamIterator(num: Int, stream: Stream[Int]): Unit = {
+ val iter = stream.iterator
+ print(num)
+ // if num == -1, then steram is infinite sequence
+ if (num == INFINITE) {
+ for(i <- 0 until 10) {
+ print(" " + iter.next())
+ }
+ } else {
+ while(iter.hasNext) {
+ print(" " + iter.next())
+ }
+ }
+ println()
+ }
+
+ def main(args: Array[String]): Unit = {
+ import Stream.{from, cons, empty}
+ testStreamIterator(INFINITE, from(0))
+ testStreamIterator(INFINITE, from(0).filter(_ % 2 == 1))
+ testStreamIterator(1, Stream(1))
+ testStreamIterator(2, Stream(1, 2))
+ //Stream with side effect
+ testStreamIterator(2, cons(1, cons({ print(" A"); 2}, empty)))
+ testStreamIterator(3, Stream(1, 2, 3))
+ //Stream with side effect
+ testStreamIterator(3, cons(1, cons({ print(" A"); 2}, cons({ print(" B"); 3}, Stream.empty))))
+ }
+}
diff --git a/test/files/run/trait-renaming.check b/test/files/run/trait-renaming.check new file mode 100644 index 0000000000..b2e5affde5 --- /dev/null +++ b/test/files/run/trait-renaming.check @@ -0,0 +1,2 @@ +public static int bippy.A$B$1$class.f(bippy.A$B$1) +public static void bippy.A$B$1$class.$init$(bippy.A$B$1) diff --git a/test/files/run/trait-renaming/A_1.scala b/test/files/run/trait-renaming/A_1.scala new file mode 100644 index 0000000000..2c3d4f566f --- /dev/null +++ b/test/files/run/trait-renaming/A_1.scala @@ -0,0 +1,15 @@ +package bippy { + class A { + def f = { + trait B { + def f = 5 + } + trait C { + def g = 10 + } + new B with C { } + } + + def g = Class.forName("bippy.A$B$1$class") + } +} diff --git a/test/files/run/trait-renaming/B_2.scala b/test/files/run/trait-renaming/B_2.scala new file mode 100644 index 0000000000..174e929fe2 --- /dev/null +++ b/test/files/run/trait-renaming/B_2.scala @@ -0,0 +1,5 @@ +object Test { + def main(args: Array[String]): Unit = { + (new bippy.A).g.getDeclaredMethods.map(_.toString).sorted foreach println + } +} diff --git a/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala b/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala index fbacb9f45c..8273e302a2 100644 --- a/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala +++ b/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala @@ -414,21 +414,21 @@ abstract class ParallelIterableCheck[T](collName: String) extends Properties(col }).reduceLeft(_ && _) } - // property("groupBy must be equal") = forAll(collectionPairs) { - // case (t, coll) => - // (for ((f, ind) <- groupByFunctions.zipWithIndex) yield { - // val tgroup = t.groupBy(f) - // val cgroup = coll.groupBy(f) - // if (tgroup != cgroup || cgroup != tgroup) { - // println("from: " + t) - // println("and: " + coll) - // println("groups are: ") - // println(tgroup) - // println(cgroup) - // } - // ("operator " + ind) |: tgroup == cgroup && cgroup == tgroup - // }).reduceLeft(_ && _) - // } + property("groupBy must be equal") = forAll(collectionPairs) { + case (t, coll) => + (for ((f, ind) <- groupByFunctions.zipWithIndex) yield { + val tgroup = t.groupBy(f) + val cgroup = coll.groupBy(f) + if (tgroup != cgroup || cgroup != tgroup) { + println("from: " + t) + println("and: " + coll) + println("groups are: ") + println(tgroup) + println(cgroup) + } + ("operator " + ind) |: tgroup == cgroup && cgroup == tgroup + }).reduceLeft(_ && _) + } } diff --git a/test/pending/run/t5418.check b/test/pending/run/t5418.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/pending/run/t5418.check diff --git a/test/pending/run/t5418.scala b/test/pending/run/t5418.scala new file mode 100644 index 0000000000..065710f15e --- /dev/null +++ b/test/pending/run/t5418.scala @@ -0,0 +1,14 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + new Object().getClass + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(code.tree) + toolbox.runExpr(ttree) +}
\ No newline at end of file diff --git a/tools/binary-repo-lib.sh b/tools/binary-repo-lib.sh index 4221e3205c..3a75593f21 100755 --- a/tools/binary-repo-lib.sh +++ b/tools/binary-repo-lib.sh @@ -7,6 +7,8 @@ remote_urlbase="http://typesafe.artifactoryonline.com/typesafe/scala-sha-bootstr libraryJar="$(pwd)/lib/scala-library.jar" desired_ext=".desired.sha1" push_jar="$(pwd)/tools/push.jar" +# Cache dir has .sbt in it to line up with SBT build. +cache_dir="${HOME}/.sbt/cache/scala" # Checks whether or not curl is installed and issues a warning on failure. checkCurl() { @@ -126,6 +128,25 @@ pushJarFiles() { else echo "Binary changes have been pushed. You may now submit the new *${desired_ext} files to git." fi +} + +# Pulls a single binary artifact from a remote repository. +# Argument 1 - The uri to the file that should be downloaded. +# Argument 2 - SHA of the file... +# Returns: Cache location. +pullJarFileToCache() { + local uri=$1 + local sha=$2 + local cache_loc=$cache_dir/$uri + local cdir=$(dirname $cache_loc) + if [[ ! -d $cdir ]]; then + mkdir -p $cdir + fi + # TODO - Check SHA of local cache is accurate. + if [[ ! -f $cache_loc ]]; then + curlDownload $cache_loc ${remote_urlbase}/${uri} + fi + echo "$cache_loc" } # Pulls a single binary artifact from a remote repository. @@ -139,8 +160,9 @@ pullJarFile() { local jar_name=${jar#$jar_dir/} local version=${sha1% ?$jar_name} local remote_uri=${version}/${jar#$basedir/} - echo "Downloading from ${remote_urlbase}/${remote_uri}" - curlDownload $jar ${remote_urlbase}/${remote_uri} + echo "Resolving [${remote_uri}]" + local cached_file=$(pullJarFileToCache $remote_uri $version) + cp $cached_file $jar } # Pulls binary artifacts from the remote repository. @@ -152,7 +174,6 @@ pullJarFiles() { jar=${sha%$desired_ext} local valid=$(isJarFileValid $jar) if [[ "$valid" != "OK" ]]; then - echo "Obtaining [$jar] from binary repository..." pullJarFile $jar $basedir fi done |