about summary refs log tree commit diff
path: root/src/libsyntax/feature_gate.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-12-24 07:34:13 +0000
committerbors <bors@rust-lang.org>2017-12-24 07:34:13 +0000
commit11a24d9c3940f60e527c571680d64e80e0889abe (patch)
treeac2db20e2e6e33adb63330a3cf50370530cf4960 /src/libsyntax/feature_gate.rs
parent51b47dc4a1af3260738aa7c5d4e31e8d77c0c0b6 (diff)
parentc026d19baf4b2ea96b218fd5d83275ae6e8220a1 (diff)
downloadrust-11a24d9c3940f60e527c571680d64e80e0889abe.tar.gz
rust-11a24d9c3940f60e527c571680d64e80e0889abe.zip
Auto merge of #46888 - cramertj:nested-impl-trait-error, r=nikomatsakis
Add a feature gate for nested uses of `impl Trait`

This allows us to delay stabilization of nested `impl Trait` until we have a plan to solve the problem posed [here](https://github.com/rust-lang/rust/issues/34511#issuecomment-350715858).

r? @nikomatsakis
Diffstat (limited to 'src/libsyntax/feature_gate.rs')
-rw-r--r--src/libsyntax/feature_gate.rs72
1 files changed, 70 insertions, 2 deletions
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 2d47382ac0f..f8d6b419f7a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -441,6 +441,9 @@ declare_features! (
 
     // `foo.rs` as an alternative to `foo/mod.rs`
     (active, non_modrs_mods, "1.24.0", Some(44660)),
+
+    // Nested `impl Trait`
+    (active, nested_impl_trait, "1.24.0", Some(34511)),
 );
 
 declare_features! (
@@ -1314,8 +1317,73 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool {
     }
 }
 
+// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
+// Nested `impl Trait` _is_ allowed in associated type position,
+// e.g `impl Iterator<Item=impl Debug>`
+struct NestedImplTraitVisitor<'a> {
+    context: &'a Context<'a>,
+    is_in_impl_trait: bool,
+}
+
+impl<'a> NestedImplTraitVisitor<'a> {
+    fn with_impl_trait<F>(&mut self, is_in_impl_trait: bool, f: F)
+        where F: FnOnce(&mut NestedImplTraitVisitor<'a>)
+    {
+        let old_is_in_impl_trait = self.is_in_impl_trait;
+        self.is_in_impl_trait = is_in_impl_trait;
+        f(self);
+        self.is_in_impl_trait = old_is_in_impl_trait;
+    }
+}
+
+
+impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
+    fn visit_ty(&mut self, t: &'a ast::Ty) {
+        if let ast::TyKind::ImplTrait(_) = t.node {
+            if self.is_in_impl_trait {
+                gate_feature_post!(&self, nested_impl_trait, t.span,
+                    "nested `impl Trait` is experimental"
+                );
+            }
+            self.with_impl_trait(true, |this| visit::walk_ty(this, t));
+        } else {
+            visit::walk_ty(self, t);
+        }
+    }
+    fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a ast::PathParameters) {
+        match *path_parameters {
+            ast::PathParameters::AngleBracketed(ref params) => {
+                for type_ in &params.types {
+                    self.visit_ty(type_);
+                }
+                for type_binding in &params.bindings {
+                    // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
+                    // are allowed to contain nested `impl Trait`.
+                    self.with_impl_trait(false, |this| visit::walk_ty(this, &type_binding.ty));
+                }
+            }
+            ast::PathParameters::Parenthesized(ref params) => {
+                for type_ in &params.inputs {
+                    self.visit_ty(type_);
+                }
+                if let Some(ref type_) = params.output {
+                    // `-> Foo` syntax is essentially an associated type binding,
+                    // so it is also allowed to contain nested `impl Trait`.
+                    self.with_impl_trait(false, |this| visit::walk_ty(this, type_));
+                }
+            }
+        }
+    }
+}
+
 impl<'a> PostExpansionVisitor<'a> {
-    fn whole_crate_feature_gates(&mut self) {
+    fn whole_crate_feature_gates(&mut self, krate: &ast::Crate) {
+        visit::walk_crate(
+            &mut NestedImplTraitVisitor {
+                context: self.context,
+                is_in_impl_trait: false,
+            }, krate);
+
         for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() {
             if !span.allows_unstable() {
                 let cx = &self.context;
@@ -1889,7 +1957,7 @@ pub fn check_crate(krate: &ast::Crate,
         plugin_attributes,
     };
     let visitor = &mut PostExpansionVisitor { context: &ctx };
-    visitor.whole_crate_feature_gates();
+    visitor.whole_crate_feature_gates(krate);
     visit::walk_crate(visitor, krate);
 }