diff options
37 files changed, 1710 insertions, 133 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index b88fa64584..57dc564e8a 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -48,6 +48,217 @@ filter { { matchName="scala.collection.immutable.HashMap#HashMapCollision1.contains0" problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps.unzip" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps.unzip3" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip3" + problemName=IncompatibleMethTypeProblem + }, + // see SI-8200 + { + matchName="scala.reflect.api.StandardLiftables#StandardLiftableInstances.liftTree" + problemName=MissingMethodProblem + }, + // see SI-8331 + { + matchName="scala.reflect.api.Internals#ReificationSupportApi#SyntacticTypeAppliedExtractor.unapply" + problemName=IncompatibleResultTypeProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi#SyntacticTypeAppliedExtractor.unapply" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticSelectType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticAppliedType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticSelectTerm" + problemName=MissingMethodProblem + }, + // see SI-8366 + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticPartialFunction" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Mirror.symbolOf" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Mirror.typeOf" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Mirror.weakTypeOf" + problemName=MissingMethodProblem + }, + // see SI-8388 + { + matchName="scala.reflect.api.Internals$ReificationSupportApi$SyntacticIdentExtractor" + problemName=MissingClassProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticIdent" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticSingletonType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticTermIdent" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticTypeIdent" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticCompoundType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticAnnotatedType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticTypeProjection" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticExistentialType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope" + problemName=MissingMethodProblem + }, + // https://github.com/scala/scala/pull/3848 -- SI-8680 + { + matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$6" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$5" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$4" + problemName=MissingMethodProblem + }, + // SI-8946 + { + matchName="scala.reflect.runtime.ThreadLocalStorage#MyThreadLocalStorage.values" + problemName=MissingMethodProblem + }, + // the below method was the unused private (sic!) method but the compatibility checker was complaining about it + { + matchName="scala.reflect.io.ZipArchive.scala$reflect$io$ZipArchive$$walkIterator" + problemName=MissingMethodProblem + }, + // SI-8362: AbstractPromise extends AtomicReference + // It's ok to change a package-protected class in an impl package, + // even though it's not clear why it changed -- bug in generic signature generation? + // -public class scala.concurrent.impl.Promise$DefaultPromise<T> extends scala.concurrent.impl.AbstractPromise implements scala.concurrent.impl.Promise<T> + // +public class scala.concurrent.impl.Promise$DefaultPromise<T extends java.lang.Object> extends scala.concurrent.impl.AbstractPromise implements scala.concurrent.impl.Promise<T> + { + matchName="scala.concurrent.impl.Promise$DefaultPromise" + problemName=MissingTypesProblem + }, + // SI-9488: Due to SI-8362 above, toString was silently changed to the AtomicReference toString implementation, + // This is fixed by SI-9488, and this should be safe since the class in question is stdlib internal. + { + matchName="scala.concurrent.impl.Promise.toString" + problemName=MissingMethodProblem + }, + // https://github.com/scala/scala/pull/5652 + { + matchName="scala.collection.mutable.ArrayOps#ofChar.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.slice" + problemName=FinalMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index eee2d6df34..ad778f447a 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -60,6 +60,355 @@ filter { problemName=DirectMissingMethodProblem }, { + matchName="scala.reflect.api.SerializedTypeTag.serialVersionUID" + problemName=MissingFieldProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofChar" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofShort" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofByte.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofByte.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofBoolean.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofBoolean.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofChar.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofChar.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofDouble.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofDouble.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofUnit" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofInt" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofBoolean" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofShort.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofShort.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofRef.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofRef.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofUnit.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofUnit.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOpsImpl" + problemName=MissingClassProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofInt.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofInt.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofDouble" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofRef" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofLong.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofLong.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofByte" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofByte" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofBoolean" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofChar" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofDouble" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofShort" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofRef" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofUnit" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofInt" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArrayImpl" + problemName=MissingClassProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofLong" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofFloat" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofFloat.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofFloat.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofLong" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofFloat" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.emptyImpl" + problemName=DirectMissingMethodProblem + }, + // introduce FilteredTraversableInternal + { + matchName="scala.collection.immutable.Nil$" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.immutable.FilteredTraversableInternal" + problemName=MissingClassProblem + }, + { + matchName="scala.collection.immutable.List" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.immutable.$colon$colon" + problemName=MissingTypesProblem + }, + { matchName="scala.annotation.showAsInfix$" problemName=MissingClassProblem }, diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 1a4671e15f..9129478b41 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -663,10 +663,9 @@ abstract class ClassfileParser { // so have to check unsafeTypeParams.isEmpty before worrying about raw type case below, // or we'll create a boatload of needless existentials. else if (classSym.isMonomorphicType || classSym.unsafeTypeParams.isEmpty) tp - else debuglogResult(s"raw type from $classSym"){ + else debuglogResult(s"raw type from $classSym") { // raw type - existentially quantify all type parameters - val eparams = typeParamsToExistentials(classSym, classSym.unsafeTypeParams) - newExistentialType(eparams, typeRef(pre, classSym, eparams.map(_.tpeHK))) + classExistentialType(pre, classSym) } case tp => assert(sig.charAt(index) != '<', s"sig=$sig, index=$index, tp=$tp") diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 3ce7db35d8..e327a6658c 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -456,7 +456,15 @@ abstract class Erasure extends InfoTransform override def newTyper(context: Context) = new Eraser(context) class ComputeBridges(unit: CompilationUnit, root: Symbol) { - assert(phase == currentRun.erasurePhase, phase) + + class BridgesCursor(root: Symbol) extends overridingPairs.Cursor(root) { + override def parents = List(root.info.firstParent) + // Varargs bridges may need generic bridges due to the non-repeated part of the signature of the involved methods. + // The vararg bridge is generated during refchecks (probably to simplify override checking), + // but then the resulting varargs "bridge" method may itself need an actual erasure bridge. + // TODO: like javac, generate just one bridge method that wraps Seq <-> varargs and does erasure-induced casts + override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym) + } var toBeRemoved = immutable.Set[Symbol]() val site = root.thisType @@ -464,12 +472,7 @@ abstract class Erasure extends InfoTransform val bridgeTarget = mutable.HashMap[Symbol, Symbol]() var bridges = List[Tree]() - val opc = enteringExplicitOuter { - new overridingPairs.Cursor(root) { - override def parents = List(root.info.firstParent) - override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym) - } - } + val opc = enteringExplicitOuter { new BridgesCursor(root) } def compute(): (List[Tree], immutable.Set[Symbol]) = { while (opc.hasNext) { @@ -860,6 +863,16 @@ abstract class Erasure extends InfoTransform } } + private class DoubleDefsCursor(root: Symbol) extends Cursor(root) { + // specialized members have no type history before 'specialize', causing double def errors for curried defs + override def exclude(sym: Symbol): Boolean = ( + sym.isType + || super.exclude(sym) + || !sym.hasTypeAt(currentRun.refchecksPhase.id) + ) + override def matches(lo: Symbol, high: Symbol) = !high.isPrivate + } + /** Emit an error if there is a double definition. This can happen if: * * - A template defines two members with the same name and erased type. @@ -870,21 +883,12 @@ abstract class Erasure extends InfoTransform */ private def checkNoDoubleDefs(root: Symbol) { checkNoDeclaredDoubleDefs(root) - object opc extends Cursor(root) { - // specialized members have no type history before 'specialize', causing double def errors for curried defs - override def exclude(sym: Symbol): Boolean = ( - sym.isType - || super.exclude(sym) - || !sym.hasTypeAt(currentRun.refchecksPhase.id) - ) - override def matches(lo: Symbol, high: Symbol) = !high.isPrivate - } def isErasureDoubleDef(pair: SymbolPair) = { import pair._ log(s"Considering for erasure clash:\n$pair") !exitingRefchecks(lowType matches highType) && sameTypeAfterErasure(low, high) } - opc.iterator filter isErasureDoubleDef foreach doubleDefError + (new DoubleDefsCursor(root)).iterator filter isErasureDoubleDef foreach doubleDefError } /** Add bridge definitions to a template. This means: diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala index 6fdaa79c10..dc0a457be7 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala @@ -116,8 +116,8 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { case _ => } - debug.patmat("sharedPrefix: "+ sharedPrefix) - debug.patmat("suffix: "+ sharedPrefix) + debug.patmat(s"sharedPrefix: $sharedPrefix") + debug.patmat(s"suffix: $suffix") // if the shared prefix contains interesting conditions (!= True) // and the last of such interesting shared conditions reuses another treemaker's test // replace the whole sharedPrefix by a ReusingCondTreeMaker diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 5750f8f7e7..39971590c7 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -109,25 +109,29 @@ trait MatchTranslation { // example check: List[Int] <:< ::[Int] private def extractorStep(): TranslationStep = { - def paramType = extractor.aligner.wholeType import extractor.treeMaker - // chain a type-testing extractor before the actual extractor call - // it tests the type, checks the outer pointer and casts to the expected type - // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC] - // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder) - lazy val typeTest = TypeTestTreeMaker(binder, binder, paramType, paramType)(pos, extractorArgTypeTest = true) - // check whether typetest implies binder is not null, - // even though the eventual null check will be on typeTest.nextBinder - // it'll be equal to binder casted to paramType anyway (and the type test is on binder) - def extraction: TreeMaker = treeMaker(typeTest.nextBinder, typeTest impliesBinderNonNull binder, pos) // paramType = the type expected by the unapply // TODO: paramType may contain unbound type params (run/t2800, run/t3530) - val makers = ( + val makers = { + val paramType = extractor.aligner.wholeType // Statically conforms to paramType if (tpe <:< paramType) treeMaker(binder, false, pos) :: Nil - else typeTest :: extraction :: Nil - ) + else { + // chain a type-testing extractor before the actual extractor call + // it tests the type, checks the outer pointer and casts to the expected type + // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC] + // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder) + val typeTest = TypeTestTreeMaker(binder, binder, paramType, paramType)(pos, extractorArgTypeTest = true) + val binderKnownNonNull = typeTest impliesBinderNonNull binder + + // check whether typetest implies binder is not null, + // even though the eventual null check will be on typeTest.nextBinder + // it'll be equal to binder casted to paramType anyway (and the type test is on binder) + typeTest :: treeMaker(typeTest.nextBinder, binderKnownNonNull, pos) :: Nil + } + } + step(makers: _*)(extractor.subBoundTrees: _*) } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index a787a7bc12..31476e86cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -189,7 +189,7 @@ abstract class RefChecks extends Transform { def varargBridge(member: Symbol, bridgetpe: Type): Tree = { log(s"Generating varargs bridge for ${member.fullLocationString} of type $bridgetpe") - val newFlags = (member.flags | VBRIDGE | ARTIFACT) & ~PRIVATE + val newFlags = (member.flags | VBRIDGE) & ~PRIVATE val bridge = member.cloneSymbolImpl(clazz, newFlags) setPos clazz.pos bridge.setInfo(bridgetpe.cloneInfo(bridge)) clazz.info.decls enter bridge diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 6d883aee3d..7943187f35 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -130,8 +130,9 @@ trait SyntheticMethods extends ast.TreeDSL { */ def canEqualMethod: Tree = { syntheticCanEqual = true - createMethod(nme.canEqual_, List(AnyTpe), BooleanTpe)(m => - Ident(m.firstParam) IS_OBJ classExistentialType(clazz)) + createMethod(nme.canEqual_, List(AnyTpe), BooleanTpe) { m => + Ident(m.firstParam) IS_OBJ classExistentialType(context.prefix, clazz) + } } /* that match { case _: this.C => true ; case _ => false } diff --git a/src/library/scala/collection/immutable/FilteredTraversableInternal.scala b/src/library/scala/collection/immutable/FilteredTraversableInternal.scala new file mode 100644 index 0000000000..35585b7826 --- /dev/null +++ b/src/library/scala/collection/immutable/FilteredTraversableInternal.scala @@ -0,0 +1,104 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package immutable + +import scala.annotation.tailrec + +/** + * Optimised filter functions for List + * n.b. this is an internal class to help maintain compatibility and should not be used directly. + */ +private[immutable] trait FilteredTraversableInternal[+A, +Repr <: AnyRef with TraversableLike[A, Repr]] extends TraversableLike[A, Repr] { + + // Optimized for List + + override def filter(p: A => Boolean): Self = filterImpl(p, isFlipped = false) + + override def filterNot(p: A => Boolean): Self = filterImpl(p, isFlipped = true) + + private[this] def filterImpl(p: A => Boolean, isFlipped: Boolean): Self = { + + // everything seen so far so far is not included + @tailrec def noneIn(l: Repr): Repr = { + if (l.isEmpty) + Nil.asInstanceOf[Repr] + else { + val h = l.head + val t = l.tail + if (p(h) != isFlipped) + allIn(l, t) + else + noneIn(t) + } + } + + // everything from 'start' is included, if everything from this point is in we can return the origin + // start otherwise if we discover an element that is out we must create a new partial list. + @tailrec def allIn(start: Repr, remaining: Repr): Repr = { + if (remaining.isEmpty) + start + else { + val x = remaining.head + if (p(x) != isFlipped) + allIn(start, remaining.tail) + else + partialFill(start, remaining) + } + } + + // we have seen elements that should be included then one that should be excluded, start building + def partialFill(origStart: Repr, firstMiss: Repr): Repr = { + val newHead = new ::(origStart.head, Nil) + var toProcess = origStart.tail + var currentLast = newHead + + // we know that all elements are :: until at least firstMiss.tail + while (!(toProcess eq firstMiss)) { + val newElem = new ::(toProcess.head, Nil) + currentLast.tl = newElem + currentLast = newElem + toProcess = toProcess.tail + } + + // at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss. + // currentLast is the last element in that list. + + // now we are going to try and share as much of the tail as we can, only moving elements across when we have to. + var next = firstMiss.tail + var nextToCopy = next // the next element we would need to copy to our list if we cant share. + while (!next.isEmpty) { + // generally recommended is next.isNonEmpty but this incurs an extra method call. + val head: A = next.head + if (p(head) != isFlipped) { + next = next.tail + } else { + // its not a match - do we have outstanding elements? + while (!(nextToCopy eq next)) { + val newElem = new ::(nextToCopy.head, Nil) + currentLast.tl = newElem + currentLast = newElem + nextToCopy = nextToCopy.tail + } + nextToCopy = next.tail + next = next.tail + } + } + + // we have remaining elements - they are unchanged attach them to the end + if (!nextToCopy.isEmpty) + currentLast.tl = nextToCopy.asInstanceOf[List[A]] + + newHead.asInstanceOf[Repr] + } + + noneIn(repr) + } +}
\ No newline at end of file diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index e5444533a8..e12ce7c2eb 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -88,6 +88,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] + with FilteredTraversableInternal[A, List[A]] with scala.Serializable { override def companion: GenericCompanion[List] = List @@ -163,30 +164,41 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Note to developers: there exists a duplication between this function and `reflect.internal.util.Collections#map2Conserve`. // If any successful optimization attempts or other changes are made, please rehash them there too. @tailrec - def loop(mapped: ListBuffer[B], unchanged: List[A], pending: List[A]): List[B] = - if (pending.isEmpty) { - if (mapped eq null) unchanged - else mapped.prependToList(unchanged) + def loop(mappedHead: List[B] = Nil, mappedLast: ::[B], unchanged: List[A], pending: List[A]): List[B] = + if (pending.isEmpty) { + if (mappedHead eq null) unchanged + else { + mappedLast.tl = unchanged + mappedHead } + } + else { + val head0 = pending.head + val head1 = f(head0) + + if (head1 eq head0.asInstanceOf[AnyRef]) + loop(mappedHead, mappedLast, unchanged, pending.tail) else { - val head0 = pending.head - val head1 = f(head0) - - if (head1 eq head0.asInstanceOf[AnyRef]) - loop(mapped, unchanged, pending.tail) - else { - val b = if (mapped eq null) new ListBuffer[B] else mapped - var xc = unchanged - while (xc ne pending) { - b += xc.head - xc = xc.tail - } - b += head1 - val tail0 = pending.tail - loop(b, tail0, tail0) + var xc = unchanged + var mappedHead1: List[B] = mappedHead + var mappedLast1: ::[B] = mappedLast + while (xc ne pending) { + val next = new ::[B](xc.head, Nil) + if (mappedHead1 eq null) mappedHead1 = next + if (mappedLast1 ne null) mappedLast1.tl = next + mappedLast1 = next + xc = xc.tail } + val next = new ::(head1, Nil) + if (mappedHead1 eq null) mappedHead1 = next + if (mappedLast1 ne null) mappedLast1.tl = next + mappedLast1 = next + val tail0 = pending.tail + loop(mappedHead1, mappedLast1, tail0, tail0) + } - loop(null, this, this) + } + loop(null, null, this, this) } // Overridden methods from IterableLike and SeqLike or overloaded variants of such methods @@ -402,6 +414,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Create a proxy for Java serialization that allows us to avoid mutation // during deserialization. This is the Serialization Proxy Pattern. protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) + } /** The empty list. diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 240b5c899e..5081b39bdc 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -125,7 +125,7 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L /** Returns a new queue with all elements provided by an `Iterable` object * added at the end of the queue. * - * The elements are prepended in the order they are given out by the + * The elements are appended in the order they are given out by the * iterator. * * @param iter an iterable object diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index afb4c9c552..4f2e9115fe 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -516,9 +516,10 @@ object RedBlackTree { * * According to {@see Integer#numberOfLeadingZeros} ceil(log_2(n)) = (32 - Integer.numberOfLeadingZeros(n - 1)) * - * We also don't store the deepest nodes in the path so the maximum path length is further reduced by one. + * Although we don't store the deepest nodes in the path during iteration, + * we potentially do so in `startFrom`. */ - val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2 - 1 + val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2 new Array[Tree[A, B]](maximumHeight) } private[this] var index = 0 diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 29382134aa..5de3dad256 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -10,6 +10,8 @@ package scala package collection package mutable +import java.util + import scala.reflect.ClassTag import parallel.mutable.ParArray @@ -180,6 +182,23 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara def seq = thisCollection } +/** to provide binary compat for 2.11 and 2.12 this class contains + * functionality that should be migrated to ArrayOps in 2.13 + * + */ +private[mutable] sealed trait ArrayOpsImpl[T] extends Any with ArrayOps[T] { + override final def slice(from: Int, until: Int): Array[T] = { + val start = if (from < 0) 0 else from + if (until <= start || start >= repr.length) + return emptyImpl + val end = if (until > length) length else until + sliceImpl(start, end) + } + protected def emptyImpl: Array[T] + protected def sliceImpl(from: Int, until: Int): Array[T] + +} + /** * A companion object for `ArrayOps`. * @@ -187,12 +206,24 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara */ object ArrayOps { + private val emptyByteArray = new Array[Byte](0) + private val emptyShortArray = new Array[Short](0) + private val emptyIntArray = new Array[Int](0) + private val emptyLongArray = new Array[Long](0) + private val emptyFloatArray = new Array[Float](0) + private val emptyDoubleArray = new Array[Double](0) + private val emptyUnitArray = new Array[Unit](0) + private val emptyCharArray = new Array[Char](0) + private val emptyBooleanArray = new Array[Boolean](0) + /** A subclass of `ArrayOps` for arrays containing reference types. */ - final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] { + final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOpsImpl[T] with ArrayLike[T, Array[T]] { override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr) override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr) override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](repr.getClass.getComponentType)) + protected override def emptyImpl:Array[T] = util.Arrays.copyOf[T](repr,0) + protected override def sliceImpl(from: Int, until: Int): Array[T] = util.Arrays.copyOfRange[T](repr, from, until) def length: Int = repr.length def apply(index: Int): T = repr(index) @@ -200,11 +231,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Byte`s. */ - final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { + final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOpsImpl[Byte] with ArrayLike[Byte, Array[Byte]] { override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def newBuilder = new ArrayBuilder.ofByte + protected override def emptyImpl = emptyByteArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Byte = repr(index) @@ -212,11 +245,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Short`s. */ - final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { + final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOpsImpl[Short] with ArrayLike[Short, Array[Short]] { override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def newBuilder = new ArrayBuilder.ofShort + protected override def emptyImpl = emptyShortArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Short = repr(index) @@ -224,11 +259,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Char`s. */ - final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { + final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOpsImpl[Char] with ArrayLike[Char, Array[Char]] { override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def newBuilder = new ArrayBuilder.ofChar + protected override def emptyImpl = emptyCharArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Char = repr(index) @@ -236,11 +273,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Int`s. */ - final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { + final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOpsImpl[Int] with ArrayLike[Int, Array[Int]] { override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def newBuilder = new ArrayBuilder.ofInt + protected override def emptyImpl = emptyIntArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Int = repr(index) @@ -248,11 +287,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Long`s. */ - final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { + final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOpsImpl[Long] with ArrayLike[Long, Array[Long]] { override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def newBuilder = new ArrayBuilder.ofLong + protected override def emptyImpl = emptyLongArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Long = repr(index) @@ -260,11 +301,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Float`s. */ - final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { + final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOpsImpl[Float] with ArrayLike[Float, Array[Float]] { override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def newBuilder = new ArrayBuilder.ofFloat + protected override def emptyImpl = emptyFloatArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Float = repr(index) @@ -272,11 +315,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Double`s. */ - final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { + final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOpsImpl[Double] with ArrayLike[Double, Array[Double]] { override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def newBuilder = new ArrayBuilder.ofDouble + protected override def emptyImpl = emptyDoubleArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Double = repr(index) @@ -284,11 +329,13 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays containing `Boolean`s. */ - final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { + final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOpsImpl[Boolean] with ArrayLike[Boolean, Array[Boolean]] { override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def newBuilder = new ArrayBuilder.ofBoolean + protected override def emptyImpl = emptyBooleanArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Boolean = repr(index) @@ -296,11 +343,18 @@ object ArrayOps { } /** A subclass of `ArrayOps` for arrays of `Unit` types. */ - final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { + final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOpsImpl[Unit] with ArrayLike[Unit, Array[Unit]] { override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def newBuilder = new ArrayBuilder.ofUnit + protected override def emptyImpl = emptyUnitArray + protected override def sliceImpl(from: Int, until: Int) = { + // cant use util.Arrays.copyOfRange[Unit](repr, from, until) - Unit is special and doesnt compile + val res = new Array[Unit](until-from) + System.arraycopy(repr, from, res, 0, res.size) + res + } def length: Int = repr.length def apply(index: Int): Unit = repr(index) diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 0b5ebe7e9a..d0919c4357 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -85,12 +85,26 @@ extends AbstractSeq[T] */ override protected[this] def newBuilder: Builder[T, WrappedArray[T]] = new WrappedArrayBuilder[T](elemTag) +} + +private[mutable] abstract class WrappedArrayImpl[T] extends WrappedArray[T] { + override def slice(from: Int, until: Int): WrappedArray[T] = { + val start = if (from < 0) 0 else from + if (until <= start || start >= repr.length) + return emptyImpl + val end = if (until > length) length else until + sliceImpl(start, end) + } + protected def emptyImpl: WrappedArray[T] + + protected def sliceImpl(from: Int, until: Int): WrappedArray[T] } /** A companion object used to create instances of `WrappedArray`. */ object WrappedArray { + import java.util // This is reused for all calls to empty. private val EmptyWrappedArray = new ofRef[AnyRef](new Array[AnyRef](0)) def empty[T <: AnyRef]: WrappedArray[T] = EmptyWrappedArray.asInstanceOf[WrappedArray[T]] @@ -124,7 +138,17 @@ object WrappedArray { def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer - final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable { + private val emptyWrappedByte = new ofByte(new Array[Byte](0)) + private val emptyWrappedShort = new ofShort(new Array[Short](0)) + private val emptyWrappedInt = new ofInt(new Array[Int](0)) + private val emptyWrappedLong = new ofLong(new Array[Long](0)) + private val emptyWrappedFloat = new ofFloat(new Array[Float](0)) + private val emptyWrappedDouble = new ofDouble(new Array[Double](0)) + private val emptyWrappedUnit = new ofUnit(new Array[Unit](0)) + private val emptyWrappedChar = new ofChar(new Array[Char](0)) + private val emptyWrappedBoolean = new ofBoolean(new Array[Boolean](0)) + + final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArrayImpl[T] with Serializable { lazy val elemTag = ClassTag[T](array.getClass.getComponentType) def length: Int = array.length def apply(index: Int): T = array(index).asInstanceOf[T] @@ -134,9 +158,11 @@ object WrappedArray { case that: ofRef[_] => Arrays.equals(array.asInstanceOf[Array[AnyRef]], that.array.asInstanceOf[Array[AnyRef]]) case _ => super.equals(that) } + protected override def emptyImpl = new ofRef(util.Arrays.copyOf[T](array,0)) + protected override def sliceImpl(from: Int, until: Int) = new ofRef[T](util.Arrays.copyOfRange[T](array, from, until)) } - final class ofByte(val array: Array[Byte]) extends WrappedArray[Byte] with Serializable { + final class ofByte(val array: Array[Byte]) extends WrappedArrayImpl[Byte] with Serializable { def elemTag = ClassTag.Byte def length: Int = array.length def apply(index: Int): Byte = array(index) @@ -146,9 +172,11 @@ object WrappedArray { case that: ofByte => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedByte + protected override def sliceImpl(from: Int, until: Int) = new ofByte(util.Arrays.copyOfRange(array, from, until)) } - final class ofShort(val array: Array[Short]) extends WrappedArray[Short] with Serializable { + final class ofShort(val array: Array[Short]) extends WrappedArrayImpl[Short] with Serializable { def elemTag = ClassTag.Short def length: Int = array.length def apply(index: Int): Short = array(index) @@ -158,9 +186,11 @@ object WrappedArray { case that: ofShort => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedShort + protected override def sliceImpl(from: Int, until: Int) = new ofShort(util.Arrays.copyOfRange(array, from, until)) } - final class ofChar(val array: Array[Char]) extends WrappedArray[Char] with Serializable { + final class ofChar(val array: Array[Char]) extends WrappedArrayImpl[Char] with Serializable { def elemTag = ClassTag.Char def length: Int = array.length def apply(index: Int): Char = array(index) @@ -170,9 +200,11 @@ object WrappedArray { case that: ofChar => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedChar + protected override def sliceImpl(from: Int, until: Int) = new ofChar(util.Arrays.copyOfRange(array, from, until)) } - final class ofInt(val array: Array[Int]) extends WrappedArray[Int] with Serializable { + final class ofInt(val array: Array[Int]) extends WrappedArrayImpl[Int] with Serializable { def elemTag = ClassTag.Int def length: Int = array.length def apply(index: Int): Int = array(index) @@ -182,9 +214,11 @@ object WrappedArray { case that: ofInt => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedInt + protected override def sliceImpl(from: Int, until: Int) = new ofInt(util.Arrays.copyOfRange(array, from, until)) } - final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable { + final class ofLong(val array: Array[Long]) extends WrappedArrayImpl[Long] with Serializable { def elemTag = ClassTag.Long def length: Int = array.length def apply(index: Int): Long = array(index) @@ -194,9 +228,11 @@ object WrappedArray { case that: ofLong => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedLong + protected override def sliceImpl(from: Int, until: Int) = new ofLong(util.Arrays.copyOfRange(array, from, until)) } - final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable { + final class ofFloat(val array: Array[Float]) extends WrappedArrayImpl[Float] with Serializable { def elemTag = ClassTag.Float def length: Int = array.length def apply(index: Int): Float = array(index) @@ -206,9 +242,11 @@ object WrappedArray { case that: ofFloat => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedFloat + protected override def sliceImpl(from: Int, until: Int) = new ofFloat(util.Arrays.copyOfRange(array, from, until)) } - final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable { + final class ofDouble(val array: Array[Double]) extends WrappedArrayImpl[Double] with Serializable { def elemTag = ClassTag.Double def length: Int = array.length def apply(index: Int): Double = array(index) @@ -218,9 +256,11 @@ object WrappedArray { case that: ofDouble => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedDouble + protected override def sliceImpl(from: Int, until: Int) = new ofDouble(util.Arrays.copyOfRange(array, from, until)) } - final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable { + final class ofBoolean(val array: Array[Boolean]) extends WrappedArrayImpl[Boolean] with Serializable { def elemTag = ClassTag.Boolean def length: Int = array.length def apply(index: Int): Boolean = array(index) @@ -230,9 +270,11 @@ object WrappedArray { case that: ofBoolean => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedBoolean + protected override def sliceImpl(from: Int, until: Int) = new ofBoolean(util.Arrays.copyOfRange(array, from, until)) } - final class ofUnit(val array: Array[Unit]) extends WrappedArray[Unit] with Serializable { + final class ofUnit(val array: Array[Unit]) extends WrappedArrayImpl[Unit] with Serializable { def elemTag = ClassTag.Unit def length: Int = array.length def apply(index: Int): Unit = array(index) @@ -242,5 +284,14 @@ object WrappedArray { case that: ofUnit => array.length == that.array.length case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedUnit + protected override def sliceImpl(from: Int, until: Int) = { + // cant use + // new ofUnit(util.Arrays.copyOfRange[Unit](array, from, until)) - Unit is special and doesnt compile + // cant use util.Arrays.copyOfRange[Unit](repr, from, until) - Unit is special and doesnt compile + val res = new Array[Unit](until-from) + System.arraycopy(repr, from, res, 0, until-from) + new ofUnit(res) + } } } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 78a75c63d6..315af267bc 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -667,8 +667,8 @@ trait Definitions extends api.StandardDefinitions { isBundle && isBlackbox } - def isListType(tp: Type) = tp <:< classExistentialType(ListClass) - def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass) + def isListType(tp: Type) = tp.typeSymbol.isNonBottomSubClass(ListClass) + def isIterableType(tp: Type) = tp.typeSymbol.isNonBottomSubClass(IterableClass) // These "direct" calls perform no dealiasing. They are most needed when // printing types when one wants to preserve the true nature of the type. @@ -980,14 +980,10 @@ trait Definitions extends api.StandardDefinitions { * * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... En >: LBn <: UBn }. */ - // TODO Review the way this is used. I see two potential problems: - // 1. `existentialAbstraction` here doesn't create fresh existential type symbols, it just - // uses the class type parameter symbols directly as the list of quantified symbols. - // See SI-8244 for the trouble that this can cause. - // Compare with callers of `typeParamsToExistentials` (used in Java raw type handling) - // 2. Why don't we require a prefix? Could its omission lead to wrong results in CheckabilityChecker? - def classExistentialType(clazz: Symbol): Type = - existentialAbstraction(clazz.typeParams, clazz.tpe_*) + def classExistentialType(prefix: Type, clazz: Symbol): Type = { + val eparams = typeParamsToExistentials(clazz, clazz.unsafeTypeParams) + newExistentialType(eparams, typeRef(prefix, clazz, eparams.map(_.tpeHK))) + } // members of class scala.Any diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 8aa6b16e06..d5bf8b7cef 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -163,7 +163,7 @@ class Flags extends ModifierFlags { final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies final val SPECIALIZED = 1L << 40 // symbol is a generated specialized member - final val VBRIDGE = 1L << 42 // symbol is a varargs bridge + final val VBRIDGE = 1L << 42 // symbol is a varargs bridge (but not a bridge at the bytecode level) final val VARARGS = 1L << 43 // symbol is a Java-style varargs method final val TRIEDCOOKING = 1L << 44 // `Cooking` has been tried on this symbol diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 2a0fb5298b..b46f071717 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3974,7 +3974,7 @@ trait Types * any corresponding non-variant type arguments of bt1 and bt2 are the same */ def isPopulated(tp1: Type, tp2: Type): Boolean = { - def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1.dealias, tp2.dealias) match { case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2, (sym1, sym2)) ( pre1 =:= pre2 diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 9138ed3f02..72e21f67fe 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -459,8 +459,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.DoubleTpe definitions.BooleanTpe definitions.ScalaNumericValueClasses - definitions.ScalaValueClassesNoUnit definitions.ScalaValueClasses + definitions.ScalaValueClassesNoUnit uncurry.VarargsSymbolAttachment uncurry.DesugaredParameterType diff --git a/test/benchmarks/src/main/scala/scala/collection/immutable/ListBenchmark.scala b/test/benchmarks/src/main/scala/scala/collection/immutable/ListBenchmark.scala new file mode 100644 index 0000000000..94844dcae2 --- /dev/null +++ b/test/benchmarks/src/main/scala/scala/collection/immutable/ListBenchmark.scala @@ -0,0 +1,72 @@ +package scala.collection.immutable + +import java.util.concurrent.TimeUnit + +import org.openjdk.jmh.annotations._ + +object ListBenchmark { + case class Content(value: Int) +} + +@BenchmarkMode(Array(Mode.AverageTime)) +@Fork(2) +@Threads(1) +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +class ListBenchmark { + import ListBenchmark._ + @Param(Array("0", "1", "10", "100", "1000")) + var size: Int = _ + + var values: List[Content] = _ + var mid: Content = _ + var last: Content = _ + + + @Setup(Level.Trial) def initKeys(): Unit = { + values = List.tabulate(size)(v => Content(v)) + mid = Content(size / 2) + last = Content(Math.max(0,size -1)) + } + + @Benchmark def filter_includeAll: Any = { + values.filter(v => true) + } + + @Benchmark def filter_excludeAll: Any = { + values.filter(_ => false) + } + + @Benchmark def filter_exc_mid: Any = { + values.filter(v => v.value != mid.value) + } + + @Benchmark def filter_from_mid: Any = { + values.filter(v => v.value <= mid.value) + } + + @Benchmark def filter_exc_last: Any = { + values.filter(v => v.value != last.value) + } + + @Benchmark def filter_only_last: Any = { + values.filter(v => v.value == last.value) + } + + @Setup(Level.Trial) def initKeys(): Unit = { + values = List.tabulate(size)(n => if (n == size / 2) "mid" else "") + } + + @Benchmark def mapConserve_identity: Any = { + values.mapConserve(x => x) + } + + @Benchmark def mapConserve_modifyAll: Any = { + values.mapConserve(x => "replace") + } + @Benchmark def mapConserve_modifyMid: Any = { + values.mapConserve(x => if (x == "mid") "replace" else x) + } +} diff --git a/test/files/pos/t9331.scala b/test/files/pos/t9331.scala new file mode 100644 index 0000000000..00a667886f --- /dev/null +++ b/test/files/pos/t9331.scala @@ -0,0 +1,6 @@ +import scala.language.higherKinds + +trait Proxy[+T] +case class Stuff[+P[PP] <: Proxy[PP]]() { + // canEqual was incorrectly synthetized and started reporting a kind error. +} diff --git a/test/files/run/existentials-in-compiler.check b/test/files/run/existentials-in-compiler.check index b0d852865d..8800df0823 100644 --- a/test/files/run/existentials-in-compiler.check +++ b/test/files/run/existentials-in-compiler.check @@ -2,28 +2,28 @@ abstract trait Bippy[A <: AnyRef, B] extends AnyRef extest.Bippy[_ <: AnyRef, _] abstract trait BippyBud[A <: AnyRef, B, C <: List[A]] extends AnyRef - extest.BippyBud[A,B,C] forSome { A <: AnyRef; B; C <: List[A] } + extest.BippyBud[?0,?1,?2] forSome { type ?0 <: AnyRef; type ?1; type ?2 <: List[?0] } abstract trait BippyLike[A <: AnyRef, B <: List[A], This <: extest.BippyLike[A,B,This] with extest.Bippy[A,B]] extends AnyRef - extest.BippyLike[A,B,This] forSome { A <: AnyRef; B <: List[A]; This <: extest.BippyLike[A,B,This] with extest.Bippy[A,B] } + extest.BippyLike[?0,?1,?2] forSome { type ?0 <: AnyRef; type ?1 <: List[?0]; type ?2 <: extest.BippyLike[?0,?1,?2] with extest.Bippy[?0,?1] } abstract trait Contra[-A >: AnyRef, -B] extends AnyRef - extest.Contra[AnyRef, _] + extest.Contra[_ >: AnyRef, _] abstract trait ContraLike[-A >: AnyRef, -B >: List[A]] extends AnyRef - extest.ContraLike[A,B] forSome { -A >: AnyRef; -B >: List[A] } + extest.ContraLike[?0,?1] forSome { type ?0 >: AnyRef; type ?1 >: List[?0] } abstract trait Cov01[+A <: AnyRef, +B] extends AnyRef - extest.Cov01[AnyRef,Any] + extest.Cov01[_ <: AnyRef, _] abstract trait Cov02[+A <: AnyRef, B] extends AnyRef - extest.Cov02[AnyRef, _] + extest.Cov02[_ <: AnyRef, _] abstract trait Cov03[+A <: AnyRef, -B] extends AnyRef - extest.Cov03[AnyRef, _] + extest.Cov03[_ <: AnyRef, _] abstract trait Cov04[A <: AnyRef, +B] extends AnyRef - extest.Cov04[_ <: AnyRef, Any] + extest.Cov04[_ <: AnyRef, _] abstract trait Cov05[A <: AnyRef, B] extends AnyRef extest.Cov05[_ <: AnyRef, _] @@ -32,7 +32,7 @@ abstract trait Cov06[A <: AnyRef, -B] extends AnyRef extest.Cov06[_ <: AnyRef, _] abstract trait Cov07[-A <: AnyRef, +B] extends AnyRef - extest.Cov07[_ <: AnyRef, Any] + extest.Cov07[_ <: AnyRef, _] abstract trait Cov08[-A <: AnyRef, B] extends AnyRef extest.Cov08[_ <: AnyRef, _] @@ -41,16 +41,16 @@ abstract trait Cov09[-A <: AnyRef, -B] extends AnyRef extest.Cov09[_ <: AnyRef, _] abstract trait Cov11[+A <: AnyRef, +B <: List[_]] extends AnyRef - extest.Cov11[AnyRef,List[_]] + extest.Cov11[_ <: AnyRef, _ <: List[_]] abstract trait Cov12[+A <: AnyRef, B <: List[_]] extends AnyRef - extest.Cov12[AnyRef, _ <: List[_]] + extest.Cov12[_ <: AnyRef, _ <: List[_]] abstract trait Cov13[+A <: AnyRef, -B <: List[_]] extends AnyRef - extest.Cov13[AnyRef, _ <: List[_]] + extest.Cov13[_ <: AnyRef, _ <: List[_]] abstract trait Cov14[A <: AnyRef, +B <: List[_]] extends AnyRef - extest.Cov14[_ <: AnyRef, List[_]] + extest.Cov14[_ <: AnyRef, _ <: List[_]] abstract trait Cov15[A <: AnyRef, B <: List[_]] extends AnyRef extest.Cov15[_ <: AnyRef, _ <: List[_]] @@ -59,7 +59,7 @@ abstract trait Cov16[A <: AnyRef, -B <: List[_]] extends AnyRef extest.Cov16[_ <: AnyRef, _ <: List[_]] abstract trait Cov17[-A <: AnyRef, +B <: List[_]] extends AnyRef - extest.Cov17[_ <: AnyRef, List[_]] + extest.Cov17[_ <: AnyRef, _ <: List[_]] abstract trait Cov18[-A <: AnyRef, B <: List[_]] extends AnyRef extest.Cov18[_ <: AnyRef, _ <: List[_]] @@ -68,16 +68,16 @@ abstract trait Cov19[-A <: AnyRef, -B <: List[_]] extends AnyRef extest.Cov19[_ <: AnyRef, _ <: List[_]] abstract trait Cov21[+A, +B] extends AnyRef - extest.Cov21[Any,Any] + extest.Cov21[_, _] abstract trait Cov22[+A, B] extends AnyRef - extest.Cov22[Any, _] + extest.Cov22[_, _] abstract trait Cov23[+A, -B] extends AnyRef - extest.Cov23[Any, _] + extest.Cov23[_, _] abstract trait Cov24[A, +B] extends AnyRef - extest.Cov24[_, Any] + extest.Cov24[_, _] abstract trait Cov25[A, B] extends AnyRef extest.Cov25[_, _] @@ -86,7 +86,7 @@ abstract trait Cov26[A, -B] extends AnyRef extest.Cov26[_, _] abstract trait Cov27[-A, +B] extends AnyRef - extest.Cov27[_, Any] + extest.Cov27[_, _] abstract trait Cov28[-A, B] extends AnyRef extest.Cov28[_, _] @@ -95,43 +95,43 @@ abstract trait Cov29[-A, -B] extends AnyRef extest.Cov29[_, _] abstract trait Cov31[+A, +B, C <: (A, B)] extends AnyRef - extest.Cov31[A,B,C] forSome { +A; +B; C <: (A, B) } + extest.Cov31[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov32[+A, B, C <: (A, B)] extends AnyRef - extest.Cov32[A,B,C] forSome { +A; B; C <: (A, B) } + extest.Cov32[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov33[+A, -B, C <: Tuple2[A, _]] extends AnyRef - extest.Cov33[A,B,C] forSome { +A; -B; C <: Tuple2[A, _] } + extest.Cov33[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[?0, _] } abstract trait Cov34[A, +B, C <: (A, B)] extends AnyRef - extest.Cov34[A,B,C] forSome { A; +B; C <: (A, B) } + extest.Cov34[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov35[A, B, C <: (A, B)] extends AnyRef - extest.Cov35[A,B,C] forSome { A; B; C <: (A, B) } + extest.Cov35[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov36[A, -B, C <: Tuple2[A, _]] extends AnyRef - extest.Cov36[A,B,C] forSome { A; -B; C <: Tuple2[A, _] } + extest.Cov36[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[?0, _] } abstract trait Cov37[-A, +B, C <: Tuple2[_, B]] extends AnyRef - extest.Cov37[A,B,C] forSome { -A; +B; C <: Tuple2[_, B] } + extest.Cov37[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[_, ?1] } abstract trait Cov38[-A, B, C <: Tuple2[_, B]] extends AnyRef - extest.Cov38[A,B,C] forSome { -A; B; C <: Tuple2[_, B] } + extest.Cov38[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[_, ?1] } abstract trait Cov39[-A, -B, C <: Tuple2[_, _]] extends AnyRef extest.Cov39[_, _, _ <: Tuple2[_, _]] abstract trait Cov41[+A >: Null, +B] extends AnyRef - extest.Cov41[Any,Any] + extest.Cov41[_ >: Null, _] abstract trait Cov42[+A >: Null, B] extends AnyRef - extest.Cov42[Any, _] + extest.Cov42[_ >: Null, _] abstract trait Cov43[+A >: Null, -B] extends AnyRef - extest.Cov43[Any, _] + extest.Cov43[_ >: Null, _] abstract trait Cov44[A >: Null, +B] extends AnyRef - extest.Cov44[_ >: Null, Any] + extest.Cov44[_ >: Null, _] abstract trait Cov45[A >: Null, B] extends AnyRef extest.Cov45[_ >: Null, _] @@ -140,7 +140,7 @@ abstract trait Cov46[A >: Null, -B] extends AnyRef extest.Cov46[_ >: Null, _] abstract trait Cov47[-A >: Null, +B] extends AnyRef - extest.Cov47[_ >: Null, Any] + extest.Cov47[_ >: Null, _] abstract trait Cov48[-A >: Null, B] extends AnyRef extest.Cov48[_ >: Null, _] @@ -149,8 +149,8 @@ abstract trait Cov49[-A >: Null, -B] extends AnyRef extest.Cov49[_ >: Null, _] abstract trait Covariant[+A <: AnyRef, +B] extends AnyRef - extest.Covariant[AnyRef,Any] + extest.Covariant[_ <: AnyRef, _] abstract trait CovariantLike[+A <: AnyRef, +B <: List[A], +This <: extest.CovariantLike[A,B,This] with extest.Covariant[A,B]] extends AnyRef - extest.CovariantLike[A,B,This] forSome { +A <: AnyRef; +B <: List[A]; +This <: extest.CovariantLike[A,B,This] with extest.Covariant[A,B] } + extest.CovariantLike[?0,?1,?2] forSome { type ?0 <: AnyRef; type ?1 <: List[?0]; type ?2 <: extest.CovariantLike[?0,?1,?2] with extest.Covariant[?0,?1] } diff --git a/test/files/run/existentials-in-compiler.scala b/test/files/run/existentials-in-compiler.scala index e516eddf95..e35b7231c2 100644 --- a/test/files/run/existentials-in-compiler.scala +++ b/test/files/run/existentials-in-compiler.scala @@ -79,7 +79,7 @@ package extest { exitingTyper { clazz.info println(clazz.defString) - println(" " + classExistentialType(clazz) + "\n") + println(" " + classExistentialType(clazz.owner.typeOfThis, clazz) + "\n") } } } diff --git a/test/files/run/repl-colon-type.check b/test/files/run/repl-colon-type.check index 1217e8d8c2..5b7a3c7506 100644 --- a/test/files/run/repl-colon-type.check +++ b/test/files/run/repl-colon-type.check @@ -75,7 +75,7 @@ TypeRef( ) TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List( @@ -142,7 +142,7 @@ TypeRef( args = List( TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List( @@ -175,7 +175,7 @@ PolyType( args = List( TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List(TypeParamTypeRef(TypeParam(T <: AnyVal))) @@ -198,7 +198,7 @@ PolyType( params = List(TermSymbol(x: T), TermSymbol(y: List[U])) resultType = TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List(TypeParamTypeRef(TypeParam(U >: T))) diff --git a/test/files/run/t1459.check b/test/files/run/t1459.check new file mode 100644 index 0000000000..93b4c5a810 --- /dev/null +++ b/test/files/run/t1459.check @@ -0,0 +1,3 @@ +JavaPrinter: one two three +InheritingPrinter extends JavaPrinter: one two three +ScalaPrinter: onetwothree diff --git a/test/files/run/t1459/InheritingPrinter.scala b/test/files/run/t1459/InheritingPrinter.scala new file mode 100644 index 0000000000..70301307f5 --- /dev/null +++ b/test/files/run/t1459/InheritingPrinter.scala @@ -0,0 +1,6 @@ +class InheritingPrinter extends JavaPrinter { + override def doit(s: String*) { + print("InheritingPrinter extends ") + super.doit(s: _*); + } +}
\ No newline at end of file diff --git a/test/files/run/t1459/JavaPrinter.java b/test/files/run/t1459/JavaPrinter.java new file mode 100644 index 0000000000..3912ea613a --- /dev/null +++ b/test/files/run/t1459/JavaPrinter.java @@ -0,0 +1,7 @@ +public class JavaPrinter implements VarArg { + public void doit(String... s) { + System.out.print("JavaPrinter: "); + for(String str : s) + System.out.print(str + " "); + } +} diff --git a/test/files/run/t1459/ScalaPrinter.scala b/test/files/run/t1459/ScalaPrinter.scala new file mode 100644 index 0000000000..46305804c2 --- /dev/null +++ b/test/files/run/t1459/ScalaPrinter.scala @@ -0,0 +1,6 @@ +class ScalaPrinter extends VarArg { + override def doit(s: String*) = { + print("ScalaPrinter: ") + s.foreach(print _) + } +}
\ No newline at end of file diff --git a/test/files/run/t1459/Test.java b/test/files/run/t1459/Test.java new file mode 100644 index 0000000000..3cf91e2e8b --- /dev/null +++ b/test/files/run/t1459/Test.java @@ -0,0 +1,15 @@ +public class Test { + public static void main(String[] args) { + VarArg jp = new JavaPrinter(); + VarArg ip = new InheritingPrinter(); + VarArg sp = new ScalaPrinter(); + doYourThing(jp); + doYourThing(ip); + doYourThing(sp); + } + + public static void doYourThing(VarArg va) { + va.doit("one", "two", "three"); + System.out.println(); + } +} diff --git a/test/files/run/t1459/VarArg.java b/test/files/run/t1459/VarArg.java new file mode 100644 index 0000000000..7039f99e7b --- /dev/null +++ b/test/files/run/t1459/VarArg.java @@ -0,0 +1,3 @@ +public interface VarArg { + void doit(String... s); +} diff --git a/test/files/run/t1459generic.check b/test/files/run/t1459generic.check new file mode 100644 index 0000000000..346fadbc0d --- /dev/null +++ b/test/files/run/t1459generic.check @@ -0,0 +1,4 @@ +Note: t1459generic/Test.java uses unchecked or unsafe operations. +Note: Recompile with -Xlint:unchecked for details. +ab +ab diff --git a/test/files/run/t1459generic/Impl.scala b/test/files/run/t1459generic/Impl.scala new file mode 100644 index 0000000000..9234e70456 --- /dev/null +++ b/test/files/run/t1459generic/Impl.scala @@ -0,0 +1,4 @@ +class Impl extends VarargGeneric[String] { + def genericOne(x: String, arg: String): String = x + arg + def genericVar(x: String, args: String*): String = x + args.head +} diff --git a/test/files/run/t1459generic/Test.java b/test/files/run/t1459generic/Test.java new file mode 100644 index 0000000000..a97158796b --- /dev/null +++ b/test/files/run/t1459generic/Test.java @@ -0,0 +1,10 @@ +public class Test { + public static void main(String[] args) throws Exception { + VarargGeneric vg = new Impl(); + System.out.println(vg.genericOne("a", "b")); + System.out.println(vg.genericVar("a", "b")); + // should not result in java.lang.AbstractMethodError: Impl.genericVar(Ljava/lang/Object;[Ljava/lang/String;)Ljava/lang/String; + // --> genericVar needs a varargs bridge (scala -> java varargs) and a standard generics bridge + // (for comparison, including genericOne, which needs only a generics bridge) + } +} diff --git a/test/files/run/t1459generic/VarargGeneric.java b/test/files/run/t1459generic/VarargGeneric.java new file mode 100644 index 0000000000..9b37a0fe3f --- /dev/null +++ b/test/files/run/t1459generic/VarargGeneric.java @@ -0,0 +1,7 @@ +public interface VarargGeneric<T> { + String genericOne(T x, String args); + // we cannot annotate this with @SafeVarargs, because + // it's in an interface. so that's why a warning from + // javac appears in the checkfile. + String genericVar(T x, String... args); +} diff --git a/test/files/run/t9013/Test.java b/test/files/run/t9013/Test.java new file mode 100644 index 0000000000..14152b16ac --- /dev/null +++ b/test/files/run/t9013/Test.java @@ -0,0 +1,20 @@ +import java.util.Comparator; + +public class Test { + public static void main(String[] args) { + ClassImplementsClass c = new ClassImplementsClass(); + + c.x("a", "b", "c"); + c.y("a", "b", "c"); + c.z("a", "b", "c"); + + VarargAbstractClass i = new ClassImplementsClass(); + + i.x("a", "b", "c"); + i.y("a", "b", "c"); + // System.out.println(i.z("a", "b", "c")); // still incurs a LinkageError. + // Perhaps due to Uncurry: + // > for every repeated Java parameter `x: T...' --> x: Array[T], except: + // > if T is an unbounded abstract type, replace --> x: Array[Object] + } +} diff --git a/test/files/run/t9013/test.scala b/test/files/run/t9013/test.scala new file mode 100644 index 0000000000..073f8d086f --- /dev/null +++ b/test/files/run/t9013/test.scala @@ -0,0 +1,18 @@ +import scala.annotation.varargs + +abstract class VarargAbstractClass[T] { + @varargs + def x(els: String*): Int + + @varargs + def y(els: String*): Int + + @varargs + def z(els: T*): Int +} +class ClassImplementsClass extends VarargAbstractClass[String] { + + override def x(els: String*): Int = els.length + override def y(els: String*): Int = els.length + override def z(els: String*): Int = els.length +} diff --git a/test/files/run/t9114.scala b/test/files/run/t9114.scala new file mode 100644 index 0000000000..656a5c7d8d --- /dev/null +++ b/test/files/run/t9114.scala @@ -0,0 +1,31 @@ +import annotation.unchecked + +class Test { + trait Two[A, B] + type One[A] = Two[A,A] + class View extends One[Any] + + def checkAny(x: Some[One[Any]]) = x match { // okay + case Some(_: View) => true + case _ => false + } + def checkAbstract[A](x: Some[One[A]]) = x match { // okay + case Some(_: View) => true + case _ => false + } + + def checkExistential(x: Some[One[_]]) = x match { + case Some(_: View) => true // compiler crash + case _ => false + } +} + +object Test { + def main(args: Array[String]): Unit = { + val t1 = new Test + val t2 = new Test + assert(t1.checkAny(Some(new t1.View))) + assert(t1.checkAbstract(Some(new t1.View))) + assert(t1.checkExistential(Some(new t1.View))) + } +} diff --git a/test/junit/scala/collection/IndexedSeqTest.scala b/test/junit/scala/collection/IndexedSeqTest.scala new file mode 100644 index 0000000000..a33849e60b --- /dev/null +++ b/test/junit/scala/collection/IndexedSeqTest.scala @@ -0,0 +1,578 @@ +package scala.collection + +import org.junit.Test +import org.junit.Ignore +import org.junit.Assert.{assertEquals, _} +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +// with the Ant JUnit runner, it's necessary to @Ignore the abstract +// classes here, or JUnit tries to instantiate them. the annotations +// can be removed when this is merged forward (TODO 2.12.x) + +/** + * base class for testing common methods on a various implementations + * + * @tparam T the collection type + * @tparam E the element type + */ +@RunWith(classOf[JUnit4]) +@Ignore +abstract class IndexedTest[T, E] { + + protected def size = 10 + + /** + * create a new instance of the test data with known values + */ + protected def underTest(size: Int): T + + /** + * returns the value of the data that is expected to be present int the original data at index {{{index}}} + * This is conceptully the same as the normal apply operation but unavaialbe due to the base types of T not supporting apply + * + * @param index the index to use for the returned value + * @return the value at the specified index + */ + protected def expectedValueAtIndex(index: Int): E + /** + * check some simple indexed access + */ + @Test def checkIndexedAccess: Unit = { + val test = underTest(size) + for (i <- 0 until size) { + assertEquals(s" at index $i", expectedValueAtIndex(i), get(test, i)) + } + } + + /** + * check simple equallity of the initial data. + * More a test of the infra that we use in this est than a full test of equallity + */ + @Test def checkEquals: Unit = { + val test1 = underTest(size) + val test2 = underTest(size) + doAssertEquals("", test1, test2) + assertNotSame(test1, test2) + expectSameContent("basic equallity", false, test1, test2, 0, size) + } + + protected def expectSameContent(txt: String, canBeSame:Boolean, orig: T, test: T, offset: Int, len: Int): Unit = { + val txtAndState = s"$txt canBeSame $canBeSame isMutableContent $isMutableContent isTakeAllSame $isTakeAllSame offset $offset len $len length(test) ${length(test)}" + val isValidSame = canBeSame && !isMutableContent && offset == 0 && len == size + if (isValidSame && isTakeAllSame) + assertSame(txtAndState, orig, test) + else + assertNotSame(txtAndState, orig, test) + assertSame(txtAndState, len, length(test)) + for (i <- 0 until len) { + assertEquals(s" $txtAndState $i $offset $len", expectedValueAtIndex(i + offset), get(test, i)) + } + } + + /** + * check the operation of {{{take}}} when the parameter is less than the size of the test data + */ + @Test def checkTakeNormal: Unit = { + val orig = underTest(size) + for (len <- 0 until size) { + val taken = take(orig, len) + expectSameContent(s" len $len", true, orig, taken, 0, len) + } + } + + /** + * check the operation of {{{slice}}} within the bounds of the source + */ + @Test def checkSliceNormal: Unit = { + val orig = underTest(size) + for ( + from <- 0 until size; + to <- from until size) { + + val sliced = slice(orig, from, to) + expectSameContent(s"from $from, to $to", true, orig, sliced, from, to - from) + } + } + + /** + * check the operation of {{{take}}} works for size of 0 + * There is a special case tha for some implementations empty will be a singleton + */ + @Test def checkTakeEmpty: Unit = { + val orig = underTest(size) + val empty1 = take(orig, 0) + val empty2 = take(orig, 0) + assertEquals(0, length(empty1)) + if (isEmptyConstant) assertSame(empty1, empty2) + } + + /** + * check the operation of {{{slice}}} works for size of 0 + * There is a special case tha for some implementations empty will be a singleton + */ + @Test def checkSliceEmpty: Unit = { + val orig = underTest(size) + for (start <- 0 until size) { + val empty1 = slice(orig, start, start) + val empty2 = slice(orig, start, start) + assertEquals(s"start $start", 0, length(empty1)) + if (isEmptyConstant) assertSame(s"start $start", empty1, empty2) + } + } + + /** + * check the operation of {{{take}}} works for the entire content + * There is a special case that for some immutable implementations they can share the result + */ + @Test def checkTakeAll: Unit = { + val orig = underTest(size) + val all = take(orig, size) + assertEquals(size, length(all)) + expectSameContent("take all", true, orig, all, 0, size) + if (isMutableContent) + assertNotSame(orig, all) + else if (isTakeAllSame) + assertSame(orig, all) + } + + /** + * check the operation of {{{slice}}} works for the entire content + * There is a special case that for some immutable implementations they can share the result + */ + @Test def checkSliceAll: Unit = { + val orig = underTest(size) + val all = slice(orig, 0, size) + assertEquals(size, length(all)) + expectSameContent("", true, orig, all, 0, size) + if (isMutableContent) + assertNotSame(orig, all) + else if (isTakeAllSame) + assertSame(orig, all) + } + + /** + * check that take operates appropriately for negative values + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkTakeNeg: Unit = { + val orig = underTest(size) + val e = take(orig, 0) + for (len <- List(-1, -10, -99, Int.MinValue)) { + val empty = take(orig, len) + assertEquals(s"len $len", 0, length(empty)) + if (isEmptyConstant) assertSame(s"len $len", e, empty) + } + } + + /** + * check that take operates appropriately for lengths that exceed the input size + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkTakeTooBig: Unit = { + val orig = underTest(size) + val e = take(orig, 0) + for (len <- List(size + 1, size + 10, Int.MaxValue)) { + val all = take(orig, len) + assertEquals(s"len $len", size, length(all)) + expectSameContent("", true, orig, all, 0, size) + } + } + + /** + * check that slice operates appropriately for negative start point + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkSliceFromNeg: Unit = { + val orig = underTest(size) + for ( + from <- List(-1, -10, -99, Int.MinValue); + to <- List(-1, 0, 1, 5)) { + val start = slice(orig, from, to) + expectSameContent(s"from $from, to $to", true, orig, start, 0, Math.max(0, to)) + } + } + + /** + * check that slice operates appropriately for out of range end values + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkSliceToTooBig: Unit = { + val orig = underTest(size) + for ( + from <- List(-1, -10, -99, Int.MinValue, 0, 1, 5); + to <- List(size + 1, size + 10, Int.MaxValue)) { + val start = slice(orig, from, to) + val realStart = Math.max(0, from) + val realLen = size - realStart + expectSameContent(s"from $from, to $to", true, orig, start, realStart, realLen) + } + } + + /** + * check that slice operates appropriately for negative values start and ends too large + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkSliceFromNegAndToTooBig: Unit = { + val orig = underTest(size) + for ( + from <- List(-1, -10, -99, Int.MinValue); + to <- List(size + 1, size + 10, Int.MaxValue)) { + val all = slice(orig, from, to) + expectSameContent(s"from $from, to $to", true, orig, all, 0, size) + } + } + + protected def intercept[EX <: Exception : Manifest](fn: => Any) { + try { + val res = fn + fail(s"expected exception was not thrown: $res") + } catch { + case failed: AssertionError => throw failed + case e: Exception if manifest[EX].runtimeClass.isAssignableFrom(e.getClass) => + } + } + + //accessors + //the length of underTest + def length(underTest: T): Int + + //the value at index i of underTest + def get(underTest: T, i: Int): E + + def slice(underTest: T, from: Int, to: Int): T + + def take(underTest: T, size: Int): T + + //behaviour + /** is an empty value the same JVM instance */ + def isEmptyConstant: Boolean + + /** is a take / slice that results in all the data returned return this + * This is only relevant if !isMutableContent + */ + def isTakeAllSame: Boolean + + /** is the content of the collection mutable. + * If mutable there is not data sharing allowed by take/slice, if immutable then data sharing is possible + * and tested based on isTakeAllSame + */ + def isMutableContent: Boolean + + //helpers + //delegate equals check for support arrays + def doAssertEquals(txt: String, expected: T, actual: T) + +} +package IndexedTestImpl { + import java.lang.reflect.{Array => jlArray} + import java.lang.{Boolean => jlBoolean} + import java.lang.{Byte => jlByte} + import java.lang.{Short => jlShort} + import java.lang.{Integer => jlInt} + import java.lang.{Long => jlLong} + import java.lang.{Float => jlFloat} + import java.lang.{Double => jlDouble} + import java.lang.{Character => jlChar} + + import scala.collection.immutable.{StringLike, StringOps, WrappedString} + import scala.collection.mutable + import scala.runtime.BoxedUnit + trait DataProvider[E] { + protected def expectedValueAtIndex(index: Int): E = { + val someNumber = index + jlInt.bitCount(index) + toType(someNumber) + } + + protected def toType(n: Int): E + } + trait StringTestData extends DataProvider [String] { + def toType(n: Int) = n.toString + } + trait ByteTestData extends DataProvider [Byte] { + def toType(n: Int) = n.toByte + } + trait ShortTestData extends DataProvider [Short] { + def toType(n: Int) = n.toShort + } + trait IntTestData extends DataProvider [Int] { + def toType(n: Int) = n + } + trait LongTestData extends DataProvider [Long] { + def toType(n: Int) = n + } + trait FloatTestData extends DataProvider [Float] { + def toType(n: Int) = n + } + trait DoubleTestData extends DataProvider [Double] { + def toType(n: Int) = n + } + trait CharTestData extends DataProvider [Char] { + def toType(n: Int)= (n+64).toChar + } + trait BooleanTestData extends DataProvider [Boolean] { + def toType(n: Int)= (n & 0) == 0 + } + trait UnitTestData extends DataProvider [BoxedUnit] { + def toType(n: Int)= if ((n & 0) == 0) null else BoxedUnit.UNIT + } + + @Ignore + abstract class ArrayTest[E] ( + //the object or primitive type of the array + val TYPE: Class[_]) extends IndexedTest[Array[E], E]{ + override final def length(underTest: Array[E]) = underTest.length + + override def get(underTest: Array[E], i: Int) = underTest(i) + + override def slice(underTest: Array[E], from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: Array[E], size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = true + + override def isTakeAllSame = false + + override def doAssertEquals(txt: String, expected: Array[E], actual: Array[E]): Unit = { + assertEquals(txt, expected.mkString("'"), actual.mkString("'")) + } + + override def underTest(size: Int): Array[E] = { + val res = jlArray.newInstance(TYPE, size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + res.asInstanceOf[Array[E]] + } + } + + + @Ignore + abstract class WrappedArrayTest[E]( + //the object or primitive type of the array + val TYPE: Class[_]) extends IndexedTest[mutable.WrappedArray[E], E] with DataProvider[E]{ + import mutable.WrappedArray + override final def length(underTest: WrappedArray[E]) = underTest.length + + override def get(underTest: WrappedArray[E], i: Int) = underTest(i) + + override def slice(underTest: WrappedArray[E], from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: WrappedArray[E], size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = true + + override def isTakeAllSame = false + + override def doAssertEquals(txt: String, expected: WrappedArray[E], actual: WrappedArray[E]): Unit = { + assertEquals(txt, expected.mkString("'"), actual.mkString("'")) + } + + override def underTest(size: Int): WrappedArray[E] = { + val res = jlArray.newInstance(TYPE, size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + WrappedArray.make(res.asInstanceOf[Array[E]]) + } + } + + //construct the data using java as much as possible to avoid invalidating the test + + @Ignore + abstract class MutableIndexedSeqTest[T <: mutable.Seq[E], E] extends IndexedTest[T, E] with DataProvider[E]{ + override final def length(underTest: T) = underTest.length + + override def get(underTest: T, i: Int) = underTest(i) + + override def slice(underTest: T, from: Int, to: Int) = underTest.slice(from, to).asInstanceOf[T] + + override def take(underTest: T, size: Int) = underTest.take(size).asInstanceOf[T] + + override def isEmptyConstant = false + + override def isMutableContent = true + + override def isTakeAllSame = true + + override def doAssertEquals(txt: String, expected: T, actual: T): Unit = { + assertEquals(txt, expected, actual) + } + + def createEmpty(size: Int) : T + + override protected def underTest(size: Int): T = { + val res:T = createEmpty(size) + for (i <- 0 until size) + res(i) = expectedValueAtIndex(i) + res + } + + } + @Ignore + abstract class ImmutableIndexedSeqTest[T <: SeqLike[E, T], E] extends IndexedTest[T, E] with DataProvider[E] { + override final def length(underTest: T) = underTest.length + + override def get(underTest: T, i: Int) = underTest(i) + + override def slice(underTest: T, from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: T, size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = false + + override def isTakeAllSame = true + + override def doAssertEquals(txt: String, expected: T, actual: T): Unit = { + assertEquals(txt, expected, actual) + } + + } + @Ignore + abstract class StringOpsBaseTest extends IndexedTest[StringOps, Char] with DataProvider[Char] { + override final def length(underTest: StringOps) = underTest.length + + override def get(underTest: StringOps, i: Int) = underTest(i) + + override def slice(underTest: StringOps, from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: StringOps, size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = false + + override def isTakeAllSame = false + + override def doAssertEquals(txt: String, expected: StringOps, actual: StringOps): Unit = { + assertEquals(txt, expected, actual) + } + + } + + class BooleanArrayTest extends ArrayTest[Boolean](jlBoolean.TYPE) with BooleanTestData + class ByteArrayTest extends ArrayTest[Byte](jlByte.TYPE) with ByteTestData + class ShortArrayTest extends ArrayTest[Short](jlShort.TYPE) with ShortTestData + class IntArrayTest extends ArrayTest[Int](jlInt.TYPE) with IntTestData + class LongArrayTest extends ArrayTest[Long](jlLong.TYPE) with LongTestData + class DoubleArrayTest extends ArrayTest[Double](jlDouble.TYPE) with DoubleTestData + class FloatArrayTest extends ArrayTest[Float](jlFloat.TYPE) with FloatTestData + class CharArrayTest extends ArrayTest[Char](jlChar.TYPE) with CharTestData + class UnitArrayTest extends ArrayTest[BoxedUnit](null) with UnitTestData { + override def underTest(size: Int): Array[BoxedUnit] = { + val res = new Array[Unit](size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + res.asInstanceOf[Array[BoxedUnit]] + } + } + class RefArrayTest extends ArrayTest[String](classOf[String]) with StringTestData + + class BooleanWrappedArrayTest extends WrappedArrayTest[Boolean](jlBoolean.TYPE) with BooleanTestData + class ByteWrappedArrayTest extends WrappedArrayTest[Byte](jlByte.TYPE) with ByteTestData + class ShortWrappedArrayTest extends WrappedArrayTest[Short](jlShort.TYPE) with ShortTestData + class IntWrappedArrayTest extends WrappedArrayTest[Int](jlInt.TYPE) with IntTestData + class LongWrappedArrayTest extends WrappedArrayTest[Long](jlLong.TYPE) with LongTestData + class DoubleWrappedArrayTest extends WrappedArrayTest[Double](jlDouble.TYPE) with DoubleTestData + class FloatWrappedArrayTest extends WrappedArrayTest[Float](jlFloat.TYPE) with FloatTestData + class CharWrappedArrayTest extends WrappedArrayTest[Char](jlChar.TYPE) with CharTestData + class UnitWrappedArrayTest extends WrappedArrayTest[BoxedUnit](null) with UnitTestData { + import mutable.WrappedArray + override def underTest(size: Int): WrappedArray[BoxedUnit] = { + val res = new Array[Unit](size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + WrappedArray.make(res.asInstanceOf[Array[Unit]]) + } + } + class RefWrappedArrayTest extends WrappedArrayTest[String](classOf[String]) with StringTestData + + class ListBufferTest extends MutableIndexedSeqTest[mutable.ListBuffer[String], String] with StringTestData { + import mutable.ListBuffer + override def createEmpty(size: Int): ListBuffer[String] = { + val res = new ListBuffer[String] + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res + } + } + class ArraySeqTest extends MutableIndexedSeqTest[mutable.ArraySeq[String], String] with StringTestData { + import mutable.ArraySeq + override def createEmpty(size: Int): ArraySeq[String] = { + val res = new ArraySeq[String](size) + for (i <- 0 until size) + res (i) = expectedValueAtIndex(i) + res + } + } + class ArrayBufferTest extends MutableIndexedSeqTest[mutable.ArrayBuffer[String], String] with StringTestData { + import mutable.ArrayBuffer + override def createEmpty(size: Int): ArrayBuffer[String] = { + val res = new ArrayBuffer[String](size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res + } + } + class ListTest extends ImmutableIndexedSeqTest[List[String], String] with StringTestData { + + override protected def underTest(size: Int): List[String] = { + var res:List[String] = Nil + var index = size-1 + while (index >= 0) { + res = expectedValueAtIndex(index) :: res + index -= 1 + } + res + } + } + class StringBuilderTest extends MutableIndexedSeqTest[StringBuilder, Char] with CharTestData { + + override def createEmpty(size: Int): StringBuilder = new StringBuilder(size) + + override protected def underTest(size: Int): StringBuilder = { + var res = createEmpty(size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res + } + } + class StringOpsTest extends StringOpsBaseTest with CharTestData { + + override protected def underTest(size: Int): StringOps = { + var res = new StringBuilder(size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res.toString + } + } + class WrappedStringTest extends ImmutableIndexedSeqTest[WrappedString, Char] with CharTestData { + + override def isTakeAllSame: Boolean = false + + override protected def underTest(size: Int): WrappedString = { + var res = new StringBuilder(size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + new WrappedString(res.toString) + } + } + class VectorTest extends ImmutableIndexedSeqTest[Vector[String], String] with StringTestData { + + override protected def underTest(size: Int): Vector[String] = { + var res = Vector.newBuilder[String] + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res.result() + } + } + +} |