diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 41 | ||||
-rw-r--r-- | src/library/scala/concurrent/ExecutionContext.scala | 72 | ||||
-rw-r--r-- | test/files/run/names-defaults.check | 1 | ||||
-rw-r--r-- | test/files/run/names-defaults.scala | 4 |
4 files changed, 95 insertions, 23 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 43902d1c65..b6387fd56b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -379,18 +379,37 @@ trait NamesDefaults { self: Analyzer => def makeNamedTypes(syms: List[Symbol]) = syms map (sym => NamedType(sym.name, sym.tpe)) - def missingParams[T](args: List[T], params: List[Symbol], argName: T => Option[Name] = nameOfNamedArg _): (List[Symbol], Boolean) = { - val namedArgs = args.dropWhile(arg => { - val n = argName(arg) - n.isEmpty || params.forall(p => p.name != n.get) - }) - val namedParams = params.drop(args.length - namedArgs.length) - // missing: keep those with a name which doesn't exist in namedArgs - val missingParams = namedParams.filter(p => namedArgs.forall(arg => { + /** + * Returns the parameter symbols of an invocation expression that are not defined by the list + * of arguments. + * + * @param args The list of arguments + * @param params The list of parameter sybols of the invoked method + * @param argName A function that extracts the name of an argument expression, if it is a named argument. + */ + def missingParams[T](args: List[T], params: List[Symbol], argName: T => Option[Name]): (List[Symbol], Boolean) = { + // The argument list contains first a mix of positional args and named args that are on the + // right parameter position, and then a number or named args on different positions. + + // collect all named arguments whose position does not match the parameter they define + val namedArgsOnChangedPosition = args.zip(params) dropWhile { + case (arg, param) => + val n = argName(arg) + // drop the argument if + // - it's not named, or + // - it's named, but defines the parameter on its current position, or + // - it's named, but none of the parameter names matches (treated as a positional argument, an assignment expression) + n.isEmpty || n.get == param.name || params.forall(_.name != n.get) + } map (_._1) + + val paramsWithoutPositionalArg = params.drop(args.length - namedArgsOnChangedPosition.length) + + // missing parameters: those with a name which is not specified in one of the namedArgsOnChangedPosition + val missingParams = paramsWithoutPositionalArg.filter(p => namedArgsOnChangedPosition.forall { arg => val n = argName(arg) n.isEmpty || n.get != p.name - })) - val allPositional = missingParams.length == namedParams.length + }) + val allPositional = missingParams.length == paramsWithoutPositionalArg.length (missingParams, allPositional) } @@ -407,7 +426,7 @@ trait NamesDefaults { self: Analyzer => previousArgss: List[List[Tree]], params: List[Symbol], pos: scala.reflect.internal.util.Position, context: Context): (List[Tree], List[Symbol]) = { if (givenArgs.length < params.length) { - val (missing, positional) = missingParams(givenArgs, params) + val (missing, positional) = missingParams(givenArgs, params, nameOfNamedArg) if (missing forall (_.hasDefault)) { val defaultArgs = missing flatMap (p => { val defGetter = defaultGetter(p, context) diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index 4674c9174b..11d3bb8b02 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -61,28 +61,44 @@ or import scala.concurrent.ExecutionContext.Implicits.global.""") trait ExecutionContext { /** Runs a block of code on this execution context. + * + * @param runnable the task to execute */ def execute(runnable: Runnable): Unit /** Reports that an asynchronous computation failed. + * + * @param cause the cause of the failure */ def reportFailure(@deprecatedName('t) cause: Throwable): Unit - /** Prepares for the execution of a task. Returns the prepared - * execution context. A valid implementation of `prepare` is one - * that simply returns `this`. + /** Prepares for the execution of a task. Returns the prepared execution context. + * + * `prepare` should be called at the site where an `ExecutionContext` is received (for + * example, through an implicit method parameter). The returned execution context may + * then be used to execute tasks. The role of `prepare` is to save any context relevant + * to an execution's ''call site'', so that this context may be restored at the + * ''execution site''. (These are often different: for example, execution may be + * suspended through a `Promise`'s future until the `Promise` is completed, which may + * be done in another thread, on another stack.) + * + * Note: a valid implementation of `prepare` is one that simply returns `this`. + * + * @return the prepared execution context */ def prepare(): ExecutionContext = this } /** - * An [[ExecutionContext]] that is also a Java [[Executor]]. + * An [[ExecutionContext]] that is also a + * Java [[http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html Executor]]. */ trait ExecutionContextExecutor extends ExecutionContext with Executor /** - * An [[ExecutionContext]] that is also a Java [[ExecutorService]]. + * An [[ExecutionContext]] that is also a + * Java [[http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html ExecutorService]]. */ trait ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService @@ -91,38 +107,70 @@ trait ExecutionContextExecutorService extends ExecutionContextExecutor with Exec */ object ExecutionContext { /** - * This is the explicit global ExecutionContext, - * call this when you want to provide the global ExecutionContext explicitly + * The explicit global `ExecutionContext`. Invoke `global` when you want to provide the global + * `ExecutionContext` explicitly. + * + * The default `ExecutionContext` implementation is backed by a port of + * [[http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166-4jdk7docs/java/util/concurrent/ForkJoinPool.html java.util.concurrent.ForkJoinPool]]. + * + * @return the global `ExecutionContext` */ def global: ExecutionContextExecutor = Implicits.global object Implicits { /** - * This is the implicit global ExecutionContext, - * import this when you want to provide the global ExecutionContext implicitly + * The implicit global `ExecutionContext`. Import `global` when you want to provide the global + * `ExecutionContext` implicitly. + * + * The default `ExecutionContext` implementation is backed by a port of + * [[http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166-4jdk7docs/java/util/concurrent/ForkJoinPool.html java.util.concurrent.ForkJoinPool]]. */ implicit lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor) } /** Creates an `ExecutionContext` from the given `ExecutorService`. + * + * @param e the `ExecutorService` to use + * @param reporter a function for error reporting + * @return the `ExecutionContext` using the given `ExecutorService` */ def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit): ExecutionContextExecutorService = impl.ExecutionContextImpl.fromExecutorService(e, reporter) - /** Creates an `ExecutionContext` from the given `ExecutorService` with the default Reporter. + /** Creates an `ExecutionContext` from the given `ExecutorService` with the [[scala.concurrent.ExecutionContext$.defaultReporter default reporter]]. + * + * If it is guaranteed that none of the executed tasks are blocking, a single-threaded `ExecutorService` + * can be used to create an `ExecutionContext` as follows: + * + * {{{ + * import java.util.concurrent.Executors + * val ec = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor()) + * }}} + * + * @param e the `ExecutorService` to use + * @return the `ExecutionContext` using the given `ExecutorService` */ def fromExecutorService(e: ExecutorService): ExecutionContextExecutorService = fromExecutorService(e, defaultReporter) /** Creates an `ExecutionContext` from the given `Executor`. + * + * @param e the `Executor` to use + * @param reporter a function for error reporting + * @return the `ExecutionContext` using the given `Executor` */ def fromExecutor(e: Executor, reporter: Throwable => Unit): ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(e, reporter) - /** Creates an `ExecutionContext` from the given `Executor` with the default Reporter. + /** Creates an `ExecutionContext` from the given `Executor` with the [[scala.concurrent.ExecutionContext$.defaultReporter default reporter]]. + * + * @param e the `Executor` to use + * @return the `ExecutionContext` using the given `Executor` */ def fromExecutor(e: Executor): ExecutionContextExecutor = fromExecutor(e, defaultReporter) - /** The default reporter simply prints the stack trace of the `Throwable` to System.err. + /** The default reporter simply prints the stack trace of the `Throwable` to [[http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#err System.err]]. + * + * @return the function for error reporting */ def defaultReporter: Throwable => Unit = _.printStackTrace() } diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check index 25999c488a..c358dc5849 100644 --- a/test/files/run/names-defaults.check +++ b/test/files/run/names-defaults.check @@ -124,3 +124,4 @@ List(1, 2) 3 3 (1,0), (1,2) +1 1 0 diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala index 05cd4a540c..b7ed490cbc 100644 --- a/test/files/run/names-defaults.scala +++ b/test/files/run/names-defaults.scala @@ -401,6 +401,10 @@ object Test extends App { C4441a().copy() C4441b()().copy()() + // SI-8117 + def f8177(a: Int = 0, b: Int = 0, c: Int = 0) = s"$a $b $c" + println(f8177(a = 1, 1)) + // DEFINITIONS def test1(a: Int, b: String) = println(a +": "+ b) def test2(u: Int, v: Int)(k: String, l: Int) = println(l +": "+ k +", "+ (u + v)) |