1 use super::type_variable
::{TypeVariableOrigin, TypeVariableOriginKind}
;
2 use super::{FixupError, FixupResult, InferCtxt, Span}
;
3 use rustc_middle
::infer
::unify_key
::{ConstVariableOrigin, ConstVariableOriginKind}
;
4 use rustc_middle
::ty
::fold
::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}
;
5 use rustc_middle
::ty
::visit
::{TypeSuperVisitable, TypeVisitor}
;
6 use rustc_middle
::ty
::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}
;
8 use std
::ops
::ControlFlow
;
10 ///////////////////////////////////////////////////////////////////////////
11 // OPPORTUNISTIC VAR RESOLVER
13 /// The opportunistic resolver can be used at any time. It simply replaces
14 /// type/const variables that have been unified with the things they have
15 /// been unified with (similar to `shallow_resolve`, but deep). This is
16 /// useful for printing messages etc but also required at various
17 /// points for correctness.
18 pub struct OpportunisticVarResolver
<'a
, 'tcx
> {
19 infcx
: &'a InferCtxt
<'tcx
>,
22 impl<'a
, 'tcx
> OpportunisticVarResolver
<'a
, 'tcx
> {
24 pub fn new(infcx
: &'a InferCtxt
<'tcx
>) -> Self {
25 OpportunisticVarResolver { infcx }
29 impl<'a
, 'tcx
> TypeFolder
<'tcx
> for OpportunisticVarResolver
<'a
, 'tcx
> {
30 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
34 fn fold_ty(&mut self, t
: Ty
<'tcx
>) -> Ty
<'tcx
> {
35 if !t
.has_non_region_infer() {
36 t
// micro-optimize -- if there is nothing in this type that this fold affects...
38 let t
= self.infcx
.shallow_resolve(t
);
39 t
.super_fold_with(self)
43 fn fold_const(&mut self, ct
: Const
<'tcx
>) -> Const
<'tcx
> {
44 if !ct
.has_non_region_infer() {
45 ct
// micro-optimize -- if there is nothing in this const that this fold affects...
47 let ct
= self.infcx
.shallow_resolve(ct
);
48 ct
.super_fold_with(self)
53 /// The opportunistic region resolver opportunistically resolves regions
54 /// variables to the variable with the least variable id. It is used when
55 /// normalizing projections to avoid hitting the recursion limit by creating
56 /// many versions of a predicate for types that in the end have to unify.
58 /// If you want to resolve type and const variables as well, call
59 /// [InferCtxt::resolve_vars_if_possible] first.
60 pub struct OpportunisticRegionResolver
<'a
, 'tcx
> {
61 infcx
: &'a InferCtxt
<'tcx
>,
64 impl<'a
, 'tcx
> OpportunisticRegionResolver
<'a
, 'tcx
> {
65 pub fn new(infcx
: &'a InferCtxt
<'tcx
>) -> Self {
66 OpportunisticRegionResolver { infcx }
70 impl<'a
, 'tcx
> TypeFolder
<'tcx
> for OpportunisticRegionResolver
<'a
, 'tcx
> {
71 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
75 fn fold_ty(&mut self, t
: Ty
<'tcx
>) -> Ty
<'tcx
> {
76 if !t
.has_infer_regions() {
77 t
// micro-optimize -- if there is nothing in this type that this fold affects...
79 t
.super_fold_with(self)
83 fn fold_region(&mut self, r
: ty
::Region
<'tcx
>) -> ty
::Region
<'tcx
> {
90 .unwrap_region_constraints()
91 .opportunistic_resolve_var(rid
);
92 TypeFolder
::tcx(self).reuse_or_mk_region(r
, ty
::ReVar(resolved
))
98 fn fold_const(&mut self, ct
: ty
::Const
<'tcx
>) -> ty
::Const
<'tcx
> {
99 if !ct
.has_infer_regions() {
100 ct
// micro-optimize -- if there is nothing in this const that this fold affects...
102 ct
.super_fold_with(self)
107 ///////////////////////////////////////////////////////////////////////////
108 // UNRESOLVED TYPE FINDER
110 /// The unresolved type **finder** walks a type searching for
111 /// type variables that don't yet have a value. The first unresolved type is stored.
112 /// It does not construct the fully resolved type (which might
113 /// involve some hashing and so forth).
114 pub struct UnresolvedTypeOrConstFinder
<'a
, 'tcx
> {
115 infcx
: &'a InferCtxt
<'tcx
>,
118 impl<'a
, 'tcx
> UnresolvedTypeOrConstFinder
<'a
, 'tcx
> {
119 pub fn new(infcx
: &'a InferCtxt
<'tcx
>) -> Self {
120 UnresolvedTypeOrConstFinder { infcx }
124 impl<'a
, 'tcx
> TypeVisitor
<'tcx
> for UnresolvedTypeOrConstFinder
<'a
, 'tcx
> {
125 type BreakTy
= (ty
::Term
<'tcx
>, Option
<Span
>);
126 fn visit_ty(&mut self, t
: Ty
<'tcx
>) -> ControlFlow
<Self::BreakTy
> {
127 let t
= self.infcx
.shallow_resolve(t
);
128 if let ty
::Infer(infer_ty
) = *t
.kind() {
129 // Since we called `shallow_resolve` above, this must
130 // be an (as yet...) unresolved inference variable.
131 let ty_var_span
= if let ty
::TyVar(ty_vid
) = infer_ty
{
132 let mut inner
= self.infcx
.inner
.borrow_mut();
133 let ty_vars
= &inner
.type_variables();
134 if let TypeVariableOrigin
{
135 kind
: TypeVariableOriginKind
::TypeParameterDefinition(_
, _
),
137 } = *ty_vars
.var_origin(ty_vid
)
146 ControlFlow
::Break((t
.into(), ty_var_span
))
147 } else if !t
.has_non_region_infer() {
148 // All const/type variables in inference types must already be resolved,
149 // no need to visit the contents.
150 ControlFlow
::CONTINUE
152 // Otherwise, keep visiting.
153 t
.super_visit_with(self)
157 fn visit_const(&mut self, ct
: ty
::Const
<'tcx
>) -> ControlFlow
<Self::BreakTy
> {
158 let ct
= self.infcx
.shallow_resolve(ct
);
159 if let ty
::ConstKind
::Infer(i
) = ct
.kind() {
160 // Since we called `shallow_resolve` above, this must
161 // be an (as yet...) unresolved inference variable.
162 let ct_var_span
= if let ty
::InferConst
::Var(vid
) = i
{
163 let mut inner
= self.infcx
.inner
.borrow_mut();
164 let ct_vars
= &mut inner
.const_unification_table();
165 if let ConstVariableOrigin
{
167 kind
: ConstVariableOriginKind
::ConstParameterDefinition(_
, _
),
168 } = ct_vars
.probe_value(vid
).origin
177 ControlFlow
::Break((ct
.into(), ct_var_span
))
178 } else if !ct
.has_non_region_infer() {
179 // All const/type variables in inference types must already be resolved,
180 // no need to visit the contents.
181 ControlFlow
::CONTINUE
183 // Otherwise, keep visiting.
184 ct
.super_visit_with(self)
189 ///////////////////////////////////////////////////////////////////////////
190 // FULL TYPE RESOLUTION
192 /// Full type resolution replaces all type and region variables with
193 /// their concrete results. If any variable cannot be replaced (never unified, etc)
194 /// then an `Err` result is returned.
195 pub fn fully_resolve
<'tcx
, T
>(infcx
: &InferCtxt
<'tcx
>, value
: T
) -> FixupResult
<'tcx
, T
>
197 T
: TypeFoldable
<'tcx
>,
199 value
.try_fold_with(&mut FullTypeResolver { infcx }
)
202 // N.B. This type is not public because the protocol around checking the
203 // `err` field is not enforceable otherwise.
204 struct FullTypeResolver
<'a
, 'tcx
> {
205 infcx
: &'a InferCtxt
<'tcx
>,
208 impl<'a
, 'tcx
> FallibleTypeFolder
<'tcx
> for FullTypeResolver
<'a
, 'tcx
> {
209 type Error
= FixupError
<'tcx
>;
211 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
215 fn try_fold_ty(&mut self, t
: Ty
<'tcx
>) -> Result
<Ty
<'tcx
>, Self::Error
> {
216 if !t
.needs_infer() {
217 Ok(t
) // micro-optimize -- if there is nothing in this type that this fold affects...
219 let t
= self.infcx
.shallow_resolve(t
);
221 ty
::Infer(ty
::TyVar(vid
)) => Err(FixupError
::UnresolvedTy(vid
)),
222 ty
::Infer(ty
::IntVar(vid
)) => Err(FixupError
::UnresolvedIntTy(vid
)),
223 ty
::Infer(ty
::FloatVar(vid
)) => Err(FixupError
::UnresolvedFloatTy(vid
)),
225 bug
!("Unexpected type in full type resolver: {:?}", t
);
227 _
=> t
.try_super_fold_with(self),
232 fn try_fold_region(&mut self, r
: ty
::Region
<'tcx
>) -> Result
<ty
::Region
<'tcx
>, Self::Error
> {
234 ty
::ReVar(_
) => Ok(self
236 .lexical_region_resolutions
239 .expect("region resolution not performed")
240 .resolve_region(self.infcx
.tcx
, r
)),
245 fn try_fold_const(&mut self, c
: ty
::Const
<'tcx
>) -> Result
<ty
::Const
<'tcx
>, Self::Error
> {
246 if !c
.needs_infer() {
247 Ok(c
) // micro-optimize -- if there is nothing in this const that this fold affects...
249 let c
= self.infcx
.shallow_resolve(c
);
251 ty
::ConstKind
::Infer(InferConst
::Var(vid
)) => {
252 return Err(FixupError
::UnresolvedConst(vid
));
254 ty
::ConstKind
::Infer(InferConst
::Fresh(_
)) => {
255 bug
!("Unexpected const in full const resolver: {:?}", c
);
259 c
.try_super_fold_with(self)