Skip to content

Commit

Permalink
Auto merge of #37014 - nnethercote:avoid-pat_to_string, r=arielb1
Browse files Browse the repository at this point in the history
Avoid some `pat_to_string` calls.

`ty_of_method_or_bare_fn` currently calls `pat_to_string` even when it
doesn't need to. Fixing this avoids hundreds of large allocations (e.g.
171,600 bytes, in `mk_printer`) in several of rustc-benchmarks.
  • Loading branch information
bors committed Oct 8, 2016
2 parents 49be16e + e5ffade commit 195dbfa
Showing 1 changed file with 26 additions and 9 deletions.
35 changes: 26 additions & 9 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,15 +561,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
/// Returns the appropriate lifetime to use for any output lifetimes
/// (if one exists) and a vector of the (pattern, number of lifetimes)
/// corresponding to each input type/pattern.
fn find_implied_output_region(&self,
input_tys: &[Ty<'tcx>],
input_pats: Vec<String>) -> ElidedLifetime
fn find_implied_output_region<F>(&self,
input_tys: &[Ty<'tcx>],
input_pats: F) -> ElidedLifetime
where F: FnOnce() -> Vec<String>
{
let tcx = self.tcx();
let mut lifetimes_for_params = Vec::new();
let mut possible_implied_output_region = None;

for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
for input_type in input_tys.iter() {
let mut regions = FnvHashSet();
let have_bound_regions = tcx.collect_regions(input_type, &mut regions);

Expand All @@ -583,8 +584,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
possible_implied_output_region = regions.iter().cloned().next();
}

// Use a placeholder for `name` because computing it can be
// expensive and we don't want to do it until we know it's
// necessary.
lifetimes_for_params.push(ElisionFailureInfo {
name: input_pat,
name: String::new(),
lifetime_count: regions.len(),
have_bound_regions: have_bound_regions
});
Expand All @@ -593,6 +597,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
Ok(*possible_implied_output_region.unwrap())
} else {
// Fill in the expensive `name` fields now that we know they're
// needed.
for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats()) {
info.name = input_pat;
}
Err(Some(lifetimes_for_params))
}
}
Expand Down Expand Up @@ -629,7 +638,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let inputs: Vec<_> = data.inputs.iter().map(|a_t| {
self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
}).collect();
let input_params = vec![String::new(); inputs.len()];
let inputs_len = inputs.len();
let input_params = || vec![String::new(); inputs_len];
let implied_output_region = self.find_implied_output_region(&inputs, input_params);

let (output, output_span) = match data.output {
Expand Down Expand Up @@ -1861,15 +1871,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
};
let arg_tys: Vec<Ty> =
arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
let arg_pats: Vec<String> =
arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect();

// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
let implied_output_region = match explicit_self_category {
ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region),
_ => self.find_implied_output_region(&arg_tys, arg_pats)
_ => {
// `pat_to_string` is expensive and
// `find_implied_output_region` only needs its result when
// there's an error. So we wrap it in a closure to avoid
// calling it until necessary.
let arg_pats = || {
arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect()
};
self.find_implied_output_region(&arg_tys, arg_pats)
}
};

let output_ty = match decl.output {
Expand Down

0 comments on commit 195dbfa

Please sign in to comment.