about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/intravisit.rs5
-rw-r--r--src/librustc/hir/lowering.rs262
-rw-r--r--src/librustc/hir/mod.rs9
-rw-r--r--src/librustc/hir/print.rs3
-rw-r--r--src/librustc/ich/impls_hir.rs3
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_privacy/lib.rs4
-rw-r--r--src/librustc_typeck/astconv.rs57
-rw-r--r--src/librustc_typeck/collect.rs8
-rw-r--r--src/librustdoc/clean/mod.rs4
11 files changed, 211 insertions, 148 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index c23a5fb1f7e..84be68cb197 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -591,7 +591,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             }
             visitor.visit_lifetime(lifetime);
         }
-        TyImplTrait(ref bounds) => {
+        TyImplTraitExistential(ref bounds) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        TyImplTraitUniversal(_, ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
         TyTypeof(expression) => {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index ba89961adc6..2fab130895c 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -123,6 +123,24 @@ pub trait Resolver {
     fn definitions(&mut self) -> &mut Definitions;
 }
 
+#[derive(Clone, Copy, Debug)]
+enum ImplTraitContext {
+    /// Treat `impl Trait` as shorthand for a new universal generic parameter.
+    /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
+    /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
+    ///
+    /// We store a DefId here so we can look up necessary information later
+    Universal(DefId),
+
+    /// Treat `impl Trait` as shorthand for a new universal existential parameter.
+    /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
+    /// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
+    Existential,
+
+    /// `impl Trait` is not accepted in this position.
+    Disallowed,
+}
+
 pub fn lower_crate(sess: &Session,
                    cstore: &CrateStore,
                    dep_graph: &DepGraph,
@@ -644,48 +662,48 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding {
+    fn lower_ty_binding(&mut self, b: &TypeBinding, itctx: ImplTraitContext) -> hir::TypeBinding {
         hir::TypeBinding {
             id: self.lower_node_id(b.id).node_id,
             name: self.lower_ident(b.ident),
-            ty: self.lower_ty(&b.ty),
+            ty: self.lower_ty(&b.ty, itctx),
             span: b.span,
         }
     }
 
-    fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
+    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
         let kind = match t.node {
             TyKind::Infer => hir::TyInfer,
             TyKind::Err => hir::TyErr,
-            TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
-            TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
+            TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty, itctx)),
+            TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt, itctx)),
             TyKind::Rptr(ref region, ref mt) => {
                 let span = t.span.with_hi(t.span.lo());
                 let lifetime = match *region {
                     Some(ref lt) => self.lower_lifetime(lt),
                     None => self.elided_lifetime(span)
                 };
-                hir::TyRptr(lifetime, self.lower_mt(mt))
+                hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
                 hir::TyBareFn(P(hir::BareFnTy {
                     lifetimes: self.lower_lifetime_defs(&f.lifetimes),
                     unsafety: self.lower_unsafety(f.unsafety),
                     abi: f.abi,
-                    decl: self.lower_fn_decl(&f.decl),
+                    decl: self.lower_fn_decl(&f.decl, None, false),
                     arg_names: self.lower_fn_args_to_names(&f.decl),
                 }))
             }
             TyKind::Never => hir::TyNever,
             TyKind::Tup(ref tys) => {
-                hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect())
+                hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty, itctx)).collect())
             }
             TyKind::Paren(ref ty) => {
-                return self.lower_ty(ty);
+                return self.lower_ty(ty, itctx);
             }
             TyKind::Path(ref qself, ref path) => {
                 let id = self.lower_node_id(t.id);
-                let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit);
+                let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
                 return self.ty_path(id, t.span, qpath);
             }
             TyKind::ImplicitSelf => {
@@ -699,7 +717,7 @@ impl<'a> LoweringContext<'a> {
             }
             TyKind::Array(ref ty, ref length) => {
                 let length = self.lower_body(None, |this| this.lower_expr(length));
-                hir::TyArray(self.lower_ty(ty), length)
+                hir::TyArray(self.lower_ty(ty, itctx), length)
             }
             TyKind::Typeof(ref expr) => {
                 let expr = self.lower_body(None, |this| this.lower_expr(expr));
@@ -710,7 +728,7 @@ impl<'a> LoweringContext<'a> {
                 let bounds = bounds.iter().filter_map(|bound| {
                     match *bound {
                         TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
-                            Some(self.lower_poly_trait_ref(ty))
+                            Some(self.lower_poly_trait_ref(ty, itctx))
                         }
                         TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
                         RegionTyParamBound(ref lifetime) => {
@@ -727,7 +745,21 @@ impl<'a> LoweringContext<'a> {
                 hir::TyTraitObject(bounds, lifetime_bound)
             }
             TyKind::ImplTrait(ref bounds) => {
-                hir::TyImplTrait(self.lower_bounds(bounds))
+                use syntax::feature_gate::{emit_feature_err, GateIssue};
+                match itctx {
+                    ImplTraitContext::Existential => {
+                        hir::TyImplTraitExistential(self.lower_bounds(bounds, itctx))
+                    },
+                    ImplTraitContext::Universal(def_id) => {
+                        hir::TyImplTraitUniversal(def_id, self.lower_bounds(bounds, itctx))
+                    },
+                    ImplTraitContext::Disallowed => {
+                        span_err!(self.sess, t.span, E0562,
+                                  "`impl Trait` not allowed outside of function \
+                                  and inherent method return types");
+                        hir::TyErr
+                    }
+                }
             }
             TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
         };
@@ -773,10 +805,11 @@ impl<'a> LoweringContext<'a> {
                    id: NodeId,
                    qself: &Option<QSelf>,
                    p: &Path,
-                   param_mode: ParamMode)
+                   param_mode: ParamMode,
+                   itctx: ImplTraitContext)
                    -> hir::QPath {
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty));
+        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
 
         let resolution = self.resolver.get_resolution(id)
                                       .unwrap_or(PathResolution::new(Def::Err));
@@ -846,7 +879,7 @@ impl<'a> LoweringContext<'a> {
                     n
                 });
                 self.lower_path_segment(p.span, segment, param_mode, num_lifetimes,
-                                        parenthesized_generic_args)
+                                        parenthesized_generic_args, itctx)
             }).collect(),
             span: p.span,
         });
