[SPARK-33513][BUILD] Upgrade to Scala 2.13.4 to improve exhaustivity
### What changes were proposed in this pull request? This PR aims the followings. 1. Upgrade from Scala 2.13.3 to 2.13.4 for Apache Spark 3.1 2. Fix exhaustivity issues in both Scala 2.12/2.13 (Scala 2.13.4 requires this for compilation.) 3. Enforce the improved exhaustive check by using the existing Scala 2.13 GitHub Action compilation job. ### Why are the changes needed? Scala 2.13.4 is a maintenance release for 2.13 line and improves JDK 15 support. - https://github.com/scala/scala/releases/tag/v2.13.4 Also, it improves exhaustivity check. - https://github.com/scala/scala/pull/9140 (Check exhaustivity of pattern matches with "if" guards and custom extractors) - https://github.com/scala/scala/pull/9147 (Check all bindings exhaustively, e.g. tuples components) ### Does this PR introduce _any_ user-facing change? Yep. Although it's a maintenance version change, it's a Scala version change. ### How was this patch tested? Pass the CIs and do the manual testing. - Scala 2.12 CI jobs(GitHub Action/Jenkins UT/Jenkins K8s IT) to check the validity of code change. - Scala 2.13 Compilation job to check the compilation Closes #30455 from dongjoon-hyun/SCALA_3.13. Authored-by: Dongjoon Hyun <dongjoon@apache.org> Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
This commit is contained in:
parent
05921814e2
commit
3ce4ab545b
|
@ -169,7 +169,7 @@ private[spark] class StorageStatus(
|
|||
.getOrElse((0L, 0L))
|
||||
case _ if !level.useOffHeap =>
|
||||
(_nonRddStorageInfo.onHeapUsage, _nonRddStorageInfo.diskUsage)
|
||||
case _ if level.useOffHeap =>
|
||||
case _ =>
|
||||
(_nonRddStorageInfo.offHeapUsage, _nonRddStorageInfo.diskUsage)
|
||||
}
|
||||
val newMem = math.max(oldMem + changeInMem, 0L)
|
||||
|
|
|
@ -757,7 +757,7 @@ private[spark] object JsonProtocol {
|
|||
|
||||
def taskResourceRequestMapFromJson(json: JValue): Map[String, TaskResourceRequest] = {
|
||||
val jsonFields = json.asInstanceOf[JObject].obj
|
||||
jsonFields.map { case JField(k, v) =>
|
||||
jsonFields.collect { case JField(k, v) =>
|
||||
val req = taskResourceRequestFromJson(v)
|
||||
(k, req)
|
||||
}.toMap
|
||||
|
@ -765,7 +765,7 @@ private[spark] object JsonProtocol {
|
|||
|
||||
def executorResourceRequestMapFromJson(json: JValue): Map[String, ExecutorResourceRequest] = {
|
||||
val jsonFields = json.asInstanceOf[JObject].obj
|
||||
jsonFields.map { case JField(k, v) =>
|
||||
jsonFields.collect { case JField(k, v) =>
|
||||
val req = executorResourceRequestFromJson(v)
|
||||
(k, req)
|
||||
}.toMap
|
||||
|
@ -1229,7 +1229,7 @@ private[spark] object JsonProtocol {
|
|||
|
||||
def resourcesMapFromJson(json: JValue): Map[String, ResourceInformation] = {
|
||||
val jsonFields = json.asInstanceOf[JObject].obj
|
||||
jsonFields.map { case JField(k, v) =>
|
||||
jsonFields.collect { case JField(k, v) =>
|
||||
val resourceInfo = ResourceInformation.parseJson(v)
|
||||
(k, resourceInfo)
|
||||
}.toMap
|
||||
|
@ -1241,7 +1241,7 @@ private[spark] object JsonProtocol {
|
|||
|
||||
def mapFromJson(json: JValue): Map[String, String] = {
|
||||
val jsonFields = json.asInstanceOf[JObject].obj
|
||||
jsonFields.map { case JField(k, JString(v)) => (k, v) }.toMap
|
||||
jsonFields.collect { case JField(k, JString(v)) => (k, v) }.toMap
|
||||
}
|
||||
|
||||
def propertiesFromJson(json: JValue): Properties = {
|
||||
|
|
|
@ -302,6 +302,8 @@ private[spark] object BLAS extends Serializable {
|
|||
j += 1
|
||||
prevCol = col
|
||||
}
|
||||
case _ =>
|
||||
throw new IllegalArgumentException(s"spr doesn't support vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -286,6 +286,7 @@ private[ml] object RFormulaParser extends RegexParsers {
|
|||
|
||||
private val pow: Parser[Term] = term ~ "^" ~ "^[1-9]\\d*".r ^^ {
|
||||
case base ~ "^" ~ degree => power(base, degree.toInt)
|
||||
case t => throw new IllegalArgumentException(s"Invalid term: $t")
|
||||
} | term
|
||||
|
||||
private val interaction: Parser[Term] = pow * (":" ^^^ { interact _ })
|
||||
|
@ -298,7 +299,10 @@ private[ml] object RFormulaParser extends RegexParsers {
|
|||
private val expr = (sum | term)
|
||||
|
||||
private val formula: Parser[ParsedRFormula] =
|
||||
(label ~ "~" ~ expr) ^^ { case r ~ "~" ~ t => ParsedRFormula(r, t.asTerms.terms) }
|
||||
(label ~ "~" ~ expr) ^^ {
|
||||
case r ~ "~" ~ t => ParsedRFormula(r, t.asTerms.terms)
|
||||
case t => throw new IllegalArgumentException(s"Invalid term: $t")
|
||||
}
|
||||
|
||||
def parse(value: String): ParsedRFormula = parseAll(formula, value) match {
|
||||
case Success(result, _) => result
|
||||
|
|
|
@ -314,6 +314,8 @@ object StandardScalerModel extends MLReadable[StandardScalerModel] {
|
|||
case SparseVector(size, indices, values) =>
|
||||
val newValues = transformSparseWithScale(scale, indices, values.clone())
|
||||
Vectors.sparse(size, indices, newValues)
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
|
||||
case (false, false) =>
|
||||
|
|
|
@ -74,6 +74,8 @@ private[ml] object JsonMatrixConverter {
|
|||
("values" -> values.toSeq) ~
|
||||
("isTransposed" -> isTransposed)
|
||||
compact(render(jValue))
|
||||
case _ =>
|
||||
throw new IllegalArgumentException(s"Unknown matrix type ${m.getClass}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ private[ml] object JsonVectorConverter {
|
|||
case DenseVector(values) =>
|
||||
val jValue = ("type" -> 1) ~ ("values" -> values.toSeq)
|
||||
compact(render(jValue))
|
||||
case _ =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ private[spark] class VectorUDT extends UserDefinedType[Vector] {
|
|||
row.setNullAt(2)
|
||||
row.update(3, UnsafeArrayData.fromPrimitiveArray(values))
|
||||
row
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -200,6 +200,9 @@ private[ml] class BlockHingeAggregator(
|
|||
case sm: SparseMatrix if !fitIntercept =>
|
||||
val gradSumVec = new DenseVector(gradientSumArray)
|
||||
BLAS.gemv(1.0, sm.transpose, vec, 1.0, gradSumVec)
|
||||
|
||||
case m =>
|
||||
throw new IllegalArgumentException(s"Unknown matrix type ${m.getClass}.")
|
||||
}
|
||||
|
||||
if (fitIntercept) gradientSumArray(numFeatures) += vec.values.sum
|
||||
|
|
|
@ -504,6 +504,9 @@ private[ml] class BlockLogisticAggregator(
|
|||
case sm: SparseMatrix if !fitIntercept =>
|
||||
val gradSumVec = new DenseVector(gradientSumArray)
|
||||
BLAS.gemv(1.0, sm.transpose, vec, 1.0, gradSumVec)
|
||||
|
||||
case m =>
|
||||
throw new IllegalArgumentException(s"Unknown matrix type ${m.getClass}.")
|
||||
}
|
||||
|
||||
if (fitIntercept) gradientSumArray(numFeatures) += vec.values.sum
|
||||
|
|
|
@ -192,6 +192,8 @@ private[spark] object Instrumentation {
|
|||
case Failure(NonFatal(e)) =>
|
||||
instr.logFailure(e)
|
||||
throw e
|
||||
case Failure(e) =>
|
||||
throw e
|
||||
case Success(result) =>
|
||||
instr.logSuccess()
|
||||
result
|
||||
|
|
|
@ -167,6 +167,8 @@ class StandardScalerModel @Since("1.3.0") (
|
|||
val newValues = NewStandardScalerModel
|
||||
.transformSparseWithScale(localScale, indices, values.clone())
|
||||
Vectors.sparse(size, indices, newValues)
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
|
||||
case _ => vector
|
||||
|
|
|
@ -285,6 +285,8 @@ private[spark] object BLAS extends Serializable with Logging {
|
|||
j += 1
|
||||
prevCol = col
|
||||
}
|
||||
case _ =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -289,6 +289,8 @@ class VectorUDT extends UserDefinedType[Vector] {
|
|||
row.setNullAt(2)
|
||||
row.update(3, UnsafeArrayData.fromPrimitiveArray(values))
|
||||
row
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ class IndexedRowMatrix @Since("1.0.0") (
|
|||
.map { case (values, blockColumn) =>
|
||||
((blockRow.toInt, blockColumn), (rowInBlock.toInt, values.zipWithIndex))
|
||||
}
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}.groupByKey(GridPartitioner(numRowBlocks, numColBlocks, rows.getNumPartitions)).map {
|
||||
case ((blockRow, blockColumn), itr) =>
|
||||
|
@ -187,6 +189,8 @@ class IndexedRowMatrix @Since("1.0.0") (
|
|||
Iterator.tabulate(indices.length)(i => MatrixEntry(rowIndex, indices(i), values(i)))
|
||||
case DenseVector(values) =>
|
||||
Iterator.tabulate(values.length)(i => MatrixEntry(rowIndex, i, values(i)))
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
new CoordinateMatrix(entries, numRows(), numCols())
|
||||
|
|
|
@ -748,6 +748,8 @@ class RowMatrix @Since("1.0.0") (
|
|||
}
|
||||
buf
|
||||
}.flatten
|
||||
case v =>
|
||||
throw new IllegalArgumentException(s"Unknown vector type ${v.getClass}.")
|
||||
}
|
||||
}
|
||||
}.reduceByKey(_ + _).map { case ((i, j), sim) =>
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -3264,7 +3264,7 @@
|
|||
<profile>
|
||||
<id>scala-2.13</id>
|
||||
<properties>
|
||||
<scala.version>2.13.3</scala.version>
|
||||
<scala.version>2.13.4</scala.version>
|
||||
<scala.binary.version>2.13</scala.binary.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
|
|
|
@ -313,7 +313,6 @@ trait MesosSchedulerUtils extends Logging {
|
|||
// offer has the required attribute and subsumes the required values for that attribute
|
||||
case (name, requiredValues) =>
|
||||
offerAttributes.get(name) match {
|
||||
case None => false
|
||||
case Some(_) if requiredValues.isEmpty => true // empty value matches presence
|
||||
case Some(scalarValue: Value.Scalar) =>
|
||||
// check if provided values is less than equal to the offered values
|
||||
|
@ -332,6 +331,7 @@ trait MesosSchedulerUtils extends Logging {
|
|||
// check if the specified value is equal, if multiple values are specified
|
||||
// we succeed if any of them match.
|
||||
requiredValues.contains(textValue.getValue)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ class MesosFineGrainedSchedulerBackendSuite
|
|||
val (execInfo, _) = backend.createExecutorInfo(
|
||||
Arrays.asList(backend.createResource("cpus", 4)), "mockExecutor")
|
||||
assert(execInfo.getContainer.getDocker.getImage.equals("spark/mock"))
|
||||
assert(execInfo.getContainer.getDocker.getForcePullImage.equals(true))
|
||||
assert(execInfo.getContainer.getDocker.getForcePullImage)
|
||||
val portmaps = execInfo.getContainer.getDocker.getPortMappingsList
|
||||
assert(portmaps.get(0).getHostPort.equals(80))
|
||||
assert(portmaps.get(0).getContainerPort.equals(8080))
|
||||
|
|
|
@ -94,7 +94,7 @@ private[this] object JsonPathParser extends RegexParsers {
|
|||
case Success(result, _) =>
|
||||
Some(result)
|
||||
|
||||
case NoSuccess(msg, next) =>
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -322,7 +322,9 @@ case class Literal (value: Any, dataType: DataType) extends LeafExpression {
|
|||
case (a: Array[Byte], b: Array[Byte]) => util.Arrays.equals(a, b)
|
||||
case (a: ArrayBasedMapData, b: ArrayBasedMapData) =>
|
||||
a.keyArray == b.keyArray && a.valueArray == b.valueArray
|
||||
case (a, b) => a != null && a.equals(b)
|
||||
case (a: Double, b: Double) if a.isNaN && b.isNaN => true
|
||||
case (a: Float, b: Float) if a.isNaN && b.isNaN => true
|
||||
case (a, b) => a != null && a == b
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
|
|
|
@ -981,7 +981,7 @@ case class MapObjects private(
|
|||
(genValue: String) => s"$builder.add($genValue);",
|
||||
s"$builder;"
|
||||
)
|
||||
case None =>
|
||||
case _ =>
|
||||
// array
|
||||
(
|
||||
s"""
|
||||
|
|
|
@ -190,6 +190,9 @@ private[sql] class JsonInferSchema(options: JSONOptions) extends Serializable {
|
|||
}
|
||||
|
||||
case VALUE_TRUE | VALUE_FALSE => BooleanType
|
||||
|
||||
case _ =>
|
||||
throw new SparkException("Malformed JSON")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -197,9 +197,9 @@ object StarSchemaDetection extends PredicateHelper with SQLConfHelper {
|
|||
} else {
|
||||
false
|
||||
}
|
||||
case None => false
|
||||
case _ => false
|
||||
}
|
||||
case None => false
|
||||
case _ => false
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ object StarSchemaDetection extends PredicateHelper with SQLConfHelper {
|
|||
case Some(col) if t.outputSet.contains(col) =>
|
||||
val stats = t.stats
|
||||
stats.attributeStats.nonEmpty && stats.attributeStats.contains(col)
|
||||
case None => false
|
||||
case _ => false
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
|
|
|
@ -685,6 +685,7 @@ object FoldablePropagation extends Rule[LogicalPlan] {
|
|||
case LeftOuter => newJoin.right.output
|
||||
case RightOuter => newJoin.left.output
|
||||
case FullOuter => newJoin.left.output ++ newJoin.right.output
|
||||
case _ => Nil
|
||||
})
|
||||
val newFoldableMap = AttributeMap(foldableMap.baseMap.values.filterNot {
|
||||
case (attr, _) => missDerivedAttrsSet.contains(attr)
|
||||
|
|
|
@ -967,6 +967,8 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
|
|||
(UsingJoin(baseJoinType, visitIdentifierList(c.identifierList)), None)
|
||||
case Some(c) if c.booleanExpression != null =>
|
||||
(baseJoinType, Option(expression(c.booleanExpression)))
|
||||
case Some(c) =>
|
||||
throw new ParseException(s"Unimplemented joinCriteria: $c", ctx)
|
||||
case None if join.NATURAL != null =>
|
||||
if (baseJoinType == Cross) {
|
||||
throw new ParseException("NATURAL CROSS JOIN is not supported", ctx)
|
||||
|
|
|
@ -362,7 +362,7 @@ case class Join(
|
|||
left.constraints
|
||||
case RightOuter =>
|
||||
right.constraints
|
||||
case FullOuter =>
|
||||
case _ =>
|
||||
ExpressionSet()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ class GenericArrayData(val array: Array[Any]) extends ArrayData {
|
|||
if (!o2.isInstanceOf[Double] || ! java.lang.Double.isNaN(o2.asInstanceOf[Double])) {
|
||||
return false
|
||||
}
|
||||
case _ => if (!o1.equals(o2)) {
|
||||
case _ => if (o1.getClass != o2.getClass || o1 != o2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ class ScanOperationSuite extends SparkFunSuite {
|
|||
assert(projects(0) === colB)
|
||||
assert(projects(1) === aliasR)
|
||||
assert(filters.size === 1)
|
||||
case _ => assert(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +51,7 @@ class ScanOperationSuite extends SparkFunSuite {
|
|||
assert(projects(0) === colA)
|
||||
assert(projects(1) === colB)
|
||||
assert(filters.size === 1)
|
||||
case _ => assert(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +67,7 @@ class ScanOperationSuite extends SparkFunSuite {
|
|||
assert(projects.size === 2)
|
||||
assert(projects(0) === colA)
|
||||
assert(projects(1) === aliasId)
|
||||
case _ => assert(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +84,7 @@ class ScanOperationSuite extends SparkFunSuite {
|
|||
assert(projects(0) === colA)
|
||||
assert(projects(1) === aliasR)
|
||||
assert(filters.size === 1)
|
||||
case _ => assert(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +97,7 @@ class ScanOperationSuite extends SparkFunSuite {
|
|||
assert(projects(0) === colA)
|
||||
assert(projects(1) === aliasR)
|
||||
assert(filters.size === 1)
|
||||
case _ => assert(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ class ArrayDataIndexedSeqSuite extends SparkFunSuite {
|
|||
if (e != null) {
|
||||
elementDt match {
|
||||
// For Nan, etc.
|
||||
case FloatType | DoubleType => assert(seq(i).equals(e))
|
||||
case FloatType | DoubleType => assert(seq(i) == e)
|
||||
case _ => assert(seq(i) === e)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -868,12 +868,12 @@ class SparkSqlAstBuilder extends AstBuilder {
|
|||
// assert if directory is local when LOCAL keyword is mentioned
|
||||
val scheme = Option(storage.locationUri.get.getScheme)
|
||||
scheme match {
|
||||
case None =>
|
||||
case Some(pathScheme) if (!pathScheme.equals("file")) =>
|
||||
throw new ParseException("LOCAL is supported only with file: scheme", ctx)
|
||||
case _ =>
|
||||
// force scheme to be file rather than fs.default.name
|
||||
val loc = Some(UriBuilder.fromUri(CatalogUtils.stringToURI(path)).scheme("file").build())
|
||||
storage = storage.copy(locationUri = loc)
|
||||
case Some(pathScheme) if (!pathScheme.equals("file")) =>
|
||||
throw new ParseException("LOCAL is supported only with file: scheme", ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ trait BaseAggregateExec extends UnaryExecNode with AliasAwareOutputPartitioning
|
|||
override def requiredChildDistribution: List[Distribution] = {
|
||||
requiredChildDistributionExpressions match {
|
||||
case Some(exprs) if exprs.isEmpty => AllTuples :: Nil
|
||||
case Some(exprs) if exprs.nonEmpty => ClusteredDistribution(exprs) :: Nil
|
||||
case Some(exprs) => ClusteredDistribution(exprs) :: Nil
|
||||
case None => UnspecifiedDistribution :: Nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@ trait WindowExecBase extends UnaryExecNode {
|
|||
case (RowFrame, IntegerLiteral(offset)) =>
|
||||
RowBoundOrdering(offset)
|
||||
|
||||
case (RowFrame, _) =>
|
||||
sys.error(s"Unhandled bound in windows expressions: $bound")
|
||||
|
||||
case (RangeFrame, CurrentRow) =>
|
||||
val ordering = RowOrdering.create(orderSpec, child.output)
|
||||
RangeBoundOrdering(ordering, IdentityProjection, IdentityProjection)
|
||||
|
@ -249,6 +252,9 @@ trait WindowExecBase extends UnaryExecNode {
|
|||
createBoundOrdering(frameType, lower, timeZone),
|
||||
createBoundOrdering(frameType, upper, timeZone))
|
||||
}
|
||||
|
||||
case _ =>
|
||||
sys.error(s"Unsupported factory: $key")
|
||||
}
|
||||
|
||||
// Keep track of the number of expressions. This is a side-effect in a map...
|
||||
|
|
|
@ -1039,6 +1039,7 @@ private[hive] trait HiveInspectors {
|
|||
|
||||
private def decimalTypeInfo(decimalType: DecimalType): TypeInfo = decimalType match {
|
||||
case DecimalType.Fixed(precision, scale) => new DecimalTypeInfo(precision, scale)
|
||||
case dt => throw new AnalysisException(s"${dt.catalogString} is not supported.")
|
||||
}
|
||||
|
||||
def toTypeInfo: TypeInfo = dt match {
|
||||
|
|
|
@ -293,7 +293,7 @@ private[streaming] object FileBasedWriteAheadLog {
|
|||
val startTime = startTimeStr.toLong
|
||||
val stopTime = stopTimeStr.toLong
|
||||
Some(LogInfo(startTime, stopTime, file.toString))
|
||||
case None =>
|
||||
case None | Some(_) =>
|
||||
None
|
||||
}
|
||||
}.sortBy { _.startTime }
|
||||
|
|
Loading…
Reference in a new issue