Skip to content

Commit f77d562

Browse files
committed
Merge branch 'master' of https://github.com/rust-lang/rfcs
2 parents cfb4404 + af16c66 commit f77d562

5 files changed

+355
-19
lines changed

README.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,20 @@ the direction the language is evolving in.
2929
* [0141-lifetime-elision.md](text/0141-lifetime-elision.md)
3030
* [0195-associated-items.md](text/0195-associated-items.md)
3131
* [0213-defaulted-type-params.md](text/0213-defaulted-type-params.md)
32-
* [0235-collections-conventions.md](text/0235-collections-conventions.md)
3332
* [0320-nonzeroing-dynamic-drop.md](text/0320-nonzeroing-dynamic-drop.md)
3433
* [0339-statically-sized-literals.md](text/0339-statically-sized-literals.md)
35-
* [0369-num-reform.md](text/0369-num-reform.md)
3634
* [0385-module-system-cleanup.md](text/0385-module-system-cleanup.md)
3735
* [0401-coercions.md](text/0401-coercions.md)
3836
* [0447-no-unused-impl-parameters.md](text/0447-no-unused-impl-parameters.md)
39-
* [0458-send-improvements.md](text/0458-send-improvements.md)
4037
* [0495-array-pattern-changes.md](text/0495-array-pattern-changes.md)
4138
* [0501-consistent_no_prelude_attributes.md](text/0501-consistent_no_prelude_attributes.md)
42-
* [0505-api-comment-conventions.md](text/0505-api-comment-conventions.md)
4339
* [0509-collections-reform-part-2.md](text/0509-collections-reform-part-2.md)
4440
* [0517-io-os-reform.md](text/0517-io-os-reform.md)
45-
* [0544-rename-int-uint.md](text/0544-rename-int-uint.md)
4641
* [0560-integer-overflow.md](text/0560-integer-overflow.md)
47-
* [0563-remove-ndebug.md](text/0563-remove-ndebug.md)
48-
* [0572-rustc-attribute.md](text/0572-rustc-attribute.md)
49-
* [0640-debug-improvements.md](text/0640-debug-improvements.md)
50-
* [0702-rangefull-expression.md](text/0702-rangefull-expression.md)
51-
* [0738-variance.md](text/0738-variance.md)
5242
* [0769-sound-generic-drop.md](text/0769-sound-generic-drop.md)
43+
* [0803-type-ascription.md](text/0803-type-ascription.md)
5344
* [0809-box-and-in-for-stdlib.md](text/0809-box-and-in-for-stdlib.md)
45+
* [0968-closure-return-type-syntax.md](text/0968-closure-return-type-syntax.md)
5446

5547
## Table of Contents
5648
[Table of Contents]: #table-of-contents

text/0517-io-os-reform.md

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,10 +1016,11 @@ strings) and is usually what you want when working with iterators.
10161016

