-
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
Check method arguments with parametricity when static #14916
Conversation
@olhotak @liufengyun This PR replaces #14751. It is currently incomplete, as I am unsure how to check whether a param is a type variable. Additionally, it fails the added test due to the parameters of Do you have any suggestions regarding this? |
It shouldn't matter whether it's a type variable or not, only whether it's a subtype of Matchable or not. A type variable whose upper bound is a subtype of Matchable wouldn't be safe to consider parametric, while a non-type-variable parameter type of Any is parametric. Which apply is it (Array has many of them)? In |
I agree, but we previously discussed that an special case needed to be made in order to allow for calls to
It appears to be this one. |
This should also be a fix for #9795. |
1a27719
to
eff36d3
Compare
@olhotak @liufengyun This solution does mean that we can pass cold values to class M {
println(this) // error (This line no longer causes an error)
foo()
private val a = 5 // error
def foo() = a
} Should I update that test to allow this? |
It seems to suggest we should always check for type parameters. This way, we can avoid unsafe usage like |
What sort of check are you picturing? The
|
I suggest always check |
Just so we're clear, in theory, requiring the parameter type to be a type variable wouldn't be any more sound than just allowing def myPrintln[T](x: T) = println(x) Then I can bypass any warning on That said, allowing initialization to skip parametric parameters only if their types are type variables may well be a good heuristic. One worry I'd have is explaining it to users: if you do or don't get a warning in a certain case, how do you explain to users why you are/are not supposed to get a warning? For now, since @Xavientois has limited time, I propose to implement it and we can revisit the heuristic later. |
d1189c5
to
11fb1fd
Compare
@liufengyun After making the change, we are now back to failing the cases this PR was originally made to handle. If I use "or" rather than "and", it behaves exactly the same as if the |
Do you mean the enum test case? The condition looks reasonable, it's hard to tell how we should change it. It would be nice to debug why the check is false. |
11fb1fd
to
808a9ce
Compare
@liufengyun It looks like, for The tests in question are:
If I try to change it from |
That is kind of expected, I think we do want to warn in those cases. For other failing tests, they need to be analyzed case by case. If you are time-constrained, I'd suggest leaving the PR as it is. @olhotak and I can take it over. There are some design changes of parametricity coming up during our last meeting. |
The individual cases that fail due to parametricity that I am uncertain about are the following:
@liufengyun Above, you mentioned:
I think that this will help with many of these test cases, but we would need to find another way than using |
For |
808a9ce
to
4165307
Compare
@liufengyun I figured out the problem. We needed to do The only remaining test to figure out is object A:
def foo[T](x: T, array: Array[T]): Unit = array(0) = x
class B {
var a = new Array[B](2)
A.foo(this, a) // error
println(a(0).i)
val i = 99
} Should I remove this test case in order to merge this PR or should we figure out a way to trigger a warning for this case? |
Great you figured it out 👍 The argument is varargs, thus we need to get the component. Here indeed we cannot test the symbol, because in Scala 3 the method type uses For the failing test you mentioned, that's exactly the purpose of it: to defend against unsound solutions. The solution @olhotak and I discussed is the following:
The method |
@liufengyun Just tried the approach you suggested. It does fix that failing
The problem is that the signature of the apply method has an Applied Type as seen here: https://www.scala-lang.org/api/current/scala/Array$.html#apply[T](xs:T*)(implicitevidence$5:scala.reflect.ClassTag[T]):Array[T]
The
Any ideas on how to work around this? |
Thanks for trying it. In this case, we can specialize the logic to allow all arguments of the type |
4165307
to
2f5879a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done @Xavientois 🎉
I left some comments for your reference.
2f5879a
to
0322ccb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you @Xavientois 🎉
0322ccb
to
fcf823d
Compare
When a global static is called, allow for a cold argument if the corresponding parameter is not `Matchable`.
fcf823d
to
ac7aac9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Closes #14460, #14751
When a global static is called, allow for a cold argument if the corresponding parameter is not
Matchable
.When merged, this PR will bring the number of safe-init warnings from bootstrapping the compiler down to 23.