@@ -882,7 +915,8 @@ impl<'a> LoweringContext<'a> {
         // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
         for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
             let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0,
-                                                    ParenthesizedGenericArgs::Warn));
+                                                    ParenthesizedGenericArgs::Warn,
+                                                    itctx));
             let qpath = hir::QPath::TypeRelative(ty, segment);
 
             // It's finished, return the extension of the right node type.
@@ -916,7 +950,8 @@ impl<'a> LoweringContext<'a> {
             def: self.expect_full_def(id),
             segments: segments.map(|segment| {
                 self.lower_path_segment(p.span, segment, param_mode, 0,
-                                        ParenthesizedGenericArgs::Err)
+                                        ParenthesizedGenericArgs::Err,
+                                        ImplTraitContext::Disallowed)
             }).chain(name.map(|name| hir::PathSegment::from_name(name)))
               .collect(),
             span: p.span,
@@ -937,16 +972,18 @@ impl<'a> LoweringContext<'a> {
                           segment: &PathSegment,
                           param_mode: ParamMode,
                           expected_lifetimes: usize,
-                          parenthesized_generic_args: ParenthesizedGenericArgs)
+                          parenthesized_generic_args: ParenthesizedGenericArgs,
+                          itctx: ImplTraitContext)
                           -> hir::PathSegment {
         let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters {
             let msg = "parenthesized parameters may only be used with a trait";
             match **parameters {
                 PathParameters::AngleBracketed(ref data) => {
-                    self.lower_angle_bracketed_parameter_data(data, param_mode)
+                    self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
                 PathParameters::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+                    ParenthesizedGenericArgs::Ok =>
+                        self.lower_parenthesized_parameter_data(data, itctx),
                     ParenthesizedGenericArgs::Warn => {
                         self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
                                               CRATE_NODE_ID, data.span, msg.into());
@@ -960,7 +997,7 @@ impl<'a> LoweringContext<'a> {
                 }
             }
         } else {
-            self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode)
+            self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
         };
 
         if !parameters.parenthesized && parameters.lifetimes.is_empty() {
@@ -978,22 +1015,25 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_angle_bracketed_parameter_data(&mut self,
                                             data: &AngleBracketedParameterData,
-                                            param_mode: ParamMode)
+                                            param_mode: ParamMode,
+                                            itctx: ImplTraitContext)
                                             -> (hir::PathParameters, bool) {
         let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data;
         (hir::PathParameters {
             lifetimes: self.lower_lifetimes(lifetimes),
-            types: types.iter().map(|ty| self.lower_ty(ty)).collect(),
-            bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(),
+            types: types.iter().map(|ty| self.lower_ty(ty, itctx)).collect(),
+            bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx)).collect(),
             parenthesized: false,
         }, types.is_empty() && param_mode == ParamMode::Optional)
     }
 
     fn lower_parenthesized_parameter_data(&mut self,
-                                          data: &ParenthesizedParameterData)
+                                          data: &ParenthesizedParameterData,
+                                          itctx: ImplTraitContext)
                                           -> (hir::PathParameters, bool) {
+        const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed;
         let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
-        let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect();
+        let inputs = inputs.iter().map(|ty| self.lower_ty(ty, DISALLOWED)).collect();
         let mk_tup = |this: &mut Self, tys, span| {
             let LoweredNodeId { node_id, hir_id } = this.next_id();
             P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
@@ -1005,7 +1045,7 @@ impl<'a> LoweringContext<'a> {
             bindings: hir_vec![hir::TypeBinding {
                 id: self.next_id().node_id,
                 name: Symbol::intern(FN_OUTPUT_NAME),
-                ty: output.as_ref().map(|ty| self.lower_ty(&ty))
+                ty: output.as_ref().map(|ty| self.lower_ty(&ty, itctx))
                                    .unwrap_or_else(|| mk_tup(self, hir::HirVec::new(), span)),
                 span: output.as_ref().map_or(span, |ty| ty.span),
             }],
@@ -1018,7 +1058,7 @@ impl<'a> LoweringContext<'a> {
         P(hir::Local {
             id: node_id,
             hir_id,
-            ty: l.ty.as_ref().map(|t| self.lower_ty(t)),
+            ty: l.ty.as_ref().map(|t| self.lower_ty(t, ImplTraitContext::Disallowed)),
             pat: self.lower_pat(&l.pat),
             init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
             span: l.span,
@@ -1055,11 +1095,24 @@ impl<'a> LoweringContext<'a> {
         }).collect()
     }
 
-    fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
+    fn lower_fn_decl(&mut self,
+                     decl: &FnDecl,
+                     fn_def_id: Option<DefId>,
+                     impl_trait_return_allow: bool)
+                     -> P<hir::FnDecl> {
         P(hir::FnDecl {
-            inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
+            inputs: decl.inputs.iter()
+                .map(|arg| if let Some(def_id) = fn_def_id {
+                    self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
+                } else {
+                    self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
+                }).collect(),
             output: match decl.output {
-                FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
+                FunctionRetTy::Ty(ref ty) => match (impl_trait_return_allow, fn_def_id) {
+                    (false, _) => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
+                    (_, Some(_)) => hir::Return(self.lower_ty(ty, ImplTraitContext::Existential)),
+                    _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
+                },
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
             },
             variadic: decl.variadic,
@@ -1073,10 +1126,11 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn lower_ty_param_bound(&mut self, tpb: &TyParamBound) -> hir::TyParamBound {
+    fn lower_ty_param_bound(&mut self, tpb: &TyParamBound, itctx: ImplTraitContext)
+                            -> hir::TyParamBound {
         match *tpb {
             TraitTyParamBound(ref ty, modifier) => {
-                hir::TraitTyParamBound(self.lower_poly_trait_ref(ty),
+                hir::TraitTyParamBound(self.lower_poly_trait_ref(ty, itctx),
                                        self.lower_trait_bound_modifier(modifier))
             }
             RegionTyParamBound(ref lifetime) => {
@@ -1095,16 +1149,19 @@ impl<'a> LoweringContext<'a> {
             name = Symbol::gensym("Self");
         }
 
-        let mut bounds = self.lower_bounds(&tp.bounds);
+        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.into_iter().chain(self.lower_bounds(add_bounds).into_iter()).collect();
+            bounds = bounds.into_iter().chain(
+                self.lower_bounds(add_bounds, itctx).into_iter()
+            ).collect();
         }
 
         hir::TyParam {
             id: self.lower_node_id(tp.id).node_id,
             name,
             bounds,
-            default: tp.default.as_ref().map(|x| self.lower_ty(x)),
+            default: tp.default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
             span: tp.span,
             pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
             synthetic: tp.attrs.iter()
@@ -1215,11 +1272,11 @@ impl<'a> LoweringContext<'a> {
                                                                 span}) => {
                 hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                     bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes),
-                    bounded_ty: self.lower_ty(bounded_ty),
+                    bounded_ty: self.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
                     bounds: bounds.iter().filter_map(|bound| match *bound {
                         // Ignore `?Trait` bounds, they were copied into type parameters already.
                         TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
-                        _ => Some(self.lower_ty_param_bound(bound))
+                        _ => Some(self.lower_ty_param_bound(bound, ImplTraitContext::Disallowed))
                     }).collect(),
                     span,
                 })
@@ -1239,8 +1296,8 @@ impl<'a> LoweringContext<'a> {
                                                           span}) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     id: self.lower_node_id(id).node_id,
-                    lhs_ty: self.lower_ty(lhs_ty),
-                    rhs_ty: self.lower_ty(rhs_ty),
+                    lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::Disallowed),
+                    rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::Disallowed),
                     span,
                 })
             }
@@ -1267,8 +1324,8 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
-        let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) {
+    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef {
+        let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path.and_then(|path| path),
             qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath)
         };
@@ -1278,10 +1335,13 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_poly_trait_ref(&mut self, p: &PolyTraitRef) -> hir::PolyTraitRef {
+    fn lower_poly_trait_ref(&mut self,
+                            p: &PolyTraitRef,
+                            itctx: ImplTraitContext)
+                            -> hir::PolyTraitRef {
         hir::PolyTraitRef {
             bound_lifetimes: self.lower_lifetime_defs(&p.bound_lifetimes),
-            trait_ref: self.lower_trait_ref(&p.trait_ref),
+            trait_ref: self.lower_trait_ref(&p.trait_ref, itctx),
             span: p.span,
         }
     }
@@ -1296,7 +1356,7 @@ impl<'a> LoweringContext<'a> {
                 None => Ident { name: Symbol::intern(&index.to_string()), ctxt: f.span.ctxt() },
             }),
             vis: self.lower_visibility(&f.vis, None),
-            ty: self.lower_ty(&f.ty),
+            ty: self.lower_ty(&f.ty, ImplTraitContext::Disallowed),
             attrs: self.lower_attrs(&f.attrs),
         }
     }
