-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # 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.