Skip to content

Commit a489169

Browse files
committed
implement feature tuple_struct_self_ctor
1 parent f2302da commit a489169

File tree

9 files changed

+254
-41
lines changed

9 files changed

+254
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# `tuple_struct_self_ctor`
2+
3+
The tracking issue for this feature is: [#51994]
4+
[#51994]: https://github.com/rust-lang/rust/issues/51994
5+
6+
------------------------
7+
8+
The `tuple_struct_self_ctor` feature gate lets you use the special `Self`
9+
identifier as a constructor and a pattern.
10+
11+
A simple example is:
12+
13+
```rust
14+
#![feature(tuple_struct_self_ctor)]
15+
16+
struct ST(i32, i32);
17+
18+
impl ST {
19+
fn new() -> Self {
20+
ST(0, 1)
21+
}
22+
23+
fn ctor() -> Self {
24+
Self(1,2) // constructed by `Self`, it is the same as `ST(1, 2)`
25+
}
26+
27+
fn pattern(self) {
28+
match self {
29+
Self(x, y) => println!("{} {}", x, y), // used as a pattern
30+
}
31+
}
32+
}
33+
```

src/librustc_resolve/build_reduced_graph.rs

+2
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
585585
CtorKind::from_ast(struct_def));
586586
self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion));
587587
self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis));
588+
self.tuple_structs.insert(def.def_id(), ctor_def);
588589
}
589590
}
590591

@@ -703,6 +704,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
703704
self.cstore.def_key(def_id).parent
704705
.map(|index| DefId { krate: def_id.krate, index: index }) {
705706
self.struct_constructors.insert(struct_def_id, (def, vis));
707+
self.tuple_structs.insert(struct_def_id, def);
706708
}
707709
}
708710
Def::Trait(..) => {

src/librustc_resolve/lib.rs

+63-13
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,9 @@ pub struct Resolver<'a, 'b: 'a> {
14631463
/// it's not used during normal resolution, only for better error reporting.
14641464
struct_constructors: DefIdMap<(Def, ty::Visibility)>,
14651465

1466+
/// Map from tuple struct's DefId to VariantData's Def
1467+
tuple_structs: DefIdMap<Def>,
1468+
14661469
/// Only used for better errors on `fn(): fn()`
14671470
current_type_ascription: Vec<Span>,
14681471

@@ -1764,6 +1767,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
17641767
warned_proc_macros: FxHashSet(),
17651768
potentially_unused_imports: Vec::new(),
17661769
struct_constructors: DefIdMap(),
1770+
tuple_structs: DefIdMap(),
17671771
found_unresolved_macro: false,
17681772
unused_macros: FxHashSet(),
17691773
current_type_ascription: Vec::new(),
@@ -2204,6 +2208,19 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
22042208
None
22052209
}
22062210

2211+
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
2212+
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
2213+
let item_def_id = this.definitions.local_def_id(item.id);
2214+
if this.session.features_untracked().self_in_typedefs {
2215+
this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
2216+
visit::walk_item(this, item);
2217+
});
2218+
} else {
2219+
visit::walk_item(this, item);
2220+
}
2221+
});
2222+
}
2223+
22072224
fn resolve_item(&mut self, item: &Item) {
22082225
let name = item.ident.name;
22092226
debug!("(resolving item) resolving {}", name);
@@ -2216,19 +2233,25 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
22162233
|this| visit::walk_item(this, item));
22172234
}
22182235

2236+
ItemKind::Struct(ref variant, ref generics) => {
2237+
if variant.is_tuple() || variant.is_unit() {
2238+
if let Some(def_id) = self.definitions.opt_local_def_id(item.id) {
2239+
if let Some(variant_id) = self.definitions.opt_local_def_id(variant.id()) {
2240+
let variant_def = if variant.is_tuple() {
2241+
Def::StructCtor(variant_id, CtorKind::Fn)
2242+
} else {
2243+
Def::StructCtor(variant_id, CtorKind::Const)
2244+
};
2245+
self.tuple_structs.insert(def_id, variant_def);
2246+
}
2247+
}
2248+
}
2249+
self.resolve_adt(item, generics);
2250+
}
2251+
22192252
ItemKind::Enum(_, ref generics) |
2220-
ItemKind::Struct(_, ref generics) |
22212253
ItemKind::Union(_, ref generics) => {
2222-
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
2223-
let item_def_id = this.definitions.local_def_id(item.id);
2224-
if this.session.features_untracked().self_in_typedefs {
2225-
this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
2226-
visit::walk_item(this, item);
2227-
});
2228-
} else {
2229-
visit::walk_item(this, item);
2230-
}
2231-
});
2254+
self.resolve_adt(item, generics);
22322255
}
22332256

