1
1
//! Unification and canonicalization logic.
2
2
3
- use std:: { fmt, mem, sync:: Arc } ;
3
+ use std:: { fmt, iter , mem, sync:: Arc } ;
4
4
5
5
use chalk_ir:: {
6
6
cast:: Cast , fold:: TypeFoldable , interner:: HasInterner , zip:: Zip , CanonicalVarKind , FloatTy ,
@@ -128,9 +128,13 @@ pub(crate) fn unify(
128
128
) )
129
129
}
130
130
131
- #[ derive( Copy , Clone , Debug ) ]
132
- pub ( crate ) struct TypeVariableData {
133
- diverging : bool ,
131
+ bitflags:: bitflags! {
132
+ #[ derive( Default ) ]
133
+ pub ( crate ) struct TypeVariableFlags : u8 {
134
+ const DIVERGING = 1 << 0 ;
135
+ const INTEGER = 1 << 1 ;
136
+ const FLOAT = 1 << 2 ;
137
+ }
134
138
}
135
139
136
140
type ChalkInferenceTable = chalk_solve:: infer:: InferenceTable < Interner > ;
@@ -140,14 +144,14 @@ pub(crate) struct InferenceTable<'a> {
140
144
pub ( crate ) db : & ' a dyn HirDatabase ,
141
145
pub ( crate ) trait_env : Arc < TraitEnvironment > ,
142
146
var_unification_table : ChalkInferenceTable ,
143
- type_variable_table : Vec < TypeVariableData > ,
147
+ type_variable_table : Vec < TypeVariableFlags > ,
144
148
pending_obligations : Vec < Canonicalized < InEnvironment < Goal > > > ,
145
149
}
146
150
147
151
pub ( crate ) struct InferenceTableSnapshot {
148
152
var_table_snapshot : chalk_solve:: infer:: InferenceSnapshot < Interner > ,
149
153
pending_obligations : Vec < Canonicalized < InEnvironment < Goal > > > ,
150
- type_variable_table_snapshot : Vec < TypeVariableData > ,
154
+ type_variable_table_snapshot : Vec < TypeVariableFlags > ,
151
155
}
152
156
153
157
impl < ' a > InferenceTable < ' a > {
@@ -169,27 +173,27 @@ impl<'a> InferenceTable<'a> {
169
173
/// result.
170
174
pub ( super ) fn propagate_diverging_flag ( & mut self ) {
171
175
for i in 0 ..self . type_variable_table . len ( ) {
172
- if !self . type_variable_table [ i] . diverging {
176
+ if !self . type_variable_table [ i] . contains ( TypeVariableFlags :: DIVERGING ) {
173
177
continue ;
174
178
}
175
179
let v = InferenceVar :: from ( i as u32 ) ;
176
180
let root = self . var_unification_table . inference_var_root ( v) ;
177
181
if let Some ( data) = self . type_variable_table . get_mut ( root. index ( ) as usize ) {
178
- data. diverging = true ;
182
+ * data |= TypeVariableFlags :: DIVERGING ;
179
183
}
180
184
}
181
185
}
182
186
183
187
pub ( super ) fn set_diverging ( & mut self , iv : InferenceVar , diverging : bool ) {
184
- self . type_variable_table [ iv. index ( ) as usize ] . diverging = diverging;
188
+ self . type_variable_table [ iv. index ( ) as usize ] . set ( TypeVariableFlags :: DIVERGING , diverging) ;
185
189
}
186
190
187
191
fn fallback_value ( & self , iv : InferenceVar , kind : TyVariableKind ) -> Ty {
188
192
match kind {
189
193
_ if self
190
194
. type_variable_table
191
195
. get ( iv. index ( ) as usize )
192
- . map_or ( false , |data| data. diverging ) =>
196
+ . map_or ( false , |data| data. contains ( TypeVariableFlags :: DIVERGING ) ) =>
193
197
{
194
198
TyKind :: Never
195
199
}
@@ -247,18 +251,24 @@ impl<'a> InferenceTable<'a> {
247
251
}
248
252
249
253
fn extend_type_variable_table ( & mut self , to_index : usize ) {
250
- self . type_variable_table . extend (
251
- ( 0 ..1 + to_index - self . type_variable_table . len ( ) )
252
- . map ( |_| TypeVariableData { diverging : false } ) ,
253
- ) ;
254
+ let count = to_index - self . type_variable_table . len ( ) + 1 ;
255
+ self . type_variable_table . extend ( iter:: repeat ( TypeVariableFlags :: default ( ) ) . take ( count) ) ;
254
256
}
255
257
256
258
fn new_var ( & mut self , kind : TyVariableKind , diverging : bool ) -> Ty {
257
259
let var = self . var_unification_table . new_variable ( UniverseIndex :: ROOT ) ;
258
260
// Chalk might have created some type variables for its own purposes that we don't know about...
259
261
self . extend_type_variable_table ( var. index ( ) as usize ) ;
260
262
assert_eq ! ( var. index( ) as usize , self . type_variable_table. len( ) - 1 ) ;
261
- self . type_variable_table [ var. index ( ) as usize ] . diverging = diverging;
263
+ let flags = self . type_variable_table . get_mut ( var. index ( ) as usize ) . unwrap ( ) ;
264
+ if diverging {
265
+ * flags |= TypeVariableFlags :: DIVERGING ;
266
+ }
267
+ if matches ! ( kind, TyVariableKind :: Integer ) {
268
+ * flags |= TypeVariableFlags :: INTEGER ;
269
+ } else if matches ! ( kind, TyVariableKind :: Float ) {
270
+ * flags |= TypeVariableFlags :: FLOAT ;
271
+ }
262
272
var. to_ty_with_kind ( Interner , kind)
263
273
}
264
274
@@ -340,6 +350,51 @@ impl<'a> InferenceTable<'a> {
340
350
self . resolve_with_fallback ( t, & |_, _, d, _| d)
341
351
}
342
352
353
+ /// Apply a fallback to unresolved scalar types. Integer type variables and float type
354
+ /// variables are replaced with i32 and f64, respectively.
355
+ ///
356
+ /// This method is only intended to be called just before returning inference results (i.e. in
357
+ /// `InferenceContext::resolve_all()`).
358
+ ///
359
+ /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
360
+ /// whereas rustc replaces them with `()` or `!`.
361
+ pub ( super ) fn fallback_if_possible ( & mut self ) {
362
+ let int_fallback = TyKind :: Scalar ( Scalar :: Int ( IntTy :: I32 ) ) . intern ( Interner ) ;
363
+ let float_fallback = TyKind :: Scalar ( Scalar :: Float ( FloatTy :: F64 ) ) . intern ( Interner ) ;
364
+
365
+ let scalar_vars: Vec < _ > = self
366
+ . type_variable_table
367
+ . iter ( )
368
+ . enumerate ( )
369
+ . filter_map ( |( index, flags) | {
370
+ let kind = if flags. contains ( TypeVariableFlags :: INTEGER ) {
371
+ TyVariableKind :: Integer
372
+ } else if flags. contains ( TypeVariableFlags :: FLOAT ) {
373
+ TyVariableKind :: Float
374
+ } else {
375
+ return None ;
376
+ } ;
377
+
378
+ // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
379
+ // without directly constructing them from `index`?
380
+ let var = InferenceVar :: from ( index as u32 ) . to_ty ( Interner , kind) ;
381
+ Some ( var)
382
+ } )
383
+ . collect ( ) ;
384
+
385
+ for var in scalar_vars {
386
+ let maybe_resolved = self . resolve_ty_shallow ( & var) ;
387
+ if let TyKind :: InferenceVar ( _, kind) = maybe_resolved. kind ( Interner ) {
388
+ let fallback = match kind {
389
+ TyVariableKind :: Integer => & int_fallback,
390
+ TyVariableKind :: Float => & float_fallback,
391
+ TyVariableKind :: General => unreachable ! ( ) ,
392
+ } ;
393
+ self . unify ( & var, fallback) ;
394
+ }
395
+ }
396
+ }
397
+
343
398
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
344
399
pub ( crate ) fn unify < T : ?Sized + Zip < Interner > > ( & mut self , ty1 : & T , ty2 : & T ) -> bool {
345
400
let result = match self . try_unify ( ty1, ty2) {
0 commit comments