]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/astconv.rs
rustc: always include elidable lifetimes in HIR types.
[rust.git] / src / librustc_typeck / astconv.rs
index e4529b58f03ce9eeed248127ea8b8a1b0e87f248..bc8e56e811ed28b10d9d8942771448a5570a38a2 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.map.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.map.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,
@@ -245,8 +181,8 @@ fn report_elision_failure(
         } = info;
 
         let help_name = if let Some(body) = parent {
-            let arg = &tcx.map.body(body).arguments[index];
-            format!("`{}`", tcx.map.node_to_pretty_string(arg.pat.id))
+            let arg = &tcx.hir.body(body).arguments[index];
+            format!("`{}`", tcx.hir.node_to_pretty_string(arg.pat.id))
         } else {
             format!("argument {}", index + 1)
         };
@@ -296,39 +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(match rscope.anon_regions(default_span, 1) {
-                Ok(rs) => rs[0],
-                Err(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))
+            }
 
-                    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::DefEarlyBoundRegion(index, _)) => {
+                ty::ReEarlyBound(ty::EarlyBoundRegion {
+                    index: index,
+                    name: name.unwrap()
+                })
+            }
 
-                    if let Some(params) = params {
-                        report_elision_failure(self.tcx(), &mut err, params);
-                    }
-                    err.emit();
-                    ty::ReStatic
-                }
-            })
-        };
+            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)
+                })
+
+                    // (*) -- 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`,
@@ -409,24 +404,22 @@ 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 =
-                rscope.anon_regions(span, expected_num_region_params);
-
-            if supplied_num_region_params != 0 || anon_regions.is_err() {
+        let mut reported_lifetime_count_mismatch = false;
+        let mut report_lifetime_count_mismatch = || {
+            if !reported_lifetime_count_mismatch {
+                reported_lifetime_count_mismatch = true;
+                let all_infer = lifetimes.iter().all(|lt| lt.is_elided());
+                let supplied = if all_infer { 0 } else { supplied_num_region_params };
                 report_lifetime_number_error(tcx, span,
-                                             supplied_num_region_params,
+                                             supplied,
                                              expected_num_region_params);
             }
-
-            match anon_regions {
-                Ok(anon_regions) => anon_regions,
-                Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
-            }
         };
 
+        if expected_num_region_params != supplied_num_region_params {
+            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 +445,11 @@ 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 = lifetimes.get(i);
+            self.try_opt_ast_region_to_region(rscope, span, l, Some(def)).unwrap_or_else(|_| {
+                report_lifetime_count_mismatch();
+                tcx.mk_region(ty::ReStatic)
+            })
         }, |def, substs| {
             let i = def.index as usize;
 
@@ -684,7 +681,7 @@ fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
             }
             _ => {
                 span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
-                            self.tcx().map.node_to_pretty_string(trait_ref.ref_id));
+                            self.tcx().hir.node_to_pretty_string(trait_ref.ref_id));
             }
         }
     }
@@ -1152,7 +1149,7 @@ fn one_bound_for_assoc_type<I>(&self,
                 let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| {
                     item.kind == ty::AssociatedKind::Type && item.name == assoc_name
                 })
-                .and_then(|item| self.tcx().map.span_if_local(item.def_id));
+                .and_then(|item| self.tcx().hir.span_if_local(item.def_id));
 
                 if let Some(span) = bound_span {
                     err.span_label(span, &format!("ambiguous `{}` from `{}`",
@@ -1223,7 +1220,7 @@ pub fn associated_path_def_to_ty(&self,
                 }
             }
             (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
-                let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
+                let trait_node_id = tcx.hir.as_local_node_id(trait_did).unwrap();
                 match self.find_bound_for_assoc_item(trait_node_id,
                                                      keywords::SelfType.name(),
                                                      assoc_name,
@@ -1233,7 +1230,7 @@ pub fn associated_path_def_to_ty(&self,
                 }
             }
             (&ty::TyParam(_), Def::TyParam(param_did)) => {
-                let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
+                let param_node_id = tcx.hir.as_local_node_id(param_did).unwrap();
                 let param_name = tcx.type_parameter_def(param_node_id).name;
                 match self.find_bound_for_assoc_item(param_node_id,
                                                      param_name,
@@ -1379,7 +1376,7 @@ pub fn def_to_ty(&self,
                 assert_eq!(opt_self_ty, None);
                 tcx.prohibit_type_params(&path.segments);
 
-                let node_id = tcx.map.as_local_node_id(did).unwrap();
+                let node_id = tcx.hir.as_local_node_id(did).unwrap();
                 let param = tcx.ty_param_defs.borrow().get(&node_id)
                                .map(ty::ParamTy::for_def);
                 if let Some(p) = param {
@@ -1401,11 +1398,23 @@ pub fn def_to_ty(&self,
 
                 assert_eq!(opt_self_ty, None);
                 tcx.prohibit_type_params(&path.segments);
-                let ty = tcx.item_type(def_id);
-                if let Some(free_substs) = self.get_free_substs() {
-                    ty.subst(tcx, free_substs)
+
+                // FIXME: Self type is not always computed when we are here because type parameter
+                // bounds may affect Self type and have to be converted before it.
+                let ty = if def_id.is_local() {
+                    tcx.item_types.borrow().get(&def_id).cloned()
                 } else {
-                    ty
+                    Some(tcx.item_type(def_id))
+                };
+                if let Some(ty) = ty {
+                    if let Some(free_substs) = self.get_free_substs() {
+                        ty.subst(tcx, free_substs)
+                    } else {
+                        ty
+                    }
+                } else {
+                    tcx.sess.span_err(span, "`Self` type is used before it's determined");
+                    tcx.types.err
                 }
             }
             Def::SelfTy(Some(_), None) => {
@@ -1460,7 +1469,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, Some(region), None);
                 debug!("TyRef r={:?}", r);
                 let rscope1 =
                     &ObjectLifetimeDefaultRscope::new(
@@ -1532,10 +1541,10 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 use collect::{compute_bounds, SizedByDefault};
 
                 // Create the anonymized type.
-                let def_id = tcx.map.local_def_id(ast_ty.id);
+                let def_id = tcx.hir.local_def_id(ast_ty.id);
                 if let Some(anon_scope) = rscope.anon_type_scope() {
                     let substs = anon_scope.fresh_substs(self, ast_ty.span);
-                    let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
+                    let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs);
 
                     // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
                     let bounds = compute_bounds(self, ty, bounds,
@@ -1811,7 +1820,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() {