Skip to content

Commit a9b1e15

Browse files
authored
Try to fix callee type inference in typedFunctionValue (#24732)
The callee part is separated from #24697 for further investigation When typing a function literal's expression to infer the callee type, we now create placeholder tree for each argument, and make sure the function part does not refer to any parameter. This ensures that references in the expression won't incorrectly resolve to outer scope variables with the same names as the parameters. Fix the following test: ```scala def foo[T <: (B => Unit)](f: T) = ??? def transfer(in: A): Unit = foo(in => transfer(in)) // error: Found: (in : B) Required: A def transfer(in: B): Unit = ??? ```
2 parents 3c4da0d + cbdf29b commit a9b1e15

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,6 +1876,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
18761876
*/
18771877
var paramIndex = Map[Name, Int]()
18781878

1879+
def containsParamRef(tree: untpd.Tree, params: List[untpd.ValDef]): Boolean =
1880+
import untpd.*
1881+
val acc = new UntypedTreeAccumulator[Boolean]:
1882+
def apply(x: Boolean, t: Tree)(using Context) =
1883+
if x then true
1884+
else t match
1885+
case _: untpd.TypedSplice => false
1886+
case Ident(name) => params.exists(_.name == name)
1887+
case _ => foldOver(x, t)
1888+
acc(false, tree)
1889+
18791890
/** Infer parameter type from the body of the function
18801891
*
18811892
* 1. If function is of the form
@@ -1910,24 +1921,25 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
19101921
for (param <- params; idx <- paramIndices(param, args))
19111922
yield param.name -> idx
19121923
}.toMap
1913-
if (paramIndex.size == params.length)
1924+
if (paramIndex.size == params.length) then
19141925
expr match
19151926
case untpd.TypedSplice(expr1) =>
19161927
expr1.tpe
1917-
case _ =>
1928+
case _ if !containsParamRef(expr, params) =>
19181929
val outerCtx = ctx
19191930
val nestedCtx = outerCtx.fresh.setNewTyperState()
1920-
inContext(nestedCtx) {
1921-
val protoArgs = args.map(_.withType(WildcardType))
1931+
inContext(nestedCtx):
1932+
// try to type expr with fresh unknown arguments.
1933+
val protoArgs = args.map(arg => untpd.Ident(UniqueName.fresh()).withSpan(arg.span))
19221934
val callProto = FunProto(protoArgs, WildcardType)(this, app.applyKind)
19231935
val expr1 = typedExpr(expr, callProto)
19241936
if nestedCtx.reporter.hasErrors then NoType
1925-
else inContext(outerCtx) {
1937+
else inContext(outerCtx):
19261938
nestedCtx.typerState.commit()
19271939
fnBody = cpy.Apply(fnBody)(untpd.TypedSplice(expr1), args)
19281940
expr1.tpe
1929-
}
1930-
}
1941+
case _ =>
1942+
NoType
19311943
else NoType
19321944
case _ =>
19331945
NoType

tests/pos/i24689b.scala

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ object Test1:
99
foo(transfer(_))
1010
def transfer(in: B): Unit = ???
1111

12-
// TODO: need to fix callee type in typedFunctionValue
13-
// object Test2:
14-
// def foo[T <: (B => Unit)](f: T) = ???
15-
// def transfer(in: A): Unit =
16-
// foo(in => transfer(in))
17-
// foo(transfer)
18-
// foo(transfer(_))
19-
// def transfer(in: B): Unit = ???
12+
object Test2:
13+
def foo[T <: (B => Unit)](f: T) = ???
14+
def transfer(in: A): Unit =
15+
foo(in => transfer(in))
16+
foo(transfer)
17+
foo(transfer(_))
18+
def transfer(in: B): Unit = ???

0 commit comments

Comments
 (0)