-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Evaluating function value can lead to ClassCastException, when function type has by-name parameter #18756
Comments
Scala version 3.1.0 seems ok. |
It seems that |
I did not manage to fix this issue. Someone else should try to find the cause of this issue. #18761 has some insights and tests. |
reported again today on Discord fingers crossed that @smarter can figure it out |
Here's a minimal change that fixes this particular issue: diff --git compiler/src/dotty/tools/dotc/core/Denotations.scala compiler/src/dotty/tools/dotc/core/Denotations.scala
index bd92fa814a6..56e4b1b5e4d 100644
--- compiler/src/dotty/tools/dotc/core/Denotations.scala
+++ compiler/src/dotty/tools/dotc/core/Denotations.scala
@@ -1104,7 +1104,9 @@ object Denotations {
&& (derivedInfo eq info) && !needsPrefix then
this
else
- derivedSingleDenotation(symbol, derivedInfo, pre)
+ val d = derivedSingleDenotation(symbol, derivedInfo, pre)
+ d.validFor = ctx.period
+ d
end derived
// Tt could happen that we see the symbol with prefix `this` as a member a different class The issue is that when we create a new denotation from an existing one, the validity period of that denotation is set based on the validity of the original denotation. When I run: scala> val f: ( => Int) => Int = i => i ; f(1)
...
scala> val f: ( => Int) => Int = i => i ; f(1)
ClassCastException The difference is that in the second run, the denotation for It seems that this problem is pervasive in the codebase and not just limited to
The conservative approach would be to go through all denotation creation sites and use val validFor =
if newInfo == oldDenot.info || !infoDependsOnPrefix(...) then
oldDenot.validFor
else
ctx.period /cc @odersky |
We can try to change all denotation creation sites to currentStablePeriod. If that works and compile speed is not affected that would be simplest. |
I did a quick scan. We already do the right thing for SymDenotation. For the others, it seems to be essentially the newLikeThis calls and maybe on instance in goSuper. |
When running: val f: ( => Int) => Int = i => i ; f(1) twice in the REPL, the second time crashed with a ClassCastException. The difference is that in the second run, the denotation for `f.apply` is created from the SymDenotation for `Function1#apply` which already exists and is known to be valid in every phase, but that doesn't mean that the derived denotation for `f.apply` has the same validity: unlike the SymDenotation it needs to be transformed (in particular to run the `ElimByName` transformer). It turns out that there were multiple places in the compiler where we created a new denotation with a validity based on the existing one when this was not legitimate. I've gone through all these places and replaced them by `currentStablePeriod`. Fixes scala#18756.
When running: val f: ( => Int) => Int = i => i ; f(1) twice in the REPL, the second time crashed with a ClassCastException. The difference is that in the second run, the denotation for `f.apply` is created from the SymDenotation for `Function1#apply` which already exists and is known to be valid in every phase, but that doesn't mean that the derived denotation for `f.apply` has the same validity: unlike the SymDenotation it needs to be transformed (in particular to run the `ElimByName` transformer). It turns out that there were multiple places in the compiler where we created a new denotation with a validity based on the existing one when this was not legitimate. I've gone through all these places and replaced them by `currentStablePeriod`. Fixes scala#18756.
When running: val f: ( => Int) => Int = i => i ; f(1) twice in the REPL, the second time crashed with a ClassCastException. The difference is that in the second run, the denotation for `f.apply` is created from the SymDenotation for `Function1#apply` which already exists and is known to be valid in every phase, but that doesn't mean that the derived denotation for `f.apply` has the same validity: unlike the SymDenotation it needs to be transformed (in particular to run the `ElimByName` transformer). It turns out that there were multiple places in the compiler where we created a new denotation with a validity based on the existing one when this was not legitimate. I've gone through all these places and replaced them by `currentStablePeriod`. Fixes scala#18756.
When running: val f: ( => Int) => Int = i => i ; f(1) twice in the REPL, the second time crashed with a ClassCastException. The difference is that in the second run, the denotation for `f.apply` is created from the SymDenotation for `Function1#apply` which already exists and is known to be valid in every phase, but that doesn't mean that the derived denotation for `f.apply` has the same validity: unlike the SymDenotation it needs to be transformed (in particular to run the `ElimByName` transformer). It turns out that there were multiple places in the compiler where we created a new denotation with a validity based on the existing one when this was not legitimate. I've gone through all these places and replaced them by `currentStablePeriod`. Fixes #18756.
When running: val f: ( => Int) => Int = i => i ; f(1) twice in the REPL, the second time crashed with a ClassCastException. The difference is that in the second run, the denotation for `f.apply` is created from the SymDenotation for `Function1#apply` which already exists and is known to be valid in every phase, but that doesn't mean that the derived denotation for `f.apply` has the same validity: unlike the SymDenotation it needs to be transformed (in particular to run the `ElimByName` transformer). It turns out that there were multiple places in the compiler where we created a new denotation with a validity based on the existing one when this was not legitimate. I've gone through all these places and replaced them by `currentStablePeriod`. Fixes #18756. [Cherry-picked 49571fa]
Compiler version
3.3.0, 3.2.2, 3.2.1, 3.2.0
Minimized code
For reproduction, use Scala REPL, the issue seems to be REPL-related.
Output
Expectation
As
f
is basically the identity (forInt
s),f(1)
shall evaluate to1
.Note: if the assignment and the evaluation entered on the same line, or entered in the same entry, such as:
the issue exhibits itself only when
f
is evaluated upon a different entry.The text was updated successfully, but these errors were encountered: