]> git.lizzy.rs Git - rust.git/commitdiff
rustc_typeck: pass all lifetimes through AstConv::opt_ast_region_to_region.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Wed, 4 Jan 2017 21:23:11 +0000 (23:23 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Sat, 28 Jan 2017 00:55:37 +0000 (02:55 +0200)
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/rscope.rs

index 166178d6c29c1ef9c66258ffcda0d97b9b7e67ff..0a836a8ba22297bfb11d7fec4bf8ec8d278a2145 100644 (file)
@@ -64,7 +64,7 @@
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
              ElisionFailureInfo, ElidedLifetime};
-use rscope::{AnonTypeScope, MaybeWithAnonTypes};
+use rscope::{AnonTypeScope, MaybeWithAnonTypes, ExplicitRscope};
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::{NodeMap, FxHashSet};
 
@@ -161,70 +161,6 @@ struct ConvertedBinding<'tcx> {
 /// This type must not appear anywhere in other converted types.
 const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0));
 
-pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                            lifetime: &hir::Lifetime)
-                                            -> &'tcx ty::Region {
-    let r = match tcx.named_region_map.defs.get(&lifetime.id) {
-        None => {
-            // should have been recorded by the `resolve_lifetime` pass
-            span_bug!(lifetime.span, "unresolved lifetime");
-        }
-
-        Some(&rl::DefStaticRegion) => {
-            ty::ReStatic
-        }
-
-        Some(&rl::DefLateBoundRegion(debruijn, id)) => {
-            // If this region is declared on a function, it will have
-            // an entry in `late_bound`, but if it comes from
-            // `for<'a>` in some type or something, it won't
-            // necessarily have one. In that case though, we won't be
-            // changed from late to early bound, so we can just
-            // substitute false.
-            let issue_32330 = tcx.named_region_map
-                                 .late_bound
-                                 .get(&id)
-                                 .cloned()
-                                 .unwrap_or(ty::Issue32330::WontChange);
-            ty::ReLateBound(debruijn, ty::BrNamed(tcx.hir.local_def_id(id),
-                                                  lifetime.name,
-                                                  issue_32330))
-        }
-
-        Some(&rl::DefEarlyBoundRegion(index, _)) => {
-            ty::ReEarlyBound(ty::EarlyBoundRegion {
-                index: index,
-                name: lifetime.name
-            })
-        }
-
-        Some(&rl::DefFreeRegion(scope, id)) => {
-            // As in DefLateBoundRegion above, could be missing for some late-bound
-            // regions, but also for early-bound regions.
-            let issue_32330 = tcx.named_region_map
-                                 .late_bound
-                                 .get(&id)
-                                 .cloned()
-                                 .unwrap_or(ty::Issue32330::WontChange);
-            ty::ReFree(ty::FreeRegion {
-                    scope: scope.to_code_extent(&tcx.region_maps),
-                    bound_region: ty::BrNamed(tcx.hir.local_def_id(id),
-                                              lifetime.name,
-                                              issue_32330)
-            })
-
-                // (*) -- not late-bound, won't change
-        }
-    };
-
-    debug!("ast_region_to_region(lifetime={:?} id={}) yields {:?}",
-           lifetime,
-           lifetime.id,
-           r);
-
-    tcx.mk_region(r)
-}
-
 fn report_elision_failure(
     tcx: TyCtxt,
     db: &mut DiagnosticBuilder,
@@ -296,38 +232,98 @@ fn report_elision_failure(
 }
 
 impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
-    pub fn opt_ast_region_to_region(&self,
+    pub fn ast_region_to_region(&self, lifetime: &hir::Lifetime) -> &'tcx ty::Region {
+        self.opt_ast_region_to_region(&ExplicitRscope, lifetime.span, Some(lifetime), None)
+    }
+
+    fn try_opt_ast_region_to_region(&self,
         rscope: &RegionScope,
         default_span: Span,
-        opt_lifetime: &Option<hir::Lifetime>) -> &'tcx ty::Region
+        opt_lifetime: Option<&hir::Lifetime>,
+        def: Option<&ty::RegionParameterDef>)
+        -> Result<&'tcx ty::Region, Option<Vec<ElisionFailureInfo>>>
     {
-        let r = match *opt_lifetime {
-            Some(ref lifetime) => {
-                ast_region_to_region(self.tcx(), lifetime)
+        let tcx = self.tcx();
+        let name = opt_lifetime.map(|l| l.name);
+        let resolved = opt_lifetime.and_then(|l| tcx.named_region_map.defs.get(&l.id));
+        let r = tcx.mk_region(match resolved {
+            Some(&rl::DefStaticRegion) => {
+                ty::ReStatic
             }
 
-            None => {
-                self.tcx().mk_region(rscope.anon_region(default_span).unwrap_or_else(|params| {
-                    let ampersand_span = Span { hi: default_span.lo, ..default_span};
+            Some(&rl::DefLateBoundRegion(debruijn, id)) => {
+                // If this region is declared on a function, it will have
+                // an entry in `late_bound`, but if it comes from
+                // `for<'a>` in some type or something, it won't
+                // necessarily have one. In that case though, we won't be
+                // changed from late to early bound, so we can just
+                // substitute false.
+                let issue_32330 = tcx.named_region_map
+                                     .late_bound
+                                     .get(&id)
+                                     .cloned()
+                                     .unwrap_or(ty::Issue32330::WontChange);
+                ty::ReLateBound(debruijn, ty::BrNamed(tcx.hir.local_def_id(id),
+                                                      name.unwrap(),
+                                                      issue_32330))
+            }
+
+            Some(&rl::DefEarlyBoundRegion(index, _)) => {
+                ty::ReEarlyBound(ty::EarlyBoundRegion {
+                    index: index,
+                    name: name.unwrap()
+                })
+            }
 
-                    let mut err = struct_span_err!(self.tcx().sess, ampersand_span, E0106,
-                                                 "missing lifetime specifier");
-                    err.span_label(ampersand_span, &format!("expected lifetime parameter"));
+            Some(&rl::DefFreeRegion(scope, id)) => {
+                // As in DefLateBoundRegion above, could be missing for some late-bound
+                // regions, but also for early-bound regions.
+                let issue_32330 = tcx.named_region_map
+                                     .late_bound
+                                     .get(&id)
+                                     .cloned()
+                                     .unwrap_or(ty::Issue32330::WontChange);
+                ty::ReFree(ty::FreeRegion {
+                        scope: scope.to_code_extent(&tcx.region_maps),
+                        bound_region: ty::BrNamed(tcx.hir.local_def_id(id),
+                                                  name.unwrap(),
+                                                  issue_32330)
+                })
 
-                    if let Some(params) = params {
-                        report_elision_failure(self.tcx(), &mut err, params);
-                    }
-                    err.emit();
-                    ty::ReStatic
-                }))
+                    // (*) -- not late-bound, won't change
             }
-        };
+
+            None => rscope.anon_region(default_span, def)?
+        });
 
         debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
                 opt_lifetime,
                 r);
 
-        r
+        Ok(r)
+    }
+
+    pub fn opt_ast_region_to_region(&self,
+        rscope: &RegionScope,
+        default_span: Span,
+        opt_lifetime: Option<&hir::Lifetime>,
+        def: Option<&ty::RegionParameterDef>) -> &'tcx ty::Region
+    {
+        let tcx = self.tcx();
+        self.try_opt_ast_region_to_region(rscope, default_span, opt_lifetime, def)
+            .unwrap_or_else(|params| {
+                let ampersand_span = Span { hi: default_span.lo, ..default_span};
+
+                let mut err = struct_span_err!(tcx.sess, ampersand_span, E0106,
+                                               "missing lifetime specifier");
+                err.span_label(ampersand_span, &format!("expected lifetime parameter"));
+
+                if let Some(params) = params {
+                    report_elision_failure(tcx, &mut err, params);
+                }
+                err.emit();
+                tcx.mk_region(ty::ReStatic)
+            })
     }
 
     /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
@@ -408,25 +404,21 @@ fn create_substs_for_ast_path(&self,
         };
         let expected_num_region_params = decl_generics.regions.len();
         let supplied_num_region_params = lifetimes.len();
-        let regions = if expected_num_region_params == supplied_num_region_params {
-            lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect()
-        } else {
-            let anon_regions = (0..expected_num_region_params).map(|_| {
-                rscope.anon_region(span)
-            }).collect::<Result<Vec<_>, _>>();
-
-            if supplied_num_region_params != 0 || anon_regions.is_err() {
+        let has_exact_lifetimes = expected_num_region_params == supplied_num_region_params;
+        let mut can_report_lifetime_count_mismatch = !has_exact_lifetimes;
+        let mut maybe_report_lifetime_count_mismatch = || {
+            if can_report_lifetime_count_mismatch {
+                can_report_lifetime_count_mismatch = false;
                 report_lifetime_number_error(tcx, span,
                                              supplied_num_region_params,
                                              expected_num_region_params);
             }
-
-            match anon_regions {
-                Ok(anon_regions) => anon_regions,
-                Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
-            }
         };
 
+        if supplied_num_region_params != 0 {
+            maybe_report_lifetime_count_mismatch();
+        }
+
         // If a self-type was declared, one should be provided.
         assert_eq!(decl_generics.has_self, self_ty.is_some());
 
@@ -452,7 +444,15 @@ fn create_substs_for_ast_path(&self,
         let mut output_assoc_binding = None;
         let substs = Substs::for_item(tcx, def_id, |def, _| {
             let i = def.index as usize - self_ty.is_some() as usize;
-            tcx.mk_region(regions[i])
+            let l = if has_exact_lifetimes {
+                Some(&lifetimes[i])
+            } else {
+                None
+            };
+            self.try_opt_ast_region_to_region(rscope, span, l, Some(def)).unwrap_or_else(|_| {
+                maybe_report_lifetime_count_mismatch();
+                tcx.mk_region(ty::ReStatic)
+            })
         }, |def, substs| {
             let i = def.index as usize;
 
@@ -1472,7 +1472,7 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 })
             }
             hir::TyRptr(ref region, ref mt) => {
-                let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region);
+                let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region.as_ref(), None);
                 debug!("TyRef r={:?}", r);
                 let rscope1 =
                     &ObjectLifetimeDefaultRscope::new(
@@ -1823,7 +1823,7 @@ fn compute_object_lifetime_bound(&self,
 
         if let Some(&r) = explicit_region_bounds.get(0) {
             // Explicitly specified region bound. Use that.
-            return Some(ast_region_to_region(tcx, r));
+            return Some(self.ast_region_to_region(r));
         }
 
         if let Some(principal) = existential_predicates.principal() {
index 1e76267f32c3811148aaf565f690da082bc5276b..e7544c10be3e74a065fae8eb799aa7fa52f334d8 100644 (file)
@@ -80,7 +80,7 @@
 pub use self::compare_method::{compare_impl_method, compare_const_impl};
 use self::TupleArgumentsFlag::*;
 
-use astconv::{AstConv, ast_region_to_region};
+use astconv::AstConv;
 use dep_graph::DepNode;
 use fmt_macros::{Parser, Piece, Position};
 use hir::def::{Def, CtorKind};
@@ -1466,9 +1466,13 @@ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
         *self.next_region_var(infer::MiscVariable(span))
     }
 
-    fn anon_region(&self, span: Span)
+    fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
-        Ok(*self.next_region_var(infer::MiscVariable(span)))
+        let v = match def {
+            Some(def) => infer::EarlyBoundRegion(span, def.name),
+            None => infer::MiscVariable(span)
+        };
+        Ok(*self.next_region_var(v))
     }
 }
 
@@ -4404,11 +4408,7 @@ pub fn instantiate_value_path(&self,
                 None => &[]
             };
 
-            if let Some(ast_lifetime) = lifetimes.get(i) {
-                ast_region_to_region(self.tcx, ast_lifetime)
-            } else {
-                self.region_var_for_def(span, def)
-            }
+            AstConv::opt_ast_region_to_region(self, self, span, lifetimes.get(i), Some(def))
         }, |def, substs| {
             let mut i = def.index as usize;
 
index 1fd03b33a7612b8ecb9123f0f37589f6029117fd..f954d2a5d616885e04e0836d0dd525755086a2bf 100644 (file)
@@ -57,7 +57,7 @@
 
 */
 
-use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds};
+use astconv::{AstConv, Bounds, PartitionedBounds, partition_bounds};
 use lint;
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
@@ -1472,7 +1472,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 index: own_start + i as u32,
                 def_id: tcx.hir.local_def_id(l.lifetime.id),
                 bounds: l.bounds.iter().map(|l| {
-                    ast_region_to_region(tcx, l)
+                    AstConv::ast_region_to_region(&ccx.icx(&()), l)
                 }).collect(),
                 pure_wrt_drop: l.pure_wrt_drop,
             }
