1
1
use std:: iter:: zip;
2
2
3
3
use formality_core:: { judgment_fn, Fallible , Map , Upcast } ;
4
- use formality_prove:: { prove_normalize, Constraints , Decls , Env } ;
4
+ use formality_prove:: { prove_normalize, AdtDeclBoundData , AdtDeclVariant , Constraints , Decls , 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 , ArgumentExpression , BasicBlock , BbId , LocalId , PlaceExpression , ValueExpression ,
10
10
} ;
11
11
use formality_rust:: grammar:: FnBoundData ;
12
- use formality_types:: grammar:: { CrateId , FnId , Parameter , RigidName , RigidTy } ;
13
- use formality_types:: grammar:: { Relation , Ty , Wcs } ;
12
+ use formality_types:: grammar:: {
13
+ CrateId , FnId , Parameter , Relation , RigidName , RigidTy , Ty , VariantId , Wcs ,
14
+ } ;
14
15
15
16
use crate :: { Check , CrateItem } ;
16
17
use anyhow:: bail;
@@ -93,6 +94,7 @@ impl Check<'_> {
93
94
declared_input_tys,
94
95
callee_input_tys : Map :: new ( ) ,
95
96
crate_id : crate_id. clone ( ) ,
97
+ fn_args : body. args . clone ( ) ,
96
98
} ;
97
99
98
100
// (4) Check statements in body are valid
@@ -130,7 +132,7 @@ impl Check<'_> {
130
132
let place_ty = self . check_place ( typeck_env, place_expression) ?;
131
133
132
134
// Check if the value expression is well-formed.
133
- let value_ty = self . check_value ( typeck_env, value_expression) ?;
135
+ let value_ty = self . check_value ( typeck_env, fn_assumptions , value_expression) ?;
134
136
135
137
// Check that the type of the value is a subtype of the place's type
136
138
self . prove_goal (
@@ -149,6 +151,24 @@ impl Check<'_> {
149
151
self . check_place ( typeck_env, place_expression) ?;
150
152
// FIXME: check that access the place is allowed per borrowck rules
151
153
}
154
+ minirust:: Statement :: StorageLive ( local_id) => {
155
+ // FIXME: We need more checks here after loan is introduced.
156
+ if self . find_local_id ( & typeck_env, local_id) . is_none ( ) {
157
+ bail ! ( "Statement::StorageLive: invalid local variable" )
158
+ }
159
+ }
160
+ minirust:: Statement :: StorageDead ( local_id) => {
161
+ // FIXME: We need more checks here after loan is introduced.
162
+ let Some ( ( local_id, _) ) = self . find_local_id ( & typeck_env, local_id) else {
163
+ bail ! ( "Statement::StorageDead: invalid local variable" )
164
+ } ;
165
+ // Make sure function arguments and return place are not marked as dead.
166
+ if local_id == typeck_env. ret_id
167
+ || typeck_env. fn_args . iter ( ) . any ( |fn_arg| local_id == * fn_arg)
168
+ {
169
+ bail ! ( "Statement::StorageDead: trying to mark function arguments or return local as dead" )
170
+ }
171
+ }
152
172
}
153
173
Ok ( ( ) )
154
174
}
@@ -172,7 +192,7 @@ impl Check<'_> {
172
192
next_block,
173
193
} => {
174
194
// Function is part of the value expression, so we will check if the function exists in check_value.
175
- self . check_value ( typeck_env, callee) ?;
195
+ self . check_value ( typeck_env, fn_assumptions , callee) ?;
176
196
177
197
// Get argument information from the callee.
178
198
let Fn ( callee_fn_id) = callee else {
@@ -189,7 +209,11 @@ impl Check<'_> {
189
209
let arguments = zip ( callee_declared_input_tys, actual_arguments) ;
190
210
for ( declared_ty, actual_argument) in arguments {
191
211
// Check if the arguments are well formed.
192
- let actual_ty = self . check_argument_expression ( typeck_env, actual_argument) ?;
212
+ let actual_ty = self . check_argument_expression (
213
+ typeck_env,
214
+ fn_assumptions,
215
+ actual_argument,
216
+ ) ?;
193
217
// Check if the actual argument type passed in is the subtype of expect argument type.
194
218
self . prove_goal (
195
219
& typeck_env. env ,
@@ -226,7 +250,9 @@ impl Check<'_> {
226
250
fallback,
227
251
} => {
228
252
// Check if the value is well-formed.
229
- let value_ty = self . check_value ( typeck_env, switch_value) . unwrap ( ) ;
253
+ let value_ty = self
254
+ . check_value ( typeck_env, fn_assumptions, switch_value)
255
+ . unwrap ( ) ;
230
256
231
257
self . prove_judgment ( & typeck_env. env , & fn_assumptions, value_ty, ty_is_int) ?;
232
258
@@ -246,24 +272,65 @@ impl Check<'_> {
246
272
match place {
247
273
Local ( local_id) => {
248
274
// Check if place id is a valid local id.
249
- let Some ( ( _, ty) ) = env
250
- . local_variables
251
- . iter ( )
252
- . find ( |( declared_local_id, _) | * declared_local_id == local_id)
253
- else {
275
+ let Some ( ( _, ty) ) = self . find_local_id ( env, local_id) else {
254
276
bail ! (
255
277
"PlaceExpression::Local: unknown local name `{:?}`" ,
256
278
local_id
257
279
)
258
280
} ;
259
281
place_ty = ty;
260
282
}
283
+ Field ( field_projection) => {
284
+ let ty = self . check_place ( env, & field_projection. root ) . unwrap ( ) ;
285
+
286
+ // FIXME(tiif): We eventually want to do normalization here, so check_place should be
287
+ // a judgment fn.
288
+ let Some ( adt_id) = ty. get_adt_id ( ) else {
289
+ bail ! ( "The local used for field projection is not adt." )
290
+ } ;
291
+
292
+ let (
293
+ _,
294
+ AdtDeclBoundData {
295
+ where_clause : _,
296
+ variants,
297
+ } ,
298
+ ) = self . decls . adt_decl ( & adt_id) . binder . open ( ) ;
299
+ let AdtDeclVariant { name, fields } = variants. last ( ) . unwrap ( ) ;
300
+
301
+ if * name != VariantId :: for_struct ( ) {
302
+ bail ! ( "The local used for field projection must be struct." )
303
+ }
304
+
305
+ // Check if the index is valid for the tuple.
306
+ if field_projection. index >= fields. len ( ) {
307
+ bail ! ( "The field index used in PlaceExpression::Field is invalid." )
308
+ }
309
+
310
+ place_ty = fields[ field_projection. index ] . ty . clone ( ) ;
311
+ }
261
312
}
262
313
Ok ( place_ty. clone ( ) )
263
314
}
264
315
316
+ fn find_local_id ( & self , env : & TypeckEnv , local_id : & LocalId ) -> Option < ( LocalId , Ty ) > {
317
+ if let Some ( ( local_id, ty) ) = env
318
+ . local_variables
319
+ . iter ( )
320
+ . find ( |( declared_local_id, _) | * declared_local_id == local_id)
321
+ {
322
+ return Some ( ( local_id. clone ( ) , ty. clone ( ) ) ) ;
323
+ }
324
+ return None ;
325
+ }
326
+
265
327
// Check if the value expression is well-formed, and return the type of the value expression.
266
- fn check_value ( & self , typeck_env : & mut TypeckEnv , value : & ValueExpression ) -> Fallible < Ty > {
328
+ fn check_value (
329
+ & self ,
330
+ typeck_env : & mut TypeckEnv ,
331
+ fn_assumptions : & Wcs ,
332
+ value : & ValueExpression ,
333
+ ) -> Fallible < Ty > {
267
334
let value_ty;
268
335
match value {
269
336
Load ( place_expression) => {
@@ -312,18 +379,74 @@ impl Check<'_> {
312
379
// it will be rejected by the parser.
313
380
Ok ( constant. get_ty ( ) )
314
381
}
382
+ Struct ( value_expressions, ty) => {
383
+ // Check if the adt is well-formed.
384
+ self . prove_goal ( & typeck_env. env , & fn_assumptions, ty. well_formed ( ) ) ?;
385
+
386
+ let Some ( adt_id) = ty. get_adt_id ( ) else {
387
+ bail ! ( "The type used in ValueExpression::Struct must be adt" )
388
+ } ;
389
+
390
+ // Make sure that the adt is struct.
391
+ let (
392
+ _,
393
+ AdtDeclBoundData {
394
+ where_clause : _,
395
+ variants,
396
+ } ,
397
+ ) = self . decls . adt_decl ( & adt_id) . binder . open ( ) ;
398
+
399
+ let AdtDeclVariant { name, fields } = variants. last ( ) . unwrap ( ) ;
400
+
401
+ if * name != VariantId :: for_struct ( ) {
402
+ bail ! ( "This type used in ValueExpression::Struct should be a struct" )
403
+ }
404
+
405
+ // Check if the number of value provided match the number of field.
406
+ let struct_field_tys: Vec < Ty > =
407
+ fields. iter ( ) . map ( |field| field. ty . clone ( ) ) . collect ( ) ;
408
+
409
+ if value_expressions. len ( ) != struct_field_tys. len ( ) {
410
+ bail ! ( "The length of ValueExpression::Tuple does not match the type of the ADT declared" )
411
+ }
412
+
413
+ let mut value_tys: Vec < Ty > = Vec :: new ( ) ;
414
+
415
+ for value_expression in value_expressions {
416
+ // FIXME: we only support const in value expression of struct for now, we can add support
417
+ // more in future.
418
+ let Constant ( _) = value_expression else {
419
+ bail ! ( "Only Constant is supported in ValueExpression::Struct for now." )
420
+ } ;
421
+ value_tys. push ( self . check_value (
422
+ typeck_env,
423
+ fn_assumptions,
424
+ value_expression,
425
+ ) ?) ;
426
+ }
427
+
428
+ // Make sure all the types supplied are the subtype of declared types.
429
+ self . prove_goal (
430
+ & typeck_env. env ,
431
+ & fn_assumptions,
432
+ Wcs :: all_sub ( value_tys, struct_field_tys) ,
433
+ ) ?;
434
+
435
+ Ok ( ty. clone ( ) )
436
+ }
315
437
}
316
438
}
317
439
318
440
fn check_argument_expression (
319
441
& self ,
320
442
env : & mut TypeckEnv ,
443
+ fn_assumptions : & Wcs ,
321
444
arg_expr : & ArgumentExpression ,
322
445
) -> Fallible < Ty > {
323
446
let ty;
324
447
match arg_expr {
325
448
ByValue ( val_expr) => {
326
- ty = self . check_value ( env, val_expr) ?;
449
+ ty = self . check_value ( env, fn_assumptions , val_expr) ?;
327
450
}
328
451
InPlace ( place_expr) => {
329
452
ty = self . check_place ( env, place_expr) ?;
@@ -370,6 +493,9 @@ struct TypeckEnv {
370
493
/// We need this to access information about other functions
371
494
/// declared in the current crate.
372
495
crate_id : CrateId ,
496
+
497
+ /// LocalId of function argument.
498
+ fn_args : Vec < LocalId > ,
373
499
}
374
500
375
501
judgment_fn ! {
0 commit comments