Skip to content

Commit 8de7fd8

Browse files
Keep allocated vectors during dropck
Previously we'd frequently throw away vectors which is bad for performance
1 parent 62fba55 commit 8de7fd8

File tree

1 file changed

+50
-61
lines changed

1 file changed

+50
-61
lines changed

src/librustc_traits/dropck_outlives.rs

+50-61
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,30 @@ fn dropck_outlives<'tcx>(
8080
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
8181

8282
let cause = ObligationCause::dummy();
83+
let mut constraints = DtorckConstraint::empty();
8384
while let Some((ty, depth)) = ty_stack.pop() {
84-
let DtorckConstraint {
85-
dtorck_types,
86-
outlives,
87-
overflows,
88-
} = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?;
85+
info!("{} kinds, {} overflows, {} ty_stack",
86+
result.kinds.len(), result.overflows.len(), ty_stack.len());
87+
dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
8988

9089
// "outlives" represent types/regions that may be touched
9190
// by a destructor.
92-
result.kinds.extend(outlives);
93-
result.overflows.extend(overflows);
91+
result.kinds.extend(constraints.outlives.drain(..));
92+
result.overflows.extend(constraints.overflows.drain(..));
93+
94+
// If we have even one overflow, we should stop trying to evaluate further --
95+
// chances are, the subsequent overflows for this evaluation won't provide useful
96+
// information and will just decrease the speed at which we can emit these errors
97+
// (since we'll be printing for just that much longer for the often enormous types
98+
// that result here).
99+
if result.overflows.len() >= 1 {
100+
break;
101+
}
94102

95103
// dtorck types are "types that will get dropped but which
96104
// do not themselves define a destructor", more or less. We have
97105
// to push them onto the stack to be expanded.
98-
for ty in dtorck_types {
106+
for ty in constraints.dtorck_types.drain(..) {
99107
match infcx.at(&cause, param_env).normalize(&ty) {
100108
Ok(Normalized {
101109
value: ty,
@@ -152,25 +160,23 @@ fn dtorck_constraint_for_ty<'tcx>(
152160
for_ty: Ty<'tcx>,
153161
depth: usize,
154162
ty: Ty<'tcx>,
155-
) -> Result<DtorckConstraint<'tcx>, NoSolution> {
163+
constraints: &mut DtorckConstraint<'tcx>,
164+
) -> Result<(), NoSolution> {
156165
debug!(
157166
"dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
158167
span, for_ty, depth, ty
159168
);
160169

161170
if depth >= *tcx.sess.recursion_limit.get() {
162-
return Ok(DtorckConstraint {
163-
outlives: vec![],
164-
dtorck_types: vec![],
165-
overflows: vec![ty],
166-
});
171+
constraints.overflows.push(ty);
172+
return Ok(());
167173
}
168174

169175
if tcx.trivial_dropck_outlives(ty) {
170-
return Ok(DtorckConstraint::empty());
176+
return Ok(());
171177
}
172178

173-
let result = match ty.kind {
179+
match ty.kind {
174180
ty::Bool
175181
| ty::Char
176182
| ty::Int(_)
@@ -185,22 +191,20 @@ fn dtorck_constraint_for_ty<'tcx>(
185191
| ty::FnPtr(_)
186192
| ty::GeneratorWitness(..) => {
187193
// these types never have a destructor
188-
Ok(DtorckConstraint::empty())
189194
}
190195

191196
ty::Array(ety, _) | ty::Slice(ety) => {
192197
// single-element containers, behave like their element
193-
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
198+
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)?;
194199
}
195200

196-
ty::Tuple(tys) => tys.iter()
197-
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty.expect_ty()))
198-
.collect(),
201+
ty::Tuple(tys) => for ty in tys.iter() {
202+
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty.expect_ty(), constraints)?;
203+
},
199204

200-
ty::Closure(def_id, substs) => substs.as_closure()
201-
.upvar_tys(def_id, tcx)
202-
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
203-
.collect(),
205+
ty::Closure(def_id, substs) => for ty in substs.as_closure().upvar_tys(def_id, tcx) {
206+
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
207+
}
204208

205209
ty::Generator(def_id, substs, _movability) => {
206210
// rust-lang/rust#49918: types can be constructed, stored
@@ -226,17 +230,8 @@ fn dtorck_constraint_for_ty<'tcx>(
226230
// derived from lifetimes attached to the upvars, and we
227231
// *do* incorporate the upvars here.
228232

229-
let constraint = DtorckConstraint {
230-
outlives: substs.as_generator().upvar_tys(def_id, tcx).map(|t| t.into()).collect(),
231-
dtorck_types: vec![],
232-
overflows: vec![],
233-
};
234-
debug!(
235-
"dtorck_constraint: generator {:?} => {:?}",
236-
def_id, constraint
237-
);
238-
239-
Ok(constraint)
233+
constraints.outlives.extend(substs.as_generator().upvar_tys(def_id, tcx)
234+
.map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }));
240235
}
241236

242237
ty::Adt(def, substs) => {
@@ -245,41 +240,34 @@ fn dtorck_constraint_for_ty<'tcx>(
245240
outlives,
246241
overflows,
247242
} = tcx.at(span).adt_dtorck_constraint(def.did)?;
248-
Ok(DtorckConstraint {
249-
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
250-
// there, but that needs some way to handle cycles.
251-
dtorck_types: dtorck_types.subst(tcx, substs),
252-
outlives: outlives.subst(tcx, substs),
253-
overflows: overflows.subst(tcx, substs),
254-
})
243+
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
244+
// there, but that needs some way to handle cycles.
245+
constraints.dtorck_types.extend(dtorck_types.subst(tcx, substs));
246+
constraints.outlives.extend(outlives.subst(tcx, substs));
247+
constraints.overflows.extend(overflows.subst(tcx, substs));
255248
}
256249

257250
// Objects must be alive in order for their destructor
258251
// to be called.
259-
ty::Dynamic(..) => Ok(DtorckConstraint {
260-
outlives: vec![ty.into()],
261-
dtorck_types: vec![],
262-
overflows: vec![],
263-
}),
252+
ty::Dynamic(..) => {
253+
constraints.outlives.push(ty.into());
254+
},
264255

265256
// Types that can't be resolved. Pass them forward.
266-
ty::Projection(..) | ty::Opaque(..) | ty::Param(..) => Ok(DtorckConstraint {
267-
outlives: vec![],
268-
dtorck_types: vec![ty],
269-
overflows: vec![],
270-
}),
257+
ty::Projection(..) | ty::Opaque(..) | ty::Param(..) => {
258+
constraints.dtorck_types.push(ty);
259+
},
271260

272261
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
273262

274263
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => {
275264
// By the time this code runs, all type variables ought to
276265
// be fully resolved.
277-
Err(NoSolution)
266+
return Err(NoSolution)
278267
}
279-
};
268+
}
280269

281-
debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
282-
result
270+
Ok(())
283271
}
284272

285273
/// Calculates the dtorck constraint for a type.
@@ -305,10 +293,11 @@ crate fn adt_dtorck_constraint(
305293
return Ok(result);
306294
}
307295

308-
let mut result = def.all_fields()
309-
.map(|field| tcx.type_of(field.did))
310-
.map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty))
311-
.collect::<Result<DtorckConstraint<'_>, NoSolution>>()?;
296+
let mut result = DtorckConstraint::empty();
297+
for field in def.all_fields() {
298+
let fty = tcx.type_of(field.did);
299+
dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?;
300+
}
312301
result.outlives.extend(tcx.destructor_constraints(def));
313302
dedup_dtorck_constraint(&mut result);
314303

0 commit comments

Comments
 (0)