@@ -1765,7 +1765,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             name: param.lifetime.name
         }));
         for bound in &param.bounds {
-            let bound_region = ast_region_to_region(ccx.tcx, bound);
+            let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound);
             let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
             predicates.push(outlives.to_predicate());
         }
@@ -1816,7 +1816,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                         }
 
                         &hir::TyParamBound::RegionTyParamBound(ref lifetime) => {
-                            let region = ast_region_to_region(tcx, lifetime);
+                            let region = AstConv::ast_region_to_region(&ccx.icx(&()), lifetime);
                             let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
                             predicates.push(ty::Predicate::TypeOutlives(pred))
                         }
@@ -1825,9 +1825,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             }
 
             &hir::WherePredicate::RegionPredicate(ref region_pred) => {
-                let r1 = ast_region_to_region(tcx, &region_pred.lifetime);
+                let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), &region_pred.lifetime);
                 for bound in &region_pred.bounds {
-                    let r2 = ast_region_to_region(tcx, bound);
+                    let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound);
                     let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
                     predicates.push(ty::Predicate::RegionOutlives(pred))
                 }
@@ -1935,7 +1935,7 @@ fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                       hir::TraitTyParamBound(..) =>
                           None,
                       hir::RegionTyParamBound(ref lifetime) =>
