From 378bd4967c4f1c5fac87515b052435fa7554eecc Mon Sep 17 00:00:00 2001
From: Shotaro Yamada <sinkuu@sinkuu.xyz>
Date: Tue, 10 Apr 2018 11:04:32 +0900
Subject: [PATCH] Disallow `impl Trait` in unsupported position

---
 src/librustc/hir/lowering.rs         | 53 +++++++++++++++++++---------
 src/test/compile-fail/issue-47715.rs | 38 ++++++++++++++++++++
 2 files changed, 74 insertions(+), 17 deletions(-)
 create mode 100644 src/test/compile-fail/issue-47715.rs

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index b13c289394a7b..a0931dcad786e 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -780,8 +780,9 @@ impl<'a> LoweringContext<'a> {
                 _ => None,
             }),
             |this| {
+                let itctx = ImplTraitContext::Universal(parent_id);
                 this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
-                    (this.lower_generics(generics), f(this))
+                    (this.lower_generics(generics, itctx), f(this))
                 })
             },
         );
@@ -1043,7 +1044,11 @@ impl<'a> LoweringContext<'a> {
                 }),
                 |this| {
                     hir::TyBareFn(P(hir::BareFnTy {
-                        generic_params: this.lower_generic_params(&f.generic_params, &NodeMap()),
+                        generic_params: this.lower_generic_params(
+                            &f.generic_params,
+                            &NodeMap(),
+                            ImplTraitContext::Disallowed,
+                        ),
                         unsafety: this.lower_unsafety(f.unsafety),
                         abi: f.abi,
                         decl: this.lower_fn_decl(&f.decl, None, false),
@@ -1784,7 +1789,12 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_ty_param(&mut self, tp: &TyParam, add_bounds: &[TyParamBound]) -> hir::TyParam {
+    fn lower_ty_param(
+        &mut self,
+        tp: &TyParam,
+        add_bounds: &[TyParamBound],
+        itctx: ImplTraitContext,
+    ) -> hir::TyParam {
         let mut name = self.lower_ident(tp.ident);
 
         // Don't expose `Self` (recovered "keyword used as ident" parse error).
@@ -1794,7 +1804,6 @@ impl<'a> LoweringContext<'a> {
             name = Symbol::gensym("Self");
         }
 
-        let itctx = ImplTraitContext::Universal(self.resolver.definitions().local_def_id(tp.id));
         let mut bounds = self.lower_bounds(&tp.bounds, itctx);
         if !add_bounds.is_empty() {
             bounds = bounds
@@ -1879,6 +1888,7 @@ impl<'a> LoweringContext<'a> {
         &mut self,
         params: &Vec<GenericParam>,
         add_bounds: &NodeMap<Vec<TyParamBound>>,
+        itctx: ImplTraitContext,
     ) -> hir::HirVec<hir::GenericParam> {
         params
             .iter()
@@ -1889,12 +1899,13 @@ impl<'a> LoweringContext<'a> {
                 GenericParam::Type(ref ty_param) => hir::GenericParam::Type(self.lower_ty_param(
                     ty_param,
                     add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x),
+                    itctx,
                 )),
             })
             .collect()
     }
 
-    fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
+    fn lower_generics(&mut self, g: &Generics, itctx: ImplTraitContext) -> hir::Generics {
         // Collect `?Trait` bounds in where clause and move them to parameter definitions.
         // FIXME: This could probably be done with less rightward drift. Also looks like two control
         //        paths where report_error is called are also the only paths that advance to after
@@ -1947,7 +1958,7 @@ impl<'a> LoweringContext<'a> {
         }
 
         hir::Generics {
-            params: self.lower_generic_params(&g.params, &add_bounds),
+            params: self.lower_generic_params(&g.params, &add_bounds, itctx),
             where_clause: self.lower_where_clause(&g.where_clause),
             span: g.span,
         }
@@ -1981,6 +1992,7 @@ impl<'a> LoweringContext<'a> {
                             bound_generic_params: this.lower_generic_params(
                                 bound_generic_params,
                                 &NodeMap(),
+                                ImplTraitContext::Disallowed,
                             ),
                             bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
                             bounds: bounds
@@ -2064,7 +2076,8 @@ impl<'a> LoweringContext<'a> {
         p: &PolyTraitRef,
         itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef {
-        let bound_generic_params = self.lower_generic_params(&p.bound_generic_params, &NodeMap());
+        let bound_generic_params =
+            self.lower_generic_params(&p.bound_generic_params, &NodeMap(), itctx);
         let trait_ref = self.with_parent_impl_lifetime_defs(
             &bound_generic_params
                 .iter()
@@ -2216,7 +2229,7 @@ impl<'a> LoweringContext<'a> {
             ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)),
             ItemKind::Ty(ref t, ref generics) => hir::ItemTy(
                 self.lower_ty(t, ImplTraitContext::Disallowed),
-                self.lower_generics(generics),
+                self.lower_generics(generics, ImplTraitContext::Disallowed),
             ),
             ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemEnum(
                 hir::EnumDef {
@@ -2226,15 +2239,21 @@ impl<'a> LoweringContext<'a> {
                         .map(|x| self.lower_variant(x))
                         .collect(),
                 },
-                self.lower_generics(generics),
+                self.lower_generics(generics, ImplTraitContext::Disallowed),
             ),
             ItemKind::Struct(ref struct_def, ref generics) => {
                 let struct_def = self.lower_variant_data(struct_def);
-                hir::ItemStruct(struct_def, self.lower_generics(generics))
+                hir::ItemStruct(
+                    struct_def,
+                    self.lower_generics(generics, ImplTraitContext::Disallowed),
+                )
             }
             ItemKind::Union(ref vdata, ref generics) => {
                 let vdata = self.lower_variant_data(vdata);
-                hir::ItemUnion(vdata, self.lower_generics(generics))
+                hir::ItemUnion(
+                    vdata,
+                    self.lower_generics(generics, ImplTraitContext::Disallowed),
+                )
             }
             ItemKind::Impl(
                 unsafety,
@@ -2313,13 +2332,13 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemTrait(
                     self.lower_is_auto(is_auto),
                     self.lower_unsafety(unsafety),
-                    self.lower_generics(generics),
+                    self.lower_generics(generics, ImplTraitContext::Disallowed),
                     bounds,
                     items,
                 )
             }
             ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemTraitAlias(
-                self.lower_generics(generics),
+                self.lower_generics(generics, ImplTraitContext::Disallowed),
                 self.lower_bounds(bounds, ImplTraitContext::Disallowed),
             ),
             ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
@@ -2454,7 +2473,7 @@ impl<'a> LoweringContext<'a> {
 
             let (generics, node) = match i.node {
                 TraitItemKind::Const(ref ty, ref default) => (
-                    this.lower_generics(&i.generics),
+                    this.lower_generics(&i.generics, ImplTraitContext::Disallowed),
                     hir::TraitItemKind::Const(
                         this.lower_ty(ty, ImplTraitContext::Disallowed),
                         default
@@ -2495,7 +2514,7 @@ impl<'a> LoweringContext<'a> {
                     )
                 }
                 TraitItemKind::Type(ref bounds, ref default) => (
-                    this.lower_generics(&i.generics),
+                    this.lower_generics(&i.generics, ImplTraitContext::Disallowed),
                     hir::TraitItemKind::Type(
                         this.lower_bounds(bounds, ImplTraitContext::Disallowed),
                         default
@@ -2552,7 +2571,7 @@ impl<'a> LoweringContext<'a> {
                 ImplItemKind::Const(ref ty, ref expr) => {
                     let body_id = this.lower_body(None, |this| this.lower_expr(expr));
                     (
-                        this.lower_generics(&i.generics),
+                        this.lower_generics(&i.generics, ImplTraitContext::Disallowed),
                         hir::ImplItemKind::Const(
                             this.lower_ty(ty, ImplTraitContext::Disallowed),
                             body_id,
@@ -2583,7 +2602,7 @@ impl<'a> LoweringContext<'a> {
                     )
                 }
                 ImplItemKind::Type(ref ty) => (
-                    this.lower_generics(&i.generics),
+                    this.lower_generics(&i.generics, ImplTraitContext::Disallowed),
                     hir::ImplItemKind::Type(this.lower_ty(ty, ImplTraitContext::Disallowed)),
                 ),
                 ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
diff --git a/src/test/compile-fail/issue-47715.rs b/src/test/compile-fail/issue-47715.rs
new file mode 100644
index 0000000000000..b6b720f088aee
--- /dev/null
+++ b/src/test/compile-fail/issue-47715.rs
@@ -0,0 +1,38 @@
+// 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.
+
+trait Foo {}
+
+trait Bar<T> {}
+
+trait Iterable {
+    type Item;
+}
+
+struct Container<T: Iterable<Item = impl Foo>> {
+    //~^ ERROR `impl Trait` not allowed
+    field: T
+}
+
+enum Enum<T: Iterable<Item = impl Foo>> {
+    //~^ ERROR `impl Trait` not allowed
+    A(T),
+}
+
+union Union<T: Iterable<Item = impl Foo> + Copy> {
+    //~^ ERROR `impl Trait` not allowed
+    x: T,
+}
+
+type Type<T: Iterable<Item = impl Foo>> = T;
+//~^ ERROR `impl Trait` not allowed
+
+fn main() {
+}