From a4891699125fa12d46217890e4eb68b35e9ff6d5 Mon Sep 17 00:00:00 2001 From: F001 Date: Tue, 28 Aug 2018 12:51:43 +0800 Subject: [PATCH] implement feature tuple_struct_self_ctor --- .../tuple-struct-self-ctor.md | 33 ++++++ src/librustc_resolve/build_reduced_graph.rs | 2 + src/librustc_resolve/lib.rs | 76 ++++++++++--- src/libsyntax/feature_gate.rs | 12 +++ src/test/run-pass/tuple-struct-self-ctor.rs | 102 ++++++++++++++++++ .../feature-gate-tuple-struct-self-ctor.rs | 19 ++++ ...feature-gate-tuple-struct-self-ctor.stderr | 20 ++++ src/test/ui/resolve/tuple-struct-alias.rs | 9 -- src/test/ui/resolve/tuple-struct-alias.stderr | 22 +--- 9 files changed, 254 insertions(+), 41 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/tuple-struct-self-ctor.md create mode 100644 src/test/run-pass/tuple-struct-self-ctor.rs create mode 100644 src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.rs create mode 100644 src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.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 index 00000000000..7ea52ebe243 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/tuple-struct-self-ctor.md @@ -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 + } + } +} +``` diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d1a05964c8f..c7aea641e35 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c725d56d0cf..f2d46c0510c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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, + /// Only used for better errors on `fn(): fn()` current_type_ascription: Vec, @@ -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(&self, mut ident: Ident, pred: P) -> Option 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(&mut self, self_def: Def, f: F) self.ribs[TypeNS].pop(); } + fn with_tuple_struct_self_ctor_rib(&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, @@ -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 diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d98e4574399..4d24abcf90e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -512,6 +512,9 @@ pub fn walk_feature_fields(&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 index 00000000000..7392003bb23 --- /dev/null +++ b/src/test/run-pass/tuple-struct-self-ctor.rs @@ -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 or the MIT license +// , 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); // With type parameter + +impl ST2 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) -> Option { + 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 index 00000000000..aa907e813ed --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.rs @@ -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 or the MIT license +// , 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 index 00000000000..e92924e9602 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-tuple-struct-self-ctor.stderr @@ -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`. diff --git a/src/test/ui/resolve/tuple-struct-alias.rs b/src/test/ui/resolve/tuple-struct-alias.rs index 0dbca07b771..1f3588dd3ca 100644 --- a/src/test/ui/resolve/tuple-struct-alias.rs +++ b/src/test/ui/resolve/tuple-struct-alias.rs @@ -11,15 +11,6 @@ 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 { diff --git a/src/test/ui/resolve/tuple-struct-alias.stderr b/src/test/ui/resolve/tuple-struct-alias.stderr index cdac6277bcf..ad2ae4acb8b 100644 --- a/src/test/ui/resolve/tuple-struct-alias.stderr +++ b/src/test/ui/resolve/tuple-struct-alias.stderr @@ -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`. -- 2.44.0