@@ -30,16 +30,16 @@ use qsc_eval::{
30
30
use qsc_fir:: {
31
31
fir:: {
32
32
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 ,
36
36
} ,
37
37
ty:: { Prim , Ty } ,
38
38
} ;
39
39
use qsc_lowerer:: map_fir_package_to_hir;
40
40
use qsc_rca:: {
41
41
ComputeKind , ComputePropertiesLookup , ItemComputeProperties , PackageStoreComputeProperties ,
42
- QuantumProperties , RuntimeFeatureFlags ,
42
+ QuantumProperties , RuntimeFeatureFlags , RuntimeKind , ValueKind ,
43
43
errors:: {
44
44
Error as CapabilityError , generate_errors_from_runtime_features,
45
45
get_missing_runtime_features,
@@ -1180,10 +1180,7 @@ impl<'a> PartialEvaluator<'a> {
1180
1180
"using a dynamic value in a fail statement is invalid" . to_string ( ) ,
1181
1181
expr_package_span,
1182
1182
) ) ,
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 ( ) ) ,
1187
1184
ExprKind :: Hole => Err ( Error :: Unexpected (
1188
1185
"hole expressions are not expected during partial evaluation" . to_string ( ) ,
1189
1186
expr_package_span,
@@ -1978,6 +1975,47 @@ impl<'a> PartialEvaluator<'a> {
1978
1975
Ok ( EvalControlFlow :: Continue ( value) )
1979
1976
}
1980
1977
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
+
1981
2019
fn eval_expr_return ( & mut self , expr_id : ExprId ) -> Result < EvalControlFlow , Error > {
1982
2020
let control_flow = self . try_eval_expr ( expr_id) ?;
1983
2021
Ok ( EvalControlFlow :: Return ( control_flow. into_value ( ) ) )
@@ -2155,17 +2193,19 @@ impl<'a> PartialEvaluator<'a> {
2155
2193
condition_expr_id : ExprId ,
2156
2194
body_block_id : BlockId ,
2157
2195
) -> 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).
2159
2198
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
+ ) ,
2161
2207
"loop conditions must be purely classical"
2162
2208
) ;
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
- ) ;
2169
2209
2170
2210
// Evaluate the block until the loop condition is false.
2171
2211
let condition_expr_span = self . get_expr_package_span ( condition_expr_id) ;
0 commit comments