22//! Doing this via a separate goal is called "deferred alias relation" and part
33//! of our more general approach to "lazy normalization".
44//!
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.
77//! These are related further according to the rules below:
88//!
99//! (1.) If we end up with two rigid aliases, then we relate them structurally.
1414//!
1515//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
1616//! 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.
2317
2418use super :: EvalCtxt ;
25- use rustc_infer:: traits:: query:: NoSolution ;
26- use rustc_infer:: traits:: solve:: GoalSource ;
2719use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
28- use rustc_middle:: ty:: { self , Ty } ;
20+ use rustc_middle:: ty;
2921
3022impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
3123 #[ instrument( level = "debug" , skip( self ) , ret) ]
@@ -36,141 +28,58 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3628 let tcx = self . tcx ( ) ;
3729 let Goal { param_env, predicate : ( lhs, rhs, direction) } = goal;
3830
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
4238 } ;
4339
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
4747 } ;
4848
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+
4955 let variance = match direction {
5056 ty:: AliasRelationDirection :: Equate => ty:: Variance :: Invariant ,
5157 ty:: AliasRelationDirection :: Subtype => ty:: Variance :: Covariant ,
5258 } ;
53-
5459 match ( lhs. to_alias_ty ( tcx) , rhs. to_alias_ty ( tcx) ) {
5560 ( None , None ) => {
5661 self . relate ( param_env, lhs, variance, rhs) ?;
5762 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
5863 }
5964
6065 ( 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 )
6277 }
63- ( None , Some ( alias) ) => self . relate_rigid_alias_non_alias (
64- param_env,
65- alias,
66- variance. xform ( ty:: Variance :: Contravariant ) ,
67- lhs,
68- ) ,
6978
7079 ( Some ( alias_lhs) , Some ( alias_rhs) ) => {
7180 self . relate ( param_env, alias_lhs, variance, alias_rhs) ?;
7281 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
7382 }
7483 }
7584 }
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- }
17685}
0 commit comments