@@ -22,25 +22,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
22
22
& mut self ,
23
23
goal : Goal < ' tcx , ProjectionPredicate < ' tcx > > ,
24
24
) -> QueryResult < ' tcx > {
25
- match goal. predicate . projection_ty . kind ( self . tcx ( ) ) {
26
- ty:: AliasKind :: Projection => {
25
+ let def_id = goal. predicate . def_id ( ) ;
26
+ match self . tcx ( ) . def_kind ( def_id) {
27
+ DefKind :: AssocTy | DefKind :: AssocConst => {
27
28
// To only compute normalization once for each projection we only
28
- // normalize if the expected term is an unconstrained inference variable.
29
+ // assemble normalization candidates if the expected term is an
30
+ // unconstrained inference variable.
31
+ //
32
+ // Why: For better cache hits, since if we have an unconstrained RHS then
33
+ // there are only as many cache keys as there are (canonicalized) alias
34
+ // types in each normalizes-to goal. This also weakens inference in a
35
+ // forwards-compatible way so we don't use the value of the RHS term to
36
+ // affect candidate assembly for projections.
29
37
//
30
38
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
31
39
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
32
40
// `U` and equate it with `u32`. This means that we don't need a separate
33
- // projection cache in the solver.
41
+ // projection cache in the solver, since we're piggybacking off of regular
42
+ // goal caching.
34
43
if self . term_is_fully_unconstrained ( goal) {
35
- let candidates = self . assemble_and_evaluate_candidates ( goal) ;
36
- self . merge_candidates ( candidates)
44
+ match self . tcx ( ) . associated_item ( def_id) . container {
45
+ ty:: AssocItemContainer :: TraitContainer => {
46
+ let candidates = self . assemble_and_evaluate_candidates ( goal) ;
47
+ self . merge_candidates ( candidates)
48
+ }
49
+ ty:: AssocItemContainer :: ImplContainer => {
50
+ bug ! ( "IATs not supported here yet" )
51
+ }
52
+ }
37
53
} else {
38
54
self . set_normalizes_to_hack_goal ( goal) ;
39
55
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
40
56
}
41
57
}
42
- ty:: AliasKind :: Opaque => self . normalize_opaque_type ( goal) ,
43
- ty:: AliasKind :: Inherent => bug ! ( "IATs not supported here yet" ) ,
58
+ DefKind :: AnonConst => self . normalize_anon_const ( goal) ,
59
+ DefKind :: OpaqueTy => self . normalize_opaque_type ( goal) ,
60
+ kind => bug ! ( "unknown DefKind {} in projection goal: {goal:#?}" , kind. descr( def_id) ) ,
61
+ }
62
+ }
63
+
64
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
65
+ fn normalize_anon_const (
66
+ & mut self ,
67
+ goal : Goal < ' tcx , ty:: ProjectionPredicate < ' tcx > > ,
68
+ ) -> QueryResult < ' tcx > {
69
+ if let Some ( normalized_const) = self . try_const_eval_resolve (
70
+ goal. param_env ,
71
+ ty:: UnevaluatedConst :: new (
72
+ goal. predicate . projection_ty . def_id ,
73
+ goal. predicate . projection_ty . substs ,
74
+ ) ,
75
+ self . tcx ( )
76
+ . type_of ( goal. predicate . projection_ty . def_id )
77
+ . no_bound_vars ( )
78
+ . expect ( "const ty should not rely on other generics" ) ,
79
+ ) {
80
+ self . eq ( goal. param_env , normalized_const, goal. predicate . term . ct ( ) . unwrap ( ) ) ?;
81
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
82
+ } else {
83
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
44
84
}
45
85
}
46
86
}
@@ -173,17 +213,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
173
213
) ;
174
214
175
215
// Finally we construct the actual value of the associated type.
176
- let is_const = matches ! ( tcx. def_kind( assoc_def. item. def_id) , DefKind :: AssocConst ) ;
177
- let ty = tcx. type_of ( assoc_def. item . def_id ) ;
178
- let term: ty:: EarlyBinder < ty:: Term < ' tcx > > = if is_const {
179
- let identity_substs =
180
- ty:: InternalSubsts :: identity_for_item ( tcx, assoc_def. item . def_id ) ;
181
- let did = assoc_def. item . def_id ;
182
- let kind =
183
- ty:: ConstKind :: Unevaluated ( ty:: UnevaluatedConst :: new ( did, identity_substs) ) ;
184
- ty. map_bound ( |ty| tcx. mk_const ( kind, ty) . into ( ) )
185
- } else {
186
- ty. map_bound ( |ty| ty. into ( ) )
216
+ let term = match assoc_def. item . kind {
217
+ ty:: AssocKind :: Type => tcx. type_of ( assoc_def. item . def_id ) . map_bound ( |ty| ty. into ( ) ) ,
218
+ ty:: AssocKind :: Const => bug ! ( "associated const projection is not supported yet" ) ,
219
+ ty:: AssocKind :: Fn => unreachable ! ( "we should never project to a fn" ) ,
187
220
} ;
188
221
189
222
ecx. eq ( goal. param_env , goal. predicate . term , term. subst ( tcx, substs) )
0 commit comments