-                          Some(ast_region_to_region(ccx.tcx, lifetime)),
+                          Some(AstConv::ast_region_to_region(&ccx.icx(&()), lifetime)),
                   }
               })
               .collect()
@@ -1981,7 +1981,6 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                                         span: Span)
                                         -> Bounds<'tcx>
 {
-    let tcx = astconv.tcx();
     let PartitionedBounds {
         trait_bounds,
         region_bounds
@@ -1998,7 +1997,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
     }).collect();
 
     let region_bounds = region_bounds.into_iter().map(|r| {
-        ast_region_to_region(tcx, r)
+        astconv.ast_region_to_region(r)
     }).collect();
 
     trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
@@ -2040,7 +2039,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
                        .collect()
         }
         hir::RegionTyParamBound(ref lifetime) => {
-            let region = ast_region_to_region(astconv.tcx(), lifetime);
+            let region = astconv.ast_region_to_region(lifetime);
             let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region));
             vec![ty::Predicate::TypeOutlives(pred)]
         }
index 839eb8be9ace8c093ccaa115e4a174acab0e0fc4..2ad1a7c3d685f07f2797358c75a2e3e89e0c762f 100644 (file)
@@ -41,7 +41,7 @@ pub struct ElisionFailureInfo {
 /// can return `Err(())` to indicate that this is not a scope in which
 /// regions can legally be omitted.
 pub trait RegionScope {
-    fn anon_region(&self, span: Span)
+    fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>)
                     -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>;
 
     /// If an object omits any explicit lifetime bound, and none can
@@ -115,9 +115,9 @@ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
         self.base_scope.object_lifetime_default(span)
     }
 
