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
SI-8177 co-evolve more than just RefinedTypes #3516
Conversation
`asSeenFrom` produced a typeref of the shape `T'#A` where `A` referred to a symbol defined in a `T` of times past. More precisely, the `TypeRef` case of `TypeMap`'s `mapOver` correctly modified a prefix from having an underlying type of `{ type A = AIn }` to `{ type A = Int }`, with a new symbol for `A` (now with info `Int`), but the symbol in the outer `TypeRef` wasn't co-evolved (so it still referred to the `A` in `{ type A = AIn }` underlying the old prefix). `coEvolveSym` used to only look at prefixes that were directly `RefinedType`s, but this bug shows they could also be `SingleType`s with an underlying `RefinedType`.
Cleaned up the test cases in the last commit a bit. |
FWIW, the tests pass locally |
LGTM |
The IDE failure is because the jenkins slaves are overloaded and the IDE's scalacheck tests are timing out |
I'll rebuild the ide job individually. It should be fine. |
At some point I offered a variation of pos/t8177.scala which at the time didn't compile. I don't see it. It had one extra line and added a type alias. Is that somewhere to be found? |
It IS compiling with this PR, assuming I remember it correctly. But since at one point it wasn't, maybe throw it into the test case mix.
|
Sorry, I must have missed that one somehow. I'll add it an trigger a rebuild that way, then. |
We look for any prefix that has a refinement class for a type symbol. This includes ThisTypes, which were not considered before. pos/t8177g.scala, neg/t0764*scala now compile, as they should Additional test cases contributed by Jason & Paul.
i christened it t8177b |
The comment with that test case enclosed began "Tsk Tsk Dude", and here I thought that would be memorable. |
My suppressing those is another interesting insight into my psychology, I guess. |
Happily everyone can have their own definition of "interesting". |
That's why that word is so interesting. |
Finally! All green! (on jenkins) |
SI-8177 co-evolve more than just RefinedTypes
The second commit broke shapeless: https://gist.github.com/8973653 https://jenkins-dbuild.typesafe.com:8499/job/Community-2.11.x-retronym/26/console I'm minimizing. /cc @milessabin |
trait A { type Result }
class PolyTests {
def wrong(x: A { type Result = Int })
: A { type Result = String} = x
} |
@adriaanm I poked around at this here: https://github.com/retronym/scala/compare/ticket;8177-3?expand=1 |
Thanks! The fix SGTM, looks like SI-7753 (or some permutation of its digits) broke t0764. It really should compile (at some point -- it is another bug after all), since subtyping on type members is covariant:
so the subtpying question becomes
skolemizing, and applying to T-SUB-TRANSITIVE:
|
Can't be. Subtyping on abstract type members ok, but not once they have been specified. Example with current master:
|
And I still think t0764 should compile, but the reason is that I think the singleton type of v should propagate all the way through. |
Adriaan made the fatal error of replying before his third cup of coffee this morning... Regrading This part must remain a type error, no?:
|
Subtyping of type aliases is invariant. That was my kryptonite On Thursday, February 13, 2014, Jason Zaugg notifications@github.com
|
@retronym look at this variation.
This compiles even in 2.10. But all I did was perform the type substitutions the compiler should be doing. Rather than calling prepend, I placed the return type of prepend there directly. Then I replaced outer.type (aka v.type) with v's non-singleton type Node { type T = A }. And at that point the only methods which don't compile are the ones which take v.type explicitly, which of course no longer compiles because I weakened v. |
Actually I guess it's going to be a problem that I've replaced { type T = outer.type } with the widened type, because one could construct a similar example to the CCE above where outer.type is an incoming type and the widened type is not equivalent, even though its type member will be equivalent. However it should be compilable by sprinkling some <: where there are =s. But I'm not even sure about any of that - this example is confusing as hell . |
Hmm, even though I had another cup of coffee by now, I need to try this out before I'm sure, but my next theory would be that &1 was skolemized too soon (indicated by the "where" in the erorr message), because we should even be able to satisfy type equality, which would then turn my earlier argument into a convincing case:
this would be satisfiable if X was an existential type variable and not a skolem (though I'm not sure about the |
TBH, I'm not sure whether this is right:
|
(Sorry about the live comment editing.) |
This couldn't be falser:
|
(Well, except by actually being considered false.) |
On consideration, fuck if I know anything. Stop enticing me to think about these things. |
I always have to look up the rules to convince myself because they are so unintuitive to me, but I believe
|
With |
@adriaanm I think you pulled from the wrong section of the paper you linked: The ƐΧₗₘₚₗ calculus from which you took that definition and explanation only holds where existentials can only specify implementation (upper) bounds. You have to look at ƐΧᵤₚₗₒ (which renders weird in my font) to find rules that hold when existentials can specify both upper and lower bounds. I'm working on getting to the point where I can post and explain a screenshot without getting things wrong, but to prove to yourself that the substitution method of judgement won't work, consider |
I think the subtyping judgment holds more generally. It just talks about constraints, whether they are lower or upper bounds or even richer. The key is how you instantiate the meta-variables in the proof rules. |
More concretely, applied to scala and scalac:
T is a subtype of some existential if all constraints of the existential hold |
which leads me to believe withTypeVars is wrong I think it should be:
|
I can certainly testify that many is the bug trail which went into withTypeVars and then went dark. |
I'm actually reading the through the code, trying to get acquainted with what's going on (I haven't spent much time in this part of the compiler). I'm not sure I will gain a sufficient understanding of what's going on in the typechecker in time to be of any use to anyone on this, but oh well. I do have to say that I'm kind of astounded at how many things seem to be slightly (dangerously?) misnamed (e.g. instantiateTypeParams is perfectly happy subbing things that aren't type parameters). Anyway, in the unlikely event that anyone cares, I did work a few examples using the rule Adriaan suggested his most recent couple comments. My examples are at https://gist.github.com/clhodapp/5bb0ad993cd60ca556e8, with the final one being Paul's |
Ha ha, you have no idea. |
Would you mind submitting a pull request with that in "literate test case" form? |
Sure, though it's more likely to be of the form "Here's proof that the thing should hold. Here's an |
Or, better, I'll just use |
I'd say a |
Submitted: #3534 |
[Rebase and improvement of #3482]
asSeenFrom
produced a typeref of the shapeT'#A
whereA
referred to a symboldefined in a
T
of times past.More precisely, the
TypeRef
case ofTypeMap
'smapOver
correctly modified a prefixfrom having an underlying type of
{ type A = AIn }
to{ type A = Int }
,with a new symbol for
A
(now with infoInt
), but the symbol in the outerTypeRef
wasn't co-evolved (so it still referred to theA
in{ type A = AIn }
underlying the old prefix).
coEvolveSym
used to only look at prefixes that were directlyRefinedType
s,but this bug shows they could also be
SingleType
/ThisType
s with an underlyingRefinedType
,so we look for a prefix's for a refinement class for a type symbol instead.
Review by @retronym