10171017
The `BufReader`, `BufWriter` and `BufStream` types stay
10181018
essentially as they are today, except that for streams and writers the
1019-
`into_inner` method yields the structure back in the case of a flush error:
1020-
1019+
`into_inner` method yields the structure back in the case of a write error,
1020+
and its behavior is clarified to writing out the buffered data without
1021+
flushing the underlying reader:
10211022
```rust
1022-
// If flushing fails, you get the unflushed data back
1023+
// If writing fails, you get the unwritten data back
10231024
fn into_inner(self) -> Result<W, IntoInnerError<Self>>;
10241025

10251026
pub struct IntoInnerError<W>(W, Error);
@@ -1540,6 +1541,59 @@ The contents of `std::io::net` submodules `tcp`, `udp`, `ip` and
15401541
the other modules are being moved or removed and are described
15411542
elsewhere.
15421543

1544+
#### SocketAddr
1545+
1546+
This structure will represent either a `sockaddr_in` or `sockaddr_in6` which is
1547+
commonly just a pairing of an IP address and a port.
1548+
1549+
```rust
1550+
enum SocketAddr {
1551+
V4(SocketAddrV4),
1552+
V6(SocketAddrV6),
1553+
}
1554+
1555+
impl SocketAddrV4 {
1556+
fn new(addr: Ipv4Addr, port: u16) -> SocketAddrV4;
1557+
fn ip(&self) -> &Ipv4Addr;
1558+
fn port(&self) -> u16;
1559+
}
1560+
1561+
impl SocketAddrV6 {
1562+
fn new(addr: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6;
1563+
fn ip(&self) -> &Ipv6Addr;
1564+
fn port(&self) -> u16;
1565+
fn flowinfo(&self) -> u32;
1566+
fn scope_id(&self) -> u32;
1567+
}
1568+
```
1569+
1570+
#### Ipv4Addr
1571+
1572+
Represents a version 4 IP address. It has the following interface:
1573+
1574+
```rust
1575+
impl Ipv4Addr {
1576+
fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr;
1577+
fn any() -> Ipv4Addr;
1578+
fn octets(&self) -> [u8; 4];
1579+
fn to_ipv6_compatible(&self) -> Ipv6Addr;
1580+
fn to_ipv6_mapped(&self) -> Ipv6Addr;
1581+
}
1582+
```
1583+
1584+
#### Ipv6Addr
1585+
1586+
Represents a version 6 IP address. It has the following interface:
1587+
1588+
```rust
1589+
impl Ipv6Addr {
1590+
fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr;
1591+
fn any() -> Ipv6Addr;
1592+
fn segments(&self) -> [u16; 8]
1593+
fn to_ipv4(&self) -> Option<Ipv4Addr>;
1594+
}
1595+
```
1596+
15431597
#### TCP
15441598
[TCP]: #tcp
15451599

@@ -1552,7 +1606,7 @@ following interface:
15521606
impl TcpStream {
15531607
fn connect<A: ToSocketAddrs>(addr: &A) -> io::Result<TcpStream>;
15541608
fn peer_addr(&self) -> io::Result<SocketAddr>;
1555-
fn socket_addr(&self) -> io::Result<SocketAddr>;
1609+
fn local_addr(&self) -> io::Result<SocketAddr>;
15561610
fn shutdown(&self, how: Shutdown) -> io::Result<()>;
15571611
fn duplicate(&self) -> io::Result<TcpStream>;
15581612
}
@@ -1591,7 +1645,7 @@ into the `TcpListener` structure. Specifically, this will be the resulting API:
15911645
```rust
15921646
impl TcpListener {
15931647
fn bind<A: ToSocketAddrs>(addr: &A) -> io::Result<TcpListener>;
1594-
fn socket_addr(&self) -> io::Result<SocketAddr>;
1648+
fn local_addr(&self) -> io::Result<SocketAddr>;
15951649
fn duplicate(&self) -> io::Result<TcpListener>;
15961650
fn accept(&self) -> io::Result<(TcpStream, SocketAddr)>;
15971651
fn incoming(&self) -> Incoming;
@@ -1635,7 +1689,7 @@ impl UdpSocket {
16351689
fn bind<A: ToSocketAddrs>(addr: &A) -> io::Result<UdpSocket>;
16361690
fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)>;
16371691
fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: &A) -> io::Result<usize>;
1638-
fn socket_addr(&self) -> io::Result<SocketAddr>;
1692+
fn local_addr(&self) -> io::Result<SocketAddr>;
16391693
fn duplicate(&self) -> io::Result<UdpSocket>;
16401694
}
16411695

@@ -1687,8 +1741,18 @@ For the current `ip` module:
16871741
* The `ToSocketAddr` trait should become `ToSocketAddrs`
16881742
* The default `to_socket_addr_all` method should be removed.
16891743

1690-
The actual address structures could use some scrutiny, but any
1691-
revisions there are left as an unresolved question.
1744+
The following implementations of `ToSocketAddrs` will be available:
1745+
1746+
```rust
1747+
impl ToSocketAddrs for SocketAddr { ... }
1748+
impl ToSocketAddrs for SocketAddrV4 { ... }
1749+
impl ToSocketAddrs for SocketAddrV6 { ... }
1750+
impl ToSocketAddrs for (Ipv4Addr, u16) { ... }
1751+
impl ToSocketAddrs for (Ipv6Addr, u16) { ... }
1752+
impl ToSocketAddrs for (&str, u16) { ... }
1753+
impl ToSocketAddrs for str { ... }
1754+
impl<T: ToSocketAddrs> ToSocketAddrs for &T { ... }
1755+
```
16921756

16931757
### `std::process`
16941758
[std::process]: #stdprocess

text/0640-debug-improvements.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Summary
66

7-
The `Debug` trait is intended to be implemented by every trait and display
7+
The `Debug` trait is intended to be implemented by every type and display
88
useful runtime information to help with debugging. This RFC proposes two
99
additions to the fmt API, one of which aids implementors of `Debug`, and one
1010
which aids consumers of the output of `Debug`. Specifically, the `#` format

