From f79feba2053c78425b6490c8587359846fa6648f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 4 Jan 2017 23:23:11 +0200 Subject: [PATCH] rustc_typeck: pass all lifetimes through AstConv::opt_ast_region_to_region. --- src/librustc_typeck/astconv.rs | 200 +++++++++++++++---------------- src/librustc_typeck/check/mod.rs | 16 +-- src/librustc_typeck/collect.rs | 19 ++- src/librustc_typeck/rscope.rs | 24 ++-- 4 files changed, 129 insertions(+), 130 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 166178d6c29..0a836a8ba22 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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) -> &'tcx ty::Region + opt_lifetime: Option<&hir::Lifetime>, + def: Option<&ty::RegionParameterDef>) + -> Result<&'tcx ty::Region, Option>> { - 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::, _>>(); - - 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() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e76267f32c..e7544c10be3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>> { - 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; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1fd03b33a76..f954d2a5d61 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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 ¶m.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, ®ion_pred.lifetime); + let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), ®ion_pred.lifetime); for bound in ®ion_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)] } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 839eb8be9ac..2ad1a7c3d68 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -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>>; /// If an object omits any explicit lifetime bound, and none can @@ -115,9 +115,9 @@ fn object_lifetime_default(&self, span: Span) -> Option { self.base_scope.object_lifetime_default(span) } - fn anon_region(&self, span: Span) + fn anon_region(&self, span: Span, def: Option<&ty::RegionParameterDef>) -> Result>> { - 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 { pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { - fn anon_region(&self, _span: Span) + fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { Err(None) } @@ -159,7 +159,7 @@ pub fn new(v: Option>) -> UnelidableRscope { } impl RegionScope for UnelidableRscope { - fn anon_region(&self, _span: Span) + fn anon_region(&self, _span: Span, _: Option<&ty::RegionParameterDef>) -> Result>> { 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>> { 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>> { 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>> { 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>> { - self.base_scope.anon_region(span) + self.base_scope.anon_region(span, def) } fn anon_type_scope(&self) -> Option { @@ -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>> { - 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 { -- 2.44.0