Skip to content

Commit c780fe4

Browse files
committed
Clean create_substs_for_generic_args
1 parent 9155a9d commit c780fe4

File tree

1 file changed

+136
-78
lines changed

1 file changed

+136
-78
lines changed

compiler/rustc_typeck/src/astconv/generics.rs

+136-78
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
144144
stack.push((def_id, parent_defs));
145145
}
146146

147+
let report_error =
148+
|mut args: std::iter::Peekable<std::slice::Iter<'_, GenericArg<'_>>>,
149+
mut params: std::iter::Peekable<std::slice::Iter<'_, GenericParamDef>>| {
150+
// redo some work to compute the lifetime inferred.
151+
let mut force_infer_lt = None;
152+
loop {
153+
match (args.peek(), params.peek()) {
154+
(Some(&a), Some(&p)) => match (a, &p.kind) {
155+
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime)
156+
| (GenericArg::Type(_), GenericParamDefKind::Type { .. })
157+
| (GenericArg::Const(_), GenericParamDefKind::Const) => {
158+
params.next();
159+
args.next();
160+
}
161+
(
162+
GenericArg::Type(_) | GenericArg::Const(_),
163+
GenericParamDefKind::Lifetime,
164+
) => {
165+
force_infer_lt = Some((a, p));
166+
params.next();
167+
}
168+
(GenericArg::Lifetime(_), _)
169+
if arg_count.explicit_late_bound == ExplicitLateBound::Yes =>
170+
{
171+
args.next();
172+
}
173+
(_, _) => {}
174+
},
175+
(None, Some(_)) => {
176+
params.next();
177+
}
178+
(Some(_) | None, None) => break,
179+
}
180+
}
181+
let (provided_arg, param) =
182+
force_infer_lt.expect("lifetimes ought to have been inferred");
183+
Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
184+
};
185+
147186
// We manually build up the substitution, rather than using convenience
148187
// methods in `subst.rs`, so that we can iterate over the arguments and
149188
// parameters in lock-step linearly, instead of trying to match each pair.
150189
let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
151190
// Iterate over each segment of the path.
152-
while let Some((def_id, defs)) = stack.pop() {
191+
'outer: while let Some((def_id, defs)) = stack.pop() {
153192
let mut params = defs.params.iter().peekable();
154193

194+
let mut skip = 0;
155195
// If we have already computed substitutions for parents, we can use those directly.
156196
while let Some(&param) = params.peek() {
157197
if let Some(&kind) = parent_substs.get(param.index as usize) {
158198
substs.push(kind);
159199
params.next();
200+
skip += 1;
160201
} else {
161202
break;
162203
}
@@ -173,22 +214,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
173214
.unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
174215
);
175216
params.next();
217+
skip += 1;
176218
}
177219
}
178220
}
179221
}
180222

181223
// Check whether this segment takes generic arguments and the user has provided any.
182224
let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
225+
let generic_args = match generic_args {
226+
Some(ga) => ga,
227+
None => {
228+
substs.reserve(params.len());
229+
for p in params {
230+
substs.push(ctx.inferred_kind(Some(&substs), p, infer_args));
231+
}
232+
continue 'outer;
233+
}
234+
};
183235

184-
let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter());
185-
let mut args = args_iter.clone().peekable();
186-
187-
// If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
188-
// If we later encounter a lifetime, we know that the arguments were provided in the
189-
// wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
190-
// inferred, so we can use it for diagnostics later.
191-
let mut force_infer_lt = None;
236+
let mut args = generic_args.args.iter().peekable();
192237

