Skip to content

Commit ead0f11

Browse files
KacperFKorbanWojciechMazur
authored andcommitted
Fail when a poly function value has a different number of type
params than the expected poly function [Cherry-picked c973d9b]
1 parent 2baefd5 commit ead0f11

File tree

3 files changed

+38
-25
lines changed

3 files changed

+38
-25
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Typer.scala

+27-25
Original file line numberDiff line numberDiff line change
@@ -1895,32 +1895,34 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
18951895
val untpd.Function(vparams: List[untpd.ValDef] @unchecked, body) = fun: @unchecked
18961896
val dpt = pt.dealias
18971897

1898-
// If the expected type is a polymorphic function with the same number of
1899-
// type and value parameters, then infer the types of value parameters from the expected type.
1900-
val inferredVParams = dpt match
1901-
case defn.PolyFunctionOf(poly @ PolyType(_, mt: MethodType))
1902-
if tparams.lengthCompare(poly.paramNames) == 0 && vparams.lengthCompare(mt.paramNames) == 0 =>
1903-
vparams.zipWithConserve(mt.paramInfos): (vparam, formal) =>
1904-
// Unlike in typedFunctionValue, `formal` cannot be a TypeBounds since
1905-
// it must be a valid method parameter type.
1906-
if vparam.tpt.isEmpty && isFullyDefined(formal, ForceDegree.failBottom) then
1907-
cpy.ValDef(vparam)(tpt = new untpd.InLambdaTypeTree(isResult = false, (tsyms, vsyms) =>
1908-
// We don't need to substitute `mt` by `vsyms` because we currently disallow
1909-
// dependencies between value parameters of a closure.
1910-
formal.substParams(poly, tsyms.map(_.typeRef)))
1911-
)
1912-
else vparam
1913-
case _ =>
1914-
vparams
1915-
1916-
val resultTpt = dpt match
1898+
dpt match
19171899
case defn.PolyFunctionOf(poly @ PolyType(_, mt: MethodType)) =>
1918-
untpd.InLambdaTypeTree(isResult = true, (tsyms, vsyms) =>
1919-
mt.resultType.substParams(mt, vsyms.map(_.termRef)).substParams(poly, tsyms.map(_.typeRef)))
1920-
case _ => untpd.TypeTree()
1921-
1922-
val desugared = desugar.makeClosure(tparams, inferredVParams, body, resultTpt, tree.span)
1923-
typed(desugared, pt)
1900+
if tparams.lengthCompare(poly.paramNames) == 0 && vparams.lengthCompare(mt.paramNames) == 0 then
1901+
// If the expected type is a polymorphic function with the same number of
1902+
// type and value parameters, then infer the types of value parameters from the expected type.
1903+
val inferredVParams = vparams.zipWithConserve(mt.paramInfos): (vparam, formal) =>
1904+
// Unlike in typedFunctionValue, `formal` cannot be a TypeBounds since
1905+
// it must be a valid method parameter type.
1906+
if vparam.tpt.isEmpty && isFullyDefined(formal, ForceDegree.failBottom) then
1907+
cpy.ValDef(vparam)(tpt = new untpd.InLambdaTypeTree(isResult = false, (tsyms, vsyms) =>
1908+
// We don't need to substitute `mt` by `vsyms` because we currently disallow
1909+
// dependencies between value parameters of a closure.
1910+
formal.substParams(poly, tsyms.map(_.typeRef)))
1911+
)
1912+
else vparam
1913+
val resultTpt =
1914+
untpd.InLambdaTypeTree(isResult = true, (tsyms, vsyms) =>
1915+
mt.resultType.substParams(mt, vsyms.map(_.termRef)).substParams(poly, tsyms.map(_.typeRef)))
1916+
val desugared = desugar.makeClosure(tparams, inferredVParams, body, resultTpt, tree.span)
1917+
typed(desugared, pt)
1918+
else
1919+
val msg =
1920+
em"""|Provided polymorphic function value doesn't match the expected type $dpt.
1921+
|Expected type should be a polymorphic function with the same number of type and value parameters."""
1922+
errorTree(EmptyTree, msg, tree.srcPos)
1923+
case _ =>
1924+
val desugared = desugar.makeClosure(tparams, vparams, body, untpd.TypeTree(), tree.span)
1925+
typed(desugared, pt)
19241926
end typedPolyFunctionValue
19251927

19261928
def typedClosure(tree: untpd.Closure, pt: Type)(using Context): Tree = {

Diff for: tests/neg/i20533.check

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- Error: tests/neg/i20533.scala:5:8 -----------------------------------------------------------------------------------
2+
5 | [X] => (x, y) => Map(x -> y) // error
3+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
| Provided polymorphic function value doesn't match the expected type [X, Y] => (x$1: X, x$2: Y) => Map[X, Y].
5+
| Expected type should be a polymorphic function with the same number of type and value parameters.

Diff for: tests/neg/i20533.scala

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def mapF(h: [X, Y] => (X, Y) => Map[X, Y]): Unit = ???
2+
3+
def test =
4+
mapF(
5+
[X] => (x, y) => Map(x -> y) // error
6+
)

0 commit comments

Comments
 (0)