@@ -39,6 +39,7 @@ use qsc_circuit::{
3939} ;
4040use qsc_codegen:: qir_base:: BaseProfSim ;
4141use qsc_data_structures:: {
42+ functors:: FunctorApp ,
4243 language_features:: LanguageFeatures ,
4344 line_column:: { Encoding , Range } ,
4445 span:: Span ,
@@ -83,18 +84,19 @@ pub enum Error {
8384 #[ error( "runtime error" ) ]
8485 #[ diagnostic( transparent) ]
8586 Eval ( #[ from] WithStack < WithSource < qsc_eval:: Error > > ) ,
87+ #[ error( "circuit error" ) ]
88+ #[ diagnostic( transparent) ]
89+ Circuit ( #[ from] qsc_circuit:: Error ) ,
8690 #[ error( "entry point not found" ) ]
8791 #[ diagnostic( code( "Qsc.Interpret.NoEntryPoint" ) ) ]
8892 NoEntryPoint ,
8993 #[ error( "unsupported runtime capabilities for code generation" ) ]
9094 #[ diagnostic( code( "Qsc.Interpret.UnsupportedRuntimeCapabilities" ) ) ]
9195 UnsupportedRuntimeCapabilities ,
92- #[ error( "expression does not evaluate to an operation that takes qubit parameters" ) ]
93- #[ diagnostic( code( "Qsc.Interpret.NoCircuitForOperation" ) ) ]
94- #[ diagnostic( help(
95- "provide the name of a callable or a lambda expression that only takes qubits as parameters"
96- ) ) ]
97- NoCircuitForOperation ,
96+ #[ error( "expression does not evaluate to an operation" ) ]
97+ #[ diagnostic( code( "Qsc.Interpret.NotAnOperation" ) ) ]
98+ #[ diagnostic( help( "provide the name of a callable or a lambda expression" ) ) ]
99+ NotAnOperation ,
98100}
99101
100102/// A Q# interpreter.
@@ -338,52 +340,22 @@ impl Interpreter {
338340
339341 let entry_expr = match entry {
340342 CircuitEntryPoint :: Operation ( operation_expr) => {
341- // To determine whether the passed in expression is a valid callable name
342- // or lambda, we evaluate it and inspect the runtime value.
343- let maybe_operation = match self . eval_fragments ( & mut out, & operation_expr) ? {
344- Value :: Closure ( b) => Some ( ( b. id , b. functor ) ) ,
345- Value :: Global ( item_id, functor_app) => Some ( ( item_id, functor_app) ) ,
346- _ => None ,
347- } ;
348-
349- let maybe_invoke_expr = if let Some ( ( item_id, functor_app) ) = maybe_operation {
350- // Controlled operations are not supported at the moment.
351- if functor_app. controlled > 0 {
352- return Err ( vec ! [ Error :: NoCircuitForOperation ] ) ;
353- }
354-
355- // Find the item in the HIR
356- let package = map_fir_package_to_hir ( item_id. package ) ;
357- let local_item_id = crate :: hir:: LocalItemId :: from ( usize:: from ( item_id. item ) ) ;
358- let package_store = self . compiler . package_store ( ) ;
359-
360- let item = package_store
361- . get ( package)
362- . and_then ( |unit| unit. package . items . get ( local_item_id) ) ;
363-
364- // Generate the entry expression to invoke the operation.
365- // Will return `None` if item is not a valid callable that takes qubits.
366- item. and_then ( |item| entry_expr_for_qubit_operation ( item, & operation_expr) )
367- } else {
368- return Err ( vec ! [ Error :: NoCircuitForOperation ] ) ;
369- } ;
370-
371- if maybe_invoke_expr. is_none ( ) {
372- return Err ( vec ! [ Error :: NoCircuitForOperation ] ) ;
373- }
374- maybe_invoke_expr
343+ let ( item, functor_app) = self . eval_to_operation ( & operation_expr) ?;
344+ let expr = entry_expr_for_qubit_operation ( item, functor_app, & operation_expr)
345+ . map_err ( |e| vec ! [ e. into( ) ] ) ?;
346+ Some ( expr)
375347 }
376348 CircuitEntryPoint :: EntryExpr ( expr) => Some ( expr) ,
377349 CircuitEntryPoint :: EntryPoint => None ,
378350 } ;
379351
380- let val = if let Some ( entry_expr) = entry_expr {
352+ if let Some ( entry_expr) = entry_expr {
381353 self . run_with_sim ( & mut sim, & mut out, & entry_expr) ?
382354 } else {
383355 self . eval_entry_with_sim ( & mut sim, & mut out)
384356 } ?;
385357
386- Ok ( sim. finish ( & val ) )
358+ Ok ( sim. finish ( ) )
387359 }
388360
389361 /// Runs the given entry expression on the given simulator with a new instance of the environment
@@ -459,6 +431,36 @@ impl Interpreter {
459431 self . lines += 1 ;
460432 label
461433 }
434+
435+ /// Evaluate the name of an operation, or any expression that evaluates to a callable,
436+ /// and return the Item ID and function application for the callable.
437+ /// Examples: "Microsoft.Quantum.Diagnostics.DumpMachine", "(qs: Qubit[]) => H(qs[0])",
438+ /// "Controlled SWAP"
439+ fn eval_to_operation (
440+ & mut self ,
441+ operation_expr : & str ,
442+ ) -> std:: result:: Result < ( & qsc_hir:: hir:: Item , FunctorApp ) , Vec < Error > > {
443+ let mut sink = std:: io:: sink ( ) ;
444+ let mut out = GenericReceiver :: new ( & mut sink) ;
445+ let ( store_item_id, functor_app) = match self . eval_fragments ( & mut out, operation_expr) ? {
446+ Value :: Closure ( b) => ( b. id , b. functor ) ,
447+ Value :: Global ( item_id, functor_app) => ( item_id, functor_app) ,
448+ _ => return Err ( vec ! [ Error :: NotAnOperation ] ) ,
449+ } ;
450+ let package = map_fir_package_to_hir ( store_item_id. package ) ;
451+ let local_item_id = crate :: hir:: LocalItemId :: from ( usize:: from ( store_item_id. item ) ) ;
452+ let unit = self
453+ . compiler
454+ . package_store ( )
455+ . get ( package)
456+ . expect ( "package should exist in the package store" ) ;
457+ let item = unit
458+ . package
459+ . items
460+ . get ( local_item_id)
461+ . expect ( "item should exist in the package" ) ;
462+ Ok ( ( item, functor_app) )
463+ }
462464}
463465
464466/// Describes the entry point for circuit generation.
0 commit comments