Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e5fcbbb

Browse files
authored
Merge pull request scala#10486 from som-snytt/issue/4940-numeric-anonfun
Use type of function literal param for PF synthesis [ci: last-only]
2 parents bc5fc23 + f187783 commit e5fcbbb

File tree

5 files changed

+104
-12
lines changed

5 files changed

+104
-12
lines changed

src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ trait MatchTranslation {
200200
if (phase.id >= currentRun.uncurryPhase.id)
201201
devWarning(s"running translateMatch past uncurry (at $phase) on $selector match $cases")
202202

203-
debug.patmat("translating "+ cases.mkString("{", "\n", "}"))
203+
debug.patmat(cases.mkString("translating {", "\n", "}"))
204204

205205
val start = if (settings.areStatisticsEnabled) statistics.startTimer(statistics.patmatNanos) else null
206206

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,22 +2761,25 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
27612761
* an alternative TODO: add partial function AST node or equivalent and get rid of this synthesis --> do everything in uncurry (or later)
27622762
* however, note that pattern matching codegen is designed to run *before* uncurry
27632763
*/
2764-
def synthesizePartialFunction(paramName: TermName, paramPos: Position, paramSynthetic: Boolean,
2764+
def synthesizePartialFunction(paramName: TermName, paramPos: Position, paramType: Type, paramSynthetic: Boolean,
27652765
tree: Tree, mode: Mode, pt: Type): Tree = {
27662766
assert(pt.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt.")
2767-
val (argTp, resTp) = partialFunctionArgResTypeFromProto(pt)
2767+
val (argTp0, resTp) = partialFunctionArgResTypeFromProto(pt)
27682768

27692769
// if argTp isn't fully defined, we can't translate --> error
27702770
// NOTE: resTp still might not be fully defined
2771-
if (!isFullyDefined(argTp)) {
2771+
if (!isFullyDefined(argTp0)) {
27722772
MissingParameterTypeAnonMatchError(tree, pt)
27732773
return setError(tree)
27742774
}
2775+
val argTp =
2776+
if (paramType.ne(NoType)) paramType
2777+
else argTp0
27752778

27762779
// targs must conform to Any for us to synthesize an applyOrElse (fallback to apply otherwise -- typically for @cps annotated targs)
27772780
val targsValidParams = (argTp <:< AnyTpe) && (resTp <:< AnyTpe)
27782781

2779-
val anonClass = context.owner newAnonymousFunctionClass tree.pos addAnnotation SerialVersionUIDAnnotation
2782+
val anonClass = context.owner.newAnonymousFunctionClass(tree.pos).addAnnotation(SerialVersionUIDAnnotation)
27802783

27812784
import CODE._
27822785

@@ -2816,7 +2819,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
28162819
}
28172820

28182821
// `def applyOrElse[A1 <: $argTp, B1 >: $matchResTp](x: A1, default: A1 => B1): B1 =
2819-
// ${`$selector match { $cases; case default$ => default(x) }`
2822+
// ${`$selector match { $cases; case default$ => default(x) }`}
28202823
def applyOrElseMethodDef = {
28212824
val methodSym = anonClass.newMethod(nme.applyOrElse, tree.pos, FINAL | OVERRIDE)
28222825

@@ -2836,8 +2839,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
28362839

28372840
// First, type without the default case; only the cases provided
28382841
// by the user are typed. The LUB of these becomes `B`, the lower
2839-
// bound of `B1`, which in turn is the result type of the default
2840-
// case
2842+
// bound of `B1`, which in turn is the result type of the default case
28412843
val match0 = methodBodyTyper.typedMatch(selector(x), cases, mode, resTp)
28422844
val matchResTp = match0.tpe
28432845

@@ -3178,9 +3180,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
31783180
// you won't know you're using the wrong owner until lambda lift crashes (unless you know better than to use the wrong owner)
31793181
val outerTyper = newTyper(context.outer)
31803182
val p = vparams.head
3181-
if (p.tpt.tpe == null) p.tpt setType outerTyper.typedType(p.tpt).tpe
3182-
3183-
outerTyper.synthesizePartialFunction(p.name, p.pos, paramSynthetic = false, funBody, mode, pt)
3183+
if (p.tpt.tpe == null) p.tpt.setType(outerTyper.typedType(p.tpt).tpe)
3184+
outerTyper.synthesizePartialFunction(p.name, p.pos, p.tpt.tpe, paramSynthetic = false, funBody, mode, pt)
31843185
} else doTypedFunction(fun, resProto)
31853186
}
31863187
}
@@ -4916,7 +4917,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
49164917
val cases = tree.cases
49174918
if (selector == EmptyTree) {
49184919
if (pt.typeSymbol == PartialFunctionClass)
4919-
synthesizePartialFunction(newTermName(fresh.newName("x")), tree.pos, paramSynthetic = true, tree, mode, pt)
4920+
synthesizePartialFunction(newTermName(fresh.newName("x")), tree.pos, paramType = NoType, paramSynthetic = true, tree, mode, pt)
49204921
else {
49214922
val arity = functionArityFromType(pt) match { case -1 => 1 case arity => arity } // scala/bug#8429: consider sam and function type equally in determining function arity
49224923

test/files/neg/t4940.check

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
t4940.scala:3: error: type mismatch;
2+
found : String("x")
3+
required: Int
4+
val f: PartialFunction[String, Int] = (x: Int) => x match { case "x" => 3 } // error
5+
^
6+
t4940.scala:3: error: type mismatch;
7+
found : scala.runtime.AbstractPartialFunction[Int,Int] with java.io.Serializable
8+
required: PartialFunction[String,Int]
9+
val f: PartialFunction[String, Int] = (x: Int) => x match { case "x" => 3 } // error
10+
^
11+
t4940.scala:5: error: type mismatch;
12+
found : String("x")
13+
required: X
14+
val g: PartialFunction[String, Int] = (x: X) => x match { case "x" => 3 } // error
15+
^
16+
t4940.scala:5: error: type mismatch;
17+
found : scala.runtime.AbstractPartialFunction[X,Int] with java.io.Serializable
18+
required: PartialFunction[String,Int]
19+
val g: PartialFunction[String, Int] = (x: X) => x match { case "x" => 3 } // error
20+
^
21+
t4940.scala:7: error: type mismatch;
22+
found : scala.runtime.AbstractPartialFunction[Double,Int] with java.io.Serializable
23+
required: PartialFunction[Int,Int]
24+
val m: PartialFunction[Int, Int] = (x: Double) => x match { case 3.14 => 3 } // error
25+
^
26+
t4940.scala:9: error: type mismatch;
27+
found : scala.runtime.AbstractPartialFunction[X,Int] with java.io.Serializable
28+
required: PartialFunction[Y,Int]
29+
val g3: PartialFunction[Y, Int] = (x: X) => x match { case _: X => 3 } // error
30+
^
31+
6 errors

test/files/neg/t4940.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//> using options -Werror -Xlint
2+
class C {
3+
val f: PartialFunction[String, Int] = (x: Int) => x match { case "x" => 3 } // error
4+
5+
val g: PartialFunction[String, Int] = (x: X) => x match { case "x" => 3 } // error
6+
7+
val m: PartialFunction[Int, Int] = (x: Double) => x match { case 3.14 => 3 } // error
8+
9+
val g3: PartialFunction[Y, Int] = (x: X) => x match { case _: X => 3 } // error
10+
}
11+
12+
class Y
13+
class X extends Y
14+
15+
object Test extends App {
16+
val c = new C
17+
println(c.f.applyOrElse("hello, world", (s: String) => -1))
18+
println(c.f.applyOrElse("x", (s: String) => -1))
19+
println(c.g.applyOrElse("hello, world", (s: String) => -1))
20+
println(c.m.applyOrElse(42, (n: Int) => -1))
21+
}

test/files/pos/t4940.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//> using options -Werror -Xlint
2+
class C {
3+
val f: PartialFunction[String, Int] = (x: String) => x match { case "x" => 3 }
4+
val f2: PartialFunction[String, Int] = (x: String) => x match { case "x" => x.toString.toInt }
5+
6+
val g: PartialFunction[X, Int] = (x: X) => x match { case X(i) => i }
7+
val g2: PartialFunction[X, Int] = (x: Y) => x match { case X(i) => i }
8+
//val g3: PartialFunction[Y, Int] = (x: X) => x match { case X(i) => i }
9+
10+
val m: PartialFunction[Double, Int] = (x: Double) => x match { case 3.14 => 3 }
11+
}
12+
13+
class D {
14+
val f: PartialFunction[String, Int] = _ match { case "x" => 3 }
15+
16+
val g: PartialFunction[X, Int] = _ match { case X(i) => i }
17+
18+
val m: PartialFunction[Double, Int] = _ match { case 3.14 => 3 }
19+
}
20+
21+
class E {
22+
val f: PartialFunction[String, Int] = x => x.toInt
23+
24+
val g: PartialFunction[X, Int] = x => x.x
25+
26+
val m: PartialFunction[Double, Long] = d => d.round
27+
}
28+
29+
trait Y
30+
case class X(x: Int) extends Y
31+
32+
class ActuallyOK {
33+
val map = Map(42 -> "foo")
34+
def k = List(27).collect {
35+
map.get(_) match {
36+
case Some(i) => i
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)