Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for scala 2.13.0-M5 #2298

Merged
merged 39 commits into from Feb 6, 2019
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7c55090
akka-http-core scalafix
raboof Nov 28, 2018
85da038
Dependencies
raboof Nov 28, 2018
1833f2b
akka-parsing scalafix
raboof Nov 28, 2018
c103bde
Use unapply to get value
raboof Nov 28, 2018
0ca8219
Manual changes to compile
raboof Nov 28, 2018
27a172f
Add akka snapshot repository
raboof Nov 29, 2018
6915e29
akka-http-core test:scalafix
raboof Nov 29, 2018
3437fe8
Compile fixes
raboof Nov 29, 2018
10655cb
Make akka-http-core/test succeed
raboof Nov 29, 2018
765822d
Make Uri.Query compile on 2.12 as well
raboof Dec 4, 2018
b150432
Add ccompat for scala 2.11
raboof Dec 4, 2018
55a09ba
make akka-http2-support compile
raboof Jan 4, 2019
2023f95
akka-http scalafix
raboof Jan 4, 2019
744b989
akka-http fixes
raboof Jan 4, 2019
7518902
Make all modules compile under 2.13.0-M5
raboof Jan 4, 2019
8cb07ab
Add copyright headers
raboof Jan 4, 2019
498e744
Separate MiMa for 2.13
raboof Jan 7, 2019
6498111
'Internal API' markers
raboof Jan 9, 2019
ffd4e8b
Remove dependency on scala-collection-compat
raboof Jan 10, 2019
645c386
Rename akka.http.impl.util.SettingsCompanion to SettingsCompanionImpl
raboof Jan 28, 2019
85e5b64
Try dealing with varargs via macro
raboof Jan 29, 2019
eebcacd
Use an empty tree rather than unit
raboof Jan 30, 2019
767a517
No bincompat for 2.13.0-M5 yet
raboof Jan 30, 2019
ff323c9
Replace VASeq everywhere
raboof Jan 30, 2019
63b904f
Remove comment
raboof Jan 30, 2019
d372732
Remove Akka snapshot repository
raboof Jan 30, 2019
20160e3
Move jsr305 to 'Provided' section
raboof Jan 30, 2019
25e30ed
Only provide a single fork for 2.11 and 2.12 source files (#2407)
jrudolph Jan 30, 2019
b3d8a3a
Merge branch 'scala-2.13.0-M5' of github.com:akka/akka-http into scal…
raboof Jan 30, 2019
6391ccd
Add copyright headers
raboof Jan 30, 2019
a9a485c
Remove duplication in scala macro sbt config
raboof Jan 30, 2019
089b1b1
Fix MultiNodeConfig imports
raboof Jan 30, 2019
d070c2b
Cosmetic changes to remove some warnings
jrudolph Feb 5, 2019
ca0fb00
Add missing builder implemenation of 2.13 QuerySeqOptimized impl
jrudolph Feb 5, 2019
a6d3321
Several more warnings fixed
jrudolph Feb 5, 2019
901832e
Fix formatting
jrudolph Feb 5, 2019
ce0ee63
remove unused imports
jrudolph Feb 5, 2019
c17bf0b
Fix 2.13 Stream incompatability
jrudolph Feb 5, 2019
75abac5
Don't rely on exact Map.toString
jrudolph Feb 5, 2019
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -0,0 +1,2 @@
# Scala 2.13.0-M5
ProblemFilters.exclude[MissingTypesProblem]("akka.http.caching.scaladsl.CachingSettings$")

This comment has been minimized.

Copy link
@jrudolph

jrudolph Jan 30, 2019

Member

What happened here?

This comment has been minimized.

Copy link
@raboof

raboof Jan 30, 2019

Author Member

We renamed akka.http.impl.util.SettingsCompanion to akka.http.impl.util.SettingsCompanionImpl, and CachingSettings$ inherits from that, causing a MiMa warning about the type hierarchy. MissingTypesProblem looks a bit weird indeed.

This comment has been minimized.

Copy link
@jrudolph

jrudolph Jan 30, 2019

Member

I think that settings class doesn't seem to follow the usual pattern anyway. Shouldn't it derive from the public akka.http.scaladsl.settings.SettingsCompanion? Not really related to this one here. So, let's create a ticket for that and fix that afterwards.

@@ -38,7 +38,7 @@ object LfuCache {
require(settings.maxCapacity >= 0, "maxCapacity must not be negative")
require(settings.initialCapacity <= settings.maxCapacity, "initialCapacity must be <= maxCapacity")

if (settings.timeToLive.isFinite() || settings.timeToIdle.isFinite()) expiringLfuCache(settings.maxCapacity, settings.initialCapacity, settings.timeToLive, settings.timeToIdle)
if (settings.timeToLive.isFinite || settings.timeToIdle.isFinite) expiringLfuCache(settings.maxCapacity, settings.initialCapacity, settings.timeToLive, settings.timeToIdle)
else simpleLfuCache(settings.maxCapacity, settings.initialCapacity)
}

@@ -6,7 +6,7 @@ package akka.http.caching.scaladsl

import akka.annotation.{ DoNotInherit, InternalApi }
import akka.http.caching.javadsl
import akka.http.impl.util.SettingsCompanion
import akka.http.impl.util.SettingsCompanionImpl
import com.typesafe.config.Config

import scala.concurrent.duration.Duration
@@ -62,7 +62,7 @@ private[http] final case class LfuCacheSettingsImpl(
override def productPrefix = "LfuCacheSettings"
}

object CachingSettings extends SettingsCompanion[CachingSettings]("akka.http.caching") {
object CachingSettings extends SettingsCompanionImpl[CachingSettings]("akka.http.caching") {
def fromSubConfig(root: Config, c: Config): CachingSettingsImpl = {
val lfuConfig = c.getConfig("lfu-cache")
CachingSettingsImpl(
@@ -9,6 +9,7 @@
import scala.collection.immutable.Map$;
import scala.collection.immutable.Seq;
import akka.stream.scaladsl.Source;
import akka.http.ccompat.MapHelpers;

import java.util.Arrays;
import java.util.Map;
@@ -35,7 +36,7 @@
return (Source<U, scala.Unit>)(Object) p;
}
public static scala.collection.immutable.Map<String, String> convertMapToScala(Map<String, String> map) {
return emptyMap.$plus$plus(scala.collection.JavaConverters.mapAsScalaMapConverter(map).asScala());
return MapHelpers.convertMapToScala(map);
}
@SuppressWarnings("unchecked") // contains an upcast
public static <T, U extends T> scala.Option<U> convertOptionalToScala(Optional<T> o) {
@@ -12,9 +12,10 @@
import java.util.Collections;
import java.util.Map;

import akka.http.ccompat.MapHelpers;

import static akka.http.impl.util.Util.convertArray;
import static akka.http.impl.util.Util.convertMapToScala;
import static akka.http.impl.util.Util.emptyMap;

/**
* Constructors for Multipart instances
@@ -140,7 +141,7 @@
}

private static scala.collection.immutable.Map<String, HttpEntity.Strict> toScalaMap(Map<String, HttpEntity.Strict> map) {
return emptyMap.$plus$plus(scala.collection.JavaConverters.mapAsScalaMapConverter(map).asScala());
return MapHelpers.convertMapToScala(map);
}

private static scala.collection.Iterable<HttpHeader> toScalaSeq(java.util.List<HttpHeader> _headers) {
@@ -0,0 +1,10 @@
# 2.13.0-M5 support:
ProblemFilters.exclude[MissingClassProblem]("akka.http.impl.util.SettingsCompanion")
ProblemFilters.exclude[MissingClassProblem]("akka.http.impl.util.SettingsCompanion$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ConnectionPoolSettingsImpl$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.HttpsProxySettingsImpl$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ParserSettingsImpl$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ServerSettingsImpl$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.PreviewServerSettingsImpl$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ClientConnectionSettingsImpl$")
ProblemFilters.exclude[MissingTypesProblem]("akka.http.scaladsl.settings.Http2ServerSettings$Http2ServerSettingsImpl$")
@@ -0,0 +1,12 @@
/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http.ccompat

object MapHelpers {
def convertMapToScala[K, V](jmap: java.util.Map[K, V]): scala.collection.immutable.Map[K, V] = {
import scala.collection.JavaConverters._
Map.empty.concat(jmap.asScala)
}
}
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http.ccompat

import scala.collection.immutable

/**
* INTERNAL API
*/
package object imm {
// Nothing yet, but present to be source-compatible with 2.13-
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http

/**
* INTERNAL API
*/
package object ccompat {

type Builder[-A, +To] = scala.collection.mutable.Builder[A, To]
}

/**
* INTERNAL API
*/
package ccompat {
import akka.http.scaladsl.model.Uri.Query
trait QuerySeqOptimized extends scala.collection.immutable.LinearSeq[(String, String)] with scala.collection.StrictOptimizedLinearSeqOps[(String, String), scala.collection.immutable.LinearSeq, Query] {
override protected def fromSpecific(coll: IterableOnce[(String, String)]): Query =
Query(coll.iterator.to(Seq): _*)

def newBuilder: Any = akka.http.scaladsl.model.Uri.Query.newBuilder
}
}
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http.scaladsl.util

import scala.language.higherKinds
import scala.util.control.NonFatal
import scala.util.{ Failure, Success, Try }
import scala.collection.BuildFrom
import scala.concurrent.duration.Duration
import scala.concurrent._

/**
* Provides alternative implementations of the basic transformation operations defined on [[scala.concurrent.Future]],
* which try to avoid scheduling to an [[scala.concurrent.ExecutionContext]] if possible, i.e. if the given future
* value is already present.
*/
class FastFuture[A](val future: Future[A]) extends AnyVal {
import FastFuture._

def map[B](f: A B)(implicit ec: ExecutionContext): Future[B] =
transformWith(a FastFuture.successful(f(a)), FastFuture.failed)

def flatMap[B](f: A Future[B])(implicit ec: ExecutionContext): Future[B] =
transformWith(f, FastFuture.failed)

def filter(pred: A Boolean)(implicit executor: ExecutionContext): Future[A] =
flatMap { r
if (pred(r)) future
else throw new NoSuchElementException("Future.filter predicate is not satisfied")
}

def foreach(f: A Unit)(implicit ec: ExecutionContext): Unit = map(f)

def transformWith[B](f: Try[A] Future[B])(implicit executor: ExecutionContext): Future[B] =
transformWith(a f(Success(a)), e f(Failure(e)))

def transformWith[B](s: A Future[B], f: Throwable Future[B])(implicit executor: ExecutionContext): Future[B] = {
def strictTransform[T](x: T, f: T Future[B]) =
try f(x)
catch { case NonFatal(e) ErrorFuture(e) }

future match {
case FulfilledFuture(a) strictTransform(a, s)
case ErrorFuture(e) strictTransform(e, f)
case _ future.value match {
case None
val p = Promise[B]()
future.onComplete {
case Success(a) p completeWith strictTransform(a, s)
case Failure(e) p completeWith strictTransform(e, f)
}
p.future
case Some(Success(a)) strictTransform(a, s)
case Some(Failure(e)) strictTransform(e, f)
}
}
}

def recover[B >: A](pf: PartialFunction[Throwable, B])(implicit ec: ExecutionContext): Future[B] =
transformWith(FastFuture.successful, t if (pf isDefinedAt t) FastFuture.successful(pf(t)) else future)

def recoverWith[B >: A](pf: PartialFunction[Throwable, Future[B]])(implicit ec: ExecutionContext): Future[B] =
transformWith(FastFuture.successful, t pf.applyOrElse(t, (_: Throwable) future))
}

object FastFuture {
def apply[T](value: Try[T]): Future[T] = value match {
case Success(t) FulfilledFuture(t)
case Failure(e) ErrorFuture(e)
}
private[this] val _successful: Any Future[Any] = FulfilledFuture.apply
def successful[T]: T Future[T] = _successful.asInstanceOf[T Future[T]]
val failed: Throwable Future[Nothing] = ErrorFuture.apply

private case class FulfilledFuture[+A](a: A) extends Future[A] {
def value = Some(Success(a))
def onComplete[U](f: Try[A] U)(implicit executor: ExecutionContext) = Future.successful(a).onComplete(f)
def isCompleted = true
def result(atMost: Duration)(implicit permit: CanAwait) = a
def ready(atMost: Duration)(implicit permit: CanAwait) = this
def transform[S](f: scala.util.Try[A] scala.util.Try[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] =
FastFuture(f(Success(a)))
def transformWith[S](f: scala.util.Try[A] scala.concurrent.Future[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] =
new FastFuture(this).transformWith(f)
}
private case class ErrorFuture(error: Throwable) extends Future[Nothing] {
def value = Some(Failure(error))
def onComplete[U](f: Try[Nothing] U)(implicit executor: ExecutionContext) = Future.failed(error).onComplete(f)
def isCompleted = true
def result(atMost: Duration)(implicit permit: CanAwait) = throw error
def ready(atMost: Duration)(implicit permit: CanAwait) = this
def transform[S](f: scala.util.Try[Nothing] scala.util.Try[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] =
FastFuture(f(Failure(error)))
def transformWith[S](f: scala.util.Try[Nothing] scala.concurrent.Future[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] =
new FastFuture(this).transformWith(f)
}

implicit class EnhancedFuture[T](val future: Future[T]) extends AnyVal {
def fast: FastFuture[T] = new FastFuture[T](future)
}

def sequence[T, M[_] <: IterableOnce[_]](in: M[Future[T]])(implicit cbf: BuildFrom[M[Future[T]], T, M[T]], executor: ExecutionContext): Future[M[T]] =
in.iterator.foldLeft(successful(cbf.newBuilder(in))) {
(fr, fa) for (r fr.fast; a fa.asInstanceOf[Future[T]].fast) yield r += a
}.fast.map(_.result())

/* FIXME
def fold[T, R](futures: IterableOnce[Future[T]])(zero: R)(f: (R, T) ⇒ R)(implicit executor: ExecutionContext): Future[R] =
if (futures.isEmpty) successful(zero)
else sequence(futures).fast.map(_.foldLeft(zero)(f))
def reduce[T, R >: T](futures: IterableOnce[Future[T]])(op: (R, T) ⇒ R)(implicit executor: ExecutionContext): Future[R] =
if (futures.isEmpty) failed(new NoSuchElementException("reduce attempted on empty collection"))
else sequence(futures).fast.map(_ reduceLeft op)
*/

def traverse[A, B, M[_] <: IterableOnce[_]](in: M[A])(fn: A Future[B])(implicit cbf: BuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
in.iterator.foldLeft(successful(cbf.newBuilder(in))) { (fr, a)
val fb = fn(a.asInstanceOf[A])
for (r fr.fast; b fb.fast) yield r += b
}.fast.map(_.result())
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http.ccompat

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable

/**
* INTERNAL API
*
* Based on https://github.com/scala/scala-collection-compat/blob/master/compat/src/main/scala-2.11_2.12/scala/collection/compat/CompatImpl.scala
* but reproduced here so we don't need to add a dependency on this library. It contains much more than we need right now, and is
* not promising binary compatibility yet at the time of writing.
*/
private[ccompat] object CompatImpl {
def simpleCBF[A, C](f: mutable.Builder[A, C]): CanBuildFrom[Any, A, C] = new CanBuildFrom[Any, A, C] {
def apply(from: Any): mutable.Builder[A, C] = apply()
def apply(): mutable.Builder[A, C] = f
}
}
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http.ccompat

/**
* INTERNAL API
*/
object MapHelpers {
def convertMapToScala[K, V](jmap: java.util.Map[K, V]): scala.collection.immutable.Map[K, V] = {
import scala.collection.JavaConverters._
Map.empty ++ jmap.asScala
}
}
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http.ccompat

import scala.collection.immutable

/**
* INTERNAL API
*/
package object imm {
implicit class SortedSetOps[A](val real: immutable.SortedSet[A]) extends AnyVal {
def unsorted: immutable.Set[A] = real
}

implicit class StreamOps[A](val underlying: immutable.Stream[A]) extends AnyVal {
// renamed in 2.13
def lazyAppendedAll[B >: A](rest: TraversableOnce[B]): Stream[B] = underlying.append(rest)
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.http

import scala.collection.generic.{ CanBuildFrom, GenericCompanion }
import scala.collection.{ GenTraversable, mutable }
import scala.{ collection c }

/**
* INTERNAL API
*
* Partly based on https://github.com/scala/scala-collection-compat/blob/master/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala
* but reproduced here so we don't need to add a dependency on this library. It contains much more than we need right now, and is
* not promising binary compatibility yet at the time of writing.
*/
package object ccompat {
import CompatImpl._

implicit def genericCompanionToCBF[A, CC[X] <: GenTraversable[X]](
fact: GenericCompanion[CC]): CanBuildFrom[Any, A, CC[A]] =
simpleCBF(fact.newBuilder[A])

// This really belongs into scala.collection but there's already a package object
// in scala-library so we can't add to it
type IterableOnce[+X] = c.TraversableOnce[X]
val IterableOnce = c.TraversableOnce
}

/**
* INTERNAL API
*/
package ccompat {
trait Builder[-Elem, +To] extends mutable.Builder[Elem, To] { self
// This became final in 2.13 so cannot be overridden there anymore
final override def +=(elem: Elem): this.type = addOne(elem)
def addOne(elem: Elem): this.type = self.+=(elem)
}

trait QuerySeqOptimized extends scala.collection.immutable.LinearSeq[(String, String)] with scala.collection.LinearSeqOptimized[(String, String), akka.http.scaladsl.model.Uri.Query] {
self: akka.http.scaladsl.model.Uri.Query
override def newBuilder: mutable.Builder[(String, String), akka.http.scaladsl.model.Uri.Query] = akka.http.scaladsl.model.Uri.Query.newBuilder
}
}
@@ -17,8 +17,9 @@ import akka.http.scaladsl.settings.ParserSettings
import scala.annotation.tailrec
import akka.parboiled2.CharUtils
import akka.util.ByteString
import akka.http.ccompat._
import akka.http.impl.util._
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.{ ErrorInfo, HttpHeader, MediaTypes, StatusCode, StatusCodes }
import akka.http.scaladsl.model.headers.{ EmptyHeader, RawHeader }
import akka.http.impl.model.parser.HeaderParser
import akka.http.impl.model.parser.CharacterClasses._
@@ -476,10 +477,10 @@ private[http] object HttpHeaderParser {

val valueParsers: Seq[HeaderValueParser] =
HeaderParser.ruleNames
.filter(headerParserFilter)
.filter(headerParserFilter).iterator
.map { name
new ModeledHeaderValueParser(name, parser.settings.maxHeaderValueLength, parser.settings.headerValueCacheLimit(name), parser.log, parser.settings)
}(collection.breakOut)
}.to(scala.collection.immutable.IndexedSeq)

def insertInGoodOrder(items: Seq[Any])(startIx: Int = 0, endIx: Int = items.size): Unit =
if (endIx - startIx > 0) {
@@ -14,7 +14,7 @@ import akka.parboiled2.CharUtils
import akka.util.ByteString
import akka.http.impl.model.parser.CharacterClasses
import akka.http.scaladsl.settings.ParserSettings
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.{ ParsingException _, _ }
import headers._
import HttpProtocols._
import ParserOutput._
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.