@@ -3,15 +3,15 @@ use std::iter::zip;
3
3
use formality_core:: { Fallible , Map , Upcast } ;
4
4
use formality_prove:: Env ;
5
5
use formality_rust:: grammar:: minirust:: ArgumentExpression :: { ByValue , InPlace } ;
6
- use formality_rust:: grammar:: minirust:: PlaceExpression :: Local ;
7
- use formality_rust:: grammar:: minirust:: ValueExpression :: { Constant , Fn , Load } ;
6
+ use formality_rust:: grammar:: minirust:: PlaceExpression :: * ;
7
+ use formality_rust:: grammar:: minirust:: ValueExpression :: { Constant , Fn , Load , Struct } ;
8
8
use formality_rust:: grammar:: minirust:: {
9
9
self , ty_is_int, ArgumentExpression , BasicBlock , BbId , LocalId , PlaceExpression ,
10
10
ValueExpression ,
11
11
} ;
12
- use formality_rust:: grammar:: FnBoundData ;
13
- use formality_types:: grammar:: { CrateId , FnId } ;
14
- use formality_types:: grammar:: { Relation , Ty , Wcs } ;
12
+ use formality_rust:: grammar:: { FnBoundData , StructBoundData } ;
13
+ use formality_types:: grammar:: { AdtId , Relation , Ty , TyData , Wcs } ;
14
+ use formality_types:: grammar:: { CrateId , FnId , RigidName } ;
15
15
16
16
use crate :: { Check , CrateItem } ;
17
17
use anyhow:: bail;
@@ -95,6 +95,7 @@ impl Check<'_> {
95
95
callee_input_tys : Map :: new ( ) ,
96
96
crate_id : crate_id. clone ( ) ,
97
97
fn_args : body. args . clone ( ) ,
98
+ adt_tys : Map :: new ( ) ,
98
99
} ;
99
100
100
101
// (4) Check statements in body are valid
@@ -276,6 +277,38 @@ impl Check<'_> {
276
277
} ;
277
278
place_ty = ty;
278
279
}
280
+ Field ( field_projection) => {
281
+ let Local ( ref local_id) = * field_projection. root else {
282
+ bail ! ( "Only Local is allowed as the root of FieldProjection" )
283
+ } ;
284
+
285
+ // Check if the index is valid for the tuple.
286
+ // FIXME: use let chain here?
287
+
288
+ let Some ( ty) = env. local_variables . get ( & local_id) else {
289
+ bail ! ( "The local id used in PlaceExpression::Field is invalid." )
290
+ } ;
291
+
292
+ // Get the ADT type information.
293
+ let TyData :: RigidTy ( rigid_ty) = ty. data ( ) else {
294
+ bail ! ( "The type for field projection must be rigid ty" )
295
+ } ;
296
+
297
+ // FIXME: it'd be nice to have the field information in ty data
298
+ let RigidName :: AdtId ( ref adt_id) = rigid_ty. name else {
299
+ bail ! ( "The type for field projection must be adt" )
300
+ } ;
301
+
302
+ let Some ( tys) = env. adt_tys . get ( & adt_id) else {
303
+ bail ! ( "The ADT used is invalid." )
304
+ } ;
305
+
306
+ if field_projection. index >= tys. len ( ) {
307
+ bail ! ( "The field index used in PlaceExpression::Field is invalid." )
308
+ }
309
+
310
+ place_ty = tys[ field_projection. index ] . clone ( ) ;
311
+ }
279
312
}
280
313
Ok ( place_ty. clone ( ) )
281
314
}
@@ -317,6 +350,7 @@ impl Check<'_> {
317
350
if fn_declared. id == * fn_id {
318
351
let fn_bound_data =
319
352
typeck_env. env . instantiate_universally ( & fn_declared. binder ) ;
353
+ // FIXME: maybe we should store the information somewhere else, like in the value expression?
320
354
// Store the callee information in typeck_env, we will need this when type checking Terminator::Call.
321
355
typeck_env
322
356
. callee_input_tys
@@ -341,6 +375,77 @@ impl Check<'_> {
341
375
// it will be rejected by the parser.
342
376
Ok ( constant. get_ty ( ) )
343
377
}
378
+ Struct ( value_expressions, ty) => {
379
+ let mut struct_field_ty = Vec :: new ( ) ;
380
+
381
+ // Check if the adt type is valid in current crate.
382
+ if let TyData :: RigidTy ( rigid_ty) = ty. data ( ) {
383
+ if let RigidName :: AdtId ( adt_id) = & rigid_ty. name {
384
+ // Find the crate that is currently being typeck.
385
+ let curr_crate = self
386
+ . program
387
+ . crates
388
+ . iter ( )
389
+ . find ( |c| c. id == typeck_env. crate_id )
390
+ . unwrap ( ) ;
391
+
392
+ // Find the struct from current crate.
393
+ let target_struct = curr_crate. items . iter ( ) . find ( |item| {
394
+ match item {
395
+ CrateItem :: Struct ( struct_item) => {
396
+ if struct_item. id == * adt_id {
397
+ // Get the ty data of the field.
398
+ let (
399
+ _,
400
+ StructBoundData {
401
+ where_clauses : _,
402
+ fields,
403
+ } ,
404
+ ) = struct_item. binder . open ( ) ;
405
+ for field in fields {
406
+ struct_field_ty. push ( field. ty ) ;
407
+ }
408
+ return true ;
409
+ }
410
+ false
411
+ }
412
+ _ => false ,
413
+ }
414
+ } ) ;
415
+
416
+ if target_struct. is_none ( ) {
417
+ bail ! ( "The type used in Tuple is not declared in current crate" )
418
+ }
419
+ // We will need the adt type information when type checking field projection.
420
+ typeck_env
421
+ . adt_tys
422
+ . insert ( adt_id. clone ( ) , struct_field_ty. clone ( ) ) ;
423
+ }
424
+ }
425
+
426
+ // Make sure the length of value expression matches the length of field of adt.
427
+ if value_expressions. len ( ) != struct_field_ty. len ( ) {
428
+ bail ! ( "The length of ValueExpression::Tuple does not match the type of the ADT declared" )
429
+ }
430
+
431
+ let expression_ty_pair = zip ( value_expressions, struct_field_ty) ;
432
+
433
+ // FIXME: we only support const in value expression of tuple for now, we can add support
434
+ // more in future.
435
+
436
+ for ( value_expression, declared_ty) in expression_ty_pair {
437
+ let Constant ( _) = value_expression else {
438
+ bail ! ( "Only Constant is supported in ValueExpression::Tuple for now." )
439
+ } ;
440
+ let ty = self . check_value ( typeck_env, value_expression) ?;
441
+
442
+ // Make sure the type matches the declared adt.
443
+ if ty != declared_ty {
444
+ bail ! ( "The type in ValueExpression::Tuple does not match the ADT declared" )
445
+ }
446
+ }
447
+ Ok ( ty. clone ( ) )
448
+ }
344
449
}
345
450
}
346
451
@@ -402,4 +507,7 @@ struct TypeckEnv {
402
507
403
508
/// LocalId of function argument.
404
509
fn_args : Vec < LocalId > ,
510
+
511
+ /// Type information of adt
512
+ adt_tys : Map < AdtId , Vec < Ty > > ,
405
513
}
0 commit comments