@@ -30,16 +30,16 @@ use qsc_eval::{
3030use qsc_fir:: {
3131 fir:: {
3232 self , BinOp , Block , BlockId , CallableDecl , CallableImpl , ExecGraph , Expr , ExprId , ExprKind ,
33- Global , Ident , LocalVarId , Mutability , PackageId , PackageStore , PackageStoreLookup , Pat ,
34- PatId , PatKind , Res , SpecDecl , SpecImpl , Stmt , StmtId , StmtKind , StoreBlockId , StoreExprId ,
35- StoreItemId , StorePatId , StoreStmtId , UnOp ,
33+ Field , Global , Ident , LocalVarId , Mutability , PackageId , PackageStore , PackageStoreLookup ,
34+ Pat , PatId , PatKind , PrimField , Res , SpecDecl , SpecImpl , Stmt , StmtId , StmtKind ,
35+ StoreBlockId , StoreExprId , StoreItemId , StorePatId , StoreStmtId , UnOp ,
3636 } ,
3737 ty:: { Prim , Ty } ,
3838} ;
3939use qsc_lowerer:: map_fir_package_to_hir;
4040use qsc_rca:: {
4141 ComputeKind , ComputePropertiesLookup , ItemComputeProperties , PackageStoreComputeProperties ,
42- QuantumProperties , RuntimeFeatureFlags ,
42+ QuantumProperties , RuntimeFeatureFlags , RuntimeKind , ValueKind ,
4343 errors:: {
4444 Error as CapabilityError , generate_errors_from_runtime_features,
4545 get_missing_runtime_features,
@@ -1180,10 +1180,7 @@ impl<'a> PartialEvaluator<'a> {
11801180 "using a dynamic value in a fail statement is invalid" . to_string ( ) ,
11811181 expr_package_span,
11821182 ) ) ,
1183- ExprKind :: Field ( _, _) => Err ( Error :: Unexpected (
1184- "accessing a field of a dynamic user-defined type is invalid" . to_string ( ) ,
1185- expr_package_span,
1186- ) ) ,
1183+ ExprKind :: Field ( expr_id, field) => self . eval_expr_field ( * expr_id, field. clone ( ) ) ,
11871184 ExprKind :: Hole => Err ( Error :: Unexpected (
11881185 "hole expressions are not expected during partial evaluation" . to_string ( ) ,
11891186 expr_package_span,
@@ -1978,6 +1975,47 @@ impl<'a> PartialEvaluator<'a> {
19781975 Ok ( EvalControlFlow :: Continue ( value) )
19791976 }
19801977
1978+ fn eval_expr_field (
1979+ & mut self ,
1980+ record_id : ExprId ,
1981+ field : Field ,
1982+ ) -> Result < EvalControlFlow , Error > {
1983+ let control_flow = self . try_eval_expr ( record_id) ?;
1984+ let EvalControlFlow :: Continue ( record) = control_flow else {
1985+ return Err ( Error :: Unexpected (
1986+ "embedded return in field access expression" . to_string ( ) ,
1987+ self . get_expr_package_span ( record_id) ,
1988+ ) ) ;
1989+ } ;
1990+
1991+ let field_value = match ( record, field) {
1992+ ( Value :: Range ( inner) , Field :: Prim ( PrimField :: Start ) ) => Value :: Int (
1993+ inner
1994+ . start
1995+ . expect ( "range access should be validated by compiler" ) ,
1996+ ) ,
1997+ ( Value :: Range ( inner) , Field :: Prim ( PrimField :: Step ) ) => Value :: Int ( inner. step ) ,
1998+ ( Value :: Range ( inner) , Field :: Prim ( PrimField :: End ) ) => Value :: Int (
1999+ inner
2000+ . end
2001+ . expect ( "range access should be validated by compiler" ) ,
2002+ ) ,
2003+ ( mut record, Field :: Path ( path) ) => {
2004+ for index in path. indices {
2005+ let Value :: Tuple ( items, _) = record else {
2006+ panic ! ( "invalid tuple access" ) ;
2007+ } ;
2008+ record = items[ index] . clone ( ) ;
2009+ }
2010+ record
2011+ }
2012+ ( ref value, ref field) => {
2013+ panic ! ( "invalid field access. value: {value:?}, field: {field:?}" )
2014+ }
2015+ } ;
2016+ Ok ( EvalControlFlow :: Continue ( field_value) )
2017+ }
2018+
19812019 fn eval_expr_return ( & mut self , expr_id : ExprId ) -> Result < EvalControlFlow , Error > {
19822020 let control_flow = self . try_eval_expr ( expr_id) ?;
19832021 Ok ( EvalControlFlow :: Return ( control_flow. into_value ( ) ) )
@@ -2155,17 +2193,19 @@ impl<'a> PartialEvaluator<'a> {
21552193 condition_expr_id : ExprId ,
21562194 body_block_id : BlockId ,
21572195 ) -> Result < EvalControlFlow , Error > {
2158- // Verify assumptions.
2196+ // Verify assumptions: the condition expression must either classical (such that it can be fully evaluated) or
2197+ // quantum but statically known at runtime (such that it can be partially evaluated to a known value).
21592198 assert ! (
2160- self . is_classical_expr( condition_expr_id) ,
2199+ matches!(
2200+ self . get_expr_compute_kind( condition_expr_id) ,
2201+ ComputeKind :: Classical
2202+ | ComputeKind :: Quantum ( QuantumProperties {
2203+ runtime_features: _,
2204+ value_kind: ValueKind :: Element ( RuntimeKind :: Static ) ,
2205+ } )
2206+ ) ,
21612207 "loop conditions must be purely classical"
21622208 ) ;
2163- let body_block = self . get_block ( body_block_id) ;
2164- assert_eq ! (
2165- body_block. ty,
2166- Ty :: UNIT ,
2167- "the type of a loop block is expected to be Unit"
2168- ) ;
21692209
21702210 // Evaluate the block until the loop condition is false.
21712211 let condition_expr_span = self . get_expr_package_span ( condition_expr_id) ;
0 commit comments