about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-09-08 07:52:03 +0100
committerAlexander Regueiro <alexreg@me.com>2018-09-25 03:05:55 +0100
commit218189536d95c12d7abbe01af3725c84a628bc51 (patch)
treed952116d63f517204987df8dcb7e20029c5a20f1
parentcf915849f0f9467e67823a9d7eb1128828a9f334 (diff)
downloadrust-218189536d95c12d7abbe01af3725c84a628bc51.tar.gz
rust-218189536d95c12d7abbe01af3725c84a628bc51.zip
Handle impl trait in MIR type checked for assignments.
-rw-r--r--src/librustc/diagnostics.rs5
-rw-r--r--src/librustc/hir/lowering.rs57
-rw-r--r--src/librustc/ty/relate.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/input_output.rs147
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs159
-rw-r--r--src/librustc_typeck/check/mod.rs186
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs17
-rw-r--r--src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr21
-rw-r--r--src/test/ui/feature-gates/feature-gate-self_in_typedefs.rs (renamed from src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs)0
-rw-r--r--src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr (renamed from src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr)2
11 files changed, 368 insertions, 235 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index c38b3510a0c..84afdd53cf4 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1739,7 +1739,7 @@ specified exit code, use `std::process::exit`.
 
 E0562: r##"
 Abstract return types (written `impl Trait` for some trait `Trait`) are only
-allowed as function and inherent impl return types or binding types.
+allowed as function and inherent impl return types.
 
 Erroneous code example:
 
@@ -1754,8 +1754,7 @@ fn main() {
 }
 ```
 
-Make sure `impl Trait` only appears in return-type position or as the type of a
-binding.
+Make sure `impl Trait` only appears in return-type position.
 
 ```
 fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 275ca6e1694..f25a17304f9 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1284,12 +1284,18 @@ impl<'a> LoweringContext<'a> {
                         ))
                     }
                     ImplTraitContext::Disallowed => {
+                        let allowed_in = if self.sess.features_untracked()
+                                                .impl_trait_in_bindings {
+                            "bindings or function and inherent method return types"
+                        } else {
+                            "function and inherent method return types"
+                        };
                         span_err!(
                             self.sess,
                             t.span,
                             E0562,
-                            "`impl Trait` not allowed outside of function \
-                             and inherent method return types or bindings"
+                            "`impl Trait` not allowed outside of {}",
+                            allowed_in,
                         );
                         hir::TyKind::Err
                     }
