Closed Sporarum closed 2 weeks ago
Following today's investigation, here is what I found:
This results from fromSymbols
return expression, where it calls tl.integrate
, which replaces the parameters (x, z
) in the type of z
by corresponding TermParamRef
s, which have an empty underlying
When the compiler later tries to select .+
on x
, it fails, as it was replaced during the step described above
Note that tl
has already found a type with a correct underlying
, so this should definitely be possible
I added the tests in the PR above
This results from
fromSymbols
return expression, where it callstl.integrate
, which replaces the parameters (x, z
) in the type ofz
by correspondingTermParamRef
s, which have an emptyunderlying
Yup, binder.paramInfos
is null
there. We are actually computing it at this point; the problematic call goes through the application of paramInfosExp
:
paramInfos
while its being computed. The quick and dirty fix there is however not a viable solution as @sjrd mentioned.I am wondering what other approaches we could take to solve this problem. Seems like we should generally avoid TermParamRef.underlying
returning NoType
, but I don't see yet how. Could we somehow return a backup type there when binder.paramInfos
is null
? If yes, what should it be?
Another possibility could be to disable the check in TypeAssigner.assignType(tree: untpd.Apply, ...
in some cases:
diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 98e9cb638c1..8f3a18f38f3 100644
--- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -289,6 +289,10 @@ trait TypeAssigner {
else fntpe.resultType // fast path optimization
else
errorType(em"wrong number of arguments at ${ctx.phase.prev} for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.srcPos)
+ case NoType if fn.tpe.isInstanceOf[TermRef] =>
+ // TermRef is not bound yet. Wait silently.
+ // See https://github.com/lampepfl/dotty/issues/17242.
+ fn.tpe
case t =>
if (ctx.settings.Ydebug.value) new FatalError("").printStackTrace()
errorType(err.takesNoParamsMsg(fn, ""), tree.srcPos)
But this is probably too general (makes tests/neg-custom-args/fatal-warnings/i15503e.scala
fail for example). It seems that in our case, we can only substitute for a more precise type, so we might avoid the check, but that's not the case in general.
This compiles:
class local(predicate: Int) extends annotation.StaticAnnotation
def working4(x: Int, y: Int @local((() => x + x)())) = ()
This might be related to the following:
def foo[A, B](x: A, y: B = x) = () //error: not found: x
def bar[A, B](x: A)(y: B = x) = ()
(This also showcases why it's useful that default parameters are checked at call-site)
Compiler version
Scala 3.2.2
Minimized code and Ouptut
Scastie which also contains the examples below: https://scastie.scala-lang.org/jfNlEM8sR26DI2priR6mWQ
Expectation
Assuming following definitions in scope
The above should compile since the reference to x is totally valid here, for example the following compiles:
You can see in particular that it is the selection that causes the problem, and not the reference to
x
In dependent types, the selection doesn't cause the same problem:
Notice that the error mentions
Int
explicitly, so it has to knowx.length
is both a valid selection, and of typeInt
I do not advocate for changing the following however:
Finally, here is another failing example, even though the selection in question is
==
which is defined on (pretty much?) every Scala type: