]> git.lizzy.rs Git - rust.git/commitdiff
implement feature tuple_struct_self_ctor
authorF001 <changchun.fan@qq.com>
Tue, 28 Aug 2018 04:51:43 +0000 (12:51 +0800)
committerF001 <changchun.fan@qq.com>
Thu, 13 Sep 2018 02:57:28 +0000 (10:57 +0800)
src/doc/unstable-book/src/language-features/tuple-struct-self-ctor.md [new file with mode: 0644]
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/libsyntax/feature_gate.rs
src/test/run-pass/tuple-struct-self-ctor.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.stderr [new file with mode: 0644]
src/test/ui/resolve/tuple-struct-alias.rs
src/test/ui/resolve/tuple-struct-alias.stderr

diff --git a/src/doc/unstable-book/src/language-features/tuple-struct-self-ctor.md b/src/doc/unstable-book/src/language-features/tuple-struct-self-ctor.md
new file mode 100644 (file)
index 0000000..7ea52eb
--- /dev/null
@@ -0,0 +1,33 @@
+# `tuple_struct_self_ctor`
+
+The tracking issue for this feature is: [#51994]
+[#51994]: https://github.com/rust-lang/rust/issues/51994
+
+------------------------
+
+The `tuple_struct_self_ctor` feature gate lets you use the special `Self`
+identifier as a constructor and a pattern.
+
+A simple example is:
+
+```rust
+#![feature(tuple_struct_self_ctor)]
+
+struct ST(i32, i32);
+
+impl ST {
+    fn new() -> Self {
+        ST(0, 1)
+    }
+
+    fn ctor() -> Self {
+        Self(1,2)           // constructed by `Self`, it is the same as `ST(1, 2)`
+    }
+
+    fn pattern(self) {
+        match self {
+            Self(x, y) => println!("{} {}", x, y), // used as a pattern
+        }
+    }
+}
+```
index d1a05964c8f6497c0993fc342a40ee201c7e1817..c7aea641e35d42e0eb0b9dcd92fc80c828d269cb 100644 (file)
@@ -585,6 +585,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                                                    CtorKind::from_ast(struct_def));
                     self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion));
                     self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis));
+                    self.tuple_structs.insert(def.def_id(), ctor_def);
                 }
             }
 
@@ -703,6 +704,7 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
                         self.cstore.def_key(def_id).parent
                             .map(|index| DefId { krate: def_id.krate, index: index }) {
                     self.struct_constructors.insert(struct_def_id, (def, vis));
+                    self.tuple_structs.insert(struct_def_id, def);
                 }
             }
             Def::Trait(..) => {
index c725d56d0cfdc8b178dbace230bb982c1e8395e6..f2d46c0510c756801481e79d612145ac44d5c80a 100644 (file)
@@ -1463,6 +1463,9 @@ pub struct Resolver<'a, 'b: 'a> {
     /// it's not used during normal resolution, only for better error reporting.
     struct_constructors: DefIdMap<(Def, ty::Visibility)>,
 
+    /// Map from tuple struct's DefId to VariantData's Def
+    tuple_structs: DefIdMap<Def>,
+
     /// Only used for better errors on `fn(): fn()`
     current_type_ascription: Vec<Span>,
 
@@ -1764,6 +1767,7 @@ pub fn new(session: &'a Session,
             warned_proc_macros: FxHashSet(),
             potentially_unused_imports: Vec::new(),
             struct_constructors: DefIdMap(),
+            tuple_structs: DefIdMap(),
             found_unresolved_macro: false,
             unused_macros: FxHashSet(),
             current_type_ascription: Vec::new(),
@@ -2204,6 +2208,19 @@ fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
         None
     }
 
+    fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
+        self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
+            let item_def_id = this.definitions.local_def_id(item.id);
+            if this.session.features_untracked().self_in_typedefs {
+                this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
+                    visit::walk_item(this, item);
+                });
+            } else {
+                visit::walk_item(this, item);
+            }
+        });
+    }
+
     fn resolve_item(&mut self, item: &Item) {
         let name = item.ident.name;
         debug!("(resolving item) resolving {}", name);
@@ -2216,19 +2233,25 @@ fn resolve_item(&mut self, item: &Item) {
                                              |this| visit::walk_item(this, item));
             }
 
+            ItemKind::Struct(ref variant, ref generics) => {
+                if variant.is_tuple() || variant.is_unit() {
+                    if let Some(def_id) = self.definitions.opt_local_def_id(item.id) {
+                        if let Some(variant_id) = self.definitions.opt_local_def_id(variant.id()) {
+                            let variant_def = if variant.is_tuple() {
+                                Def::StructCtor(variant_id, CtorKind::Fn)
+                            } else {
+                                Def::StructCtor(variant_id, CtorKind::Const)
+                            };
+                            self.tuple_structs.insert(def_id, variant_def);
+                        }
+                    }
+                }
+                self.resolve_adt(item, generics);
+            }
+
             ItemKind::Enum(_, ref generics) |
-            ItemKind::Struct(_, ref generics) |
             ItemKind::Union(_, ref generics) => {
-                self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
-                    let item_def_id = this.definitions.local_def_id(item.id);
-                    if this.session.features_untracked().self_in_typedefs {
-                        this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
-                            visit::walk_item(this, item);
-                        });
-                    } else {
-                        visit::walk_item(this, item);
-                    }
-                });
+                self.resolve_adt(item, generics);
             }
 
             ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
@@ -2503,6 +2526,32 @@ fn with_self_rib<F>(&mut self, self_def: Def, f: F)
         self.ribs[TypeNS].pop();
     }
 
+    fn with_tuple_struct_self_ctor_rib<F>(&mut self, self_ty: &Ty, f: F)
+        where F: FnOnce(&mut Resolver)
+    {
+        let variant_def = if self.session.features_untracked().tuple_struct_self_ctor {
+            let base_def = self.def_map.get(&self_ty.id).map(|r| r.base_def());
+            if let Some(Def::Struct(ref def_id)) = base_def {
+                self.tuple_structs.get(def_id).cloned()
+            } else {
+                None
+            }
+        } else {
+            None
+        };
+
+        // when feature gate is enabled and `Self` is a tuple struct
+        if let Some(variant_def) = variant_def {
+            let mut self_type_rib = Rib::new(NormalRibKind);
+            self_type_rib.bindings.insert(keywords::SelfType.ident(), variant_def);
+            self.ribs[ValueNS].push(self_type_rib);
+            f(self);
+            self.ribs[ValueNS].pop();
+        } else {
+            f(self);
+        }
+    }
+
     fn resolve_implementation(&mut self,
                               generics: &Generics,
                               opt_trait_reference: &Option<TraitRef>,
@@ -2554,8 +2603,9 @@ fn resolve_implementation(&mut self,
                                                                   ValueNS,
                                                                   impl_item.span,
                                                 |n, s| MethodNotMemberOfTrait(n, s));
-
-                                            visit::walk_impl_item(this, impl_item);
+                                            this.with_tuple_struct_self_ctor_rib(self_type, |this| {
+                                                visit::walk_impl_item(this, impl_item);
+                                            });
                                         }
                                         ImplItemKind::Type(ref ty) => {
                                             // If this is a trait impl, ensure the type
index d98e457439927fac53f01e016c15dab5bb1ee4a0..4d24abcf90eb33b3c3bb72d4ad9da8f1fee5be79 100644 (file)
@@ -512,6 +512,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
 
     // Non-builtin attributes in inner attribute position
     (active, custom_inner_attributes, "1.30.0", Some(38356), None),
+
+    // tuple struct self constructor (RFC 2302)
+    (active, tuple_struct_self_ctor, "1.31.0", Some(51994), None),
 );
 
 declare_features! (
@@ -1736,6 +1739,15 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
             ast::ExprKind::Async(..) => {
                 gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
             }
+            ast::ExprKind::Call(ref callee, _) => {
+                if let ast::ExprKind::Path(_, ref p) = callee.node {
+                    if p.segments.len() == 1 &&
+                       p.segments[0].ident.name == keywords::SelfType.name() {
+                        gate_feature_post!(&self, tuple_struct_self_ctor, e.span,
+                            "tuple struct Self constructors are unstable");
+                    }
+                }
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
diff --git a/src/test/run-pass/tuple-struct-self-ctor.rs b/src/test/run-pass/tuple-struct-self-ctor.rs
new file mode 100644 (file)
index 0000000..7392003
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(tuple_struct_self_ctor)]
+
+#![allow(dead_code)]
+
+use std::fmt::Display;
+
+struct ST1(i32, i32);
+
+impl ST1 {
+    fn new() -> Self {
+        ST1(0, 1)
+    }
+
+    fn ctor() -> Self {
+        Self(1,2)         // Self as a constructor
+    }
+
+    fn pattern(self) {
+        match self {
+            Self(x, y) => println!("{} {}", x, y), // Self as a pattern
+        }
+    }
+}
+
+struct ST2<T>(T); // With type parameter
+
+impl<T> ST2<T> where T: Display {
+
+    fn ctor(v: T) -> Self {
+        Self(v)
+    }
+
+    fn pattern(&self) {
+        match self {
+            Self(ref v) => println!("{}", v),
+        }
+    }
+}
+
+struct ST3<'a>(&'a i32); // With lifetime parameter
+
+impl<'a> ST3<'a> {
+
+    fn ctor(v: &'a i32) -> Self {
+        Self(v)
+    }
+
+    fn pattern(self) {
+        let Self(ref v) = self;
+        println!("{}", v);
+    }
+}
+
+struct ST4(usize);
+
+impl ST4 {
+    fn map(opt: Option<usize>) -> Option<Self> {
+        opt.map(Self)     // use `Self` as a function passed somewhere
+    }
+}
+
+struct ST5;               // unit struct
+
+impl ST5 {
+    fn ctor() -> Self {
+        Self               // `Self` as a unit struct value
+    }
+
+    fn pattern(self) -> Self {
+        match self {
+            Self => Self,   // `Self` as a unit struct value for matching
+        }
+    }
+}
+
+fn main() {
+    let v1 = ST1::ctor();
+    v1.pattern();
+
+    let v2 = ST2::ctor(10);
+    v2.pattern();
+
+    let local = 42;
+    let v3 = ST3::ctor(&local);
+    v3.pattern();
+
+    let v4 = Some(1usize);
+    let _ = ST4::map(v4);
+
+    let v5 = ST5::ctor();
+    v5.pattern();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.rs b/src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.rs
new file mode 100644 (file)
index 0000000..aa907e8
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct ST(i32, i32);
+
+impl ST {
+    fn ctor() -> Self {
+        Self(1,2)
+        //~^ ERROR: expected function, found self type `Self` [E0423]
+        //~^^ ERROR: tuple struct Self constructors are unstable (see issue #51994) [E0658]
+    }
+}
diff --git a/src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.stderr b/src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.stderr
new file mode 100644 (file)
index 0000000..e92924e
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0423]: expected function, found self type `Self`
+  --> $DIR/feature-gate-tuple-struct-self-ctor.rs:15:9
+   |
+LL |         Self(1,2)
+   |         ^^^^ not a function
+   |
+   = note: can't use `Self` as a constructor, you must use the implemented struct
+
+error[E0658]: tuple struct Self constructors are unstable (see issue #51994)
+  --> $DIR/feature-gate-tuple-struct-self-ctor.rs:15:9
+   |
+LL |         Self(1,2)
+   |         ^^^^^^^^^
+   |
+   = help: add #![feature(tuple_struct_self_ctor)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0423, E0658.
+For more information about an error, try `rustc --explain E0423`.
index 0dbca07b771d747837a20eb94bcd67a51ce09a58..1f3588dd3ca4ece95b999e942258fdedd44368e6 100644 (file)
 struct S(u8, u16);
 type A = S;
 
-impl S {
-    fn f() {
-        let s = Self(0, 1); //~ ERROR expected function
-        match s {
-            Self(..) => {} //~ ERROR expected tuple struct/variant
-        }
-    }
-}
-
 fn main() {
     let s = A(0, 1); //~ ERROR expected function
     match s {
index cdac6277bcfa3b4d57f8d4b92e12e2673c248d84..ad2ae4acb8b0e387cf4bab04f5cef24a79ddaf8f 100644 (file)
@@ -1,21 +1,5 @@
-error[E0423]: expected function, found self type `Self`
-  --> $DIR/tuple-struct-alias.rs:16:17
-   |
-LL |         let s = Self(0, 1); //~ ERROR expected function
-   |                 ^^^^ not a function
-   |
-   = note: can't use `Self` as a constructor, you must use the implemented struct
-
-error[E0532]: expected tuple struct/variant, found self type `Self`
-  --> $DIR/tuple-struct-alias.rs:18:13
-   |
-LL |             Self(..) => {} //~ ERROR expected tuple struct/variant
-   |             ^^^^ not a tuple struct/variant
-   |
-   = note: can't use `Self` as a constructor, you must use the implemented struct
-
 error[E0423]: expected function, found type alias `A`
-  --> $DIR/tuple-struct-alias.rs:24:13
+  --> $DIR/tuple-struct-alias.rs:15:13
    |
 LL |     let s = A(0, 1); //~ ERROR expected function
    |             ^ did you mean `S`?
@@ -23,14 +7,14 @@ LL |     let s = A(0, 1); //~ ERROR expected function
    = note: can't use a type alias as a constructor
 
 error[E0532]: expected tuple struct/variant, found type alias `A`
-  --> $DIR/tuple-struct-alias.rs:26:9
+  --> $DIR/tuple-struct-alias.rs:17:9
    |
 LL |         A(..) => {} //~ ERROR expected tuple struct/variant
    |         ^ did you mean `S`?
    |
    = note: can't use a type alias as a constructor
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 Some errors occurred: E0423, E0532.
 For more information about an error, try `rustc --explain E0423`.