@@ -2206,8 +2212,10 @@ impl<'a> LoweringContext<'a> {
         let impl_trait_ty = self.lower_existential_impl_trait(
             span, Some(fn_def_id), return_impl_trait_id, |this| {
             let output_ty = match output {
-                FunctionRetTy::Ty(ty) =>
-                    this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))),
+                FunctionRetTy::Ty(ty) => {
+                    let impl_trait_owner_id = *this.current_impl_trait_owner.last().unwrap();
+                    this.lower_ty(ty, ImplTraitContext::Existential(Some(impl_trait_owner_id)))
+                }
                 FunctionRetTy::Default(span) => {
                     let LoweredNodeId { node_id, hir_id } = this.next_id();
                     P(hir::Ty {
@@ -2702,14 +2710,31 @@ impl<'a> LoweringContext<'a> {
             ItemKind::Static(ref t, m, ref e) => {
                 let value = self.lower_body(None, |this| this.lower_expr(e));
                 hir::ItemKind::Static(
-                    self.lower_ty(t, ImplTraitContext::Disallowed),
+                    self.lower_ty(
+                        t,
+                        if self.sess.features_untracked().impl_trait_in_bindings {
+                            ImplTraitContext::Existential(None)
+                        } else {
+                            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::ItemKind::Const(self.lower_ty(t, ImplTraitContext::Disallowed), value)
+                hir::ItemKind::Const(
+                    self.lower_ty(
+                        t,
+                        if self.sess.features_untracked().impl_trait_in_bindings {
+                            ImplTraitContext::Existential(None)
+                        } else {
+                            ImplTraitContext::Disallowed
+                        }
+                    ),
+                    value
+                )
             }
             ItemKind::Fn(ref decl, header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
@@ -3258,6 +3283,22 @@ impl<'a> LoweringContext<'a> {
                 }
                 ids
             },
+            ItemKind::Static(ref ty, ..) => {
+                let mut ids = smallvec![hir::ItemId { id: i.id }];
+                if self.sess.features_untracked().impl_trait_in_bindings {
+                    let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
+                    visitor.visit_ty(ty);
+                }
+                ids
+            },
+            ItemKind::Const(ref ty, ..) => {
+                let mut ids = smallvec![hir::ItemId { id: i.id }];
+                if self.sess.features_untracked().impl_trait_in_bindings {
+                    let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
+                    visitor.visit_ty(ty);
+                }
+                ids
+            },
             _ => smallvec![hir::ItemId { id: i.id }],
         }
     }
@@ -3817,8 +3858,8 @@ impl<'a> LoweringContext<'a> {
             }
             ExprKind::Block(ref blk, opt_label) => {
                 hir::ExprKind::Block(self.lower_block(blk,
-                                                opt_label.is_some()),
-                                                self.lower_label(opt_label))
+                                                      opt_label.is_some()),
+                                                      self.lower_label(opt_label))
             }
             ExprKind::Assign(ref el, ref er) => {
                 hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 8f84fb7e391..98042e18d32 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -361,7 +361,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
     let tcx = relation.tcx();
     let a_sty = &a.sty;
     let b_sty = &b.sty;
-    debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
+    debug!("super_relate_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
     match (a_sty, b_sty) {
         (&ty::Infer(_), _) |
         (_, &ty::Infer(_)) =>
diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
index d3b215fa070..acde4587d77 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
@@ -17,15 +17,8 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
-use borrow_check::nll::renumber;
-use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
 use borrow_check::nll::universal_regions::UniversalRegions;
-use rustc::hir::def_id::DefId;
-use rustc::infer::InferOk;
 use rustc::mir::*;
-use rustc::traits::query::type_op::custom::CustomTypeOp;
-use rustc::traits::{ObligationCause, PredicateObligations};
-use rustc::ty::subst::Subst;
 use rustc::ty::Ty;
 
 use rustc_data_structures::indexed_vec::Idx;
@@ -37,16 +30,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     pub(super) fn equate_inputs_and_outputs(
         &mut self,
         mir: &Mir<'tcx>,
-        mir_def_id: DefId,
         universal_regions: &UniversalRegions<'tcx>,
-        universal_region_relations: &UniversalRegionRelations<'tcx>,
         normalized_inputs_and_output: &[Ty<'tcx>],
     ) {
-        let tcx = self.infcx.tcx;
-
         let (&normalized_output_ty, normalized_input_tys) =
             normalized_inputs_and_output.split_last().unwrap();
-        let infcx = self.infcx;
 
         // Equate expected input tys with those in the MIR.
         let argument_locals = (1..).map(Local::new);
@@ -77,111 +65,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
         // Return types are a bit more complex. They may contain existential `impl Trait`
         // types.
-        let param_env = self.param_env;
         let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
         let output_span = mir.local_decls[RETURN_PLACE].source_info.span;
-        let opaque_type_map =
-            self.fully_perform_op(
-                Locations::All(output_span),
-                ConstraintCategory::BoringNoLocation,
-                CustomTypeOp::new(
-                    |infcx| {
-                        let mut obligations = ObligationAccumulator::default();
-
-                        let dummy_body_id = ObligationCause::dummy().body_id;
-                        let (output_ty, opaque_type_map) =
-                            obligations.add(infcx.instantiate_opaque_types(
-                                mir_def_id,
-                                dummy_body_id,
-                                param_env,
-                                &normalized_output_ty,
-                            ));
-                        debug!(
-                            "equate_inputs_and_outputs: instantiated output_ty={:?}",
-                            output_ty
-                        );
-                        debug!(
-                            "equate_inputs_and_outputs: opaque_type_map={:#?}",
-                            opaque_type_map
-                        );
-
-                        debug!(
-                            "equate_inputs_and_outputs: mir_output_ty={:?}",
-                            mir_output_ty
-                        );
-                        obligations.add(
-                            infcx
-                                .at(&ObligationCause::dummy(), param_env)
-                                .eq(output_ty, mir_output_ty)?,
-                        );
-
-                        for (&opaque_def_id, opaque_decl) in &opaque_type_map {
-                            let opaque_defn_ty = tcx.type_of(opaque_def_id);
-                            let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
-                            let opaque_defn_ty = renumber::renumber_regions(
-                                infcx,
-                                &opaque_defn_ty,
-                            );
-                            debug!(
-                                "equate_inputs_and_outputs: concrete_ty={:?}",
-                                opaque_decl.concrete_ty
-                            );
-                            debug!("equate_inputs_and_outputs: opaque_defn_ty={:?}",
-                                   opaque_defn_ty);
-                            obligations.add(
-                                infcx
-                                    .at(&ObligationCause::dummy(), param_env)
-                                    .eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
-                            );
-                        }
-
-                        debug!("equate_inputs_and_outputs: equated");
-
-                        Ok(InferOk {
-                            value: Some(opaque_type_map),
-                            obligations: obligations.into_vec(),
-                        })
-                    },
-                    || "input_output".to_string(),
-                ),
-            ).unwrap_or_else(|terr| {
-                span_mirbug!(
-                    self,
-                    Location::START,
-                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
-                    normalized_output_ty,
-                    mir_output_ty,
-                    terr
-                );
-                None
-            });
-
-        // Finally, if we instantiated the opaque types successfully, we
-        // have to solve any bounds (e.g., `-> impl Iterator` needs to
-        // prove that `T: Iterator` where `T` is the type we
-        // instantiated it with).
-        if let Some(opaque_type_map) = opaque_type_map {
-            for (opaque_def_id, opaque_decl) in opaque_type_map {
-                self.fully_perform_op(
-                    Locations::All(infcx.tcx.def_span(opaque_def_id)),
-                    ConstraintCategory::OpaqueType,
-                    CustomTypeOp::new(
-                        |_cx| {
-                            infcx.constrain_opaque_type(
-                                opaque_def_id,
-                                &opaque_decl,
-                                universal_region_relations
-                            );
-                            Ok(InferOk {
-                                value: (),
-                                obligations: vec![],
-                            })
-                        },
-                        || "opaque_type_map".to_string(),
-                    ),
-                ).unwrap();
-            }
-        }
+        if let Err(terr) = self.eq_opaque_type_and_type(
+            mir_output_ty,
+            normalized_output_ty,
+            Locations::All(output_span),
+            ConstraintCategory::BoringNoLocation,
+        ) {
+            span_mirbug!(
+                self,
+                Location::START,
+                "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
+                normalized_output_ty,
+                mir_output_ty,
+                terr
+            );
+        };
     }
 
     fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
@@ -204,20 +104,3 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 }
-
-#[derive(Debug, Default)]
-struct ObligationAccumulator<'tcx> {
-    obligations: PredicateObligations<'tcx>,
-}
-
-impl<'tcx> ObligationAccumulator<'tcx> {
-    fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
-        let InferOk { value, obligations } = value;
-        self.obligations.extend(obligations);
-        value
-    }
-
-    fn into_vec(self) -> PredicateObligations<'tcx> {
-        self.obligations
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 250db4d15e6..8d260e0970a 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -22,6 +22,7 @@ use borrow_check::nll::type_check::free_region_relations::{
 };
 use borrow_check::nll::universal_regions::UniversalRegions;
 use borrow_check::nll::ToRegionVid;
+use borrow_check::nll::renumber;
 use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
 use dataflow::MaybeInitializedPlaces;
@@ -29,15 +30,18 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::region_constraints::GenericKind;
-use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
+use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{PlaceContext, Visitor};
 use rustc::mir::*;
+use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::traits::query::type_op;
+use rustc::traits::query::type_op::custom::CustomTypeOp;
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
+use rustc::ty::subst::Subst;
 use std::fmt;
 use std::rc::Rc;
 use syntax_pos::{Span, DUMMY_SP};
@@ -155,12 +159,11 @@ pub(crate) fn type_check<'gcx, 'tcx>(
             &region_bound_pairs,
             Some(implicit_region_bound),
             Some(&mut borrowck_context),
+            Some(&universal_region_relations),
             |cx| {
                 cx.equate_inputs_and_outputs(
                     mir,
-                    mir_def_id,
                     universal_regions,
-                    &universal_region_relations,
                     &normalized_inputs_and_output,
                 );
                 liveness::generate(cx, mir, elements, flow_inits, move_data);
@@ -182,6 +185,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
     region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: Option<ty::Region<'tcx>>,
     borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
+    universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
     mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R,
 ) -> R where {
     let mut checker = TypeChecker::new(
@@ -192,6 +196,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
         region_bound_pairs,
         implicit_region_bound,
         borrowck_context,
+        universal_region_relations,
     );
     let errors_reported = {
         let mut verifier = TypeVerifier::new(&mut checker, mir);
@@ -692,6 +697,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
     implicit_region_bound: Option<ty::Region<'tcx>>,
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
+    universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
 }
 
 struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -799,6 +805,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
         implicit_region_bound: Option<ty::Region<'tcx>>,
         borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
+        universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
     ) -> Self {
         TypeChecker {
             infcx,
@@ -810,6 +817,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             implicit_region_bound,
             borrowck_context,
             reported_errors: FxHashSet(),
+            universal_region_relations,
         }
     }
 
@@ -883,6 +891,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         )
     }
 
+    fn sub_types_or_anon(
+        &mut self,
+        sub: Ty<'tcx>,
+        sup: Ty<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) -> Fallible<()> {
+        if let Err(terr) = self.sub_types(sub, sup, locations) {
+            if let TyKind::Opaque(..) = sup.sty {
+                return self.eq_opaque_type_and_type(sub, sup, locations, category);
+            } else {
+                return Err(terr);
+            }
+        }
+        Ok(())
+    }
+
     fn eq_types(
         &mut self,
         a: Ty<'tcx>,
@@ -919,6 +944,111 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         )
     }
 
+    fn eq_opaque_type_and_type(
+        &mut self,
+        revealed_ty: Ty<'tcx>,
+        anon_ty: Ty<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) -> Fallible<()> {
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
+        let param_env = self.param_env;
+        let mir_def_id = self.mir_def_id;
+        let opaque_type_map =
+            self.fully_perform_op(
+                locations,
+                CustomTypeOp::new(
+                    |infcx| {
+                        let mut obligations = ObligationAccumulator::default();
+
+                        let dummy_body_id = ObligationCause::dummy().body_id;
+                        let (output_ty, opaque_type_map) =
+                            obligations.add(infcx.instantiate_opaque_types(
+                                mir_def_id,
+                                dummy_body_id,
+                                param_env,
+                                &anon_ty,
+                            ));
+                        debug!(
+                            "eq_opaque_type_and_type: \
+                             instantiated output_ty={:?} \
+                             opaque_type_map={:#?} \
+                             revealed_ty={:?}",
+                            output_ty,
+                            opaque_type_map,
+                            revealed_ty
+                        );
+                        obligations.add(
+                            infcx
+                                .at(&ObligationCause::dummy(), param_env)
+                                .eq(output_ty, revealed_ty)?,
+                        );
+
+                        for (&opaque_def_id, opaque_decl) in &opaque_type_map {
+                            let opaque_defn_ty = tcx.type_of(opaque_def_id);
+                            let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
+                            let opaque_defn_ty = renumber::renumber_regions(
+                                infcx,
+                                &opaque_defn_ty,
+                            );
+                            debug!(
+                                "eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
+                                opaque_decl.concrete_ty,
+                                opaque_defn_ty
+                            );
+                            obligations.add(
+                                infcx
+                                    .at(&ObligationCause::dummy(), param_env)
+                                    .eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
+                            );
+                        }
+
+                        debug!("eq_opaque_type_and_type: equated");
+
+                        Ok(InferOk {
+                            value: Some(opaque_type_map),
+                            obligations: obligations.into_vec(),
+                        })
+                    },
+                    || "input_output".to_string(),
+                ),
+            )?;
+
+        let universal_region_relations = match self.universal_region_relations {
+            Some(rel) => rel,
+            None => return Ok(()),
+        };
+
+        // Finally, if we instantiated the anon types successfully, we
+        // have to solve any bounds (e.g., `-> impl Iterator` needs to
+        // prove that `T: Iterator` where `T` is the type we
+        // instantiated it with).
+        if let Some(opaque_type_map) = opaque_type_map {
+            for (opaque_def_id, opaque_decl) in opaque_type_map {
+                self.fully_perform_op(
+                    locations,
+                    category,
+                    CustomTypeOp::new(
+                        |_cx| {
+                            infcx.constrain_opaque_type(
+                                opaque_def_id,
+                                &opaque_decl,
+                                universal_region_relations
+                            );
+                            Ok(InferOk {
+                                value: (),
+                                obligations: vec![],
+                            })
+                        },
+                        || "opaque_type_map".to_string(),
+                    ),
+                )?;
+            }
+        }
+        Ok(())
+    }
+
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
@@ -942,7 +1072,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Err(terr) = self.sub_types(
+                if let Err(terr) = self.sub_types_or_anon(
                     rv_ty,
                     place_ty,
                     location.to_locations(),
@@ -1235,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                 let locations = term_location.to_locations();
 
-                if let Err(terr) = self.sub_types(
+                if let Err(terr) = self.sub_types_or_anon(
                     sig.output(),
                     dest_ty,
                     locations,
@@ -2104,6 +2234,7 @@ impl MirPass for TypeckMir {
                 &[],
                 None,
                 None,
+                None,
                 |_| (),
             );
 
@@ -2128,3 +2259,21 @@ impl NormalizeLocation for Location {
         Locations::Single(self)
     }
 }
+
+#[derive(Debug, Default)]
+struct ObligationAccumulator<'tcx> {
+    obligations: PredicateObligations<'tcx>,
+}
+
+impl<'tcx> ObligationAccumulator<'tcx> {
+    fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
+        let InferOk { value, obligations } = value;
+        self.obligations.extend(obligations);
+        value
+    }
+
+    fn into_vec(self) -> PredicateObligations<'tcx> {
+        self.obligations
+    }
+}
+
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d68899e216c..7265d82935b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -65,7 +65,7 @@ nodes within the function.
 The types of top-level items, which never contain unbound type
 variables, are stored directly into the `tcx` tables.
 
-n.b.: A type variable is not the same thing as a type parameter.  A
+N.B.: A type variable is not the same thing as a type parameter.  A
 type variable is rather an "instance" of a type parameter: that is,
 given a generic function `fn foo<T>(t: T)`: while checking the
 function `foo`, the type `ty_param(0)` refers to the type `T`, which
@@ -852,7 +852,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             check_abi(tcx, span, fn_sig.abi());
 
-            // Compute the fty from point of view of inside fn.
+            // Compute the fty from point of view of inside the fn.
             let fn_sig =
                 tcx.liberate_late_bound_regions(def_id, &fn_sig);
             let fn_sig =
@@ -869,10 +869,20 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
             fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
+            let revealed_ty = if tcx.features().impl_trait_in_bindings {
+                fcx.require_type_is_sized(expected_type, body.value.span, traits::SizedReturnType);
+                fcx.instantiate_opaque_types_from_value(
+                    id,
+                    &expected_type
+                )
+            } else {
+                expected_type
+            };
+
             // Gather locals in statics (because of block expressions).
             GatherLocalsVisitor { fcx: &fcx, parent_id: id, }.visit_body(body);
 
-            fcx.check_expr_coercable_to_type(&body.value, expected_type);
+            fcx.check_expr_coercable_to_type(&body.value, revealed_ty);
 
             fcx
         };
@@ -957,9 +967,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
                 let o_ty = self.fcx.to_ty(&ty);
                 debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1);
 
-                let revealed_ty = self.fcx.instantiate_opaque_types_from_value(
-                    self.parent_id,
-                    &o_ty);
+                let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
+                    self.fcx.instantiate_opaque_types_from_value(
+                        self.parent_id,
+                        &o_ty
+                    )
+                } else {
+                    o_ty
+                };
 
                 let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty);
                 self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