@@ -1310,15 +1370,16 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_mt(&mut self, mt: &MutTy) -> hir::MutTy {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy {
         hir::MutTy {
-            ty: self.lower_ty(&mt.ty),
+            ty: self.lower_ty(&mt.ty, itctx),
             mutbl: self.lower_mutability(mt.mutbl),
         }
     }
 
-    fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds {
-        bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect()
+    fn lower_bounds(&mut self, bounds: &[TyParamBound], itctx: ImplTraitContext)
+                    -> hir::TyParamBounds {
+        bounds.iter().map(|bound| self.lower_ty_param_bound(bound, itctx)).collect()
     }
 
     fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
@@ -1437,33 +1498,35 @@ impl<'a> LoweringContext<'a> {
             }
             ItemKind::Static(ref t, m, ref e) => {
                 let value = self.lower_body(None, |this| this.lower_expr(e));
-                hir::ItemStatic(self.lower_ty(t),
+                hir::ItemStatic(self.lower_ty(t, ImplTraitContext::Disallowed),
                                 self.lower_mutability(m),
                                 value)
             }
             ItemKind::Const(ref t, ref e) => {
                 let value = self.lower_body(None, |this| this.lower_expr(e));
-                hir::ItemConst(self.lower_ty(t), value)
+                hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value)
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
+                let fn_def_id = self.resolver.definitions().opt_local_def_id(id);
                 self.with_new_scopes(|this| {
                     let body_id = this.lower_body(Some(decl), |this| {
                         let body = this.lower_block(body, false);
                         this.expr_block(body, ThinVec::new())
                     });
-                    hir::ItemFn(this.lower_fn_decl(decl),
-                                              this.lower_unsafety(unsafety),
-                                              this.lower_constness(constness),
-                                              abi,
-                                              this.lower_generics(generics),
-                                              body_id)
+                    hir::ItemFn(this.lower_fn_decl(decl, fn_def_id, true),
+                                this.lower_unsafety(unsafety),
+                                this.lower_constness(constness),
+                                abi,
+                                this.lower_generics(generics),
+                                body_id)
                 })
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
             ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)),
             ItemKind::Ty(ref t, ref generics) => {
-                hir::ItemTy(self.lower_ty(t), self.lower_generics(generics))
+                hir::ItemTy(self.lower_ty(t, ImplTraitContext::Disallowed),
+                            self.lower_generics(generics))
             }
             ItemKind::Enum(ref enum_definition, ref generics) => {
                 hir::ItemEnum(hir::EnumDef {
@@ -1483,7 +1546,7 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemUnion(vdata, self.lower_generics(generics))
             }
             ItemKind::AutoImpl(unsafety, ref trait_ref) => {
-                let trait_ref = self.lower_trait_ref(trait_ref);
+                let trait_ref = self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed);
 
                 if let Def::Trait(def_id) = trait_ref.path.def {
                     self.trait_auto_impl.insert(def_id, id);
@@ -1502,7 +1565,9 @@ impl<'a> LoweringContext<'a> {
                 let new_impl_items = impl_items.iter()
                                                .map(|item| self.lower_impl_item_ref(item))
                                                .collect();
-                let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
+                let ifce = ifce.as_ref().map(|trait_ref| {
+                    self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
+                });
 
                 if let Some(ref trait_ref) = ifce {
                     if let Def::Trait(def_id) = trait_ref.path.def {
@@ -1515,11 +1580,11 @@ impl<'a> LoweringContext<'a> {
                               self.lower_defaultness(defaultness, true /* [1] */),
                               self.lower_generics(generics),
                               ifce,
-                              self.lower_ty(ty),
+                              self.lower_ty(ty, ImplTraitContext::Disallowed),
                               new_impl_items)
             }
             ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
-                let bounds = self.lower_bounds(bounds);
+                let bounds = self.lower_bounds(bounds, ImplTraitContext::Disallowed);
                 let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
                 hir::ItemTrait(self.lower_is_auto(is_auto),
                                self.lower_unsafety(unsafety),
@@ -1537,6 +1602,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
         self.with_parent_def(i.id, |this| {
             let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id);
+            let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id);
 
             hir::TraitItem {
                 id: node_id,
@@ -1546,14 +1612,14 @@ impl<'a> LoweringContext<'a> {
                 generics: this.lower_generics(&i.generics),
                 node: match i.node {
                     TraitItemKind::Const(ref ty, ref default) => {
-                        hir::TraitItemKind::Const(this.lower_ty(ty),
+                        hir::TraitItemKind::Const(this.lower_ty(ty, ImplTraitContext::Disallowed),
                                                   default.as_ref().map(|x| {
                             this.lower_body(None, |this| this.lower_expr(x))
                         }))
                     }
                     TraitItemKind::Method(ref sig, None) => {
                         let names = this.lower_fn_args_to_names(&sig.decl);
-                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false),
                                                    hir::TraitMethod::Required(names))
                     }
                     TraitItemKind::Method(ref sig, Some(ref body)) => {
@@ -1561,12 +1627,15 @@ impl<'a> LoweringContext<'a> {
                             let body = this.lower_block(body, false);
                             this.expr_block(body, ThinVec::new())
                         });
-                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false),
                                                    hir::TraitMethod::Provided(body_id))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
-                        hir::TraitItemKind::Type(this.lower_bounds(bounds),
-                                                 default.as_ref().map(|x| this.lower_ty(x)))
+                        hir::TraitItemKind::Type(this.lower_bounds(bounds,
+                                                                   ImplTraitContext::Disallowed),
+                                                 default.as_ref().map(|x| {
+                                                     this.lower_ty(x, ImplTraitContext::Disallowed)
+                                                 }))
                     }
                     TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
                 },
@@ -1602,6 +1671,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
         self.with_parent_def(i.id, |this| {
             let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id);
+            let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id);
 
             hir::ImplItem {
                 id: node_id,
@@ -1614,16 +1684,23 @@ impl<'a> LoweringContext<'a> {
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
                         let body_id = this.lower_body(None, |this| this.lower_expr(expr));
-                        hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
+                        hir::ImplItemKind::Const(
+                            this.lower_ty(ty, ImplTraitContext::Disallowed),
+                            body_id
+                        )
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body_id = this.lower_body(Some(&sig.decl), |this| {
                             let body = this.lower_block(body, false);
                             this.expr_block(body, ThinVec::new())
                         });
-                        hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
+                        let impl_trait_return_allow = !this.is_in_trait_impl;
+                        hir::ImplItemKind::Method(this.lower_method_sig(sig, fn_def_id,
+                                                                        impl_trait_return_allow),
+                                                  body_id)
                     }
-                    ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
+                    ImplItemKind::Type(ref ty) =>
+                        hir::ImplItemKind::Type(this.lower_ty(ty, ImplTraitContext::Disallowed)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
                 },
                 span: i.span,
@@ -1643,8 +1720,10 @@ impl<'a> LoweringContext<'a> {
             kind: match i.node {
                 ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
                 ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
-                ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
-                    has_self: sig.decl.has_self(),
+                ImplItemKind::Method(ref sig, _) => {
+                    hir::AssociatedItemKind::Method {
+                        has_self: sig.decl.has_self(),
+                    }
                 },
                 ImplItemKind::Macro(..) => unimplemented!(),
             },
@@ -1719,12 +1798,13 @@ impl<'a> LoweringContext<'a> {
                 attrs: this.lower_attrs(&i.attrs),
                 node: match i.node {
                     ForeignItemKind::Fn(ref fdec, ref generics) => {
-                        hir::ForeignItemFn(this.lower_fn_decl(fdec),
+                        let fn_def_id = this.resolver.definitions().opt_local_def_id(i.id);
+                        hir::ForeignItemFn(this.lower_fn_decl(fdec, fn_def_id, true),
                                            this.lower_fn_args_to_names(fdec),
                                            this.lower_generics(generics))
                     }
                     ForeignItemKind::Static(ref t, m) => {
-                        hir::ForeignItemStatic(this.lower_ty(t), m)
+                        hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)
                     }
                     ForeignItemKind::Ty => {
                         hir::ForeignItemType
@@ -1736,12 +1816,16 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
+    fn lower_method_sig(&mut self,
+                        sig: &MethodSig,
+                        fn_def_id: Option<DefId>,
+                        impl_trait_return_allow: bool)
+                        -> hir::MethodSig {
         hir::MethodSig {
             abi: sig.abi,
             unsafety: self.lower_unsafety(sig.unsafety),
             constness: self.lower_constness(sig.constness),
-            decl: self.lower_fn_decl(&sig.decl),
+            decl: self.lower_fn_decl(&sig.decl, fn_def_id, impl_trait_return_allow),
         }
     }
 
@@ -1834,16 +1918,19 @@ impl<'a> LoweringContext<'a> {
                 }
                 PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
                 PatKind::TupleStruct(ref path, ref pats, ddpos) => {
-                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional);
+                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
+                                                 ImplTraitContext::Disallowed);
                     hir::PatKind::TupleStruct(qpath,
                                               pats.iter().map(|x| self.lower_pat(x)).collect(),
                                               ddpos)
                 }
                 PatKind::Path(ref qself, ref path) => {
-                    hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional))
+                    hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
+                                                        ImplTraitContext::Disallowed))
                 }
                 PatKind::Struct(ref path, ref fields, etc) => {
-                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional);
+                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
+                                                 ImplTraitContext::Disallowed);
 
                     let fs = fields.iter()
                                    .map(|f| {
@@ -2020,7 +2107,8 @@ impl<'a> LoweringContext<'a> {
             }
             ExprKind::MethodCall(ref seg, ref args) => {
                 let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0,
-                                                      ParenthesizedGenericArgs::Err);
+                                                      ParenthesizedGenericArgs::Err,
+                                                      ImplTraitContext::Disallowed);
                 let args = args.iter().map(|x| self.lower_expr(x)).collect();
                 hir::ExprMethodCall(hir_seg, seg.span, args)
             }
@@ -2038,11 +2126,11 @@ impl<'a> LoweringContext<'a> {
             ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())),
             ExprKind::Cast(ref expr, ref ty) => {
                 let expr = P(self.lower_expr(expr));
-                hir::ExprCast(expr, self.lower_ty(ty))
+                hir::ExprCast(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
             }
             ExprKind::Type(ref expr, ref ty) => {
                 let expr = P(self.lower_expr(expr));
-                hir::ExprType(expr, self.lower_ty(ty))
+                hir::ExprType(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
             }
             ExprKind::AddrOf(m, ref ohs) => {
                 let m = self.lower_mutability(m);
@@ -2119,7 +2207,7 @@ impl<'a> LoweringContext<'a> {
                             this.sess.abort_if_errors();
                         }
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
-                                         this.lower_fn_decl(decl),
+                                         this.lower_fn_decl(decl, None, false),
                                          body_id,
                                          fn_decl_span,
                                          is_generator)
@@ -2193,7 +2281,8 @@ impl<'a> LoweringContext<'a> {
                 };
             }
             ExprKind::Path(ref qself, ref path) => {
-                hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
+                hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
+                                               ImplTraitContext::Disallowed))
             }
             ExprKind::Break(opt_ident, ref opt_expr) => {
                 let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
@@ -2246,7 +2335,8 @@ impl<'a> LoweringContext<'a> {
                 hir::ExprInlineAsm(P(hir_asm), outputs, inputs)
             }
             ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
-                hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional),
+                hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional,
+                                                 ImplTraitContext::Disallowed),
                                 fields.iter().map(|x| self.lower_field(x)).collect(),
                                 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))))
             }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index a7206f5d420..ee83000c440 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1461,9 +1461,12 @@ pub enum Ty_ {
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
-    /// An `impl Bound1 + Bound2 + Bound3` type
-    /// where `Bound` is a trait or a lifetime.
-    TyImplTrait(TyParamBounds),
+    /// An exsitentially quantified (there exists a type satisfying) `impl
+    /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
+    TyImplTraitExistential(TyParamBounds),
+    /// An universally quantified (for all types satisfying) `impl
+    /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
+    TyImplTraitUniversal(DefId, TyParamBounds),
     /// Unused for now
     TyTypeof(BodyId),
     /// TyInfer means the type should be inferred instead of it having been
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 7d0f26ba34d..5d8e732b17c 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -421,7 +421,8 @@ impl<'a> State<'a> {
                     self.print_lifetime(lifetime)?;
                 }
             }
