1
- use crate :: check:: FallbackMode ;
2
1
use crate :: check:: FnCtxt ;
2
+ use rustc_infer:: infer:: type_variable:: Diverging ;
3
+ use rustc_middle:: ty:: { self , Ty } ;
3
4
4
5
impl < ' tcx > FnCtxt < ' _ , ' tcx > {
5
6
pub ( super ) fn type_inference_fallback ( & self ) {
@@ -12,8 +13,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
12
13
// The first time, we do *not* replace opaque types.
13
14
for ty in & self . unsolved_variables ( ) {
14
15
debug ! ( "unsolved_variable = {:?}" , ty) ;
15
- fallback_has_occurred |= self . fallback_if_possible ( ty, FallbackMode :: NoOpaque ) ;
16
+ fallback_has_occurred |= self . fallback_if_possible ( ty) ;
16
17
}
18
+
17
19
// We now see if we can make progress. This might
18
20
// cause us to unify inference variables for opaque types,
19
21
// since we may have unified some other type variables
@@ -43,10 +45,113 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
43
45
// unconstrained opaque type variables, in addition to performing
44
46
// other kinds of fallback.
45
47
for ty in & self . unsolved_variables ( ) {
46
- fallback_has_occurred |= self . fallback_if_possible ( ty, FallbackMode :: All ) ;
48
+ fallback_has_occurred |= self . fallback_opaque_type_vars ( ty) ;
47
49
}
48
50
49
51
// See if we can make any more progress.
50
52
self . select_obligations_where_possible ( fallback_has_occurred, |_| { } ) ;
51
53
}
54
+
55
+ // Tries to apply a fallback to `ty` if it is an unsolved variable.
56
+ //
57
+ // - Unconstrained ints are replaced with `i32`.
58
+ //
59
+ // - Unconstrained floats are replaced with with `f64`.
60
+ //
61
+ // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
62
+ // is enabled. Otherwise, they are replaced with `()`.
63
+ //
64
+ // Fallback becomes very dubious if we have encountered type-checking errors.
65
+ // In that case, fallback to Error.
66
+ // The return value indicates whether fallback has occurred.
67
+ fn fallback_if_possible ( & self , ty : Ty < ' tcx > ) -> bool {
68
+ // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
69
+ // is an unsolved variable, and we determine its fallback based
70
+ // solely on how it was created, not what other type variables
71
+ // it may have been unified with since then.
72
+ //
73
+ // The reason this matters is that other attempts at fallback may
74
+ // (in principle) conflict with this fallback, and we wish to generate
75
+ // a type error in that case. (However, this actually isn't true right now,
76
+ // because we're only using the builtin fallback rules. This would be
77
+ // true if we were using user-supplied fallbacks. But it's still useful
78
+ // to write the code to detect bugs.)
79
+ //
80
+ // (Note though that if we have a general type variable `?T` that is then unified
81
+ // with an integer type variable `?I` that ultimately never gets
82
+ // resolved to a special integral type, `?T` is not considered unsolved,
83
+ // but `?I` is. The same is true for float variables.)
84
+ let fallback = match ty. kind ( ) {
85
+ _ if self . is_tainted_by_errors ( ) => self . tcx . ty_error ( ) ,
86
+ ty:: Infer ( ty:: IntVar ( _) ) => self . tcx . types . i32 ,
87
+ ty:: Infer ( ty:: FloatVar ( _) ) => self . tcx . types . f64 ,
88
+ _ => match self . type_var_diverges ( ty) {
89
+ Diverging :: Diverges => self . tcx . mk_diverging_default ( ) ,
90
+ Diverging :: NotDiverging => return false ,
91
+ } ,
92
+ } ;
93
+ debug ! ( "fallback_if_possible(ty={:?}): defaulting to `{:?}`" , ty, fallback) ;
94
+
95
+ let span = self
96
+ . infcx
97
+ . type_var_origin ( ty)
98
+ . map ( |origin| origin. span )
99
+ . unwrap_or ( rustc_span:: DUMMY_SP ) ;
100
+ self . demand_eqtype ( span, ty, fallback) ;
101
+ true
102
+ }
103
+
104
+ /// Second round of fallback: Unconstrained type variables
105
+ /// created from the instantiation of an opaque
106
+ /// type fall back to the opaque type itself. This is a
107
+ /// somewhat incomplete attempt to manage "identity passthrough"
108
+ /// for `impl Trait` types.
109
+ ///
110
+ /// For example, in this code:
111
+ ///
112
+ ///```
113
+ /// type MyType = impl Copy;
114
+ /// fn defining_use() -> MyType { true }
115
+ /// fn other_use() -> MyType { defining_use() }
116
+ /// ```
117
+ ///
118
+ /// `defining_use` will constrain the instantiated inference
119
+ /// variable to `bool`, while `other_use` will constrain
120
+ /// the instantiated inference variable to `MyType`.
121
+ ///
122
+ /// When we process opaque types during writeback, we
123
+ /// will handle cases like `other_use`, and not count
124
+ /// them as defining usages
125
+ ///
126
+ /// However, we also need to handle cases like this:
127
+ ///
128
+ /// ```rust
129
+ /// pub type Foo = impl Copy;
130
+ /// fn produce() -> Option<Foo> {
131
+ /// None
132
+ /// }
133
+ /// ```
134
+ ///
135
+ /// In the above snippet, the inference variable created by
136
+ /// instantiating `Option<Foo>` will be completely unconstrained.
137
+ /// We treat this as a non-defining use by making the inference
138
+ /// variable fall back to the opaque type itself.
139
+ fn fallback_opaque_type_vars ( & self , ty : Ty < ' tcx > ) -> bool {
140
+ let span = self
141
+ . infcx
142
+ . type_var_origin ( ty)
143
+ . map ( |origin| origin. span )
144
+ . unwrap_or ( rustc_span:: DUMMY_SP ) ;
145
+ let oty = self . inner . borrow ( ) . opaque_types_vars . get ( ty) . map ( |v| * v) ;
146
+ if let Some ( opaque_ty) = oty {
147
+ debug ! (
148
+ "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}" ,
149
+ ty, opaque_ty
150
+ ) ;
151
+ self . demand_eqtype ( span, ty, opaque_ty) ;
152
+ true
153
+ } else {
154
+ return false ;
155
+ }
156
+ }
52
157
}
0 commit comments