@@ -1288,90 +1303,96 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     check_packed(tcx, span, def_id);
 }
 
-pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
-    debug!("check_item_type(it.id={}, it.name={})",
-           it.id,
-           tcx.item_path_str(tcx.hir.local_def_id(it.id)));
+pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
+    debug!(
+        "check_item_type(it.id={}, it.name={})",
+        it.id,
+        tcx.item_path_str(tcx.hir.local_def_id(it.id))
+    );
     let _indenter = indenter();
     match it.node {
-      // Consts can play a role in type-checking, so they are included here.
-      hir::ItemKind::Static(..) => {
-        let def_id = tcx.hir.local_def_id(it.id);
-        tcx.typeck_tables_of(def_id);
-        maybe_check_static_with_link_section(tcx, def_id, it.span);
-      }
-      hir::ItemKind::Const(..) => {
-        tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
-      }
-      hir::ItemKind::Enum(ref enum_definition, _) => {
-        check_enum(tcx,
-                   it.span,
-                   &enum_definition.variants,
-                   it.id);
-      }
-      hir::ItemKind::Fn(..) => {} // entirely within check_item_body
-      hir::ItemKind::Impl(.., ref impl_item_refs) => {
-          debug!("ItemKind::Impl {} with id {}", it.name, it.id);
-          let impl_def_id = tcx.hir.local_def_id(it.id);
-          if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
-              check_impl_items_against_trait(tcx,
-                                             it.span,
-                                             impl_def_id,
-                                             impl_trait_ref,
-                                             impl_item_refs);
-              let trait_def_id = impl_trait_ref.def_id;
-              check_on_unimplemented(tcx, trait_def_id, it);
-          }
-      }
-      hir::ItemKind::Trait(..) => {
-        let def_id = tcx.hir.local_def_id(it.id);
-        check_on_unimplemented(tcx, def_id, it);
-      }
-      hir::ItemKind::Struct(..) => {
-        check_struct(tcx, it.id, it.span);
-      }
-      hir::ItemKind::Union(..) => {
-        check_union(tcx, it.id, it.span);
-      }
-      hir::ItemKind::Existential(..) |
-      hir::ItemKind::Ty(..) => {
-        let def_id = tcx.hir.local_def_id(it.id);
-        let pty_ty = tcx.type_of(def_id);
-        let generics = tcx.generics_of(def_id);
-        check_bounds_are_used(tcx, &generics, pty_ty);
-      }
-      hir::ItemKind::ForeignMod(ref m) => {
-        check_abi(tcx, it.span, m.abi);
-
-        if m.abi == Abi::RustIntrinsic {
-            for item in &m.items {
-                intrinsic::check_intrinsic_type(tcx, item);
-            }
-        } else if m.abi == Abi::PlatformIntrinsic {
-            for item in &m.items {
-                intrinsic::check_platform_intrinsic_type(tcx, item);
+        // Consts can play a role in type-checking, so they are included here.
+        hir::ItemKind::Static(..) => {
+            let def_id = tcx.hir.local_def_id(it.id);
+            tcx.typeck_tables_of(def_id);
+            maybe_check_static_with_link_section(tcx, def_id, it.span);
+        }
+        hir::ItemKind::Const(..) => {
+            tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
+        }
+        hir::ItemKind::Enum(ref enum_definition, _) => {
+            check_enum(tcx, it.span, &enum_definition.variants, it.id);
+        }
+        hir::ItemKind::Fn(..) => {} // entirely within check_item_body
+        hir::ItemKind::Impl(.., ref impl_item_refs) => {
+            debug!("ItemKind::Impl {} with id {}", it.name, it.id);
+            let impl_def_id = tcx.hir.local_def_id(it.id);
+            if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+                check_impl_items_against_trait(
+                    tcx,
+                    it.span,
+                    impl_def_id,
+                    impl_trait_ref,
+                    impl_item_refs,
+                );
+                let trait_def_id = impl_trait_ref.def_id;
+                check_on_unimplemented(tcx, trait_def_id, it);
             }
-        } else {
-            for item in &m.items {
-                let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
-                if generics.params.len() - generics.own_counts().lifetimes != 0 {
-                    let mut err = struct_span_err!(tcx.sess, item.span, E0044,
-                        "foreign items may not have type parameters");
-                    err.span_label(item.span, "can't have type parameters");
-                    // FIXME: once we start storing spans for type arguments, turn this into a
-                    // suggestion.
-                    err.help("use specialization instead of type parameters by replacing them \
-                              with concrete types like `u32`");
-                    err.emit();
+        }
+        hir::ItemKind::Trait(..) => {
+            let def_id = tcx.hir.local_def_id(it.id);
+            check_on_unimplemented(tcx, def_id, it);
+        }
+        hir::ItemKind::Struct(..) => {
+            check_struct(tcx, it.id, it.span);
+        }
+        hir::ItemKind::Union(..) => {
+            check_union(tcx, it.id, it.span);
+        }
+        hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => {
+            let def_id = tcx.hir.local_def_id(it.id);
+            let pty_ty = tcx.type_of(def_id);
+            let generics = tcx.generics_of(def_id);
+            check_bounds_are_used(tcx, &generics, pty_ty);
+        }
+        hir::ItemKind::ForeignMod(ref m) => {
+            check_abi(tcx, it.span, m.abi);
+
+            if m.abi == Abi::RustIntrinsic {
+                for item in &m.items {
+                    intrinsic::check_intrinsic_type(tcx, item);
+                }
+            } else if m.abi == Abi::PlatformIntrinsic {
+                for item in &m.items {
+                    intrinsic::check_platform_intrinsic_type(tcx, item);
                 }
+            } else {
+                for item in &m.items {
+                    let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
+                    if generics.params.len() - generics.own_counts().lifetimes != 0 {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            item.span,
+                            E0044,
+                            "foreign items may not have type parameters"
+                        );
+                        err.span_label(item.span, "can't have type parameters");
+                        // FIXME: once we start storing spans for type arguments, turn this into a
+                        // suggestion.
+                        err.help(
+                            "use specialization instead of type parameters by replacing them \
+                             with concrete types like `u32`",
+                        );
+                        err.emit();
+                    }
 
-                if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
-                    require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
+                    if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
+                        require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
+                    }
                 }
             }
         }
-      }
-      _ => {/* nothing to do */ }
+        _ => { /* nothing to do */ }
     }
 }
 