193238
loop {
194239
// We're going to iterate through the generic arguments that the user
@@ -213,7 +258,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
213258
// We expected a lifetime argument, but got a type or const
214259
// argument. That means we're inferring the lifetimes.
215260
substs.push(ctx.inferred_kind(None, param, infer_args));
216-
force_infer_lt = Some((arg, param));
217261
params.next();
218262
}
219263
(GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
@@ -231,73 +275,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
231275
if arg_count.correct.is_ok()
232276
&& arg_count.explicit_late_bound == ExplicitLateBound::No
233277
{
234-
// We're going to iterate over the parameters to sort them out, and
235-
// show that order to the user as a possible order for the parameters
236-
let mut param_types_present = defs
237-
.params
238-
.clone()
239-
.into_iter()
240-
.map(|param| {
241-
(
242-
match param.kind {
243-
GenericParamDefKind::Lifetime => {
244-
ParamKindOrd::Lifetime
245-
}
246-
GenericParamDefKind::Type { .. } => {
247-
ParamKindOrd::Type
248-
}
249-
GenericParamDefKind::Const => {
250-
ParamKindOrd::Const {
251-
unordered: tcx
252-
.features()
253-
.const_generics,
254-
}
255-
}
256-
},
257-
param,
258-
)
259-
})
260-
.collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
261-
param_types_present.sort_by_key(|(ord, _)| *ord);
262-
let (mut param_types_present, ordered_params): (
263-
Vec<ParamKindOrd>,
264-
Vec<GenericParamDef>,
265-
) = param_types_present.into_iter().unzip();
266-
param_types_present.dedup();
267-
268-
Self::generic_arg_mismatch_err(
278+
Self::generic_arg_mismatch_errs(
269279
tcx,
280+
defs,
281+
generic_args.args.iter(),
270282
arg,
271283
param,
272-
!args_iter.clone().is_sorted_by_key(|arg| match arg {
273-
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
274-
GenericArg::Type(_) => ParamKindOrd::Type,
275-
GenericArg::Const(_) => ParamKindOrd::Const {
276-
unordered: tcx.features().const_generics,
277-
},
278-
}),
279-
Some(&format!(
280-
"reorder the arguments: {}: `<{}>`",
281-
param_types_present
282-
.into_iter()
283-
.map(|ord| format!("{}s", ord.to_string()))
284-
.collect::<Vec<String>>()
285-
.join(", then "),
286-
ordered_params
287-
.into_iter()
288-
.filter_map(|param| {
289-
if param.name == kw::SelfUpper {
290-
None
291-
} else {
292-
Some(param.name.to_string())
293-
}
294-
})
295-
.collect::<Vec<String>>()
296-
.join(", ")
297-
)),
298-
);
284+
)
299285
}
300-
301286
// We've reported the error, but we want to make sure that this
302287
// problem doesn't bubble down and create additional, irrelevant
303288
// errors. In this case, we're simply going to ignore the argument
@@ -323,11 +308,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
323308
if arg_count.correct.is_ok()
324309
&& arg_count.explicit_late_bound == ExplicitLateBound::No
325310
{
326-
let kind = arg.descr();
327-
assert_eq!(kind, "lifetime");
328-
let (provided_arg, param) =
329-
force_infer_lt.expect("lifetimes ought to have been inferred");
330-
Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
311+
assert!(matches!(arg, GenericArg::Lifetime(_)));
312+
// If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
313+
// If we later encounter a lifetime, we know that the arguments were provided in the
314+
// wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
315+
// inferred, so we can use it for diagnostics later.
316+
report_error(
317+
generic_args.args.iter().peekable(),
318+
defs.params[skip..].iter().peekable(),
319+
)
331320
}
332321

333322
break;
@@ -338,6 +327,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
338327
// we're inferring the remaining arguments.
339328
substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
340329
params.next();
330+
substs.reserve(params.len());
331+
for p in params {
332+
substs.push(ctx.inferred_kind(Some(&substs), p, infer_args));
333+
}
334+
break;
341335
}
342336

343337
(None, None) => break,
@@ -348,6 +342,70 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
348342
tcx.intern_substs(&substs)
349343
}
350344

345+
fn generic_arg_mismatch_errs<'a>(
346+
tcx: TyCtxt<'_>,
347+
defs: &rustc_middle::ty::Generics,
348+
args_iter: impl Iterator<Item = &'a GenericArg<'a>>,
349+
arg: &GenericArg<'_>,
350+
param: &GenericParamDef,
351+
) {
352+
// We're going to iterate over the parameters to sort them out, and
353+
// show that order to the user as a possible order for the parameters
354+
let mut param_types_present = defs
355+
.params
356+
.clone()
357+
.into_iter()
358+
.map(|param| {
359+
(
360+
match param.kind {
361+
GenericParamDefKind::Lifetime => ParamKindOrd::Lifetime,
362+
GenericParamDefKind::Type { .. } => ParamKindOrd::Type,
363+
GenericParamDefKind::Const => {
364+
ParamKindOrd::Const { unordered: tcx.features().const_generics }
365+
}
366+
},
367+
param,
368+
)
369+
})
370+
.collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
371+
param_types_present.sort_by_key(|(ord, _)| *ord);
372+
let (mut param_types_present, ordered_params): (Vec<ParamKindOrd>, Vec<GenericParamDef>) =
373+
param_types_present.into_iter().unzip();
374+
param_types_present.dedup();
375+
376+
Self::generic_arg_mismatch_err(
377+
tcx,
378+
arg,
379+
param,
380+
!args_iter.is_sorted_by_key(|arg| match arg {
381+
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
382+
GenericArg::Type(_) => ParamKindOrd::Type,
383+
GenericArg::Const(_) => {
384+
ParamKindOrd::Const { unordered: tcx.features().const_generics }
385+
}
386+
}),
387+
Some(&format!(
388+
"reorder the arguments: {}: `<{}>`",
389+
param_types_present
390+
.into_iter()
391+
.map(|ord| format!("{}s", ord.to_string()))
392+
.collect::<Vec<String>>()
393+
.join(", then "),
394+
ordered_params
395+
.into_iter()
396+
.filter_map(|param| {
397+
if param.name == kw::SelfUpper {
398+
None
399+
} else {
400+
Some(param.name.to_string())
401+
}
402+
})
403+
.collect::<Vec<String>>()
404+
.join(", ")
405+
)),
406+
);
407+
}
408+
351409
/// Checks that the correct number of generic arguments have been provided.
352410
/// Used specifically for function calls.
353411
pub fn check_generic_arg_count_for_call(

0 commit comments

Comments
 (0)