text/0803-type-ascription.md

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
- Start Date: 2015-2-3
2+
- RFC PR: [rust-lang/rfcs#803](https://github.com/rust-lang/rfcs/pull/803)
3+
- Rust Issue: [rust-lang/rust#23416](https://github.com/rust-lang/rust/issues/23416)
4+
- Feature: `ascription`
5+
6+
# Summary
7+
8+
Add type ascription to expressions. (An earlier version of this RFC covered type
9+
ascription in patterns too, that has been postponed).
10+
11+
Type ascription on expression has already been implemented.
12+
13+
See also discussion on [#354](https://github.com/rust-lang/rfcs/issues/354) and
14+
[rust issue 10502](https://github.com/rust-lang/rust/issues/10502).
15+
16+
17+
# Motivation
18+
19+
Type inference is imperfect. It is often useful to help type inference by
20+
annotating a sub-expression with a type. Currently, this is only possible by
21+
extracting the sub-expression into a variable using a `let` statement and/or
22+
giving a type for a whole expression or pattern. This is un- ergonomic, and
23+
sometimes impossible due to lifetime issues. Specifically, where a variable has
24+
lifetime of its enclosing scope, but a sub-expression's lifetime is typically
25+
limited to the nearest semi-colon.
26+
27+
Typical use cases are where a function's return type is generic (e.g., collect)
28+
and where we want to force a coercion.
29+
30+
Type ascription can also be used for documentation and debugging - where it is
31+
unclear from the code which type will be inferred, type ascription can be used
32+
to precisely communicate expectations to the compiler or other programmers.
33+
34+
By allowing type ascription in more places, we remove the inconsistency that
35+
type ascription is currently only allowed on top-level patterns.
36+
37+
## Examples:
38+
39+
(Somewhat simplified examples, in these cases there are sometimes better
40+
solutions with the current syntax).
41+
42+
Generic return type:
43+
44+
```
45+
// Current.
46+
let z = if ... {
47+
let x: Vec<_> = foo.enumerate().collect();
48+
x
49+
} else {
50+
...
51+
};
52+
53+
// With type ascription.
54+
let z = if ... {
55+
foo.enumerate().collect(): Vec<_>
56+
} else {
57+
...
58+
};
59+
```
60+
61+
Coercion:
62+
63+
```
64+
fn foo<T>(a: T, b: T) { ... }
65+
66+
// Current.
67+
let x = [1u32, 2, 4];
68+
let y = [3u32];
69+
...
70+
let x: &[_] = &x;
71+
let y: &[_] = &y;
72+
foo(x, y);
73+
74+
// With type ascription.
75+
let x = [1u32, 2, 4];
76+
let y = [3u32];
77+
...
78+
foo(x: &[_], y: &[_]);
79+
```
80+
81+
Generic return type and coercion:
82+
83+
```
84+
// Current.
85+
let x: T = {
86+
let temp: U<_> = foo();
87+
temp
88+
};
89+
90+
// With type ascription.
91+
let x: T = foo(): U<_>;
92+
```
93+
94+
95+
# Detailed design
96+
97+
The syntax of expressions is extended with type ascription:
98+
99+
```
100+
e ::= ... | e: T
101+
```
102+
103+
where `e` is an expression and `T` is a type. Type ascription has the same
104+
precedence as explicit coercions using `as`.
105+
106+
When type checking `e: T`, `e` must have type `T`. The `must have type` test
107+
includes implicit coercions and subtyping, but not explicit coercions. `T` may
108+
be any well-formed type.
109+
110+
At runtime, type ascription is a no-op, unless an implicit coercion was used in
111+
type checking, in which case the dynamic semantics of a type ascription
112+
expression are exactly those of the implicit coercion.
113+
114+
@eddyb has implemented the expressions part of this RFC,
115+
[PR](https://github.com/rust-lang/rust/pull/21836).
116+
117+
This feature should land behind the `ascription` feature gate.
118+
119+
120+
### coercion and `as` vs `:`
121+
122+
A downside of type ascription is the overlap with explicit coercions (aka casts,
123+
the `as` operator). To the programmer, type ascription makes implicit coercions
124+
explicit (however, the compiler makes no distinction between coercions due to
125+
type ascription and other coercions). In RFC 401, it is proposed that all valid
126+
implicit coercions are valid explicit coercions. However, that may be too
127+
confusing for users, since there is no reason to use type ascription rather than
128+
`as` (if there is some coercion). Furthermore, if programmers do opt to use `as`
129+
as the default whether or not it is required, then it loses its function as a
130+
warning sign for programmers to beware of.
131+
132+
To address this I propose two lints which check for: trivial casts and trivial
133+
numeric casts. Other than these lints we stick with the proposal from #401 that
134+
unnecessary casts will no longer be an error.
135+
136+
A trivial cast is a cast `x as T` where `x` has type `U` and `x` can be
137+
implicitly coerced to `T` or is already a subtype of `T`.
138+
139+
A trivial numeric cast is a cast `x as T` where `x` has type `U` and `x` is
140+
implicitly coercible to `T` or `U` is a subtype of `T`, and both `U` and `T` are
141+
numeric types.
142+
143+
Like any lints, these can be customised per-crate by the programmer. Both lints
144+
are 'warn' by default.
145+
146+
Although this is a somewhat complex scheme, it allows code that works today to
147+
work with only minor adjustment, it allows for a backwards compatible path to
148+
'promoting' type conversions from explicit casts to implicit coercions, and it
149+
allows customisation of a contentious kind of error (especially so in the
150+
context of cross-platform programming).
151+
152+
153+
### Type ascription and temporaries
154+
155+
There is an implementation choice between treating `x: T` as an lvalue or
156+
rvalue. Note that when a rvalue is used in lvalue context (e.g., the subject of
157+
a reference operation), then the compiler introduces a temporary variable.
158+
Neither option is satisfactory, if we treat an ascription expression as an
159+
lvalue (i.e., no new temporary), then there is potential for unsoundness:
160+
161+
```
162+
let mut foo: S = ...;
163+
{
164+
let bar = &mut (foo: T); // S <: T, no coercion required
165+
*bar = ... : T;
166+
}
167+
// Whoops, foo has type T, but the compiler thinks it has type S, where potentially T </: S
168+
```
169+
170+
If we treat ascription expressions as rvalues (i.e., create a temporary in
171+
lvalue position), then we don't have the soundness problem, but we do get the
172+
unexpected result that `&(x: T)` is not in fact a reference to `x`, but a
173+
reference to a temporary copy of `x`.
174+
175+
The proposed solution is that type ascription expressions are rvalues, but
176+
taking a reference of such an expression is forbidden. I.e., type asciption is
177+
forbidden in the following contexts (where `<expr>` is a type ascription
178+
expression):
179+
180+
```
181+
&[mut] <expr>
182+
let ref [mut] x = <expr>
183+
match <expr> { .. ref [mut] x .. => { .. } .. }
184+
<expr>.foo() // due to autoref
185+
```
186+
187+
Like other rvalues, type ascription would not be allowed as the lhs of assignment.
188+
189+
Note that, if type asciption is required in such a context, an lvalue can be
190+
forced by using `{}`, e.g., write `&mut { foo: T }`, rather than `&mut (foo: T)`.
191+
192+
193+
# Drawbacks
194+
195+
More syntax, another feature in the language.
196+
197+
Interacts poorly with struct initialisers (changing the syntax for struct
198+
literals has been [discussed and rejected](https://github.com/rust-lang/rfcs/pull/65)
199+
and again in [discuss](http://internals.rust-lang.org/t/replace-point-x-3-y-5-with-point-x-3-y-5/198)).
200+
201+
If we introduce named arguments in the future, then it would make it more
202+
difficult to support the same syntax as field initialisers.
203+
204+
205+
# Alternatives
206+
207+
We could do nothing and force programmers to use temporary variables to specify
208+
a type. However, this is less ergonomic and has problems with scopes/lifetimes.
209+
210+
Rely on explicit coercions - the current plan [RFC 401](https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md)
211+
is to allow explicit coercion to any valid type and to use a customisable lint
212+
for trivial casts (that is, those given by subtyping, including the identity
213+
case). If we allow trivial casts, then we could always use explicit coercions
214+
instead of type ascription. However, we would then lose the distinction between
215+
implicit coercions which are safe and explicit coercions, such as narrowing,
216+
which require more programmer attention. This also does not help with patterns.
217+
218+
We could use a different symbol or keyword instead of `:`, e.g., `is`.
219+
220+
221+
# Unresolved questions
222+
223+
Is the suggested precedence correct?
224+
225+
Should we remove integer suffixes in favour of type ascription?
226+
227+
Style guidelines - should we recommend spacing or parenthesis to make type
228+
ascription syntax more easily recognisable?

0 commit comments

Comments
 (0)