-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Unsoundness from not-yet-initialized path without involving divergence #11572
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
Comments
The initialization checker can be reused to catch such errors. Currently, type statements are ignored. We can capture usage of terms in types and report an error if a field is not known to be initialized. /cc: @olhotak @natsukagami |
@liufengyun I think that would be worth a try. |
I should wait until after we discuss this with @liufengyun and @natsukagami, but one challenge we'll need to keep in mind is that initialization state is flow-sensitive while types are global, flow-insensitive. For example, if some field has type Another way of saying this is that we can allow dependency on a term only if we can prove that the term will definitely be initialized "eventually", but how do we define when "eventually" will be? Many similar examples involve terms that would get initialized after the completion of some infinite loop. Something to think about before our next initialization meeting. |
As a memo for the meeting with @olhotak and @natsukagami , we believe theoretically it makes sense to perform this kind of check using the initialization checker. The intuitive reason is that we may imagine that Scala does not have type erasure semantics, therefore, a type selection on an uninitialized field is always a semantic error. However, the initialization checker has some difficulty for the concrete case above, as it involves the initialization of local variables (not fields), which is governed by a forward reference check (not the initialization check). The same example wrapped in a class (instead of method) can be handled well by the initialization checker: class A {
trait Cov[+X] {
def get: X
}
trait Bounded {
type T >: Cov[Int] <: Cov[String]
}
val t: Bounded = new Bounded {
// Note: using this instead of t produces an error (as expected)
override type T >: t.T <: t.T
}
val covInt = new Cov[Int] {
override def get: Int = 3
}
val str: String = ((covInt: t.T): Cov[String]).get // ClassCastException: class Integer cannot be cast to class String
} |
The problem that involves fields of a class is now solved in #11716. For the version based on local variables, we need to enhance the forward reference check (use initialization checker for it?). |
Compiler version
Scala compiler version 3.0.0-RC2-bin-SNAPSHOT-nonbootstrapped-git-55da939 -- Copyright 2002-2021, LAMP/EPFL
Minimized code
Output
Click to expand
Expectation
The above instantiation of
t
should be rejected, as it is using a not-yet-initializedt
to construct non-sensical bounds using the assumption thatCov[Int] <: Cov[String]
.This issue is similar to #5854 but does not involve divergence.
The text was updated successfully, but these errors were encountered: