-
-
Notifications
You must be signed in to change notification settings - Fork 415
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
Calling box methods on an iso reference replaces this by iso #1887
Comments
This ended up much longer than I expected. Just as a note, here's how I've formalised I make the distinction between class A
fun box get1() : this->B ref
fun #read get2() : this-> B ref
class B Receivers can be approximated by implicit arguments, like so (this isn't really true, but its good enough just for explanations) : class A
fun get1[This: A box](this: This) : This->B ref
fun get2[This: A #read](this: This) : This-> B ref When calling a method, the receiver type must be specified explicitly, as the first type argument. A::get1[A box](a)
A::get1[A ref](a) // error: A ref is not in constraint A box
A::get2[A box](a)
A::get2[A ref](a)
A::get2[A val](a)
A::get2[A iso](a) // error: A iso is not in constraint A #read Using an let x : A iso
A::get2[A ref](consume a) My proposal for the compiler is to infer the receiver type argument, based on the type of the receiver expression, like is is done today. It is however necessary to decay this type in order to fit the receiver constraint. |
I'm still getting used to triaging, I'm not sure what the standards are for difficulty and priority. |
This is a workaround for ponylang#1887
@plietar have you seen the triaging guide on the website? https://www.ponylang.org/contribute/triage Would love your feedback/PRs to improve that. |
@plietar - Quick thought experiment - what if we auto-decayed an I think that would "break" your Also, it's not clear to me whether type checking the body of a I'd definitely like to hear if @Praetonus and/or @sylvanc have any bright ideas here. |
@jemc Looking at the viewpoint adaptation rules, it seems like decaying to Checking fun box m(x: this->A ref) =>
let alias : this->A ref = x It might be interesting to implement this and see how much code breaks. I'm not sure how it is implemented in the compiler, but it probably needs a new constraint with |
Talked a bit about this in the sync this week with @jemc, and decaying to I have an extremely hacky implementation of it which only decays A proper implementation of this probably requires a deeper knowledge of the compiler than I currently have, and I won't have too much time until at least end of June to work on it. Worth noting, this may interact with (auto) recovery, such that despite decaying to ref you can still get an iso back. |
It looks like the root of the problem is in the
When looking up the function being called in order to assemble a function type, I think a simple solution would be to force the capability of the receiver to |
Yes, this is exactly what my hacky fix does. However it's not obvious to me what to do when the receiver type isn't a |
The most straightforward way would be to add a function recursively walking through the type AST and building the updated type. You can see various examples in |
In my opinion, we need to have a plan of action here before merging #1888. I still think that auto-receiver recovery might be the key to pulling this off in a way that makes the maximum amount of safe code possible without extra burden on the user. @sylvanc can you please weigh in on this ticket at some point? |
@jemc We talked about this last week on the call. |
) * Downgrade iso and trn to ref when replacing this in a box method. Fixes #1887 * free orig ast if we made a copy in lookup_nominal
Currently, when type checking
box
method bodies,this
is reified bybox
,ref
,val
.However, calling such methods only require the receiver to be a subtype of
box
, and replacesthis
by the receiver type, which could beiso
ortrn
.This means calling a
box
method through aniso
receiver will reify a body which wasn't typechecked. This can lead to unsoundness, as shown below.When the body of
reveal
is typechecked,x
can only have typesbox->B ref
,ref->B ref
andval->B ref
, in other wordsB box
,B ref
andB val
. These are all subtypes of the return type, so it type checks fine.When the body of
Main
is typechecked, sincereveal
is called on aRevealer iso
,this->B ref
becomesiso->B ref
, ieB tag
. And we can successfully get abox
from atag
.This occurs at least in one place in the standard library.
The
values
method ofArray[A]
returns aArrayValues[A, this->Array[A] ref]
, but the second argument ofArrayValues
must be in#read
. Again, when typechecking the body ofvalues()
this is fine.However, calling the method on an
Array[A] iso
will succeed an return aArrayValues[A, Array[A] tag]
. This happens for example inANSITerm
. This leads to non-sensical types, such as thenext
function ofArrayValues
returning aArray[A] tag->A
.I'm not sure why the code in
ANSITerm
compiles at the moment, but my fix for #1875 broke it.TLDR: We need to make the restrictions on
this
the same from the caller's and the callee's points of views.Possible solutions :
this
to mean any subtype ofbox
. This will probably break a lot of today's use cases.box
methods to be called on#read
receivers (ref, box, val), rather than all thebox
subtypes. This is inconsistent with other receiver capability.this
. So calling a box method on an iso receiver is allowed, butthis
is replaced by something in#read
.The last one is the most flexible option, but it's not obvious what to replace
this
with.ref
andval
give different but incompatible guarantees. In any case, the caller can always manually decay itsiso
reference into the type it wants, if the one the compiler picks doesn't have the right guarantees.The text was updated successfully, but these errors were encountered: