Skip to content

Commit e79bc41

Browse files
committed
Consolidate into create_substs_for_generic_args
1 parent ccef306 commit e79bc41

File tree

3 files changed

+268
-295
lines changed

3 files changed

+268
-295
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 189 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
1515
use rustc_data_structures::accumulate_vec::AccumulateVec;
1616
use rustc_data_structures::array_vec::ArrayVec;
17-
use hir::{self, GenericArg};
17+
use hir::{self, GenericArg, GenericArgs};
1818
use hir::def::Def;
1919
use hir::def_id::DefId;
2020
use middle::resolve_lifetime as rl;
2121
use namespace::Namespace;
2222
use rustc::ty::subst::{Kind, Subst, Substs};
2323
use rustc::traits;
2424
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
25-
use rustc::ty::GenericParamDefKind;
25+
use rustc::ty::{GenericParamDef, GenericParamDefKind};
2626
use rustc::ty::wf::object_region_bounds;
2727
use rustc_target::spec::abi;
2828
use std::slice;
@@ -192,6 +192,153 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
192192
substs
193193
}
194194

195+
/// Creates the relevant generic argument substitutions
196+
/// corresponding to a set of generic parameters.
197+
pub fn create_substs_for_generic_args<'a, 'b, A, P, I>(
198+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
199+
span: Span,
200+
err_if_invalid: bool,
201+
def_id: DefId,
202+
parent_substs: &[Kind<'tcx>],
203+
has_self: bool,
204+
self_ty: Option<Ty<'tcx>>,
205+
args_for_def_id: A,
206+
provided_kind: P,
207+
inferred_kind: I,
208+
) -> &'tcx Substs<'tcx> where
209+
A: Fn(DefId) -> (Option<&'b GenericArgs>, bool),
210+
P: Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
211+
I: Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>
212+
{
213+
// Collect the segments of the path: we need to substitute arguments
214+
// for parameters throughout the entire path (wherever there are
215+
// generic parameters).
216+
let mut parent_defs = tcx.generics_of(def_id);
217+
let count = parent_defs.count();
218+
let mut stack = vec![(def_id, parent_defs)];
219+
while let Some(def_id) = parent_defs.parent {
220+
parent_defs = tcx.generics_of(def_id);
221+
stack.push((def_id, parent_defs));
222+
}
223+
224+
// We manually build up the substitution, rather than using convenience
225+
// methods in subst.rs so that we can iterate over the arguments and
226+
// parameters in lock-step linearly, rather than trying to match each pair.
227+
let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
228+
AccumulateVec::Array(ArrayVec::new())
229+
} else {
230+
AccumulateVec::Heap(Vec::with_capacity(count))
231+
};
232+
233+
fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
234+
match substs {
235+
AccumulateVec::Array(ref mut arr) => arr.push(kind),
236+
AccumulateVec::Heap(ref mut vec) => vec.push(kind),
237+
}
238+
}
239+
240+
// Iterate over each segment of the path.
241+
while let Some((def_id, defs)) = stack.pop() {
242+
let mut params = defs.params.iter();
243+
let mut next_param = params.next();
244+
245+
// If we have already computed substitutions for parents, we can use those directly.
246+
while let Some(param) = next_param {
247+
if let Some(&kind) = parent_substs.get(param.index as usize) {
248+
push_kind(&mut substs, kind);
249+
next_param = params.next();
250+
} else {
251+
break;
252+
}
253+
}
254+
255+
// (Unless it's been handled in `parent_substs`) `Self` is handled first.
256+
if has_self {
257+
if let Some(param) = next_param {
258+
if param.index == 0 {
259+
if let GenericParamDefKind::Type { .. } = param.kind {
260+
push_kind(&mut substs, self_ty.map(|ty| ty.into())
261+
.unwrap_or_else(|| inferred_kind(None, param, true)));
262+
next_param = params.next();
263+
}
264+
}
265+
}
266+
}
267+
268+
// Check whether this segment takes generic arguments and the user has provided any.
269+
let (generic_args, infer_types) = args_for_def_id(def_id);
270+
if let Some(ref generic_args) = generic_args {
271+
// We're going to iterate through the generic arguments that the user
272+
// provided, matching them with the generic parameters we expect.
273+
// Mismatches can occur as a result of elided lifetimes, or for malformed
274+
// input. We try to handle both sensibly.
275+
'args: for arg in &generic_args.args {
276+
while let Some(param) = next_param {
277+
match param.kind {
278+
GenericParamDefKind::Lifetime => match arg {
279+
GenericArg::Lifetime(_) => {
280+
push_kind(&mut substs, provided_kind(param, arg));
281+
next_param = params.next();
282+
continue 'args;
283+
}
284+
GenericArg::Type(_) => {
285+
// We expected a lifetime argument, but got a type
286+
// argument. That means we're inferring the lifetimes.
287+
push_kind(&mut substs, inferred_kind(None, param, infer_types));
288+
next_param = params.next();
289+
}
290+
}
291+
GenericParamDefKind::Type { .. } => match arg {
292+
GenericArg::Type(_) => {
293+
push_kind(&mut substs, provided_kind(param, arg));
294+
next_param = params.next();
295+
continue 'args;
296+
}
297+
GenericArg::Lifetime(_) => {
298+
// We expected a type argument, but got a lifetime
299+
// argument. This is an error, but we need to handle it
300+
// gracefully so we can report sensible errors. In this
301+
// case, we're simply going to infer the remaining
302+
// arguments.
303+
if err_if_invalid {
304+
tcx.sess.delay_span_bug(span,
305+
"found a GenericArg::Lifetime where a \
306+
GenericArg::Type was expected");
307+
}
308+
break 'args;
309+
}
310+
}
311+
}
312+
}
313+
// We should never be able to reach this point with well-formed input.
314+
// Getting to this point means the user supplied more arguments than
315+
// there are parameters.
316+
if err_if_invalid {
317+
tcx.sess.delay_span_bug(span,
318+
"GenericArg did not have matching GenericParamDef");
319+
}
320+
}
321+
}
322+
323+
// If there are fewer arguments than parameters, it means
324+
// we're inferring the remaining arguments.
325+
while let Some(param) = next_param {
326+
match param.kind {
327+
GenericParamDefKind::Lifetime => {
328+
push_kind(&mut substs, inferred_kind(None, param, infer_types));
329+
}
330+
GenericParamDefKind::Type { .. } => {
331+
let kind = inferred_kind(Some(&substs), param, infer_types);
332+
push_kind(&mut substs, kind);
333+
}
334+
}
335+
next_param = params.next();
336+
}
337+
}
338+
339+
tcx.intern_substs(&substs)
340+
}
341+
195342
/// Given the type/region arguments provided to some path (along with
196343
/// an implicit Self, if this is a trait reference) returns the complete
197344
/// set of substitutions. This may involve applying defaulted type parameters.
@@ -271,95 +418,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
271418
false
272419
};
273420

274-
// Collect the segments of the path: we need to substitute arguments
275-
// for parameters throughout the entire path (wherever there are
276-
// generic parameters).
277-
let mut parent_defs = self.tcx().generics_of(def_id);
278-
let count = parent_defs.count();
279-
let mut stack = vec![(def_id, parent_defs)];
280-
while let Some(def_id) = parent_defs.parent {
281-
parent_defs = self.tcx().generics_of(def_id);
282-
stack.push((def_id, parent_defs));
283-
}
284-
285-
// We manually build up the substitution, rather than using convenience
286-
// methods in subst.rs so that we can iterate over the arguments and
287-
// parameters in lock-step linearly, rather than trying to match each pair.
288-
let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
289-
AccumulateVec::Array(ArrayVec::new())
290-
} else {
291-
AccumulateVec::Heap(Vec::with_capacity(count))
292-
};
293-
fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
294-
match substs {
295-
AccumulateVec::Array(ref mut arr) => arr.push(kind),
296-
AccumulateVec::Heap(ref mut vec) => vec.push(kind),
297-
}
298-
}
299-
300-
// Iterate over each segment of the path.
301-
while let Some((_, defs)) = stack.pop() {
302-
let mut params = defs.params.iter();
303-
let mut next_param = params.next();
304-
305-
// `Self` is handled first.
306-
if let Some(ty) = self_ty {
307-
if let Some(param) = next_param {
308-
if param.index == 0 {
309-
if let GenericParamDefKind::Type { .. } = param.kind {
310-
push_kind(&mut substs, ty.into());
311-
next_param = params.next();
421+
let substs = Self::create_substs_for_generic_args(
422+
self.tcx(),
423+
span,
424+
false,
425+
def_id,
426+
&[][..],
427+
self_ty.is_some(),
428+
self_ty,
429+
// Provide the generic args, and whether types should be inferred.
430+
|_| (Some(generic_args), infer_types),
431+
// Provide substitutions for parameters for which (valid) arguments have been provided.
432+
|param, arg| {
433+
match param.kind {
434+
GenericParamDefKind::Lifetime => match arg {
435+
GenericArg::Lifetime(lt) => {
436+
self.ast_region_to_region(&lt, Some(param)).into()
312437
}
438+
_ => unreachable!(),
313439
}
314-
}
315-
}
316-
317-
let args = &generic_args.args;
318-
'args: for arg in args {
319-
while let Some(param) = next_param {
320-
match param.kind {
321-
GenericParamDefKind::Lifetime => match arg {
322-
GenericArg::Lifetime(lt) => {
323-
push_kind(&mut substs,
324-
self.ast_region_to_region(&lt, Some(param)).into());
325-
next_param = params.next();
326-
continue 'args;
327-
}
328-
GenericArg::Type(_) => {
329-
// We expected a lifetime argument, but got a type
330-
// argument. That means we're inferring the lifetimes.
331-
push_kind(&mut substs, tcx.types.re_static.into());
332-
next_param = params.next();
333-
}
334-
}
335-
GenericParamDefKind::Type { .. } => match arg {
336-
GenericArg::Type(ty) => {
337-
push_kind(&mut substs, self.ast_ty_to_ty(&ty).into());
338-
next_param = params.next();
339-
continue 'args;
340-
}
341-
GenericArg::Lifetime(_) => {
342-
break 'args;
343-
}
344-
}
440+
GenericParamDefKind::Type { .. } => match arg {
441+
GenericArg::Type(ty) => self.ast_ty_to_ty(&ty).into(),
442+
_ => unreachable!(),
345443
}
346444
}
347-
}
348-
349-
while let Some(param) = next_param {
445+
},
446+
// Provide substitutions for parameters for which arguments are inferred.
447+
|substs, param, infer_types| {
350448
match param.kind {
351-
GenericParamDefKind::Lifetime => {
352-
push_kind(&mut substs, tcx.types.re_static.into());
353-
}
449+
GenericParamDefKind::Lifetime => tcx.types.re_static.into(),
354450
GenericParamDefKind::Type { has_default, .. } => {
355-
if infer_types {
356-
// No type parameters were provided, we can infer all.
357-
push_kind(&mut substs, if !default_needs_object_self(param) {
358-
self.ty_infer_for_def(param, span).into()
359-
} else {
360-
self.ty_infer(span).into()
361-
});
362-
} else if has_default {
451+
if !infer_types && has_default {
363452
// No type parameter provided, but a default exists.
364453

365454
// If we are converting an object type, then the
@@ -378,26 +467,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
378467
type parameters must be specified on object \
379468
types"))
380469
.emit();
381-
push_kind(&mut substs, tcx.types.err.into());
470+
tcx.types.err.into()
382471
} else {
383472
// This is a default type parameter.
384-
let kind = self.normalize_ty(
473+
self.normalize_ty(
385474
span,
386475
tcx.at(span).type_of(param.def_id)
387-
.subst_spanned(tcx, &substs, Some(span))
388-
).into();
389-
push_kind(&mut substs, kind);
476+
.subst_spanned(tcx, substs.unwrap(), Some(span))
477+
).into()
478+
}
479+
} else if infer_types {
480+
// No type parameters were provided, we can infer all.
481+
if !default_needs_object_self(param) {
482+
self.ty_infer_for_def(param, span).into()
483+
} else {
484+
self.ty_infer(span).into()
390485
}
391486
} else {
392487
// We've already errored above about the mismatch.
393-
push_kind(&mut substs, tcx.types.err.into());
488+
tcx.types.err.into()
394489
}
395490
}
396-
};
397-
next_param = params.next();
398-
}
399-
}
400-
let substs = self.tcx().intern_substs(&substs);
491+
}
492+
},
493+
);
401494

402495
let assoc_bindings = generic_args.bindings.iter().map(|binding| {
403496
ConvertedBinding {

0 commit comments

Comments
 (0)