Skip to content

Commit c973d9b

Browse files
committed
Fail when a poly function value has a different number of type
params than the expected poly function
1 parent 0e93a38 commit c973d9b

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
@@ -1912,32 +1912,34 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
19121912
val untpd.Function(vparams: List[untpd.ValDef] @unchecked, body) = fun: @unchecked
19131913
val dpt = pt.dealias
19141914

1915-
// If the expected type is a polymorphic function with the same number of
1916-
// type and value parameters, then infer the types of value parameters from the expected type.
1917-
val inferredVParams = dpt match
1918-
case defn.PolyFunctionOf(poly @ PolyType(_, mt: MethodType))
1919-
if tparams.lengthCompare(poly.paramNames) == 0 && vparams.lengthCompare(mt.paramNames) == 0 =>
1920-
vparams.zipWithConserve(mt.paramInfos): (vparam, formal) =>
1921-
// Unlike in typedFunctionValue, `formal` cannot be a TypeBounds since
1922-
// it must be a valid method parameter type.
1923-
if vparam.tpt.isEmpty && isFullyDefined(formal, ForceDegree.failBottom) then
1924-
cpy.ValDef(vparam)(tpt = new untpd.InLambdaTypeTree(isResult = false, (tsyms, vsyms) =>
1925-
// We don't need to substitute `mt` by `vsyms` because we currently disallow
1926-
// dependencies between value parameters of a closure.
1927-
formal.substParams(poly, tsyms.map(_.typeRef)))
1928-
)
1929-
else vparam
1930-
case _ =>
1931-
vparams
1932-
1933-
val resultTpt = dpt match
1915+
dpt match
19341916
case defn.PolyFunctionOf(poly @ PolyType(_, mt: MethodType)) =>
1935-
untpd.InLambdaTypeTree(isResult = true, (tsyms, vsyms) =>
1936-
mt.resultType.substParams(mt, vsyms.map(_.termRef)).substParams(poly, tsyms.map(_.typeRef)))
1937-
case _ => untpd.TypeTree()
1938-
1939-
val desugared = desugar.makeClosure(tparams, inferredVParams, body, resultTpt, tree.span)
1940-
typed(desugared, pt)
1917+
if tparams.lengthCompare(poly.paramNames) == 0 && vparams.lengthCompare(mt.paramNames) == 0 then
1918+
// If the expected type is a polymorphic function with the same number of
1919+
// type and value parameters, then infer the types of value parameters from the expected type.
1920+
val inferredVParams = vparams.zipWithConserve(mt.paramInfos): (vparam, formal) =>
1921+
// Unlike in typedFunctionValue, `formal` cannot be a TypeBounds since
1922+
// it must be a valid method parameter type.
1923+
if vparam.tpt.isEmpty && isFullyDefined(formal, ForceDegree.failBottom) then
1924+
cpy.ValDef(vparam)(tpt = new untpd.InLambdaTypeTree(isResult = false, (tsyms, vsyms) =>
1925+
// We don't need to substitute `mt` by `vsyms` because we currently disallow
1926+
// dependencies between value parameters of a closure.
1927+
formal.substParams(poly, tsyms.map(_.typeRef)))
1928+
)
1929+
else vparam
1930+
val resultTpt =
1931+
untpd.InLambdaTypeTree(isResult = true, (tsyms, vsyms) =>
1932+
mt.resultType.substParams(mt, vsyms.map(_.termRef)).substParams(poly, tsyms.map(_.typeRef)))
1933+
val desugared = desugar.makeClosure(tparams, inferredVParams, body, resultTpt, tree.span)
1934+
typed(desugared, pt)
1935+
else
1936+
val msg =
1937+
em"""|Provided polymorphic function value doesn't match the expected type $dpt.
1938+
|Expected type should be a polymorphic function with the same number of type and value parameters."""
1939+
errorTree(EmptyTree, msg, tree.srcPos)
1940+
case _ =>
1941+
val desugared = desugar.makeClosure(tparams, vparams, body, untpd.TypeTree(), tree.span)
1942+
typed(desugared, pt)
19411943
end typedPolyFunctionValue
19421944

19431945
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)