about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-08-18 19:34:24 +0000
committerbors <bors@rust-lang.org>2018-08-18 19:34:24 +0000
commit33b923fd44c5c5925e635815fce68bdf1f98740f (patch)
treef10fd762a6fde5ed03bdc2b2ff9c9b9cda6382cd
parentf0341412ed4b7c39003f2bf409b183d7ce066814 (diff)
parent4e7d3f5a5eb9db95194cbb672f081c2ad9647674 (diff)
Auto merge of #53324 - alexreg:self_in_typedefs, r=eddyb
`Self` in type definitions (self_in_typedefs)

This implements the [`self_in_typedefs` feature](https://github.com/rust-lang/rfcs/blob/master/text/2300-self-in-typedefs.md) ([tracking issue 49303](https://github.com/rust-lang/rust/issues/49303)).

r? @eddyb

CC @Centril
-rw-r--r--src/doc/unstable-book/src/language-features/self-in-typedefs.md24
-rw-r--r--src/librustc_resolve/diagnostics.rs9
-rw-r--r--src/librustc_resolve/lib.rs54
-rw-r--r--src/libsyntax/feature_gate.rs36
-rw-r--r--src/test/run-pass/self-in-typedefs.rs40
-rw-r--r--src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs18
-rw-r--r--src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr9
7 files changed, 153 insertions, 37 deletions
diff --git a/src/doc/unstable-book/src/language-features/self-in-typedefs.md b/src/doc/unstable-book/src/language-features/self-in-typedefs.md
new file mode 100644
index 00000000000..2416e85c17d
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/self-in-typedefs.md
@@ -0,0 +1,24 @@
+# `self_in_typedefs`
+
+The tracking issue for this feature is: [#49303]
+
+[#49303]: https://github.com/rust-lang/rust/issues/49303
+
+------------------------
+
+The `self_in_typedefs` feature gate lets you use the special `Self` identifier
+in `struct`, `enum`, and `union` type definitions.
+
+A simple example is:
+
+```rust
+#![feature(self_in_typedefs)]
+
+enum List<T>
+where
+    Self: PartialOrd<Self> // can write `Self` instead of `List<T>`
+{
+    Nil,
+    Cons(T, Box<Self>) // likewise here
+}
+```
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 6593e239bc3..c1dc3041d7d 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -770,17 +770,18 @@ match x {
 "##,
 
 E0411: r##"
-The `Self` keyword was used outside an impl or a trait.
+The `Self` keyword was used outside an impl, trait, or type definition.
 
 Erroneous code example:
 
 ```compile_fail,E0411
-<Self>::foo; // error: use of `Self` outside of an impl or trait
+<Self>::foo; // error: use of `Self` outside of an impl, trait, or type
+             // definition
 ```
 
 The `Self` keyword represents the current type, which explains why it can only
-be used inside an impl or a trait. It gives access to the associated items of a
-type:
+be used inside an impl, trait, or type definition. It gives access to the
+associated items of a type:
 
 ```
 trait Foo {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index bc8ee2a8adb..b04dd07ba7d 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
-      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
-      html_root_url = "https://doc.rust-lang.org/nightly/")]
+       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+       html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![feature(crate_visibility_modifier)]
 #![cfg_attr(not(stage0), feature(nll))]
@@ -2175,14 +2175,26 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         debug!("(resolving item) resolving {}", name);
 
         match item.node {
-            ItemKind::Enum(_, ref generics) |
             ItemKind::Ty(_, ref generics) |
-            ItemKind::Existential(_, ref generics) |
-            ItemKind::Struct(_, ref generics) |
-            ItemKind::Union(_, ref generics) |
-            ItemKind::Fn(_, _, ref generics, _) => {
+            ItemKind::Fn(_, _, ref generics, _) |
+            ItemKind::Existential(_, ref generics) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
-                                         |this| visit::walk_item(this, item));
+                                             |this| visit::walk_item(this, item));
+            }
+
+            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);
+                    }
+                });
             }
 
             ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
@@ -2470,13 +2482,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                     let item_def_id = this.definitions.local_def_id(item_id);
                     this.with_self_rib(Def::SelfTy(trait_id, Some(item_def_id)), |this| {
                         if let Some(trait_ref) = opt_trait_reference.as_ref() {
-                            // Resolve type arguments in trait path
+                            // Resolve type arguments in the trait path.
                             visit::walk_trait_ref(this, trait_ref);
                         }
                         // Resolve the self type.
                         this.visit_ty(self_type);
                         // Resolve the type parameters.
                         this.visit_generics(generics);
+                        // Resolve the items within the impl.
                         this.with_current_self_type(self_type, |this| {
                             for impl_item in impl_items {
                                 this.resolve_visibility(&impl_item.vis);
@@ -2491,8 +2504,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                                             // If this is a trait impl, ensure the const
                                             // exists in trait
                                             this.check_trait_item(impl_item.ident,
-                                                                ValueNS,
-                                                                impl_item.span,
+                                                                  ValueNS,
+                                                                  impl_item.span,
                                                 |n, s| ConstNotMemberOfTrait(n, s));
                                             this.with_constant_rib(|this|
                                                 visit::walk_impl_item(this, impl_item)
@@ -2502,8 +2515,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                                             // If this is a trait impl, ensure the method
                                             // exists in trait
                                             this.check_trait_item(impl_item.ident,
-                                                                ValueNS,
-                                                                impl_item.span,
+                                                                  ValueNS,
+                                                                  impl_item.span,
                                                 |n, s| MethodNotMemberOfTrait(n, s));
 
                                             visit::walk_impl_item(this, impl_item);
@@ -2512,8 +2525,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                                             // If this is a trait impl, ensure the type
                                             // exists in trait
                                             this.check_trait_item(impl_item.ident,
-                                                                TypeNS,
-                                                                impl_item.span,
+                                                                  TypeNS,
+                                                                  impl_item.span,
                                                 |n, s| TypeNotMemberOfTrait(n, s));
 
                                             this.visit_ty(ty);
@@ -2522,8 +2535,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                                             // If this is a trait impl, ensure the type
                                             // exists in trait
                                             this.check_trait_item(impl_item.ident,
-                                                                TypeNS,
-                                                                impl_item.span,
+                                                                  TypeNS,
+                                                                  impl_item.span,
                                                 |n, s| TypeNotMemberOfTrait(n, s));
 
                                             for bound in bounds {
@@ -2948,7 +2961,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             if is_self_type(path, ns) {
                 __diagnostic_used!(E0411);
                 err.code(DiagnosticId::Error("E0411".into()));
-                err.span_label(span, "`Self` is only available in traits and impls");
+                let available_in = if this.session.features_untracked().self_in_typedefs {
+                    "impls, traits, and type definitions"
+                } else {
+                    "traits and impls"
+                };
+                err.span_label(span, format!("`Self` is only available in {}", available_in));
                 return (err, Vec::new());
             }
             if is_self_value(path, ns) {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index ed6321f6a45..3b9e1b3c265 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -127,7 +127,7 @@ declare_features! (
     (active, thread_local, "1.0.0", Some(29594), None),
     (active, trace_macros, "1.0.0", Some(29598), None),
 
-    // rustc internal, for now:
+    // rustc internal, for now
     (active, intrinsics, "1.0.0", None, None),
     (active, lang_items, "1.0.0", None, None),
     (active, format_args_nl, "1.29.0", None, None),
@@ -157,6 +157,7 @@ declare_features! (
     (active, optin_builtin_traits, "1.0.0", Some(13231), None),
 
     // Allows use of #[staged_api]
+    //
     // rustc internal
     (active, staged_api, "1.0.0", None, None),
 
@@ -234,24 +235,25 @@ declare_features! (
     // Allows associated type defaults
     (active, associated_type_defaults, "1.2.0", Some(29661), None),
 
-    // allow `repr(simd)`, and importing the various simd intrinsics
+    // Allows `repr(simd)`, and importing the various simd intrinsics
     (active, repr_simd, "1.4.0", Some(27731), None),
 
-    // allow `extern "platform-intrinsic" { ... }`
+    // Allows `extern "platform-intrinsic" { ... }`
     (active, platform_intrinsics, "1.4.0", Some(27731), None),
 
-    // allow `#[unwind(..)]`
+    // Allows `#[unwind(..)]`
     // rustc internal for rust runtime
     (active, unwind_attributes, "1.4.0", None, None),
 
-    // allow the use of `#[naked]` on functions.
+    // Allows the use of `#[naked]` on functions.
     (active, naked_functions, "1.9.0", Some(32408), None),
 
-    // allow `#[no_debug]`
+    // Allows `#[no_debug]`
     (active, no_debug, "1.5.0", Some(29721), None),
 
-    // allow `#[omit_gdb_pretty_printer_section]`
-    // rustc internal.
+    // Allows `#[omit_gdb_pretty_printer_section]`
+    //
+    // rustc internal
     (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
 
     // Allows cfg(target_vendor = "...").
@@ -281,10 +283,10 @@ declare_features! (
     // The `!` type. Does not imply exhaustive_patterns (below) any more.
     (active, never_type, "1.13.0", Some(35121), None),
 
-    // Allows exhaustive pattern matching on types that contain uninhabited types.
+    // Allows exhaustive pattern matching on types that contain uninhabited types
     (active, exhaustive_patterns, "1.13.0", Some(51085), None),
 
-    // Allows all literals in attribute lists and values of key-value pairs.
+    // Allows all literals in attribute lists and values of key-value pairs
     (active, attr_literals, "1.13.0", Some(34981), None),
 
     // Allows untagged unions `union U { ... }`
@@ -321,6 +323,7 @@ declare_features! (
     (active, sanitizer_runtime, "1.17.0", None, None),
 
     // Used to identify crates that contain the profiler runtime
+    //
     // rustc internal
     (active, profiler_runtime, "1.18.0", None, None),
 
@@ -378,7 +381,7 @@ declare_features! (
     // extern types
     (active, extern_types, "1.23.0", Some(43467), None),
 
-    // Allow trait methods with arbitrary self types
+    // Allows trait methods with arbitrary self types
     (active, arbitrary_self_types, "1.23.0", Some(44874), None),
 
     // `crate` in paths
@@ -387,7 +390,7 @@ declare_features! (
     // In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
     (active, in_band_lifetimes, "1.23.0", Some(44524), None),
 
-    // generic associated types (RFC 1598)
+    // Generic associated types (RFC 1598)
     (active, generic_associated_types, "1.23.0", Some(44265), None),
 
     // Resolve absolute paths as paths from other crates
@@ -462,7 +465,7 @@ declare_features! (
     // Scoped lints
     (active, tool_lints, "1.28.0", Some(44690), None),
 
-    // allow irrefutable patterns in if-let and while-let statements (RFC 2086)
+    // Allows irrefutable patterns in if-let and while-let statements (RFC 2086)
     (active, irrefutable_let_patterns, "1.27.0", Some(44495), None),
 
     // Allows use of the :literal macro fragment specifier (RFC 1576)
@@ -492,11 +495,14 @@ declare_features! (
     // impl Debug for Foo<'_>
     (active, impl_header_lifetime_elision, "1.30.0", Some(15872), Some(Edition::Edition2018)),
 
-    // Support for arbitrary delimited token streams in non-macro attributes.
+    // Support for arbitrary delimited token streams in non-macro attributes
     (active, unrestricted_attribute_tokens, "1.30.0", Some(44690), None),
 
-    // Allows `use x::y;` to resolve through `self::x`, not just `::x`.
+    // Allows `use x::y;` to resolve through `self::x`, not just `::x`
     (active, uniform_paths, "1.30.0", Some(53130), None),
+
+    // Allows `Self` in type definitions
+    (active, self_in_typedefs, "1.30.0", Some(49303), None),
 );
 
 declare_features! (
diff --git a/src/test/run-pass/self-in-typedefs.rs b/src/test/run-pass/self-in-typedefs.rs
new file mode 100644
index 00000000000..d262e8c60a1
--- /dev/null
+++ b/src/test/run-pass/self-in-typedefs.rs
@@ -0,0 +1,40 @@
+// 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(self_in_typedefs)]
+#![feature(untagged_unions)]
+
+#![allow(dead_code)]
+
+enum A<'a, T: 'a>
+where
+    Self: Send, T: PartialEq<Self>
+{
+    Foo(&'a Self),
+    Bar(T),
+}
+
+struct B<'a, T: 'a>
+where
+    Self: Send, T: PartialEq<Self>
+{
+    foo: &'a Self,
+    bar: T,
+}
+
+union C<'a, T: 'a>
+where
+    Self: Send, T: PartialEq<Self>
+{
+    foo: &'a Self,
+    bar: T,
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs b/src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs
new file mode 100644
index 00000000000..4b476a0a645
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs
@@ -0,0 +1,18 @@
+// 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.
+
+enum StackList<'a, T: 'a> {
+    Nil,
+    Cons(T, &'a Self)
+    //~^ ERROR cannot find type `Self` in this scope
+    //~| `Self` is only available in traits and impls
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr b/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr
new file mode 100644
index 00000000000..c3f9abd90a7
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr
@@ -0,0 +1,9 @@
+error[E0411]: cannot find type `Self` in this scope
+  --> $DIR/feature-gate-self-in-typedefs.rs:13:17
+   |
+LL |     Cons(T, &'a Self)
+   |                 ^^^^ `Self` is only available in traits and impls
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0411`.