11use std:: iter:: zip;
22
33use 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 } ;
55use 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 } ;
88use formality_rust:: grammar:: minirust:: {
99 self , ArgumentExpression , BasicBlock , BbId , LocalId , PlaceExpression , ValueExpression ,
1010} ;
1111use 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+ } ;
1415
1516use crate :: { Check , CrateItem } ;
1617use anyhow:: bail;
@@ -93,6 +94,7 @@ impl Check<'_> {
9394 declared_input_tys,
9495 callee_input_tys : Map :: new ( ) ,
9596 crate_id : crate_id. clone ( ) ,
97+ fn_args : body. args . clone ( ) ,
9698 } ;
9799
98100 // (4) Check statements in body are valid
@@ -130,7 +132,7 @@ impl Check<'_> {
130132 let place_ty = self . check_place ( typeck_env, place_expression) ?;
131133
132134 // 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) ?;
134136
135137 // Check that the type of the value is a subtype of the place's type
136138 self . prove_goal (
@@ -149,6 +151,24 @@ impl Check<'_> {
149151 self . check_place ( typeck_env, place_expression) ?;
150152 // FIXME: check that access the place is allowed per borrowck rules
151153 }
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+ }
152172 }
153173 Ok ( ( ) )
154174 }
@@ -172,7 +192,7 @@ impl Check<'_> {
172192 next_block,
173193 } => {
174194 // 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) ?;
176196
177197 // Get argument information from the callee.
178198 let Fn ( callee_fn_id) = callee else {
@@ -189,7 +209,11 @@ impl Check<'_> {
189209 let arguments = zip ( callee_declared_input_tys, actual_arguments) ;
190210 for ( declared_ty, actual_argument) in arguments {
191211 // 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+ ) ?;
193217 // Check if the actual argument type passed in is the subtype of expect argument type.
194218 self . prove_goal (
195219 & typeck_env. env ,
@@ -226,7 +250,9 @@ impl Check<'_> {
226250 fallback,
227251 } => {
228252 // 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 ( ) ;
230256
231257 self . prove_judgment ( & typeck_env. env , & fn_assumptions, value_ty, ty_is_int) ?;
232258
@@ -246,24 +272,65 @@ impl Check<'_> {
246272 match place {
247273 Local ( local_id) => {
248274 // 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 {
254276 bail ! (
255277 "PlaceExpression::Local: unknown local name `{:?}`" ,
256278 local_id
257279 )
258280 } ;
259281 place_ty = ty;
260282 }
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+ }
261312 }
262313 Ok ( place_ty. clone ( ) )
263314 }
264315
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+
265327 // 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 > {
267334 let value_ty;
268335 match value {
269336 Load ( place_expression) => {
@@ -312,18 +379,74 @@ impl Check<'_> {
312379 // it will be rejected by the parser.
313380 Ok ( constant. get_ty ( ) )
314381 }
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+ }
315437 }
316438 }
317439
318440 fn check_argument_expression (
319441 & self ,
320442 env : & mut TypeckEnv ,
443+ fn_assumptions : & Wcs ,
321444 arg_expr : & ArgumentExpression ,
322445 ) -> Fallible < Ty > {
323446 let ty;
324447 match arg_expr {
325448 ByValue ( val_expr) => {
326- ty = self . check_value ( env, val_expr) ?;
449+ ty = self . check_value ( env, fn_assumptions , val_expr) ?;
327450 }
328451 InPlace ( place_expr) => {
329452 ty = self . check_place ( env, place_expr) ?;
@@ -370,6 +493,9 @@ struct TypeckEnv {
370493 /// We need this to access information about other functions
371494 /// declared in the current crate.
372495 crate_id : CrateId ,
496+
497+ /// LocalId of function argument.
498+ fn_args : Vec < LocalId > ,
373499}
374500
375501judgment_fn ! {
0 commit comments