22342257
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
@@ -2503,6 +2526,32 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
25032526
self.ribs[TypeNS].pop();
25042527
}
25052528

2529+
fn with_tuple_struct_self_ctor_rib<F>(&mut self, self_ty: &Ty, f: F)
2530+
where F: FnOnce(&mut Resolver)
2531+
{
2532+
let variant_def = if self.session.features_untracked().tuple_struct_self_ctor {
2533+
let base_def = self.def_map.get(&self_ty.id).map(|r| r.base_def());
2534+
if let Some(Def::Struct(ref def_id)) = base_def {
2535+
self.tuple_structs.get(def_id).cloned()
2536+
} else {
2537+
None
2538+
}
2539+
} else {
2540+
None
2541+
};
2542+
2543+
// when feature gate is enabled and `Self` is a tuple struct
2544+
if let Some(variant_def) = variant_def {
2545+
let mut self_type_rib = Rib::new(NormalRibKind);
2546+
self_type_rib.bindings.insert(keywords::SelfType.ident(), variant_def);
2547+
self.ribs[ValueNS].push(self_type_rib);
2548+
f(self);
2549+
self.ribs[ValueNS].pop();
2550+
} else {
2551+
f(self);
2552+
}
2553+
}
2554+
25062555
fn resolve_implementation(&mut self,
25072556
generics: &Generics,
25082557
opt_trait_reference: &Option<TraitRef>,
@@ -2554,8 +2603,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
25542603
ValueNS,
25552604
impl_item.span,
25562605
|n, s| MethodNotMemberOfTrait(n, s));
2557-
2558-
visit::walk_impl_item(this, impl_item);
2606+
this.with_tuple_struct_self_ctor_rib(self_type, |this| {
2607+
visit::walk_impl_item(this, impl_item);
2608+
});
25592609
}
25602610
ImplItemKind::Type(ref ty) => {
25612611
// If this is a trait impl, ensure the type

src/libsyntax/feature_gate.rs

+12
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ declare_features! (
512512

513513
// Non-builtin attributes in inner attribute position
514514
(active, custom_inner_attributes, "1.30.0", Some(38356), None),
515+
516+
// tuple struct self constructor (RFC 2302)
517+
(active, tuple_struct_self_ctor, "1.31.0", Some(51994), None),
515518
);
516519

517520
declare_features! (
@@ -1736,6 +1739,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
17361739
ast::ExprKind::Async(..) => {
17371740
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
17381741
}
1742+
ast::ExprKind::Call(ref callee, _) => {
1743+
if let ast::ExprKind::Path(_, ref p) = callee.node {
1744+
if p.segments.len() == 1 &&
1745+
p.segments[0].ident.name == keywords::SelfType.name() {
1746+
gate_feature_post!(&self, tuple_struct_self_ctor, e.span,
1747+
"tuple struct Self constructors are unstable");
1748+
}
1749+
}
1750+
}
17391751
_ => {}
17401752
}
17411753
visit::walk_expr(self, e);
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(tuple_struct_self_ctor)]
12+
13+
#![allow(dead_code)]
14+
15+
use std::fmt::Display;
16+
17+
struct ST1(i32, i32);
18+
19+
impl ST1 {
20+
fn new() -> Self {
21+
ST1(0, 1)
22+
}
23+
24+
fn ctor() -> Self {
25+
Self(1,2) // Self as a constructor
26+
}
27+
28+
fn pattern(self) {
29+
match self {
30+
Self(x, y) => println!("{} {}", x, y), // Self as a pattern
31+
}
32+
}
33+
}
34+
35+
struct ST2<T>(T); // With type parameter
36+
37+
impl<T> ST2<T> where T: Display {
38+
39+
fn ctor(v: T) -> Self {
40+
Self(v)
41+
}
42+
43+
fn pattern(&self) {
44+
match self {
45+
Self(ref v) => println!("{}", v),
46+
}
47+
}
48+
}
49+
50+
struct ST3<'a>(&'a i32); // With lifetime parameter
51+
52+
impl<'a> ST3<'a> {
53+
54+
fn ctor(v: &'a i32) -> Self {
55+
Self(v)
56+
}
57+
58+
fn pattern(self) {
59+
let Self(ref v) = self;
60+
println!("{}", v);
61+
}
62+
}
63+
64+
struct ST4(usize);
65+
66+
impl ST4 {
67+
fn map(opt: Option<usize>) -> Option<Self> {
68+
opt.map(Self) // use `Self` as a function passed somewhere
69+
}
70+
}
71+
72+
struct ST5; // unit struct
73+
74+
impl ST5 {
75+
fn ctor() -> Self {
76+
Self // `Self` as a unit struct value
77+
}
78+
79+
fn pattern(self) -> Self {
80+
match self {
81+
Self => Self, // `Self` as a unit struct value for matching
82+
}
83+
}
84+
}
85+
86+
fn main() {
87+
let v1 = ST1::ctor();
88+
v1.pattern();
89+
90+
let v2 = ST2::ctor(10);
91+
v2.pattern();
92+
93+
let local = 42;
94+
let v3 = ST3::ctor(&local);
95+
v3.pattern();
96+
97+
let v4 = Some(1usize);
98+
let _ = ST4::map(v4);
99+
100+
let v5 = ST5::ctor();
101+
v5.pattern();
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct ST(i32, i32);
12+
13+
impl ST {
14+
fn ctor() -> Self {
15+
Self(1,2)
16+
//~^ ERROR: expected function, found self type `Self` [E0423]
17+
//~^^ ERROR: tuple struct Self constructors are unstable (see issue #51994) [E0658]
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0423]: expected function, found self type `Self`
2+
--> $DIR/feature-gate-tuple-struct-self-ctor.rs:15:9
3+
|
4+
LL | Self(1,2)
5+
| ^^^^ not a function
6+
|
7+
= note: can't use `Self` as a constructor, you must use the implemented struct
8+
9+
error[E0658]: tuple struct Self constructors are unstable (see issue #51994)
10+
--> $DIR/feature-gate-tuple-struct-self-ctor.rs:15:9
11+
|
12+
LL | Self(1,2)
13+
| ^^^^^^^^^
14+
|
15+
= help: add #![feature(tuple_struct_self_ctor)] to the crate attributes to enable
16+
17+
error: aborting due to 2 previous errors
18+
19+
Some errors occurred: E0423, E0658.
20+
For more information about an error, try `rustc --explain E0423`.

src/test/ui/resolve/tuple-struct-alias.rs

-9
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@
1111
struct S(u8, u16);
1212
type A = S;
1313

14-
impl S {
15-
fn f() {
16-
let s = Self(0, 1); //~ ERROR expected function
17-
match s {
18-
Self(..) => {} //~ ERROR expected tuple struct/variant
19-
}
20-
}
21-
}
22-
2314
fn main() {
2415
let s = A(0, 1); //~ ERROR expected function
2516
match s {
+3-19
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
1-
error[E0423]: expected function, found self type `Self`
2-
--> $DIR/tuple-struct-alias.rs:16:17
3-
|
4-
LL | let s = Self(0, 1); //~ ERROR expected function
5-
| ^^^^ not a function
6-
|
7-
= note: can't use `Self` as a constructor, you must use the implemented struct
8-
9-
error[E0532]: expected tuple struct/variant, found self type `Self`
10-
--> $DIR/tuple-struct-alias.rs:18:13
11-
|
12-
LL | Self(..) => {} //~ ERROR expected tuple struct/variant
13-
| ^^^^ not a tuple struct/variant
14-
|
15-
= note: can't use `Self` as a constructor, you must use the implemented struct
16-
171
error[E0423]: expected function, found type alias `A`
18-
--> $DIR/tuple-struct-alias.rs:24:13
2+
--> $DIR/tuple-struct-alias.rs:15:13
193
|
204
LL | let s = A(0, 1); //~ ERROR expected function
215
| ^ did you mean `S`?
226
|
237
= note: can't use a type alias as a constructor
248

259
error[E0532]: expected tuple struct/variant, found type alias `A`
26-
--> $DIR/tuple-struct-alias.rs:26:9
10+
--> $DIR/tuple-struct-alias.rs:17:9
2711
|
2812
LL | A(..) => {} //~ ERROR expected tuple struct/variant
2913
| ^ did you mean `S`?
3014
|
3115
= note: can't use a type alias as a constructor
3216

33-
error: aborting due to 4 previous errors
17+
error: aborting due to 2 previous errors
3418

3519
Some errors occurred: E0423, E0532.
3620
For more information about an error, try `rustc --explain E0423`.

0 commit comments

Comments
 (0)