1
1
//! Code shared by trait and projection goals for candidate assembly.
2
2
3
+ use derivative:: Derivative ;
3
4
use rustc_hir:: def_id:: DefId ;
4
5
use rustc_hir:: LangItem ;
5
6
use rustc_infer:: infer:: InferCtxt ;
6
7
use rustc_infer:: traits:: query:: NoSolution ;
7
8
use rustc_middle:: bug;
8
9
use rustc_middle:: traits:: solve:: inspect:: ProbeKind ;
9
- use rustc_middle:: traits:: solve:: {
10
- CandidateSource , CanonicalResponse , Certainty , Goal , MaybeCause , QueryResult ,
11
- } ;
10
+ use rustc_middle:: traits:: solve:: { Certainty , Goal , MaybeCause , QueryResult } ;
12
11
use rustc_middle:: traits:: BuiltinImplSource ;
13
12
use rustc_middle:: ty:: fast_reject:: { SimplifiedType , TreatParams } ;
14
13
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
15
14
use rustc_middle:: ty:: { fast_reject, TypeFoldable } ;
16
15
use rustc_middle:: ty:: { TypeVisitableExt , Upcast } ;
17
16
use rustc_span:: { ErrorGuaranteed , DUMMY_SP } ;
18
- use std:: fmt:: Debug ;
17
+ use rustc_type_ir:: solve:: { CandidateSource , CanonicalResponse } ;
18
+ use rustc_type_ir:: Interner ;
19
19
20
20
use crate :: solve:: GoalSource ;
21
21
use crate :: solve:: { EvalCtxt , SolverMode } ;
@@ -26,10 +26,11 @@ pub(super) mod structural_traits;
26
26
///
27
27
/// It consists of both the `source`, which describes how that goal would be proven,
28
28
/// and the `result` when using the given `source`.
29
- #[ derive( Debug , Clone ) ]
30
- pub ( super ) struct Candidate < ' tcx > {
31
- pub ( super ) source : CandidateSource < ' tcx > ,
32
- pub ( super ) result : CanonicalResponse < ' tcx > ,
29
+ #[ derive( Derivative ) ]
30
+ #[ derivative( Debug ( bound = "" ) , Clone ( bound = "" ) ) ]
31
+ pub ( super ) struct Candidate < I : Interner > {
32
+ pub ( super ) source : CandidateSource < I > ,
33
+ pub ( super ) result : CanonicalResponse < I > ,
33
34
}
34
35
35
36
/// Methods used to assemble candidates for either trait or projection goals.
@@ -50,22 +51,22 @@ pub(super) trait GoalKind<'tcx>:
50
51
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
51
52
fn probe_and_match_goal_against_assumption (
52
53
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
53
- source : CandidateSource < ' tcx > ,
54
+ source : CandidateSource < TyCtxt < ' tcx > > ,
54
55
goal : Goal < ' tcx , Self > ,
55
56
assumption : ty:: Clause < ' tcx > ,
56
57
then : impl FnOnce ( & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ) -> QueryResult < ' tcx > ,
57
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
58
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
58
59
59
60
/// Consider a clause, which consists of a "assumption" and some "requirements",
60
61
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
61
62
/// goal by equating it with the assumption.
62
63
fn probe_and_consider_implied_clause (
63
64
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
64
- parent_source : CandidateSource < ' tcx > ,
65
+ parent_source : CandidateSource < TyCtxt < ' tcx > > ,
65
66
goal : Goal < ' tcx , Self > ,
66
67
assumption : ty:: Clause < ' tcx > ,
67
68
requirements : impl IntoIterator < Item = ( GoalSource , Goal < ' tcx , ty:: Predicate < ' tcx > > ) > ,
68
- ) -> Result < Candidate < ' tcx > , NoSolution > {
69
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > {
69
70
Self :: probe_and_match_goal_against_assumption ( ecx, parent_source, goal, assumption, |ecx| {
70
71
for ( nested_source, goal) in requirements {
71
72
ecx. add_goal ( nested_source, goal) ;
@@ -79,10 +80,10 @@ pub(super) trait GoalKind<'tcx>:
79
80
/// since they're not implied by the well-formedness of the object type.
80
81
fn probe_and_consider_object_bound_candidate (
81
82
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
82
- source : CandidateSource < ' tcx > ,
83
+ source : CandidateSource < TyCtxt < ' tcx > > ,
83
84
goal : Goal < ' tcx , Self > ,
84
85
assumption : ty:: Clause < ' tcx > ,
85
- ) -> Result < Candidate < ' tcx > , NoSolution > {
86
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > {
86
87
Self :: probe_and_match_goal_against_assumption ( ecx, source, goal, assumption, |ecx| {
87
88
let tcx = ecx. interner ( ) ;
88
89
let ty:: Dynamic ( bounds, _, _) = * goal. predicate . self_ty ( ) . kind ( ) else {
@@ -105,7 +106,7 @@ pub(super) trait GoalKind<'tcx>:
105
106
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
106
107
goal : Goal < ' tcx , Self > ,
107
108
impl_def_id : DefId ,
108
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
109
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
109
110
110
111
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
111
112
/// errors but still want to emit errors for other trait goals. We have some special
@@ -116,7 +117,7 @@ pub(super) trait GoalKind<'tcx>:
116
117
fn consider_error_guaranteed_candidate (
117
118
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
118
119
guar : ErrorGuaranteed ,
119
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
120
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
120
121
121
122
/// A type implements an `auto trait` if its components do as well.
122
123
///
@@ -125,13 +126,13 @@ pub(super) trait GoalKind<'tcx>:
125
126
fn consider_auto_trait_candidate (
126
127
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
127
128
goal : Goal < ' tcx , Self > ,
128
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
129
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
129
130
130
131
/// A trait alias holds if the RHS traits and `where` clauses hold.
131
132
fn consider_trait_alias_candidate (
132
133
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
133
134
goal : Goal < ' tcx , Self > ,
134
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
135
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
135
136
136
137
/// A type is `Sized` if its tail component is `Sized`.
137
138
///
@@ -140,7 +141,7 @@ pub(super) trait GoalKind<'tcx>:
140
141
fn consider_builtin_sized_candidate (
141
142
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
142
143
goal : Goal < ' tcx , Self > ,
143
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
144
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
144
145
145
146
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
146
147
///
@@ -149,50 +150,50 @@ pub(super) trait GoalKind<'tcx>:
149
150
fn consider_builtin_copy_clone_candidate (
150
151
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
151
152
goal : Goal < ' tcx , Self > ,
152
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
153
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
153
154
154
155
/// A type is `PointerLike` if we can compute its layout, and that layout
155
156
/// matches the layout of `usize`.
156
157
fn consider_builtin_pointer_like_candidate (
157
158
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
158
159
goal : Goal < ' tcx , Self > ,
159
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
160
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
160
161
161
162
/// A type is a `FnPtr` if it is of `FnPtr` type.
162
163
fn consider_builtin_fn_ptr_trait_candidate (
163
164
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
164
165
goal : Goal < ' tcx , Self > ,
165
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
166
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
166
167
167
168
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
168
169
/// family of traits where `A` is given by the signature of the type.
169
170
fn consider_builtin_fn_trait_candidates (
170
171
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
171
172
goal : Goal < ' tcx , Self > ,
172
173
kind : ty:: ClosureKind ,
173
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
174
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
174
175
175
176
/// An async closure is known to implement the `AsyncFn<A>` family of traits
176
177
/// where `A` is given by the signature of the type.
177
178
fn consider_builtin_async_fn_trait_candidates (
178
179
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
179
180
goal : Goal < ' tcx , Self > ,
180
181
kind : ty:: ClosureKind ,
181
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
182
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
182
183
183
184
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
184
185
/// is used internally to delay computation for async closures until after
185
186
/// upvar analysis is performed in HIR typeck.
186
187
fn consider_builtin_async_fn_kind_helper_candidate (
187
188
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
188
189
goal : Goal < ' tcx , Self > ,
189
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
190
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
190
191
191
192
/// `Tuple` is implemented if the `Self` type is a tuple.
192
193
fn consider_builtin_tuple_candidate (
193
194
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
194
195
goal : Goal < ' tcx , Self > ,
195
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
196
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
196
197
197
198
/// `Pointee` is always implemented.
198
199
///
@@ -202,63 +203,63 @@ pub(super) trait GoalKind<'tcx>:
202
203
fn consider_builtin_pointee_candidate (
203
204
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
204
205
goal : Goal < ' tcx , Self > ,
205
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
206
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
206
207
207
208
/// A coroutine (that comes from an `async` desugaring) is known to implement
208
209
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
209
210
/// that was computed during type-checking.
210
211
fn consider_builtin_future_candidate (
211
212
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
212
213
goal : Goal < ' tcx , Self > ,
213
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
214
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
214
215
215
216
/// A coroutine (that comes from a `gen` desugaring) is known to implement
216
217
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
217
218
/// that was computed during type-checking.
218
219
fn consider_builtin_iterator_candidate (
219
220
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
220
221
goal : Goal < ' tcx , Self > ,
221
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
222
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
222
223
223
224
/// A coroutine (that comes from a `gen` desugaring) is known to implement
224
225
/// `FusedIterator`
225
226
fn consider_builtin_fused_iterator_candidate (
226
227
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
227
228
goal : Goal < ' tcx , Self > ,
228
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
229
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
229
230
230
231
fn consider_builtin_async_iterator_candidate (
231
232
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
232
233
goal : Goal < ' tcx , Self > ,
233
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
234
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
234
235
235
236
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
236
237
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
237
238
/// and return types of the coroutine computed during type-checking.
238
239
fn consider_builtin_coroutine_candidate (
239
240
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
240
241
goal : Goal < ' tcx , Self > ,
241
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
242
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
242
243
243
244
fn consider_builtin_discriminant_kind_candidate (
244
245
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
245
246
goal : Goal < ' tcx , Self > ,
246
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
247
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
247
248
248
249
fn consider_builtin_async_destruct_candidate (
249
250
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
250
251
goal : Goal < ' tcx , Self > ,
251
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
252
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
252
253
253
254
fn consider_builtin_destruct_candidate (
254
255
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
255
256
goal : Goal < ' tcx , Self > ,
256
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
257
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
257
258
258
259
fn consider_builtin_transmute_candidate (
259
260
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
260
261
goal : Goal < ' tcx , Self > ,
261
- ) -> Result < Candidate < ' tcx > , NoSolution > ;
262
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > ;
262
263
263
264
/// Consider (possibly several) candidates to upcast or unsize a type to another
264
265
/// type, excluding the coercion of a sized type into a `dyn Trait`.
@@ -270,14 +271,14 @@ pub(super) trait GoalKind<'tcx>:
270
271
fn consider_structural_builtin_unsize_candidates (
271
272
ecx : & mut EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
272
273
goal : Goal < ' tcx , Self > ,
273
- ) -> Vec < Candidate < ' tcx > > ;
274
+ ) -> Vec < Candidate < TyCtxt < ' tcx > > > ;
274
275
}
275
276
276
277
impl < ' tcx > EvalCtxt < ' _ , InferCtxt < ' tcx > > {
277
278
pub ( super ) fn assemble_and_evaluate_candidates < G : GoalKind < ' tcx > > (
278
279
& mut self ,
279
280
goal : Goal < ' tcx , G > ,
280
- ) -> Vec < Candidate < ' tcx > > {
281
+ ) -> Vec < Candidate < TyCtxt < ' tcx > > > {
281
282
let Ok ( normalized_self_ty) =
282
283
self . structurally_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
283
284
else {
@@ -324,7 +325,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
324
325
pub ( super ) fn forced_ambiguity (
325
326
& mut self ,
326
327
cause : MaybeCause ,
327
- ) -> Result < Candidate < ' tcx > , NoSolution > {
328
+ ) -> Result < Candidate < TyCtxt < ' tcx > > , NoSolution > {
328
329
// This may fail if `try_evaluate_added_goals` overflows because it
329
330
// fails to reach a fixpoint but ends up getting an error after
330
331
// running for some additional step.
@@ -340,7 +341,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
340
341
fn assemble_non_blanket_impl_candidates < G : GoalKind < ' tcx > > (
341
342
& mut self ,
342
343
goal : Goal < ' tcx , G > ,
343
- candidates : & mut Vec < Candidate < ' tcx > > ,
344
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
344
345
) {
345
346
let tcx = self . interner ( ) ;
346
347
let self_ty = goal. predicate . self_ty ( ) ;
@@ -456,7 +457,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
456
457
fn assemble_blanket_impl_candidates < G : GoalKind < ' tcx > > (
457
458
& mut self ,
458
459
goal : Goal < ' tcx , G > ,
459
- candidates : & mut Vec < Candidate < ' tcx > > ,
460
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
460
461
) {
461
462
let tcx = self . interner ( ) ;
462
463
let trait_impls = tcx. trait_impls_of ( goal. predicate . trait_def_id ( tcx) ) ;
@@ -479,7 +480,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
479
480
fn assemble_builtin_impl_candidates < G : GoalKind < ' tcx > > (
480
481
& mut self ,
481
482
goal : Goal < ' tcx , G > ,
482
- candidates : & mut Vec < Candidate < ' tcx > > ,
483
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
483
484
) {
484
485
let tcx = self . interner ( ) ;
485
486
let trait_def_id = goal. predicate . trait_def_id ( tcx) ;
@@ -552,7 +553,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
552
553
fn assemble_param_env_candidates < G : GoalKind < ' tcx > > (
553
554
& mut self ,
554
555
goal : Goal < ' tcx , G > ,
555
- candidates : & mut Vec < Candidate < ' tcx > > ,
556
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
556
557
) {
557
558
for ( i, assumption) in goal. param_env . caller_bounds ( ) . iter ( ) . enumerate ( ) {
558
559
candidates. extend ( G :: probe_and_consider_implied_clause (
@@ -569,7 +570,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
569
570
fn assemble_alias_bound_candidates < G : GoalKind < ' tcx > > (
570
571
& mut self ,
571
572
goal : Goal < ' tcx , G > ,
572
- candidates : & mut Vec < Candidate < ' tcx > > ,
573
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
573
574
) {
574
575
let ( ) = self . probe ( |_| ProbeKind :: NormalizedSelfTyAssembly ) . enter ( |ecx| {
575
576
ecx. assemble_alias_bound_candidates_recur ( goal. predicate . self_ty ( ) , goal, candidates) ;
@@ -589,7 +590,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
589
590
& mut self ,
590
591
self_ty : Ty < ' tcx > ,
591
592
goal : Goal < ' tcx , G > ,
592
- candidates : & mut Vec < Candidate < ' tcx > > ,
593
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
593
594
) {
594
595
let ( kind, alias_ty) = match * self_ty. kind ( ) {
595
596
ty:: Bool
@@ -673,7 +674,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
673
674
fn assemble_object_bound_candidates < G : GoalKind < ' tcx > > (
674
675
& mut self ,
675
676
goal : Goal < ' tcx , G > ,
676
- candidates : & mut Vec < Candidate < ' tcx > > ,
677
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
677
678
) {
678
679
let tcx = self . interner ( ) ;
679
680
if !tcx. trait_def ( goal. predicate . trait_def_id ( tcx) ) . implement_via_object {
@@ -764,7 +765,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
764
765
fn assemble_coherence_unknowable_candidates < G : GoalKind < ' tcx > > (
765
766
& mut self ,
766
767
goal : Goal < ' tcx , G > ,
767
- candidates : & mut Vec < Candidate < ' tcx > > ,
768
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
768
769
) {
769
770
let tcx = self . interner ( ) ;
770
771
@@ -793,7 +794,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
793
794
fn discard_impls_shadowed_by_env < G : GoalKind < ' tcx > > (
794
795
& mut self ,
795
796
goal : Goal < ' tcx , G > ,
796
- candidates : & mut Vec < Candidate < ' tcx > > ,
797
+ candidates : & mut Vec < Candidate < TyCtxt < ' tcx > > > ,
797
798
) {
798
799
let tcx = self . interner ( ) ;
799
800
let trait_goal: Goal < ' tcx , ty:: TraitPredicate < ' tcx > > =
@@ -841,7 +842,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
841
842
#[ instrument( level = "debug" , skip( self ) , ret) ]
842
843
pub ( super ) fn merge_candidates (
843
844
& mut self ,
844
- candidates : Vec < Candidate < ' tcx > > ,
845
+ candidates : Vec < Candidate < TyCtxt < ' tcx > > > ,
845
846
) -> QueryResult < ' tcx > {
846
847
// First try merging all candidates. This is complete and fully sound.
847
848
let responses = candidates. iter ( ) . map ( |c| c. result ) . collect :: < Vec < _ > > ( ) ;
0 commit comments