-
Notifications
You must be signed in to change notification settings - Fork 1.1k
More tweaks to type inference #1482
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import reflect.ClassTag | ||
|
||
// The same problems arise in real arrays. | ||
class A { | ||
|
||
class Array[T] | ||
object Array { | ||
def apply[T: ClassTag](xs: T*): Array[T] = ??? | ||
def apply(x: Int, xs: Int*): Array[Int] = ??? | ||
} | ||
|
||
// Any of Array[List[Symbol]], List[Array[Symbol]], or List[List[Symbol]] compile. | ||
var xs: Array[Array[Symbol]] = _ | ||
var ys: Array[Map[Symbol, Set[Symbol]]] = _ | ||
|
||
//xs = Array(Array()) | ||
// gives: | ||
// | ||
// isApplicableSafe.scala:15: error: type mismatch: | ||
// found : A.this.Array[Nothing] | ||
// required: A.this.Array[Symbol] | ||
// xs = Array(Array()) | ||
// | ||
// Here's the sequence of events that leads to this problem: | ||
// | ||
// 1. the outer Array.apply is overloaded, so we need to typecheck the inner one | ||
// without an expected prototype | ||
// | ||
// 2. The inner Array.apply needs a ClassTag, so we need to instantiate | ||
// its type variable, and the best instantiation is Nothing. | ||
// | ||
// To prevent this, we'd need to do several things: | ||
// | ||
// 1. Pass argument types lazily into the isApplicable call in resolveOverloaded, | ||
// so that we can call constrainResult before any arguments are evaluated. | ||
// | ||
// 2. This is still not enough because the result type is initially an IgnoredProto. | ||
// (because an implicit might have to be inserted around the call, so we cannot | ||
// automatically assume that the call result is a subtype of the expected type). | ||
// Hence, we need to somehow create a closure in constrainResult that does the | ||
// comparison with the real expected result type "on demand". | ||
// | ||
// 3. When instantiating a type variable we need to categorize that some instantiations | ||
// are suspicous (e.g. scalac avoids instantiating to Nothing). In these | ||
// circumstances we should try to excute the delayed constrainResult closures | ||
// in order to get a better instance type. | ||
// | ||
// Quite a lot of work. It's looking really complicated to fix this. | ||
|
||
|
||
ys = Array(Map(), Map()) | ||
|
||
val zs = Array(Map()) | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
What if instead of giving up when this fails, we tried to re-typecheck the inner call using every possible overload? Of course this would have to be done carefully to avoid ending up like the Swift typechecker which apparently gives up when trying to compile
let a: Double = -(1 + 2) + -(3 + 4) + 5
because of overloading and constraint resolutions: https://www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.htmlOn a more general note, it seems that there is a tension in Scala caused by overloading: on one hand it significantly reduces the power of type inference, on the other hand it makes some APIs much nicer to use. So either we figure out how to get overloading to play well with type inference, or we come up with a more principled alternative to overloading that helps us keep our APIs nice.
Uh oh!
There was an error while loading. Please reload this page.
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.
Yeah, I am very nervous about trying all combinations. That typically leads to blowup in compile times. Then you either become too restrictive and can't even typecheck trivial expressions or your compile times go through the roof. In both cases there's little a programmer can do.