2
2
//! Doing this via a separate goal is called "deferred alias relation" and part
3
3
//! of our more general approach to "lazy normalization".
4
4
//!
5
- //! This is done by first normalizing both sides of the goal, ending up in
6
- //! either a concrete type, rigid alias, or an infer variable.
5
+ //! This is done by first structurally normalizing both sides of the goal, ending
6
+ //! up in either a concrete type, rigid alias, or an infer variable.
7
7
//! These are related further according to the rules below:
8
8
//!
9
9
//! (1.) If we end up with two rigid aliases, then we relate them structurally.
14
14
//!
15
15
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
16
16
//! relate them structurally.
17
- //!
18
- //! Subtle: when relating an opaque to another type, we emit a
19
- //! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
20
- //! This nested goal starts out as ambiguous and does not actually define the opaque.
21
- //! However, if `?fresh_var` ends up geteting equated to another type, we retry the
22
- //! `NormalizesTo` goal, at which point the opaque is actually defined.
23
17
24
18
use super :: EvalCtxt ;
25
- use rustc_infer:: traits:: query:: NoSolution ;
26
- use rustc_infer:: traits:: solve:: GoalSource ;
27
19
use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
28
- use rustc_middle:: ty:: { self , Ty } ;
20
+ use rustc_middle:: ty;
29
21
30
22
impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
31
23
#[ instrument( level = "debug" , skip( self ) , ret) ]
@@ -36,141 +28,58 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
36
28
let tcx = self . tcx ( ) ;
37
29
let Goal { param_env, predicate : ( lhs, rhs, direction) } = goal;
38
30
39
- let Some ( lhs) = self . try_normalize_term ( param_env, lhs) ? else {
40
- return self
41
- . evaluate_added_goals_and_make_canonical_response ( Certainty :: overflow ( true ) ) ;
31
+ // Structurally normalize the lhs.
32
+ let lhs = if let Some ( alias) = lhs. to_alias_ty ( self . tcx ( ) ) {
33
+ let term = self . next_term_infer_of_kind ( lhs) ;
34
+ self . add_normalizes_to_goal ( goal. with ( tcx, ty:: NormalizesTo { alias, term } ) ) ;
35
+ term
36
+ } else {
37
+ lhs
42
38
} ;
43
39
44
- let Some ( rhs) = self . try_normalize_term ( param_env, rhs) ? else {
45
- return self
46
- . evaluate_added_goals_and_make_canonical_response ( Certainty :: overflow ( true ) ) ;
40
+ // Structurally normalize the rhs.
41
+ let rhs = if let Some ( alias) = rhs. to_alias_ty ( self . tcx ( ) ) {
42
+ let term = self . next_term_infer_of_kind ( rhs) ;
43
+ self . add_normalizes_to_goal ( goal. with ( tcx, ty:: NormalizesTo { alias, term } ) ) ;
44
+ term
45
+ } else {
46
+ rhs
47
47
} ;
48
48
49
+ // Apply the constraints.
50
+ self . try_evaluate_added_goals ( ) ?;
51
+ let lhs = self . resolve_vars_if_possible ( lhs) ;
52
+ let rhs = self . resolve_vars_if_possible ( rhs) ;
53
+ debug ! ( ?lhs, ?rhs) ;
54
+
49
55
let variance = match direction {
50
56
ty:: AliasRelationDirection :: Equate => ty:: Variance :: Invariant ,
51
57
ty:: AliasRelationDirection :: Subtype => ty:: Variance :: Covariant ,
52
58
} ;
53
-
54
59
match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
55
60
( None , None ) => {
56
61
self . relate ( param_env, lhs, variance, rhs) ?;
57
62
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
58
63
}
59
64
60
65
( Some ( alias) , None ) => {
61
- self . relate_rigid_alias_non_alias ( param_env, alias, variance, rhs)
66
+ self . relate_rigid_alias_non_alias ( param_env, alias, variance, rhs) ?;
67
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
68
+ }
69
+ ( None , Some ( alias) ) => {
70
+ self . relate_rigid_alias_non_alias (
71
+ param_env,
72
+ alias,
73
+ variance. xform ( ty:: Variance :: Contravariant ) ,
74
+ lhs,
75
+ ) ?;
76
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
62
77
}
63
- ( None , Some ( alias) ) => self . relate_rigid_alias_non_alias (
64
- param_env,
65
- alias,
66
- variance. xform ( ty:: Variance :: Contravariant ) ,
67
- lhs,
68
- ) ,
69
78
70
79
( Some ( alias_lhs) , Some ( alias_rhs) ) => {
71
80
self . relate ( param_env, alias_lhs, variance, alias_rhs) ?;
72
81
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
73
82
}
74
83
}
75
84
}
76
-
77
- /// Relate a rigid alias with another type. This is the same as
78
- /// an ordinary relate except that we treat the outer most alias
79
- /// constructor as rigid.
80
- #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
81
- fn relate_rigid_alias_non_alias (
82
- & mut self ,
83
- param_env : ty:: ParamEnv < ' tcx > ,
84
- alias : ty:: AliasTy < ' tcx > ,
85
- variance : ty:: Variance ,
86
- term : ty:: Term < ' tcx > ,
87
- ) -> QueryResult < ' tcx > {
88
- // NOTE: this check is purely an optimization, the structural eq would
89
- // always fail if the term is not an inference variable.
90
- if term. is_infer ( ) {
91
- let tcx = self . tcx ( ) ;
92
- // We need to relate `alias` to `term` treating only the outermost
93
- // constructor as rigid, relating any contained generic arguments as
94
- // normal. We do this by first structurally equating the `term`
95
- // with the alias constructor instantiated with unconstrained infer vars,
96
- // and then relate this with the whole `alias`.
97
- //
98
- // Alternatively we could modify `Equate` for this case by adding another
99
- // variant to `StructurallyRelateAliases`.
100
- let identity_args = self . fresh_args_for_item ( alias. def_id ) ;
101
- let rigid_ctor = ty:: AliasTy :: new ( tcx, alias. def_id , identity_args) ;
102
- self . eq_structurally_relating_aliases ( param_env, term, rigid_ctor. to_ty ( tcx) . into ( ) ) ?;
103
- self . eq ( param_env, alias, rigid_ctor) ?;
104
- self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
105
- } else {
106
- Err ( NoSolution )
107
- }
108
- }
109
-
110
- // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
111
- /// Normalize the `term` to equate it later.
112
- #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
113
- fn try_normalize_term (
114
- & mut self ,
115
- param_env : ty:: ParamEnv < ' tcx > ,
116
- term : ty:: Term < ' tcx > ,
117
- ) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
118
- match term. unpack ( ) {
119
- ty:: TermKind :: Ty ( ty) => {
120
- Ok ( self . try_normalize_ty_recur ( param_env, 0 , ty) . map ( Into :: into) )
121
- }
122
- ty:: TermKind :: Const ( _) => {
123
- if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
124
- let term = self . next_term_infer_of_kind ( term) ;
125
- self . add_normalizes_to_goal ( Goal :: new (
126
- self . tcx ( ) ,
127
- param_env,
128
- ty:: NormalizesTo { alias, term } ,
129
- ) ) ;
130
- self . try_evaluate_added_goals ( ) ?;
131
- Ok ( Some ( self . resolve_vars_if_possible ( term) ) )
132
- } else {
133
- Ok ( Some ( term) )
134
- }
135
- }
136
- }
137
- }
138
-
139
- #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
140
- fn try_normalize_ty_recur (
141
- & mut self ,
142
- param_env : ty:: ParamEnv < ' tcx > ,
143
- depth : usize ,
144
- ty : Ty < ' tcx > ,
145
- ) -> Option < Ty < ' tcx > > {
146
- if !self . tcx ( ) . recursion_limit ( ) . value_within_limit ( depth) {
147
- return None ;
148
- }
149
-
150
- let ty:: Alias ( kind, alias) = * ty. kind ( ) else {
151
- return Some ( ty) ;
152
- } ;
153
-
154
- match self . commit_if_ok ( |this| {
155
- let tcx = this. tcx ( ) ;
156
- let normalized_ty = this. next_ty_infer ( ) ;
157
- let normalizes_to = ty:: NormalizesTo { alias, term : normalized_ty. into ( ) } ;
158
- match kind {
159
- ty:: AliasKind :: Opaque => {
160
- // HACK: Unlike for associated types, `normalizes-to` for opaques
161
- // is currently not treated as a function. We do not erase the
162
- // expected term.
163
- this. add_goal ( GoalSource :: Misc , Goal :: new ( tcx, param_env, normalizes_to) ) ;
164
- }
165
- ty:: AliasKind :: Projection | ty:: AliasKind :: Inherent | ty:: AliasKind :: Weak => {
166
- this. add_normalizes_to_goal ( Goal :: new ( tcx, param_env, normalizes_to) )
167
- }
168
- }
169
- this. try_evaluate_added_goals ( ) ?;
170
- Ok ( this. resolve_vars_if_possible ( normalized_ty) )
171
- } ) {
172
- Ok ( ty) => self . try_normalize_ty_recur ( param_env, depth + 1 , ty) ,
173
- Err ( NoSolution ) => Some ( ty) ,
174
- }
175
- }
176
85
}
0 commit comments