@@ -23,7 +23,10 @@ mod trait_goals;
2323use derive_where:: derive_where;
2424use rustc_type_ir:: inherent:: * ;
2525pub use rustc_type_ir:: solve:: * ;
26- use rustc_type_ir:: { self as ty, Const , Interner , Region , TypeVisitableExt } ;
26+ use rustc_type_ir:: {
27+ self as ty, BoundVarIndexKind , Const , Interner , Region , TypeFlags , TypeSuperVisitable ,
28+ TypeVisitable , TypeVisitableExt , TypeVisitor ,
29+ } ;
2730use tracing:: instrument;
2831
2932pub use self :: eval_ctxt:: {
@@ -86,25 +89,101 @@ fn equal_response_modulo_region_constraints<I: Interner>(
8689 b : & CanonicalResponse < I > ,
8790) -> bool {
8891 let CanonicalResponse {
89- max_universe : a_max_universe,
90- var_kinds : a_var_kinds,
91- value :
92- Response {
93- var_values : a_var_values,
94- certainty : a_certainty,
95- external_constraints : a_external_constraints,
96- } ,
92+ max_universe : _, // implied by `var_kinds` being equal.
93+ var_kinds,
94+ value : Response { var_values, certainty, external_constraints } ,
9795 } = a;
9896
9997 let ExternalConstraintsData { region_constraints : _, opaque_types, normalization_nested_goals } =
100- & * * a_external_constraints ;
98+ & * * external_constraints ;
10199
102- a_max_universe == & b. max_universe
103- && a_var_kinds == & b. var_kinds
104- && a_var_values == & b. value . var_values
105- && a_certainty == & b. value . certainty
100+ let eq_up_to_var_kinds = var_values == & b. value . var_values
101+ && certainty == & b. value . certainty
106102 && opaque_types == & b. value . external_constraints . opaque_types
107- && normalization_nested_goals == & b. value . external_constraints . normalization_nested_goals
103+ && normalization_nested_goals == & b. value . external_constraints . normalization_nested_goals ;
104+
105+ if !eq_up_to_var_kinds {
106+ return false ;
107+ }
108+
109+ if var_kinds == & b. var_kinds {
110+ true
111+ } else {
112+ // If only the `var_kinds` are different, we have to check whether they only
113+ // differ due to region constraints.
114+ //
115+ // FIXE: This is only only sufficient if region constraints are canonicalized
116+ // last, which they are not. This means this check incorrectly returns `false` if
117+ // either the `opaque_types` or `normalization_nested_goals` reference variables
118+ // not mentioned before. The only way this happens is if they mention placeholders
119+ // or higher-ranked existential variables created inside of the query. This feels
120+ // very unlikely and maybe not even worth fixing.
121+ let num_shared: usize =
122+ var_kinds. iter ( ) . zip ( b. var_kinds . iter ( ) ) . take_while ( |( a, b) | a == b) . count ( ) ;
123+ response_only_references_shared_vars_outside_of_region_constraints ( num_shared, a)
124+ && response_only_references_shared_vars_outside_of_region_constraints ( num_shared, b)
125+ }
126+ }
127+
128+ fn response_only_references_shared_vars_outside_of_region_constraints < I : Interner > (
129+ num_shared : usize ,
130+ response : & CanonicalResponse < I > ,
131+ ) -> bool {
132+ struct ReferencesVarKindGtNumShared {
133+ num_shared : usize ,
134+ }
135+ impl < I : Interner > TypeVisitor < I > for ReferencesVarKindGtNumShared {
136+ type Result = Result < ( ) , ( ) > ;
137+
138+ fn visit_ty ( & mut self , t : I :: Ty ) -> Result < ( ) , ( ) > {
139+ if let ty:: Bound ( BoundVarIndexKind :: Canonical , b) = t. kind ( ) {
140+ if b. var . as_usize ( ) >= self . num_shared { Err ( ( ) ) } else { Ok ( ( ) ) }
141+ } else if t. has_type_flags ( TypeFlags :: HAS_CANONICAL_BOUND ) {
142+ t. super_visit_with ( self )
143+ } else {
144+ Ok ( ( ) )
145+ }
146+ }
147+
148+ fn visit_region ( & mut self , r : Region < I > ) -> Result < ( ) , ( ) > {
149+ if let ty:: ReBound ( BoundVarIndexKind :: Canonical , b) = r. kind ( ) {
150+ if b. var . as_usize ( ) >= self . num_shared { Err ( ( ) ) } else { Ok ( ( ) ) }
151+ } else {
152+ Ok ( ( ) )
153+ }
154+ }
155+
156+ fn visit_const ( & mut self , c : Const < I > ) -> Result < ( ) , ( ) > {
157+ if let ty:: ConstKind :: Bound ( BoundVarIndexKind :: Canonical , b) = c. kind ( ) {
158+ if b. var . as_usize ( ) >= self . num_shared { Err ( ( ) ) } else { Ok ( ( ) ) }
159+ } else if c. has_type_flags ( TypeFlags :: HAS_CANONICAL_BOUND ) {
160+ c. super_visit_with ( self )
161+ } else {
162+ Ok ( ( ) )
163+ }
164+ }
165+
166+ fn visit_predicate < P : rustc_type_ir:: PredicateProxy < I > > ( & mut self , p : P ) -> Result < ( ) , ( ) > {
167+ if p. has_type_flags ( TypeFlags :: HAS_CANONICAL_BOUND ) {
168+ p. super_visit_with ( self )
169+ } else {
170+ Ok ( ( ) )
171+ }
172+ }
173+ }
174+
175+ let mut visitor = ReferencesVarKindGtNumShared { num_shared } ;
176+
177+ let CanonicalResponse {
178+ max_universe : _,
179+ var_kinds : _,
180+ value : Response { var_values, certainty : _, external_constraints } ,
181+ } = response;
182+ let ExternalConstraintsData { region_constraints : _, opaque_types, normalization_nested_goals } =
183+ & * * external_constraints;
184+ var_values. visit_with ( & mut visitor) . is_ok ( )
185+ && opaque_types. visit_with ( & mut visitor) . is_ok ( )
186+ && normalization_nested_goals. visit_with ( & mut visitor) . is_ok ( )
108187}
109188
110189impl < ' a , D , I > EvalCtxt < ' a , D >
@@ -319,12 +398,6 @@ where
319398 }
320399}
321400
322- #[ derive( Debug ) ]
323- enum MergeCandidateInfo {
324- AlwaysApplicable ( usize ) ,
325- EqualResponse ,
326- }
327-
328401impl < D , I > EvalCtxt < ' _ , D >
329402where
330403 D : SolverDelegate < Interner = I > ,
@@ -337,48 +410,33 @@ where
337410 fn try_merge_candidates (
338411 & mut self ,
339412 candidates : & [ Candidate < I > ] ,
340- ) -> Option < ( CanonicalResponse < I > , MergeCandidateInfo ) > {
341- if candidates. is_empty ( ) {
413+ ) -> Option < CanonicalResponse < I > > {
414+ let Some ( ( first , rest ) ) = candidates. split_first ( ) else {
342415 return None ;
343- }
344-
345- let always_applicable = candidates. iter ( ) . enumerate ( ) . find ( |( _, candidate) | {
346- candidate. result . value . certainty == Certainty :: Yes
347- && has_no_inference_or_external_constraints ( candidate. result )
348- } ) ;
416+ } ;
349417
350- if let Some ( ( i, candidate) ) = always_applicable {
351- return Some ( ( candidate. result , MergeCandidateInfo :: AlwaysApplicable ( i) ) ) ;
418+ if rest. iter ( ) . any ( |candidate| {
419+ !equal_response_modulo_region_constraints ( & first. result , & candidate. result )
420+ } ) {
421+ return None ;
352422 }
353423
354- let one: CanonicalResponse < I > = candidates[ 0 ] . result ;
355-
356- if candidates[ 1 ..]
357- . iter ( )
358- . all ( |candidate| equal_response_modulo_region_constraints ( & one, & candidate. result ) )
359- {
360- let region_constraints = & one. value . external_constraints . region_constraints ;
361- if candidates[ 1 ..] . iter ( ) . all ( |candidate| {
362- & candidate. result . value . external_constraints . region_constraints
363- == region_constraints
364- } ) {
365- return Some ( ( one, MergeCandidateInfo :: EqualResponse ) ) ;
366- }
367-
368- // If candidates differ only in region constraints, their merged region
369- // constraints are an `Or` of their respective constraints. If one of them
370- // has no region constraints, the `Or` constraint evaluates to `true`.
371- //
372- // This is a special case of `-Zassumptions-on-binders` and should be
373- // replaced eventually.
374- if let Some ( candidate) = candidates. iter ( ) . find ( |candidate| {
375- candidate. result . value . external_constraints . region_constraints . is_empty ( )
376- } ) {
377- return Some ( ( candidate. result , MergeCandidateInfo :: EqualResponse ) ) ;
378- }
424+ let region_constraints = & first. result . value . external_constraints . region_constraints ;
425+ if candidates[ 1 ..] . iter ( ) . all ( |candidate| {
426+ & candidate. result . value . external_constraints . region_constraints == region_constraints
427+ } ) {
428+ return Some ( first. result ) ;
379429 }
380430
381- None
431+ // If candidates differ only in region constraints, their merged region
432+ // constraints are an OR of their respective constraints. We don't support
433+ // OR constraints yet, so the only way we can merge differing candidates
434+ // if one of them has no region constraints as then the OR constraint
435+ // is trivially true.
436+ candidates
437+ . iter ( )
438+ . find ( |c| c. result . value . external_constraints . region_constraints . is_empty ( ) )
439+ . map ( |c| c. result )
382440 }
383441
384442 fn bail_with_ambiguity ( & mut self , candidates : & [ Candidate < I > ] ) -> CanonicalResponse < I > {
0 commit comments