-            hir::TyImplTrait(ref bounds) => {
+            hir::TyImplTraitExistential(ref bounds) |
+                hir::TyImplTraitUniversal(_, ref bounds) => {
                 self.print_bounds("impl ", &bounds[..])?;
             }
             hir::TyArray(ref ty, v) => {
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 6b78cd473be..a04683e1b22 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -287,7 +287,8 @@ impl_stable_hash_for!(enum hir::Ty_ {
     TyTup(ts),
     TyPath(qpath),
     TyTraitObject(trait_refs, lifetime),
-    TyImplTrait(bounds),
+    TyImplTraitExistential(bounds),
+    TyImplTraitUniversal(def_id, bounds),
     TyTypeof(body_id),
     TyErr,
     TyInfer
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index ffd06ee8a2e..fc6f6ed9aa8 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -1698,7 +1698,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
         }
 
         fn visit_ty(&mut self, ty: &hir::Ty) {
-            if let hir::TyImplTrait(_) = ty.node {
+            if let hir::TyImplTraitExistential(_) = ty.node {
                 self.impl_trait = true;
             }
             intravisit::walk_ty(self, ty);
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index d5eee14bf50..8c40f303b93 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1487,7 +1487,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
 
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
         match ty.node {
-            hir::TyImplTrait(_) => {
+            hir::TyImplTraitExistential(_) => {
                 let def_id = self.tcx.hir.local_def_id(ty.id);
                 self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
             }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 630260feed7..74d92ce1c3e 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyImplTrait(..) = ty.node {
+        if let hir::TyImplTraitExistential(..) = ty.node {
             if self.get(ty.id).is_some() {
                 // Reach the (potentially private) type and the API being exposed.
                 self.reach(ty.id).ty().predicates();
@@ -1557,7 +1557,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyImplTrait(..) = ty.node {
+        if let hir::TyImplTraitExistential(..) = ty.node {
             // Check the traits being exposed, as they're separate,
             // e.g. `impl Iterator<Item=T>` has two predicates,
             // `X: Iterator` and `<X as Iterator>::Item == T`,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 95b19616e5e..34d617a2054 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -30,6 +30,7 @@ use util::nodemap::FxHashSet;
 
 use std::iter;
 use syntax::{abi, ast};
+use syntax::symbol::keywords;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax_pos::Span;
 
@@ -1033,53 +1034,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyTraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
-            hir::TyImplTrait(_) => {
-                // Figure out if we can allow an `impl Trait` here, by walking up
-                // to a `fn` or inherent `impl` method, going only through `Ty`
-                // or `TraitRef` nodes (as nothing else should be in types) and
-                // ensuring that we reach the `fn`/method signature's return type.
-                let mut node_id = ast_ty.id;
-                let fn_decl = loop {
-                    let parent = tcx.hir.get_parent_node(node_id);
-                    match tcx.hir.get(parent) {
-                        hir::map::NodeItem(&hir::Item {
-                            node: hir::ItemFn(ref fn_decl, ..), ..
-                        }) => break Some(fn_decl),
-
-                        hir::map::NodeImplItem(&hir::ImplItem {
-                            node: hir::ImplItemKind::Method(ref sig, _), ..
-                        }) => {
-                            match tcx.hir.expect_item(tcx.hir.get_parent(parent)).node {
-                                hir::ItemImpl(.., None, _, _) => {
-                                    break Some(&sig.decl)
-                                }
-                                _ => break None
-                            }
-                        }
-
-                        hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => {}
-
-                        _ => break None
-                    }
-                    node_id = parent;
-                };
-                let allow = fn_decl.map_or(false, |fd| {
-                    match fd.output {
-                        hir::DefaultReturn(_) => false,
-                        hir::Return(ref ty) => ty.id == node_id
-                    }
-                });
-
-                // Create the anonymized type.
-                if allow {
-                    let def_id = tcx.hir.local_def_id(ast_ty.id);
-                    tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
-                } else {
-                    span_err!(tcx.sess, ast_ty.span, E0562,
-                              "`impl Trait` not allowed outside of function \
-                               and inherent method return types");
-                    tcx.types.err
-                }
+            hir::TyImplTraitExistential(_) => {
+                let def_id = tcx.hir.local_def_id(ast_ty.id);
+                tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
+            }
+            hir::TyImplTraitUniversal(fn_def_id, _) => {
+                let impl_trait_def_id = tcx.hir.local_def_id(ast_ty.id);
+                let generics = tcx.generics_of(fn_def_id);
+                let index = generics.type_param_to_index[&impl_trait_def_id.index];
+                tcx.mk_param(index, keywords::Invalid.name() /* FIXME(chrisvittal) invalid? */)
             }
             hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
                 debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 81447097428..69bdb68945d 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -130,7 +130,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyImplTrait(..) = ty.node {
+        if let hir::TyImplTraitExistential(..) = ty.node {
             let def_id = self.tcx.hir.local_def_id(ty.id);
             self.tcx.generics_of(def_id);
             self.tcx.predicates_of(def_id);
@@ -854,7 +854,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
             Some(tcx.closure_base_def_id(def_id))
         }
-        NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
+        NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => {
             let mut parent_id = node_id;
             loop {
                 match tcx.hir.get(parent_id) {
@@ -1155,7 +1155,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             icx.to_ty(ty)
         }
 
-        NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
+        NodeTy(&hir::Ty { node: TyImplTraitExistential(..), .. }) => {
             let owner = tcx.hir.get_parent_did(node_id);
             let hir_id = tcx.hir.node_to_hir_id(node_id);
             tcx.typeck_tables_of(owner).node_id_to_type(hir_id)
@@ -1373,7 +1373,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
 
-        NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
+        NodeTy(&Ty { node: TyImplTraitExistential(ref bounds), span, .. }) => {
             let substs = Substs::identity_for_item(tcx, def_id);
             let anon_ty = tcx.mk_anon(def_id, substs);
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4b60536e1d1..1d107c169b0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1960,7 +1960,9 @@ impl Clean<Type> for hir::Ty {
                 }
             }
             TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
-            TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)),
+            TyImplTraitExistential(ref bounds) |
+                TyImplTraitUniversal(_, ref bounds) =>
+                    ImplTrait(bounds.clean(cx)),
             TyInfer | TyErr => Infer,
             TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
         }