1
- use rustc_hir as hir;
1
+ use std:: ops:: ControlFlow ;
2
+
2
3
use rustc_hir:: def_id:: DefId ;
3
- use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt } ;
4
+ use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , InferOk } ;
5
+ use rustc_infer:: traits:: solve:: inspect:: ProbeKind ;
6
+ use rustc_infer:: traits:: solve:: { CandidateSource , Certainty , Goal } ;
4
7
use rustc_infer:: traits:: {
5
- Obligation , PolyTraitObligation , PredicateObligation , Selection , SelectionResult , TraitEngine ,
8
+ BuiltinImplSource , ImplSource , ImplSourceUserDefinedData , Obligation , ObligationCause ,
9
+ PolyTraitObligation , PredicateObligation , Selection , SelectionError , SelectionResult ,
6
10
} ;
7
11
use rustc_macros:: extension;
8
- use rustc_middle:: traits:: solve:: { CandidateSource , CanonicalInput , Certainty , Goal } ;
9
- use rustc_middle:: traits:: {
10
- BuiltinImplSource , ImplSource , ImplSourceUserDefinedData , ObligationCause , SelectionError ,
11
- } ;
12
- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
13
- use rustc_span:: DUMMY_SP ;
12
+ use rustc_span:: Span ;
14
13
15
- use crate :: solve:: assembly:: Candidate ;
16
- use crate :: solve:: eval_ctxt:: { EvalCtxt , GenerateProofTree } ;
17
- use crate :: solve:: inspect:: ProofTreeBuilder ;
18
- use crate :: traits:: StructurallyNormalizeExt ;
19
- use crate :: traits:: TraitEngineExt ;
14
+ use crate :: solve:: inspect:: { self , ProofTreeInferCtxtExt } ;
20
15
21
16
#[ extension( pub trait InferCtxtSelectExt <' tcx>) ]
22
17
impl < ' tcx > InferCtxt < ' tcx > {
@@ -26,359 +21,192 @@ impl<'tcx> InferCtxt<'tcx> {
26
21
) -> SelectionResult < ' tcx , Selection < ' tcx > > {
27
22
assert ! ( self . next_trait_solver( ) ) ;
28
23
29
- self . enter_forall ( obligation. predicate , |pred| {
30
- let trait_goal = Goal :: new ( self . tcx , obligation. param_env , pred) ;
31
-
32
- let ( result, _) = EvalCtxt :: enter_root ( self , GenerateProofTree :: Never , |ecx| {
33
- let goal = Goal :: new ( ecx. tcx ( ) , trait_goal. param_env , trait_goal. predicate ) ;
34
- let ( orig_values, canonical_goal) = ecx. canonicalize_goal ( goal) ;
35
- let mut candidates = ecx. compute_canonical_trait_candidates ( canonical_goal) ;
24
+ self . visit_proof_tree (
25
+ Goal :: new ( self . tcx , obligation. param_env , obligation. predicate ) ,
26
+ & mut Select { span : obligation. cause . span } ,
27
+ )
28
+ . break_value ( )
29
+ . unwrap ( )
30
+ }
31
+ }
36
32
37
- // pseudo-winnow
38
- if candidates. len ( ) == 0 {
39
- return Err ( SelectionError :: Unimplemented ) ;
40
- } else if candidates. len ( ) > 1 {
41
- let mut i = 0 ;
42
- while i < candidates. len ( ) {
43
- let should_drop_i = ( 0 ..candidates. len ( ) ) . filter ( |& j| i != j) . any ( |j| {
44
- candidate_should_be_dropped_in_favor_of (
45
- ecx. tcx ( ) ,
46
- & candidates[ i] ,
47
- & candidates[ j] ,
48
- )
49
- } ) ;
50
- if should_drop_i {
51
- candidates. swap_remove ( i) ;
52
- } else {
53
- i += 1 ;
54
- if i > 1 {
55
- return Ok ( None ) ;
56
- }
57
- }
58
- }
59
- }
33
+ struct Select {
34
+ span : Span ,
35
+ }
60
36
61
- let candidate = candidates. pop ( ) . unwrap ( ) ;
62
- let ( normalization_nested_goals, certainty) = ecx
63
- . instantiate_and_apply_query_response (
64
- trait_goal. param_env ,
65
- orig_values,
66
- candidate. result ,
67
- ) ;
68
- assert ! ( normalization_nested_goals. is_empty( ) ) ;
69
- Ok ( Some ( ( candidate, certainty) ) )
70
- } ) ;
37
+ impl < ' tcx > inspect:: ProofTreeVisitor < ' tcx > for Select {
38
+ type Result = ControlFlow < SelectionResult < ' tcx , Selection < ' tcx > > > ;
71
39
72
- let ( candidate, certainty) = match result {
73
- Ok ( Some ( result) ) => result,
74
- Ok ( None ) => return Ok ( None ) ,
75
- Err ( e) => return Err ( e) ,
76
- } ;
40
+ fn span ( & self ) -> Span {
41
+ self . span
42
+ }
77
43
78
- let goal = self . resolve_vars_if_possible ( trait_goal) ;
79
- match ( certainty, candidate. source ) {
80
- // Rematching the implementation will instantiate the same nested goals that
81
- // would have caused the ambiguity, so we can still make progress here regardless.
82
- ( _, CandidateSource :: Impl ( def_id) ) => rematch_impl ( self , goal, def_id) ,
44
+ fn visit_goal ( & mut self , goal : & inspect:: InspectGoal < ' _ , ' tcx > ) -> Self :: Result {
45
+ let mut candidates = goal. candidates ( ) ;
46
+ candidates. retain ( |cand| cand. result ( ) . is_ok ( ) ) ;
83
47
84
- // If an unsize goal is ambiguous, then we can manually rematch it to make
85
- // selection progress for coercion during HIR typeck. If it is *not* ambiguous,
86
- // but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals,
87
- // and we need to rematch those to detect tuple unsizing and trait upcasting.
88
- // FIXME: This will be wrong if we have param-env or where-clause bounds
89
- // with the unsize goal -- we may need to mark those with different impl
90
- // sources.
91
- ( Certainty :: Maybe ( _) , CandidateSource :: BuiltinImpl ( src) )
92
- | ( Certainty :: Yes , CandidateSource :: BuiltinImpl ( src @ BuiltinImplSource :: Misc ) )
93
- if self . tcx . lang_items ( ) . unsize_trait ( ) == Some ( goal. predicate . def_id ( ) ) =>
94
- {
95
- rematch_unsize ( self , goal, src, certainty)
96
- }
48
+ // No candidates -- not implemented.
49
+ if candidates. is_empty ( ) {
50
+ return ControlFlow :: Break ( Err ( SelectionError :: Unimplemented ) ) ;
51
+ }
97
52
98
- // Technically some builtin impls have nested obligations, but if
99
- // `Certainty::Yes`, then they should've all been verified and don't
100
- // need re-checking.
101
- ( Certainty :: Yes , CandidateSource :: BuiltinImpl ( src) ) => {
102
- Ok ( Some ( ImplSource :: Builtin ( src, vec ! [ ] ) ) )
103
- }
53
+ // One candidate, no need to winnow.
54
+ if candidates. len ( ) == 1 {
55
+ return ControlFlow :: Break ( Ok ( to_selection (
56
+ self . span ,
57
+ candidates. into_iter ( ) . next ( ) . unwrap ( ) ,
58
+ ) ) ) ;
59
+ }
104
60
105
- // It's fine not to do anything to rematch these, since there are no
106
- // nested obligations.
107
- ( Certainty :: Yes , CandidateSource :: ParamEnv ( _) | CandidateSource :: AliasBound ) => {
108
- Ok ( Some ( ImplSource :: Param ( vec ! [ ] ) ) )
61
+ // We need to winnow. See comments on `candidate_should_be_dropped_in_favor_of`.
62
+ let mut i = 0 ;
63
+ while i < candidates. len ( ) {
64
+ let should_drop_i = ( 0 ..candidates. len ( ) )
65
+ . filter ( |& j| i != j)
66
+ . any ( |j| candidate_should_be_dropped_in_favor_of ( & candidates[ i] , & candidates[ j] ) ) ;
67
+ if should_drop_i {
68
+ candidates. swap_remove ( i) ;
69
+ } else {
70
+ i += 1 ;
71
+ if i > 1 {
72
+ return ControlFlow :: Break ( Ok ( None ) ) ;
109
73
}
110
-
111
- ( _, CandidateSource :: CoherenceUnknowable ) => bug ! ( ) ,
112
-
113
- ( Certainty :: Maybe ( _) , _) => Ok ( None ) ,
114
74
}
115
- } )
116
- }
117
- }
75
+ }
118
76
119
- impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
120
- fn compute_canonical_trait_candidates (
121
- & mut self ,
122
- canonical_input : CanonicalInput < ' tcx > ,
123
- ) -> Vec < Candidate < ' tcx > > {
124
- // This doesn't record the canonical goal on the stack during the
125
- // candidate assembly step, but that's fine. Selection is conceptually
126
- // outside of the solver, and if there were any cycles, we'd encounter
127
- // the cycle anyways one step later.
128
- EvalCtxt :: enter_canonical (
129
- self . tcx ( ) ,
130
- self . search_graph ,
131
- canonical_input,
132
- // FIXME: This is wrong, idk if we even want to track stuff here.
133
- & mut ProofTreeBuilder :: new_noop ( ) ,
134
- |ecx, goal| {
135
- let trait_goal = Goal {
136
- param_env : goal. param_env ,
137
- predicate : goal
138
- . predicate
139
- . to_opt_poly_trait_pred ( )
140
- . expect ( "we canonicalized a trait goal" )
141
- . no_bound_vars ( )
142
- . expect ( "we instantiated all bound vars" ) ,
143
- } ;
144
- ecx. assemble_and_evaluate_candidates ( trait_goal)
145
- } ,
146
- )
77
+ ControlFlow :: Break ( Ok ( to_selection ( self . span , candidates. into_iter ( ) . next ( ) . unwrap ( ) ) ) )
147
78
}
148
79
}
149
80
81
+ /// This is a lot more limited than the old solver's equivalent method. This may lead to more `Ok(None)`
82
+ /// results when selecting traits in polymorphic contexts, but we should never rely on the lack of ambiguity,
83
+ /// and should always just gracefully fail here. We shouldn't rely on this incompleteness.
150
84
fn candidate_should_be_dropped_in_favor_of < ' tcx > (
151
- tcx : TyCtxt < ' tcx > ,
152
- victim : & Candidate < ' tcx > ,
153
- other : & Candidate < ' tcx > ,
85
+ victim : & inspect:: InspectCandidate < ' _ , ' tcx > ,
86
+ other : & inspect:: InspectCandidate < ' _ , ' tcx > ,
154
87
) -> bool {
155
- match ( victim. source , other. source ) {
156
- ( CandidateSource :: ParamEnv ( victim_idx) , CandidateSource :: ParamEnv ( other_idx) ) => {
157
- victim_idx >= other_idx
88
+ // Don't winnow until `Certainty::Yes` -- we don't need to winnow until
89
+ // codegen, technically.
90
+ if matches ! ( other. result( ) . unwrap( ) , Certainty :: Maybe ( ..) ) {
91
+ return false ;
92
+ }
93
+
94
+ let inspect:: ProbeKind :: TraitCandidate { source : victim_source, result : _ } = victim. kind ( )
95
+ else {
96
+ return false ;
97
+ } ;
98
+ let inspect:: ProbeKind :: TraitCandidate { source : other_source, result : _ } = other. kind ( )
99
+ else {
100
+ return false ;
101
+ } ;
102
+
103
+ match ( victim_source, other_source) {
104
+ ( _, CandidateSource :: CoherenceUnknowable ) | ( CandidateSource :: CoherenceUnknowable , _) => {
105
+ bug ! ( "should not have assembled a CoherenceUnknowable candidate" )
158
106
}
159
- ( _, CandidateSource :: ParamEnv ( _) ) => true ,
160
107
161
- // FIXME: we could prefer earlier vtable bases perhaps...
108
+ // Prefer dyn candidates over non-dyn candidates. This is necessary to
109
+ // handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
162
110
(
163
111
CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Object { .. } ) ,
164
112
CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Object { .. } ) ,
165
113
) => false ,
166
- ( _, CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Object { .. } ) ) => true ,
114
+ (
115
+ CandidateSource :: Impl ( _) | CandidateSource :: ParamEnv ( _) | CandidateSource :: AliasBound ,
116
+ CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Object { .. } ) ,
117
+ ) => true ,
167
118
119
+ // Prefer specializing candidates over specialized candidates.
168
120
( CandidateSource :: Impl ( victim_def_id) , CandidateSource :: Impl ( other_def_id) ) => {
169
- tcx. specializes ( ( other_def_id, victim_def_id) )
170
- && other. result . value . certainty == Certainty :: Yes
121
+ victim. goal ( ) . infcx ( ) . tcx . specializes ( ( other_def_id, victim_def_id) )
171
122
}
172
123
173
124
_ => false ,
174
125
}
175
126
}
176
127
128
+ fn to_selection < ' tcx > (
129
+ span : Span ,
130
+ cand : inspect:: InspectCandidate < ' _ , ' tcx > ,
131
+ ) -> Option < Selection < ' tcx > > {
132
+ if let Certainty :: Maybe ( ..) = cand. shallow_certainty ( ) {
133
+ return None ;
134
+ }
135
+
136
+ let make_nested = || {
137
+ cand. instantiate_nested_goals ( span)
138
+ . into_iter ( )
139
+ . map ( |nested| {
140
+ Obligation :: new (
141
+ nested. infcx ( ) . tcx ,
142
+ ObligationCause :: dummy_with_span ( span) ,
143
+ nested. goal ( ) . param_env ,
144
+ nested. goal ( ) . predicate ,
145
+ )
146
+ } )
147
+ . collect ( )
148
+ } ;
149
+
150
+ Some ( match cand. kind ( ) {
151
+ ProbeKind :: TraitCandidate { source, result : _ } => match source {
152
+ CandidateSource :: Impl ( impl_def_id) => {
153
+ // FIXME: Remove this in favor of storing this in the tree
154
+ // For impl candidates, we do the rematch manually to compute the args.
155
+ ImplSource :: UserDefined ( rematch_impl ( cand. goal ( ) , impl_def_id, span) )
156
+ }
157
+ CandidateSource :: BuiltinImpl ( builtin) => ImplSource :: Builtin ( builtin, make_nested ( ) ) ,
158
+ CandidateSource :: ParamEnv ( _) => ImplSource :: Param ( make_nested ( ) ) ,
159
+ CandidateSource :: AliasBound => {
160
+ ImplSource :: Builtin ( BuiltinImplSource :: Misc , make_nested ( ) )
161
+ }
162
+ CandidateSource :: CoherenceUnknowable => {
163
+ span_bug ! ( span, "didn't expect to select an unknowable candidate" )
164
+ }
165
+ } ,
166
+ ProbeKind :: TryNormalizeNonRigid { result : _ }
167
+ | ProbeKind :: NormalizedSelfTyAssembly
168
+ | ProbeKind :: UnsizeAssembly
169
+ | ProbeKind :: UpcastProjectionCompatibility
170
+ | ProbeKind :: OpaqueTypeStorageLookup { result : _ }
171
+ | ProbeKind :: Root { result : _ } => {
172
+ span_bug ! ( span, "didn't expect to assemble trait candidate from {:#?}" , cand. kind( ) )
173
+ }
174
+ } )
175
+ }
176
+
177
177
fn rematch_impl < ' tcx > (
178
- infcx : & InferCtxt < ' tcx > ,
179
- goal : Goal < ' tcx , ty:: TraitPredicate < ' tcx > > ,
178
+ goal : & inspect:: InspectGoal < ' _ , ' tcx > ,
180
179
impl_def_id : DefId ,
181
- ) -> SelectionResult < ' tcx , Selection < ' tcx > > {
182
- let args = infcx. fresh_args_for_item ( DUMMY_SP , impl_def_id) ;
180
+ span : Span ,
181
+ ) -> ImplSourceUserDefinedData < ' tcx , PredicateObligation < ' tcx > > {
182
+ let infcx = goal. infcx ( ) ;
183
+ let goal_trait_ref = infcx
184
+ . enter_forall_and_leak_universe ( goal. goal ( ) . predicate . to_opt_poly_trait_pred ( ) . unwrap ( ) )
185
+ . trait_ref ;
186
+
187
+ let args = infcx. fresh_args_for_item ( span, impl_def_id) ;
183
188
let impl_trait_ref =
184
189
infcx. tcx . impl_trait_ref ( impl_def_id) . unwrap ( ) . instantiate ( infcx. tcx , args) ;
185
190
186
- let mut nested = infcx
187
- . at ( & ObligationCause :: dummy ( ) , goal. param_env )
188
- // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
189
- . eq ( DefineOpaqueTypes :: Yes , goal . predicate . trait_ref , impl_trait_ref )
190
- . map_err ( |_| SelectionError :: Unimplemented ) ?
191
- . into_obligations ( ) ;
191
+ let InferOk { value : ( ) , obligations : mut nested } = infcx
192
+ . at ( & ObligationCause :: dummy_with_span ( span ) , goal. goal ( ) . param_env )
193
+ . eq ( DefineOpaqueTypes :: Yes , goal_trait_ref , impl_trait_ref )
194
+ . expect ( "rematching impl failed" ) ;
195
+
196
+ // FIXME(-Znext-solver=coinductive): We need to add supertraits here eventually.
192
197
193
198
nested. extend (
194
199
infcx. tcx . predicates_of ( impl_def_id) . instantiate ( infcx. tcx , args) . into_iter ( ) . map (
195
- |( pred, _) | Obligation :: new ( infcx. tcx , ObligationCause :: dummy ( ) , goal. param_env , pred) ,
196
- ) ,
197
- ) ;
198
-
199
- Ok ( Some ( ImplSource :: UserDefined ( ImplSourceUserDefinedData { impl_def_id, args, nested } ) ) )
200
- }
201
-
202
- /// The `Unsize` trait is particularly important to coercion, so we try rematch it.
203
- /// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait
204
- /// goal assembly in the solver, both for soundness and in order to avoid ICEs.
205
- fn rematch_unsize < ' tcx > (
206
- infcx : & InferCtxt < ' tcx > ,
207
- goal : Goal < ' tcx , ty:: TraitPredicate < ' tcx > > ,
208
- source : BuiltinImplSource ,
209
- certainty : Certainty ,
210
- ) -> SelectionResult < ' tcx , Selection < ' tcx > > {
211
- let tcx = infcx. tcx ;
212
- let mut nested = vec ! [ ] ;
213
- let a_ty = structurally_normalize ( goal. predicate . self_ty ( ) , infcx, goal. param_env , & mut nested) ;
214
- let b_ty = structurally_normalize (
215
- goal. predicate . trait_ref . args . type_at ( 1 ) ,
216
- infcx,
217
- goal. param_env ,
218
- & mut nested,
219
- ) ;
220
-
221
- match ( a_ty. kind ( ) , b_ty. kind ( ) ) {
222
- // Don't try to coerce `?0` to `dyn Trait`
223
- ( ty:: Infer ( ty:: TyVar ( _) ) , _) | ( _, ty:: Infer ( ty:: TyVar ( _) ) ) => Ok ( None ) ,
224
- // Stall any ambiguous upcasting goals, since we can't rematch those
225
- ( ty:: Dynamic ( _, _, ty:: Dyn ) , ty:: Dynamic ( _, _, ty:: Dyn ) ) => match certainty {
226
- Certainty :: Yes => Ok ( Some ( ImplSource :: Builtin ( source, nested) ) ) ,
227
- _ => Ok ( None ) ,
228
- } ,
229
- // `T` -> `dyn Trait` upcasting
230
- ( _, & ty:: Dynamic ( data, region, ty:: Dyn ) ) => {
231
- // Check that the type implements all of the predicates of the def-id.
232
- // (i.e. the principal, all of the associated types match, and any auto traits)
233
- nested. extend ( data. iter ( ) . map ( |pred| {
200
+ |( clause, _) | {
234
201
Obligation :: new (
235
202
infcx. tcx ,
236
- ObligationCause :: dummy ( ) ,
237
- goal. param_env ,
238
- pred . with_self_ty ( tcx , a_ty ) ,
203
+ ObligationCause :: dummy_with_span ( span ) ,
204
+ goal. goal ( ) . param_env ,
205
+ clause ,
239
206
)
240
- } ) ) ;
241
- // The type must be Sized to be unsized.
242
- let sized_def_id = tcx. require_lang_item ( hir:: LangItem :: Sized , None ) ;
243
- nested. push ( Obligation :: new (
244
- infcx. tcx ,
245
- ObligationCause :: dummy ( ) ,
246
- goal. param_env ,
247
- ty:: TraitRef :: new ( tcx, sized_def_id, [ a_ty] ) ,
248
- ) ) ;
249
- // The type must outlive the lifetime of the `dyn` we're unsizing into.
250
- nested. push ( Obligation :: new (
251
- infcx. tcx ,
252
- ObligationCause :: dummy ( ) ,
253
- goal. param_env ,
254
- ty:: OutlivesPredicate ( a_ty, region) ,
255
- ) ) ;
256
-
257
- Ok ( Some ( ImplSource :: Builtin ( source, nested) ) )
258
- }
259
- // `[T; n]` -> `[T]` unsizing
260
- ( & ty:: Array ( a_elem_ty, ..) , & ty:: Slice ( b_elem_ty) ) => {
261
- nested. extend (
262
- infcx
263
- . at ( & ObligationCause :: dummy ( ) , goal. param_env )
264
- // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
265
- . eq ( DefineOpaqueTypes :: Yes , a_elem_ty, b_elem_ty)
266
- . expect ( "expected rematch to succeed" )
267
- . into_obligations ( ) ,
268
- ) ;
269
-
270
- Ok ( Some ( ImplSource :: Builtin ( source, nested) ) )
271
- }
272
- // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
273
- ( & ty:: Adt ( a_def, a_args) , & ty:: Adt ( b_def, b_args) )
274
- if a_def. is_struct ( ) && a_def. did ( ) == b_def. did ( ) =>
275
- {
276
- let unsizing_params = tcx. unsizing_params_for_adt ( a_def. did ( ) ) ;
277
- // We must be unsizing some type parameters. This also implies
278
- // that the struct has a tail field.
279
- if unsizing_params. is_empty ( ) {
280
- bug ! ( "expected rematch to succeed" )
281
- }
282
-
283
- let tail_field = a_def
284
- . non_enum_variant ( )
285
- . fields
286
- . raw
287
- . last ( )
288
- . expect ( "expected unsized ADT to have a tail field" ) ;
289
- let tail_field_ty = tcx. type_of ( tail_field. did ) ;
290
-
291
- let a_tail_ty = tail_field_ty. instantiate ( tcx, a_args) ;
292
- let b_tail_ty = tail_field_ty. instantiate ( tcx, b_args) ;
293
-
294
- // Instantiate just the unsizing params from B into A. The type after
295
- // this instantiation must be equal to B. This is so we don't unsize
296
- // unrelated type parameters.
297
- let new_a_args = tcx. mk_args_from_iter (
298
- a_args
299
- . iter ( )
300
- . enumerate ( )
301
- . map ( |( i, a) | if unsizing_params. contains ( i as u32 ) { b_args[ i] } else { a } ) ,
302
- ) ;
303
- let unsized_a_ty = Ty :: new_adt ( tcx, a_def, new_a_args) ;
304
-
305
- nested. extend (
306
- infcx
307
- . at ( & ObligationCause :: dummy ( ) , goal. param_env )
308
- // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
309
- . eq ( DefineOpaqueTypes :: Yes , unsized_a_ty, b_ty)
310
- . expect ( "expected rematch to succeed" )
311
- . into_obligations ( ) ,
312
- ) ;
313
-
314
- // Finally, we require that `TailA: Unsize<TailB>` for the tail field
315
- // types.
316
- nested. push ( Obligation :: new (
317
- tcx,
318
- ObligationCause :: dummy ( ) ,
319
- goal. param_env ,
320
- ty:: TraitRef :: new ( tcx, goal. predicate . def_id ( ) , [ a_tail_ty, b_tail_ty] ) ,
321
- ) ) ;
322
-
323
- Ok ( Some ( ImplSource :: Builtin ( source, nested) ) )
324
- }
325
- // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
326
- ( & ty:: Tuple ( a_tys) , & ty:: Tuple ( b_tys) )
327
- if a_tys. len ( ) == b_tys. len ( ) && !a_tys. is_empty ( ) =>
328
- {
329
- let ( a_last_ty, a_rest_tys) = a_tys. split_last ( ) . unwrap ( ) ;
330
- let b_last_ty = b_tys. last ( ) . unwrap ( ) ;
331
-
332
- // Instantiate just the tail field of B., and require that they're equal.
333
- let unsized_a_ty =
334
- Ty :: new_tup_from_iter ( tcx, a_rest_tys. iter ( ) . chain ( [ b_last_ty] ) . copied ( ) ) ;
335
- nested. extend (
336
- infcx
337
- . at ( & ObligationCause :: dummy ( ) , goal. param_env )
338
- // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
339
- . eq ( DefineOpaqueTypes :: Yes , unsized_a_ty, b_ty)
340
- . expect ( "expected rematch to succeed" )
341
- . into_obligations ( ) ,
342
- ) ;
343
-
344
- // Similar to ADTs, require that we can unsize the tail.
345
- nested. push ( Obligation :: new (
346
- tcx,
347
- ObligationCause :: dummy ( ) ,
348
- goal. param_env ,
349
- ty:: TraitRef :: new ( tcx, goal. predicate . def_id ( ) , [ * a_last_ty, * b_last_ty] ) ,
350
- ) ) ;
351
-
352
- // We need to be able to detect tuple unsizing to require its feature gate.
353
- assert_eq ! (
354
- source,
355
- BuiltinImplSource :: TupleUnsizing ,
356
- "compiler-errors wants to know if this can ever be triggered..."
357
- ) ;
358
- Ok ( Some ( ImplSource :: Builtin ( source, nested) ) )
359
- }
360
- _ => {
361
- assert_ne ! ( certainty, Certainty :: Yes ) ;
362
- Ok ( None )
363
- }
364
- }
365
- }
207
+ } ,
208
+ ) ,
209
+ ) ;
366
210
367
- fn structurally_normalize < ' tcx > (
368
- ty : Ty < ' tcx > ,
369
- infcx : & InferCtxt < ' tcx > ,
370
- param_env : ty:: ParamEnv < ' tcx > ,
371
- nested : & mut Vec < PredicateObligation < ' tcx > > ,
372
- ) -> Ty < ' tcx > {
373
- if matches ! ( ty. kind( ) , ty:: Alias ( ..) ) {
374
- let mut engine = <dyn TraitEngine < ' tcx > >:: new ( infcx) ;
375
- let normalized_ty = infcx
376
- . at ( & ObligationCause :: dummy ( ) , param_env)
377
- . structurally_normalize ( ty, & mut * engine)
378
- . expect ( "normalization shouldn't fail if we got to here" ) ;
379
- nested. extend ( engine. pending_obligations ( ) ) ;
380
- normalized_ty
381
- } else {
382
- ty
383
- }
211
+ ImplSourceUserDefinedData { impl_def_id, nested, args }
384
212
}
0 commit comments