diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 4f792ea6398a..dfe24cd1c91b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -195,21 +195,16 @@ object messages { else "" + val inferred = + if (pt == WildcardType) "" + else i"\nWhat I could infer was: $pt" + i"""Missing parameter type | - |The argument types of an anonymous function must be fully known. (SLS 8.5) - |Expected type: $pt - |Missing type for parameter ${param.name}$ofFun""" + |I could not infer the type of the parameter ${param.name}$ofFun.$inferred""" } - val explanation: String = - hl"""|Anonymous functions must define a type. For example, if you define a function like this one: - | - |${"val f = { case x: Int => x + 1 }"} - | - |Make sure you give it a type of what you expect to match and help the type inference system: - | - |${"val f: Any => Int = { case x: Int => x + 1 }"} """ + val explanation: String = "" } case class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 6e9f2d016ea8..ecdce2384336 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -832,7 +832,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case funRef: TermRef => val app = if (proto.allArgTypesAreCurrent()) - new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt) + new ApplyToTyped(tree, fun1, funRef, proto.unforcedTypedArgs, pt) else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree)) convertNewGenericArray(app.result) @@ -857,7 +857,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => } fun1.tpe match { - case err: ErrorType => cpy.Apply(tree)(fun1, proto.typedArgs).withType(err) + case err: ErrorType => cpy.Apply(tree)(fun1, proto.unforcedTypedArgs).withType(err) case TryDynamicCallType => typedDynamicApply(tree, pt) case _ => if (originalProto.isDropped) fun1 @@ -1604,7 +1604,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (isDetermined(alts2)) alts2 else { pretypeArgs(alts2, pt) - narrowByTrees(alts2, pt.typedArgs, resultType) + narrowByTrees(alts2, pt.unforcedTypedArgs, resultType) } } @@ -1665,7 +1665,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => else pt match { case pt @ FunProto(_, resType: FunProto) => // try to narrow further with snd argument list - val advanced = advanceCandidates(pt.typedArgs.tpes) + val advanced = advanceCandidates(pt.unforcedTypedArgs.tpes) resolveOverloaded(advanced.map(_._1), resType, Nil) // resolve with candidates where first params are stripped .map(advanced.toMap) // map surviving result(s) back to original candidates case _ => @@ -1697,40 +1697,38 @@ trait Applications extends Compatibility { self: Typer with Dynamic => private def pretypeArgs(alts: List[TermRef], pt: FunProto)(implicit ctx: Context): Unit = { def recur(altFormals: List[List[Type]], args: List[untpd.Tree]): Unit = args match { case arg :: args1 if !altFormals.exists(_.isEmpty) => - def isUnknownParamType(t: untpd.Tree) = t match { - case ValDef(_, tpt, _) => tpt.isEmpty - case _ => false - } - val fn = untpd.functionWithUnknownParamType(arg) - if (fn.isDefined) { - def isUniform[T](xs: List[T])(p: (T, T) => Boolean) = xs.forall(p(_, xs.head)) - val formalsForArg: List[Type] = altFormals.map(_.head) - def argTypesOfFormal(formal: Type): List[Type] = - formal match { - case defn.FunctionOf(args, result, isImplicit, isErased) => args - case defn.PartialFunctionOf(arg, result) => arg :: Nil - case _ => Nil + untpd.functionWithUnknownParamType(arg) match { + case Some(fn) => + def isUniform[T](xs: List[T])(p: (T, T) => Boolean) = xs.forall(p(_, xs.head)) + val formalsForArg: List[Type] = altFormals.map(_.head) + def argTypesOfFormal(formal: Type): List[Type] = + formal match { + case defn.FunctionOf(args, result, isImplicit, isErased) => args + case defn.PartialFunctionOf(arg, result) => arg :: Nil + case _ => Nil + } + val formalParamTypessForArg: List[List[Type]] = + formalsForArg.map(argTypesOfFormal) + if (formalParamTypessForArg.forall(_.nonEmpty) && + isUniform(formalParamTypessForArg)((x, y) => x.length == y.length)) { + val commonParamTypes = formalParamTypessForArg.transpose.map(ps => + // Given definitions above, for i = 1,...,m, + // ps(i) = List(p_i_1, ..., p_i_n) -- i.e. a column + // If all p_i_k's are the same, assume the type as formal parameter + // type of the i'th parameter of the closure. + if (isUniform(ps)(_ frozen_=:= _)) ps.head + else WildcardType) + def isPartial = // we should generate a partial function for the arg + fn.isInstanceOf[untpd.Match] && + formalsForArg.exists(_.isRef(defn.PartialFunctionClass)) + val commonFormal = + if (isPartial) defn.PartialFunctionOf(commonParamTypes.head, WildcardType) + else defn.FunctionOf(commonParamTypes, WildcardType) + overload.println(i"pretype arg $arg with expected type $commonFormal") + if (commonParamTypes.forall(isFullyDefined(_, ForceDegree.noBottom))) + pt.typedArg(arg, commonFormal)(ctx.addMode(Mode.ImplicitsEnabled)) } - val formalParamTypessForArg: List[List[Type]] = - formalsForArg.map(argTypesOfFormal) - if (formalParamTypessForArg.forall(_.nonEmpty) && - isUniform(formalParamTypessForArg)((x, y) => x.length == y.length)) { - val commonParamTypes = formalParamTypessForArg.transpose.map(ps => - // Given definitions above, for i = 1,...,m, - // ps(i) = List(p_i_1, ..., p_i_n) -- i.e. a column - // If all p_i_k's are the same, assume the type as formal parameter - // type of the i'th parameter of the closure. - if (isUniform(ps)(_ frozen_=:= _)) ps.head - else WildcardType) - def isPartial = // we should generate a partial function for the arg - fn.get.isInstanceOf[untpd.Match] && - formalsForArg.exists(_.isRef(defn.PartialFunctionClass)) - val commonFormal = - if (isPartial) defn.PartialFunctionOf(commonParamTypes.head, WildcardType) - else defn.FunctionOf(commonParamTypes, WildcardType) - overload.println(i"pretype arg $arg with expected type $commonFormal") - pt.typedArg(arg, commonFormal)(ctx.addMode(Mode.ImplicitsEnabled)) - } + case None => } recur(altFormals.map(_.tail), args1) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index a582aac88060..b913d7d5a023 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -47,7 +47,7 @@ object ErrorReporting { case _: WildcardType | _: IgnoredProto => "" case tp => em" and expected result type $tp" } - em"arguments (${tp.typedArgs.tpes}%, %)$result" + em"arguments (${tp.unforcedTypedArgs.tpes}%, %)$result" case _ => em"expected type $tp" } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 0d5a5aa2e341..9986be9631c1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1078,7 +1078,7 @@ class Namer { typer: Typer => } /** Typecheck `tree` during completion using `typed`, and remember result in TypedAhead map */ - def typedAheadImpl(tree: Tree, typed: untpd.Tree => tpd.Tree)(implicit ctx: Context): tpd.Tree = { + def typedAhead(tree: Tree, typed: untpd.Tree => tpd.Tree)(implicit ctx: Context): tpd.Tree = { val xtree = expanded(tree) xtree.getAttachment(TypedAhead) match { case Some(ttree) => ttree @@ -1090,10 +1090,10 @@ class Namer { typer: Typer => } def typedAheadType(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = - typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits addMode Mode.Type)) + typedAhead(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits addMode Mode.Type)) def typedAheadExpr(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = - typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits)) + typedAhead(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrTypeBits)) def typedAheadAnnotation(tree: Tree)(implicit ctx: Context): tpd.Tree = typedAheadExpr(tree, defn.AnnotationType) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index e06585629ef4..c074ca7a45b4 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -232,9 +232,6 @@ object ProtoTypes { /** A map in which typed arguments can be stored to be later integrated in `typedArgs`. */ var typedArg: SimpleIdentityMap[untpd.Tree, Tree] = SimpleIdentityMap.Empty - /** A map recording the typer states and constraints in which arguments stored in myTypedArg were typed */ - var evalState: SimpleIdentityMap[untpd.Tree, (TyperState, Constraint)] = SimpleIdentityMap.Empty - /** The tupled version of this prototype, if it has been computed */ var tupled: Type = NoType @@ -265,44 +262,35 @@ object ProtoTypes { override def notApplied: Type = WildcardType - /** Forget the types of any arguments that have been typed producing a constraint - * - that is in a typer state that is not yet committed into the one of the current context `ctx`, - * - or that has been retracted from its typestate because oif a failed operation. - * This is necessary to avoid "orphan" TypeParamRefs that are referred to from - * type variables in the typed arguments, but that are not registered in the - * current constraint. Test cases are pos/t1756.scala and pos/i3538.scala. - * @return True if all arguments have types (in particular, no types were forgotten). + /** @return True if all arguments have types. */ - def allArgTypesAreCurrent()(implicit ctx: Context): Boolean = { - state.evalState foreachBinding { (arg, tstateConstr) => - if ((tstateConstr._1.uncommittedAncestor.constraint `ne` ctx.typerState.constraint) || - tstateConstr._2.isRetracted) { - typr.println(i"need to invalidate $arg / ${state.typedArg(arg)}, ${tstateConstr._2}, current = ${ctx.typerState.constraint}") - state.typedArg = state.typedArg.remove(arg) - state.evalState = state.evalState.remove(arg) - } - } + def allArgTypesAreCurrent()(implicit ctx: Context): Boolean = state.typedArg.size == args.length + + private def isUndefined(tp: Type): Boolean = tp match { + case _: WildcardType => true + case defn.FunctionOf(args, result, _, _) => args.exists(isUndefined) || isUndefined(result) + case _ => false } private def cacheTypedArg(arg: untpd.Tree, typerFn: untpd.Tree => Tree, force: Boolean)(implicit ctx: Context): Tree = { var targ = state.typedArg(arg) if (targ == null) { - if (!force && untpd.functionWithUnknownParamType(arg).isDefined) - // If force = false, assume ? rather than reporting an error. - // That way we don't cause a "missing parameter" error in `typerFn(arg)` - targ = arg.withType(WildcardType) - else { - targ = typerFn(arg) - if (!ctx.reporter.hasUnreportedErrors) { - // FIXME: This can swallow warnings by updating the typerstate from a nested - // context that gets discarded later. But we do have to update the - // typerstate if there are no errors. If we also omitted the next two lines - // when warning were emitted, `pos/t1756.scala` would fail when run with -feature. - // It would produce an orphan type parameter for CI when pickling. - state.typedArg = state.typedArg.updated(arg, targ) - state.evalState = state.evalState.updated(arg, (ctx.typerState, ctx.typerState.constraint)) - } + untpd.functionWithUnknownParamType(arg) match { + case Some(untpd.Function(args, _)) if !force => + // If force = false, assume what we know about the parameter types rather than reporting an error. + // That way we don't cause a "missing parameter" error in `typerFn(arg)` + val paramTypes = args map { + case ValDef(_, tpt, _) if !tpt.isEmpty => typer.typedType(tpt).typeOpt + case _ => WildcardType + } + targ = arg.withType(defn.FunctionOf(paramTypes, WildcardType)) + case Some(_) if !force => + targ = arg.withType(WildcardType) + case _ => + targ = typerFn(arg) + if (!ctx.reporter.hasUnreportedErrors) + state.typedArg = state.typedArg.updated(arg, targ) } } targ @@ -310,21 +298,15 @@ object ProtoTypes { /** The typed arguments. This takes any arguments already typed using * `typedArg` into account. - * @param force if true try to typecheck arguments even if they are functions - * with unknown parameter types - this will then cause a - * "missing parameter type" error */ - private def typedArgs(force: Boolean): List[Tree] = + def unforcedTypedArgs: List[Tree] = if (state.typedArgs.size == args.length) state.typedArgs else { - val args1 = args.mapconserve(cacheTypedArg(_, typer.typed(_), force)) - if (force || !args1.contains(WildcardType)) state.typedArgs = args1 + val args1 = args.mapconserve(cacheTypedArg(_, typer.typed(_), force = false)) + if (!args1.exists(arg => isUndefined(arg.tpe))) state.typedArgs = args1 args1 } - def typedArgs: List[Tree] = typedArgs(force = true) - def unforcedTypedArgs: List[Tree] = typedArgs(force = false) - /** Type single argument and remember the unadapted result in `myTypedArg`. * used to avoid repeated typings of trees when backtracking. */ @@ -376,7 +358,7 @@ object ProtoTypes { derivedFunProto(args, tm(resultType), typer) def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = - ta(ta.foldOver(x, typedArgs.tpes), resultType) + ta(ta.foldOver(x, unforcedTypedArgs.tpes), resultType) override def deepenProto(implicit ctx: Context): FunProto = derivedFunProto(args, resultType.deepenProto, typer) @@ -390,7 +372,7 @@ object ProtoTypes { * [](args): resultType, where args are known to be typed */ class FunProtoTyped(args: List[tpd.Tree], resultType: Type)(typer: Typer, isContextual: Boolean)(implicit ctx: Context) extends FunProto(args, resultType)(typer, isContextual)(ctx) { - override def typedArgs: List[tpd.Tree] = args + override def unforcedTypedArgs: List[tpd.Tree] = args override def withContext(ctx: Context): FunProtoTyped = this } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b3bf15dfe745..06029a080060 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -525,7 +525,7 @@ class Typer extends Namer templ1 = cpy.Template(templ)(parents = untpd.TypeTree(pt) :: Nil) templ1.parents foreach { case parent: RefTree => - typedAheadImpl(parent, tree => inferTypeParams(typedType(tree), pt)) + typedAhead(parent, tree => inferTypeParams(typedType(tree), pt)) case _ => } val x = tpnme.ANON_CLASS @@ -940,7 +940,7 @@ class Typer extends Namer } case _ => } - errorType(AnonymousFunctionMissingParamType(param, params, tree, pt), param.sourcePos) + errorType(AnonymousFunctionMissingParamType(param, params, tree, formal), param.sourcePos) } def protoFormal(i: Int): Type = diff --git a/compiler/test-resources/repl/errorThenValid b/compiler/test-resources/repl/errorThenValid index dc61f0a4f4a2..3aea44b6392d 100644 --- a/compiler/test-resources/repl/errorThenValid +++ b/compiler/test-resources/repl/errorThenValid @@ -1,10 +1,8 @@ scala> val xs = scala.collection.mutable.ListBuffer[Int] 1 | val xs = scala.collection.mutable.ListBuffer[Int] | ^ - |Missing parameter type + | Missing parameter type | - |The argument types of an anonymous function must be fully known. (SLS 8.5) - |Expected type: ? - |Missing type for parameter elems + | I could not infer the type of the parameter elems. scala> val xs = scala.collection.mutable.ListBuffer[Int]() val xs: scala.collection.mutable.ListBuffer[Int] = ListBuffer() diff --git a/docs/docs/reference/changed-features/overload-resolution.md b/docs/docs/reference/changed-features/overload-resolution.md index c96731cdc4b6..5f3a9743f9d1 100644 --- a/docs/docs/reference/changed-features/overload-resolution.md +++ b/docs/docs/reference/changed-features/overload-resolution.md @@ -3,29 +3,82 @@ layout: doc-page title: "Changes in Overload Resolution" --- -Overload resolution in Dotty takes all argument blocks into account instead of -just the first argument block. +Overload resolution in Dotty improves on Scala 2 in two ways. +First, it takes all argument lists into account instead of +just the first argument list. +Second, it can infer parameter types of function values even if they +are in the first argument list. +## Looking Beyond the First Argument List + +Overloading resolution now can take argument lists into account when +choosing among a set of overloaded alternatives. For example, the following code compiles in Dotty, while it results in an ambiguous overload error in Scala2: -```Scala -def f(x: Int)(y: String): Int = 0 -def f(x: Int)(y: Int): Int = 0 +```scala + def f(x: Int)(y: String): Int = 0 + def f(x: Int)(y: Int): Int = 0 -f(3)("") // ok + f(3)("") // ok ``` The following code compiles as well: -```Scala -def g(x: Int)(y: Int)(z: Int): Int = 0 -def g(x: Int)(y: Int)(z: String): Int = 0 +```scala + def g(x: Int)(y: Int)(z: Int): Int = 0 + def g(x: Int)(y: Int)(z: String): Int = 0 -g(2)(3)(4) // ok -g(2)(3)("") // ok + g(2)(3)(4) // ok + g(2)(3)("") // ok ``` +To make this work, the rules for overloading resolution in section 6.23.3 of the SLS are augmented +as follows: + +> In a situation where a function is applied to more than one argument list, if overloading +resolution yields several competing alternatives when `n >= 1` parameter lists are taken +into account, then resolution re-tried using `n + 1` argument lists. + This change is motivated by the new language feature [extension methods](../contextual/extension-methods.html), where emerges the need to do overload resolution based on additional argument blocks. + +## Parameter Types of Function Values + +The handling of function values with missing parameter types has been improved. We can now +pass such values in the first argument list of an overloaded application, provided +that the remaining parameters suffice for picking a variant of the overloaded function. +For example, the following code compiles in Dotty, while it results in an +missing parameter type error in Scala2: +```scala + def f(x: Int, f: Int => Int) = f(x) + def f(x: String, f: String => String) = f(x) + f("a", _.length) +``` +To make this work, the rules for overloading resolution in section 6.23.3 of the SLS are modified +as follows: + +Replace the sentence + +> Otherwise, let `S1,…,Sm` be the vector of types obtained by typing each argument with an undefined expected type. + +with the following paragraph: + +> Otherwise, let `S1,…,Sm` be the vector of known types of all argument types, where the _known type_ of an argument `E` +is determined as followed: + + - If `E` is a function value `(p_1, ..., p_n) => B` that misses some parameter types, the known type + of `E` is `(S_1, ..., S_n) => ?`, where each `S_i` is the type of parameter `p_i` if it is given, or `?` + otherwise. Here `?` stands for a _wildcard type_ that is compatible with every other type. + - Otherwise the known type of `E` is the result of typing `E` with an undefined expected type. + +A pattern matching closure +```scala + { case P1 => B1 ... case P_n => B_n } +```` +is treated as if it was expanded to the function value +```scala + x => x match { case P1 => B1 ... case P_n => B_n } +``` +and is therefore also approximated with a `? => ?` type. diff --git a/tests/neg/i1640.scala b/tests/neg/i1640.scala index 30879fa9c765..78351a1d6f98 100644 --- a/tests/neg/i1640.scala +++ b/tests/neg/i1640.scala @@ -1,4 +1,4 @@ object Test extends App { List(1, 2, 3) map (_ match { case x => x + 1 }) - List((1, 2)) x (_ match { case (x, z) => x + z }) // error // error // error + List((1, 2)) x (_ match { case (x, z) => x + z }) // error } diff --git a/tests/neg/overloaded.scala b/tests/neg/overloaded.scala index ce971ebcf4df..79ab2a7c8dad 100644 --- a/tests/neg/overloaded.scala +++ b/tests/neg/overloaded.scala @@ -3,11 +3,11 @@ object Test { def mapX(f: Char => Char): String = ??? def mapX[U](f: U => U): U = ??? - mapX(x => x) // error: missing parameter type + mapX(x => x) //OK def foo(f: Char => Char): Unit = ??? def foo(f: Int => Int): String = ??? - foo(x => x) // error: missing parameter type + foo(x => x) // error: ambiguous def bar(f: (Char, Char) => Unit): Unit = ??? def bar(f: Char => Unit) = ??? diff --git a/tests/neg/parser-stability-10.scala b/tests/neg/parser-stability-10.scala index f72062a7f726..005476163a3d 100644 --- a/tests/neg/parser-stability-10.scala +++ b/tests/neg/parser-stability-10.scala @@ -9,6 +9,6 @@ def unapply(i1: Int)(i6: List[Int]): Int = { } // error object i5 { import collection.mutable._ - try { ??? mutable { case i1(i5, i3, i4) => i5 }} // error // error + try { ??? mutable { case i1(i5, i3, i4) => i5 }} // error } // error \ No newline at end of file diff --git a/tests/neg/t6455.scala b/tests/neg/t6455.scala index ab656a7acf27..e7ed3c8f6b77 100644 --- a/tests/neg/t6455.scala +++ b/tests/neg/t6455.scala @@ -2,5 +2,5 @@ object O { def filter(p: Int => Boolean): O.type = this } class Test { // should not compile because we no longer rewrite withFilter => filter under -Xfuture - O.withFilter(f => true) // error // error + O.withFilter(f => true) // error } diff --git a/tests/neg/t7239.scala b/tests/neg/t7239.scala index f7935dbb7bed..f3a379b4eba5 100644 --- a/tests/neg/t7239.scala +++ b/tests/neg/t7239.scala @@ -17,7 +17,7 @@ object Test { (implicit F0: NoImplicit): HasWithFilter = ??? } - BrokenMethod().withFilter(_ => true) // error // error + BrokenMethod().withFilter(_ => true) // error BrokenMethod().filter(_ => true) // ok locally { @@ -35,6 +35,6 @@ object Test { // `(B => Boolean)`. Only later during pickling does the // defensive check for erroneous types in the tree pick up // the problem. - BrokenMethod().withFilter(x => true) // error // error + BrokenMethod().withFilter(x => true) // error } } diff --git a/tests/run/overloads.check b/tests/run/overloads.check index 7d294870f6fa..9ad4681fe001 100644 --- a/tests/run/overloads.check +++ b/tests/run/overloads.check @@ -13,3 +13,6 @@ ok: Funcs.foo('a') = 2 ok: Funcs.foo(97) = 3 ok: M1.f(3) = 11 ok: M2.f(3) = 22 +ok: M3.f("abc", _.reverse) = cba +ok: M3.f(2, _ + 2) = 4 +ok: f("abc", { case s: String => s}) = abc diff --git a/tests/run/overloads.scala b/tests/run/overloads.scala index 848b6f5be0fe..58f1584fbc47 100644 --- a/tests/run/overloads.scala +++ b/tests/run/overloads.scala @@ -31,6 +31,11 @@ object M2 { def f[A](x: A) = 22; } +object M3 { + def f(x: Int, f: Int => Int) = f(x) + def f(x: String, f: String => String) = f(x) +} + object overloads { def check(what: String, actual: Any, expected: Any): Unit = { @@ -78,8 +83,12 @@ object overloads { // val y = new scala.collection.mutable.Stack[Int]; // check("M1.f(" + y +")", M1.f(y), 12); // check("M2.f(" + y +")", M2.f(y), 21); - } + check("M3.f(\"abc\", _.reverse)", M3.f("abc", _.reverse), "cba") + check("M3.f(2, _ + 2)", M3.f(2, _ + 2), 4) + + check("f(\"abc\", { case s: String => s})", M3.f("abc", { case s: String => s}), "abc") + } } //############################################################################