1111//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
1212//! may apply, then we can compute the "intersection" of both normalizes-to by
1313//! performing them together. This is used specifically to resolve ambiguities.
14- use super :: { EvalCtxt , SolverMode } ;
14+ use super :: EvalCtxt ;
15+ use rustc_infer:: infer:: DefineOpaqueTypes ;
1516use rustc_infer:: traits:: query:: NoSolution ;
1617use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
1718use rustc_middle:: ty;
1819
19- /// We may need to invert the alias relation direction if dealing an alias on the RHS.
20- #[ derive( Debug ) ]
21- enum Invert {
22- No ,
23- Yes ,
24- }
25-
2620impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
2721 #[ instrument( level = "debug" , skip( self ) , ret) ]
2822 pub ( super ) fn compute_alias_relate_goal (
@@ -31,187 +25,130 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3125 ) -> QueryResult < ' tcx > {
3226 let tcx = self . tcx ( ) ;
3327 let Goal { param_env, predicate : ( lhs, rhs, direction) } = goal;
34- if lhs. is_infer ( ) || rhs. is_infer ( ) {
35- bug ! (
36- "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
37- ) ;
38- }
39-
40- match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
41- ( None , None ) => bug ! ( "`AliasRelate` goal without an alias on either lhs or rhs" ) ,
4228
43- // RHS is not a projection, only way this is true is if LHS normalizes-to RHS
44- ( Some ( alias_lhs) , None ) => self . assemble_normalizes_to_candidate (
45- param_env,
46- alias_lhs,
47- rhs,
48- direction,
49- Invert :: No ,
50- ) ,
29+ let Some ( lhs) = self . try_normalize_term ( param_env, lhs) ? else {
30+ return self . evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) ;
31+ } ;
5132
52- // LHS is not a projection, only way this is true is if RHS normalizes-to LHS
53- ( None , Some ( alias_rhs) ) => self . assemble_normalizes_to_candidate (
54- param_env,
55- alias_rhs,
56- lhs,
57- direction,
58- Invert :: Yes ,
59- ) ,
33+ let Some ( rhs) = self . try_normalize_term ( param_env, rhs) ? else {
34+ return self . evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) ;
35+ } ;
6036
61- ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
62- debug ! ( "both sides are aliases" ) ;
37+ let variance = match direction {
38+ ty:: AliasRelationDirection :: Equate => ty:: Variance :: Invariant ,
39+ ty:: AliasRelationDirection :: Subtype => ty:: Variance :: Covariant ,
40+ } ;
6341
64- let mut candidates = Vec :: new ( ) ;
65- // LHS normalizes-to RHS
66- candidates. extend ( self . assemble_normalizes_to_candidate (
67- param_env,
68- alias_lhs,
69- rhs,
70- direction,
71- Invert :: No ,
72- ) ) ;
73- // RHS normalizes-to RHS
74- candidates. extend ( self . assemble_normalizes_to_candidate (
75- param_env,
76- alias_rhs,
77- lhs,
78- direction,
79- Invert :: Yes ,
80- ) ) ;
81- // Relate via args
82- candidates. extend (
83- self . assemble_subst_relate_candidate (
84- param_env, alias_lhs, alias_rhs, direction,
85- ) ,
86- ) ;
87- debug ! ( ?candidates) ;
42+ match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
43+ ( None , None ) => {
44+ self . relate ( param_env, lhs, variance, rhs) ?;
45+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
46+ }
8847
89- if let Some ( merged) = self . try_merge_responses ( & candidates) {
90- Ok ( merged)
48+ ( Some ( alias) , None ) => {
49+ if rhs. is_infer ( ) {
50+ self . relate ( param_env, lhs, variance, rhs) ?;
51+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
52+ } else if alias. is_opaque ( tcx) {
53+ self . define_opaque ( param_env, alias, rhs)
9154 } else {
92- // When relating two aliases and we have ambiguity, if both
93- // aliases can be normalized to something, we prefer
94- // "bidirectionally normalizing" both of them within the same
95- // candidate.
96- //
97- // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/25>.
98- //
99- // As this is incomplete, we must not do so during coherence.
100- match self . solver_mode ( ) {
101- SolverMode :: Normal => {
102- if let Ok ( bidirectional_normalizes_to_response) = self
103- . assemble_bidirectional_normalizes_to_candidate (
104- param_env, lhs, rhs, direction,
105- )
106- {
107- Ok ( bidirectional_normalizes_to_response)
108- } else {
109- self . flounder ( & candidates)
110- }
111- }
112- SolverMode :: Coherence => self . flounder ( & candidates) ,
113- }
55+ Err ( NoSolution )
11456 }
11557 }
58+ ( None , Some ( alias) ) => {
59+ if lhs. is_infer ( ) {
60+ self . relate ( param_env, lhs, variance, rhs) ?;
61+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
62+ } else if alias. is_opaque ( tcx) {
63+ self . define_opaque ( param_env, alias, lhs)
64+ } else {
65+ Err ( NoSolution )
66+ }
67+ }
68+
69+ ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
70+ self . relate_rigid_alias_or_opaque ( param_env, alias_lhs, variance, alias_rhs)
71+ }
11672 }
11773 }
11874
119- #[ instrument( level = "debug" , skip( self ) , ret) ]
120- fn assemble_normalizes_to_candidate (
75+ /// Normalize the `term` to equate it later. This does not define opaque types.
76+ #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
77+ fn try_normalize_term (
12178 & mut self ,
12279 param_env : ty:: ParamEnv < ' tcx > ,
123- alias : ty:: AliasTy < ' tcx > ,
124- other : ty:: Term < ' tcx > ,
125- direction : ty:: AliasRelationDirection ,
126- invert : Invert ,
127- ) -> QueryResult < ' tcx > {
128- self . probe_misc_candidate ( "normalizes-to" ) . enter ( |ecx| {
129- ecx. normalizes_to_inner ( param_env, alias, other, direction, invert) ?;
130- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
131- } )
80+ term : ty:: Term < ' tcx > ,
81+ ) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
82+ match term. unpack ( ) {
83+ ty:: TermKind :: Ty ( ty) => {
84+ // We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
85+ Ok ( self
86+ . try_normalize_ty_recur ( param_env, DefineOpaqueTypes :: No , 0 , ty)
87+ . map ( Into :: into) )
88+ }
89+ ty:: TermKind :: Const ( _) => {
90+ if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
91+ let term = self . next_term_infer_of_kind ( term) ;
92+ self . add_goal ( Goal :: new (
93+ self . tcx ( ) ,
94+ param_env,
95+ ty:: ProjectionPredicate { projection_ty : alias, term } ,
96+ ) ) ;
97+ self . try_evaluate_added_goals ( ) ?;
98+ Ok ( Some ( self . resolve_vars_if_possible ( term) ) )
99+ } else {
100+ Ok ( Some ( term) )
101+ }
102+ }
103+ }
132104 }
133105
134- // Computes the normalizes-to branch, with side-effects. This must be performed
135- // in a probe in order to not taint the evaluation context.
136- fn normalizes_to_inner (
106+ fn define_opaque (
137107 & mut self ,
138108 param_env : ty:: ParamEnv < ' tcx > ,
139- alias : ty:: AliasTy < ' tcx > ,
140- other : ty:: Term < ' tcx > ,
141- direction : ty:: AliasRelationDirection ,
142- invert : Invert ,
143- ) -> Result < ( ) , NoSolution > {
144- let other = match direction {
145- // This is purely an optimization. No need to instantiate a new
146- // infer var and equate the RHS to it.
147- ty:: AliasRelationDirection :: Equate => other,
148-
149- // Instantiate an infer var and subtype our RHS to it, so that we
150- // properly represent a subtype relation between the LHS and RHS
151- // of the goal.
152- ty:: AliasRelationDirection :: Subtype => {
153- let fresh = self . next_term_infer_of_kind ( other) ;
154- let ( sub, sup) = match invert {
155- Invert :: No => ( fresh, other) ,
156- Invert :: Yes => ( other, fresh) ,
157- } ;
158- self . sub ( param_env, sub, sup) ?;
159- fresh
160- }
161- } ;
109+ opaque : ty:: AliasTy < ' tcx > ,
110+ term : ty:: Term < ' tcx > ,
111+ ) -> QueryResult < ' tcx > {
162112 self . add_goal ( Goal :: new (
163113 self . tcx ( ) ,
164114 param_env,
165- ty:: ProjectionPredicate { projection_ty : alias , term : other } ,
115+ ty:: ProjectionPredicate { projection_ty : opaque , term } ,
166116 ) ) ;
167-
168- Ok ( ( ) )
117+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
169118 }
170119
171- fn assemble_subst_relate_candidate (
120+ fn relate_rigid_alias_or_opaque (
172121 & mut self ,
173122 param_env : ty:: ParamEnv < ' tcx > ,
174- alias_lhs : ty:: AliasTy < ' tcx > ,
175- alias_rhs : ty:: AliasTy < ' tcx > ,
176- direction : ty:: AliasRelationDirection ,
123+ lhs : ty:: AliasTy < ' tcx > ,
124+ variance : ty:: Variance ,
125+ rhs : ty:: AliasTy < ' tcx > ,
177126 ) -> QueryResult < ' tcx > {
178- self . probe_misc_candidate ( "args relate" ) . enter ( |ecx| {
179- match direction {
180- ty:: AliasRelationDirection :: Equate => {
181- ecx. eq ( param_env, alias_lhs, alias_rhs) ?;
182- }
183- ty:: AliasRelationDirection :: Subtype => {
184- ecx. sub ( param_env, alias_lhs, alias_rhs) ?;
185- }
186- }
127+ let tcx = self . tcx ( ) ;
128+ let mut candidates = vec ! [ ] ;
129+ if lhs. is_opaque ( tcx) {
130+ candidates. extend (
131+ self . probe_misc_candidate ( "define-lhs-opaque" )
132+ . enter ( |ecx| ecx. define_opaque ( param_env, lhs, rhs. to_ty ( tcx) . into ( ) ) ) ,
133+ ) ;
134+ }
187135
188- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
189- } )
190- }
136+ if rhs. is_opaque ( tcx) {
137+ candidates. extend (
138+ self . probe_misc_candidate ( "define-rhs-opaque" )
139+ . enter ( |ecx| ecx. define_opaque ( param_env, rhs, lhs. to_ty ( tcx) . into ( ) ) ) ,
140+ ) ;
141+ }
191142
192- fn assemble_bidirectional_normalizes_to_candidate (
193- & mut self ,
194- param_env : ty:: ParamEnv < ' tcx > ,
195- lhs : ty:: Term < ' tcx > ,
196- rhs : ty:: Term < ' tcx > ,
197- direction : ty:: AliasRelationDirection ,
198- ) -> QueryResult < ' tcx > {
199- self . probe_misc_candidate ( "bidir normalizes-to" ) . enter ( |ecx| {
200- ecx. normalizes_to_inner (
201- param_env,
202- lhs. to_alias_ty ( ecx. tcx ( ) ) . unwrap ( ) ,
203- rhs,
204- direction,
205- Invert :: No ,
206- ) ?;
207- ecx. normalizes_to_inner (
208- param_env,
209- rhs. to_alias_ty ( ecx. tcx ( ) ) . unwrap ( ) ,
210- lhs,
211- direction,
212- Invert :: Yes ,
213- ) ?;
143+ candidates. extend ( self . probe_misc_candidate ( "args-relate" ) . enter ( |ecx| {
144+ ecx. relate ( param_env, lhs, variance, rhs) ?;
214145 ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
215- } )
146+ } ) ) ;
147+
148+ if let Some ( result) = self . try_merge_responses ( & candidates) {
149+ Ok ( result)
150+ } else {
151+ self . flounder ( & candidates)
152+ }
216153 }
217154}
0 commit comments