@@ -3936,7 +3957,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             hir::ExprKind::Path(ref qpath) => {
                 let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span);
-                debug!("path_foo: {:?} {:?}", def, opt_ty);
                 let ty = if def != Def::Err {
                     self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0
                 } else {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 65ffd96e7a0..eb40ea01630 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -494,7 +494,7 @@ declare_features! (
     // Allows `Self` in type definitions
     (active, self_in_typedefs, "1.30.0", Some(49303), None),
 
-    // unsized rvalues at arguments and parameters
+    // Allows unsized rvalues at arguments and parameters
     (active, unsized_locals, "1.30.0", Some(48055), None),
 
     // #![test_runner]
@@ -505,13 +505,16 @@ declare_features! (
     (active, custom_inner_attributes, "1.30.0", Some(38356), None),
 
     // Self struct constructor  (RFC 2302)
-    (active, self_struct_ctor, "1.31.0", Some(51994), None),
+    (active, self_struct_ctor, "1.30.0", Some(51994), None),
 
     // allow mixing of bind-by-move in patterns and references to
     // those identifiers in guards, *if* we are using MIR-borrowck
     // (aka NLL). Essentially this means you need to be on
     // edition:2018 or later.
     (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
+
+    // Allows `impl Trait` in bindings (`let`, `const`, `static`)
+    (active, impl_trait_in_bindings, "1.30.0", Some(34511), None),
 );
 
 declare_features! (
diff --git a/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs
new file mode 100644
index 00000000000..9c76719e26c
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs
@@ -0,0 +1,17 @@
+// 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.
+
+const FOO: impl Copy = 42;
+
+static BAR: impl Copy = 42;
+
+fn main() {
+    let foo = impl Copy = 42;
+}
diff --git a/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr
new file mode 100644
index 00000000000..52c99a7b159
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr
@@ -0,0 +1,21 @@
+error: expected expression, found keyword `impl`
+  --> $DIR/feature-gate-impl_trait_in_bindings.rs:16:15
+   |
+LL |     let foo = impl Copy = 42;
+   |               ^^^^ expected expression
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-impl_trait_in_bindings.rs:11:12
+   |
+LL | const FOO: impl Copy = 42;
+   |            ^^^^^^^^^
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-impl_trait_in_bindings.rs:13:13
+   |
+LL | static BAR: impl Copy = 42;
+   |             ^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0562`.
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
index 4b476a0a645..4b476a0a645 100644
--- a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs
+++ b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.rs
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
index c3f9abd90a7..22ca92bbe13 100644
--- a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr
+++ b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr
@@ -1,5 +1,5 @@
 error[E0411]: cannot find type `Self` in this scope
-  --> $DIR/feature-gate-self-in-typedefs.rs:13:17
+  --> $DIR/feature-gate-self_in_typedefs.rs:13:17
    |
 LL |     Cons(T, &'a Self)
    |                 ^^^^ `Self` is only available in traits and impls