Skip to content
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

RFC: Type Ascribed Coercions #2623

Closed
wants to merge 8 commits into from

Conversation

haslersn
Copy link
Contributor

@haslersn haslersn commented Jan 5, 2019

Rendered

This improves on the merged RFC 803.

Motivation and summary

The subsection "Type ascription and temporaries" of the merged RFC 803 defines certain contexts (so-called reference contexts) in which a type ascription that needs coercion can not occur. Meanwhile and in contrast, the Rust reference defines coercion sites which are contexts in which a coercion can occur.

For consistency, we change the specification as of RFC 803 such that a type ascribed expression that needs to be coerced can only occur at these coercion sites. The aim is to reduce language complexity and increase consistency.

This change shouldn't in any way conflict with RCF 2522.

@@ -161,7 +161,7 @@ as an lvalue (i.e., no new temporary), then there is potential for unsoundness:
```
let mut foo: S = ...;
{
let bar = &mut (foo: T); // S <: T, no coercion required
let bar = &mut (foo: T); // S <: T, coercion from S to T
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case you wonder: "no coercion required" was wrong because this is one type of coercion.

@Centril Centril added T-lang Relevant to the language team, which will review and decide on the RFC. A-typesystem Type system related proposals & ideas A-ascription Type ascription related proposals & ideas A-inference Type inference related proposals & ideas labels Jan 6, 2019
The change is now covered by the paper of RFC 2623
@haslersn haslersn changed the title RFC 803: Change where type ascribed expressions can be coerced RFC: Change where type ascribed expressions can be coerced Jan 6, 2019
@haslersn haslersn changed the title RFC: Change where type ascribed expressions can be coerced RFC: Type Ascribed Coercions Jan 6, 2019
@ExpHP
Copy link

ExpHP commented Jan 7, 2019

It's not clear to me if this needs an RFC? (i.e. is there anything here for the general public to discuss?)

RFCs are not authorative, especially with regards to implementation, and in cases like this where an "obvious right solution" arises somewhere down the road, I believe the course of action taken in the past has been to simply implement that obvious right solution.

(unless perhaps somebody believes this change is not so "obviously right" as I suggest? :P)

Personally, I am familiar with the concept of coercion sites as defined in the Rust reference, and the very first thing I thought of upon seeing the unsound example was, "I don't think that's a coercion site?" I'd probably just shrug it off on the basis that the RFC is 3 years old, knowing how much our vocabulary and concepts for discussing the language have changed since then.

@ExpHP
Copy link

ExpHP commented Jan 7, 2019

I guess the most accessible thing to focus on is the disadvantages.

let _ = e : T; // ERROR, not a coercion site

This snippet uses a _ pattern, but does it extend to more general cases? (e.g. patterns that aren't _? Or _ patterns embedded in a larger pattern? I'm guessing "no; yes"?) I guess this could be a little surprising, but it's hard to picture where it would ever come up. (it seems pointless to write, so it would have to come up as a result of macro codegen)


Also, I assume this still works for selecting types for type inference?

// should be ok, since `V where V: FromIterator<i32>` can be unified with Vec<i32>?
let _ = (0..1).collect(): Vec<i32>;
let _ = (&(0..1).collect()): &Vec<i32>;

// presumably this is not ok since it requires a coercion?
let _ = (&(0..1).collect::<Vec<_>>()): &[i32];

fn reborrow<'b, 'a: 'b>(x: &'a i32) -> &'b i32 {
    // hopefully okay since subtyping doesn't *require* a coercion site?
    // (or does it?)
    x: &'b i32
}

@haslersn
Copy link
Contributor Author

haslersn commented Jan 7, 2019

@ExpHP

RFCs are not authorative, especially with regards to implementation, and in cases like this where an "obvious right solution" arises somewhere down the road, I believe the course of action taken in the past has been to simply implement that obvious right solution.

I came to Rust 2 weeks ago and am still unfamiliar with the processes.

I'd probably just shrug it off on the basis that the RFC is 3 years old, knowing how much our vocabulary and concepts for discussing the language have changed since then.

I also thought about that being a possible reason, why it's not already like I proposed.

This snippet uses a _ pattern, but does it extend to more general cases?

Like stated: Once RFC #2522 gets merged, we can help type inference at the left side of the assignment, even with arbitrary patterns. Example:

let (alpha: u8, beta: i16, gamma: bool) = (1, -2, true);

If there'd still be code that surprisingly doesn't compile, we could still fix it later.

@haslersn
Copy link
Contributor Author

haslersn commented Jan 7, 2019

@ExpHP

fn reborrow<'b, 'a: 'b>(x: &'a i32) -> &'b i32 {
    // hopefully okay since subtyping doesn't *require* a coercion site?
    // (or does it?)
    x: &'b i32
}

It's okay, but for a different reason: The last expression of a block is a coercion site.

@ExpHP
Copy link

ExpHP commented Jan 7, 2019

Ah, indeed. After reading the RFC more thoroughly that does sound like the correct explanation for the third example.

I came to Rust 2 weeks ago and am still unfamiliar with the processes.

This is still pretty good! The RFC is excellently written, I just mention this because writing an RFC can be a pretty big time sink (so when the process can be avoided, that's a good idea). Proposing these ideas first on internals as a Pre-RFC can also garner suggestions on how to get things moving in the right direction.

I'd probably just shrug it off on the basis that the RFC is 3 years old, knowing how much our vocabulary and concepts for discussing the language have changed since then.

I also thought about that being a possible reason, why it's not already like I proposed.

In this vein, mind: The reference is a Pretty New Thing (TM) and still a work in progress. For a long time, the only big resources on Rust were RTPL (which isn't much of a reference), the Nomicon (which has stagnated and is limited in topics), and any language features documented in the standard library documentation (which is very limited in scope).

@nikomatsakis
Copy link
Contributor

Hmm, so, I like the overall definition here, but I think perhaps there may be different expectations as to what constitutes a "coercion site". In particular, I would have assumed that the "initializer in a let" was considered a "coercion site" (unless the pattern contained a ref binding), precisely because let <pat>: T = <expr> will coerce the type of expression to T (unless pat contains an explicit ref-mod binding).

I guess I have to revisit the "pattern binding" RFC. It seems like in general we could make let _ = x: T be considered a coercion site, in which case -- are there other examples where coercions might reasonable by expected but do not, in fact work?

On the other hand, that might just mean that the RFC is basically "identical" to the existing, already accepted solution? (Since any non-coercion site is a "reference site"?)

I do agree with @ExpHP that this doesn't have to be an RFC per se, but it's the sort of conversation where our current process doesn't have an ideal home. Something I'd like to change. =)

@nikomatsakis
Copy link
Contributor

Man, I just re-read this RFC -- uh -- over a year later and I had completely forgotten that I had read it before. I think I still approve of its general argument, though the comment I made above is still relevant -- I would consider let _ = e: T a coercion site, and I think the obvious implementation style for this RFC would do the same. At that point, this may just be suggesting the right way to implement the previous RFC. Maybe I will try to mentor that work out, I suppose.

@nikomatsakis
Copy link
Contributor

We discussed this in the backlog bonanza and decided to close the RFC as unnecessary -- this feels like it falls well within the realm of "implementation detail". So what I am going to do is to open a tracking issue that corresponds to this RFC and link it from the type ascription issue as a suggested implementation path.

There are however some doubts within the lang-team about whether the existing type ascription syntax is the right one, as you can see in this recent Zulip thread.

@nikomatsakis
Copy link
Contributor

Er, I meant to add, thanks @haslersn for the suggestion, though, this seems like it is indeed a better approach!

@nikomatsakis
Copy link
Contributor

By the way, I think a better example of where this approach might differ from the original RFC would be something like (e: &dyn Foo).bar(), where e: &T and T: Foo. This would not work with this approach because a.b() syntax cannot coerce the type of a. And indeed it probably should not because of &mut self and so forth. I guess it's a bit debatable about whether it would have worked in the older RFC, I would have to look at what we wrote about reference contexts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ascription Type ascription related proposals & ideas A-inference Type inference related proposals & ideas A-typesystem Type system related proposals & ideas T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants