12
12
//! may apply, then we can compute the "intersection" of both normalizes-to by
13
13
//! performing them together. This is used specifically to resolve ambiguities.
14
14
use super :: EvalCtxt ;
15
+ use rustc_infer:: infer:: DefineOpaqueTypes ;
15
16
use rustc_infer:: traits:: query:: NoSolution ;
16
17
use rustc_middle:: traits:: solve:: { Certainty , Goal , QueryResult } ;
17
18
use rustc_middle:: ty;
@@ -44,38 +45,46 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
44
45
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
45
46
}
46
47
47
- ( Some ( _ ) , None ) => {
48
+ ( Some ( alias ) , None ) => {
48
49
if rhs. is_infer ( ) {
49
50
self . relate ( param_env, lhs, variance, rhs) ?;
50
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)
51
54
} else {
52
55
Err ( NoSolution )
53
56
}
54
57
}
55
- ( None , Some ( _ ) ) => {
58
+ ( None , Some ( alias ) ) => {
56
59
if lhs. is_infer ( ) {
57
60
self . relate ( param_env, lhs, variance, rhs) ?;
58
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)
59
64
} else {
60
65
Err ( NoSolution )
61
66
}
62
67
}
63
68
64
69
( Some ( alias_lhs) , Some ( alias_rhs) ) => {
65
- self . relate ( param_env, alias_lhs, variance, alias_rhs) ?;
66
- self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
70
+ self . relate_rigid_alias_or_opaque ( param_env, alias_lhs, variance, alias_rhs)
67
71
}
68
72
}
69
73
}
70
74
71
- /// Normalize the `term` to equate it later.
75
+ /// Normalize the `term` to equate it later. This does not define opaque types.
72
76
fn try_normalize_term (
73
77
& mut self ,
74
78
param_env : ty:: ParamEnv < ' tcx > ,
75
79
term : ty:: Term < ' tcx > ,
76
80
) -> Result < Option < ty:: Term < ' tcx > > , NoSolution > {
77
81
match term. unpack ( ) {
78
- ty:: TermKind :: Ty ( ty) => Ok ( self . try_normalize_ty ( param_env, ty) . map ( Into :: into) ) ,
82
+ ty:: TermKind :: Ty ( ty) => {
83
+ // We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
84
+ Ok ( self
85
+ . try_normalize_ty_recur ( param_env, DefineOpaqueTypes :: No , 0 , ty)
86
+ . map ( Into :: into) )
87
+ }
79
88
ty:: TermKind :: Const ( _) => {
80
89
if let Some ( alias) = term. to_alias_ty ( self . tcx ( ) ) {
81
90
let term = self . next_term_infer_of_kind ( term) ;
@@ -92,4 +101,53 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
92
101
}
93
102
}
94
103
}
104
+
105
+ fn define_opaque (
106
+ & mut self ,
107
+ param_env : ty:: ParamEnv < ' tcx > ,
108
+ opaque : ty:: AliasTy < ' tcx > ,
109
+ term : ty:: Term < ' tcx > ,
110
+ ) -> QueryResult < ' tcx > {
111
+ self . add_goal ( Goal :: new (
112
+ self . tcx ( ) ,
113
+ param_env,
114
+ ty:: ProjectionPredicate { projection_ty : opaque, term } ,
115
+ ) ) ;
116
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
117
+ }
118
+
119
+ fn relate_rigid_alias_or_opaque (
120
+ & mut self ,
121
+ param_env : ty:: ParamEnv < ' tcx > ,
122
+ lhs : ty:: AliasTy < ' tcx > ,
123
+ variance : ty:: Variance ,
124
+ rhs : ty:: AliasTy < ' tcx > ,
125
+ ) -> QueryResult < ' tcx > {
126
+ let tcx = self . tcx ( ) ;
127
+ let mut candidates = vec ! [ ] ;
128
+ if lhs. is_opaque ( tcx) {
129
+ candidates. extend (
130
+ self . probe_misc_candidate ( "define-lhs-opaque" )
131
+ . enter ( |ecx| ecx. define_opaque ( param_env, lhs, rhs. to_ty ( tcx) . into ( ) ) ) ,
132
+ ) ;
133
+ }
134
+
135
+ if rhs. is_opaque ( tcx) {
136
+ candidates. extend (
137
+ self . probe_misc_candidate ( "define-rhs-opaque" )
138
+ . enter ( |ecx| ecx. define_opaque ( param_env, rhs, lhs. to_ty ( tcx) . into ( ) ) ) ,
139
+ ) ;
140
+ }
141
+
142
+ candidates. extend ( self . probe_misc_candidate ( "args-relate" ) . enter ( |ecx| {
143
+ ecx. relate ( param_env, lhs, variance, rhs) ?;
144
+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
145
+ } ) ) ;
146
+
147
+ if let Some ( result) = self . try_merge_responses ( & candidates) {
148
+ Ok ( result)
149
+ } else {
150
+ self . flounder ( & candidates)
151
+ }
152
+ }
95
153
}
0 commit comments