-    fn anon_region(&self, span: Span)
+    fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
-        self.base_scope.anon_region(span)
+        self.base_scope.anon_region(span, def)
     }
 
     fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
@@ -135,7 +135,7 @@ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
 pub struct ExplicitRscope;
 
 impl RegionScope for ExplicitRscope {
-    fn anon_region(&self, _span: Span)
+    fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
         Err(None)
     }
@@ -159,7 +159,7 @@ pub fn new(v: Option<Vec<ElisionFailureInfo>>) -> UnelidableRscope {
 }
 
 impl RegionScope for UnelidableRscope {
-    fn anon_region(&self, _span: Span)
+    fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
         Err(self.0.clone())
     }
@@ -199,7 +199,7 @@ fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
         ty::ReStatic
     }
 
-    fn anon_region(&self, _span: Span)
+    fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
     {
         Ok(self.default)
@@ -221,7 +221,7 @@ pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self {
 }
 
 impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> {
-    fn anon_region(&self, span: Span)
+    fn anon_region(&self, span: Span, _: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
         if !self.tcx.sess.features.borrow().static_in_const {
             self.tcx
@@ -269,7 +269,7 @@ fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
         ty::ReStatic
     }
 
-    fn anon_region(&self, _: Span)
+    fn anon_region(&self, _: Span, _: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
     {
         let idx = self.anon_bindings.get();
@@ -315,10 +315,10 @@ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
         self.base_scope.base_object_lifetime_default(span)
     }
 
-    fn anon_region(&self, span: Span)
+    fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
     {
-        self.base_scope.anon_region(span)
+        self.base_scope.anon_region(span, def)
     }
 
     fn anon_type_scope(&self) -> Option<AnonTypeScope> {
@@ -348,10 +348,10 @@ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
         ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
     }
 
-    fn anon_region(&self, span: Span)
+    fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>)
                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
     {
-        self.base_scope.anon_region(span).map(|r| ty::fold::shift_region(r, 1))
+        self.base_scope.anon_region(span, def).map(|r| ty::fold::shift_region(r, 1))
     }
 
     fn anon_type_scope(&self) -> Option<AnonTypeScope> {