diff --git a/source/compiler/qsc_qasm/src/ast_builder.rs b/source/compiler/qsc_qasm/src/ast_builder.rs index 9e5908d828..f355a8a40a 100644 --- a/source/compiler/qsc_qasm/src/ast_builder.rs +++ b/source/compiler/qsc_qasm/src/ast_builder.rs @@ -844,6 +844,20 @@ pub(crate) fn build_call_no_params( } } +pub(crate) fn build_call_stmt_no_params( + name: &str, + idents: &[&str], + fn_call_span: Span, + fn_name_span: Span, +) -> Stmt { + build_stmt_semi_from_expr(build_call_no_params( + name, + idents, + fn_call_span, + fn_name_span, + )) +} + pub(crate) fn build_call_with_param( name: &str, idents: &[&str], diff --git a/source/compiler/qsc_qasm/src/compiler.rs b/source/compiler/qsc_qasm/src/compiler.rs index b7d053ae1b..3b6c1005f3 100644 --- a/source/compiler/qsc_qasm/src/compiler.rs +++ b/source/compiler/qsc_qasm/src/compiler.rs @@ -4,12 +4,13 @@ pub mod error; use core::f64; -use std::{rc::Rc, sync::Arc}; +use std::{rc::Rc, str::FromStr, sync::Arc}; use error::CompilerErrorKind; use num_bigint::BigInt; use qsc_data_structures::span::Span; use qsc_frontend::{compile::SourceMap, error::WithSource}; +use rustc_hash::FxHashMap; use crate::{ CompilerConfig, OperationSignature, OutputSemantics, ProgramType, QasmCompileUnit, @@ -18,9 +19,10 @@ use crate::{ build_adj_plus_ctl_functor, build_angle_cast_call_by_name, build_angle_convert_call_with_two_params, build_arg_pat, build_array_reverse_expr, build_assignment_statement, build_attr, build_barrier_call, build_binary_expr, - build_call_no_params, build_call_with_param, build_call_with_params, build_classical_decl, - build_complex_from_expr, build_convert_call_expr, build_convert_cast_call_by_name, - build_end_stmt, build_expr_array_expr, build_for_stmt, build_function_or_operation, + build_call_no_params, build_call_stmt_no_params, build_call_with_param, + build_call_with_params, build_classical_decl, build_complex_from_expr, + build_convert_call_expr, build_convert_cast_call_by_name, build_end_stmt, + build_expr_array_expr, build_for_stmt, build_function_or_operation, build_gate_call_param_expr, build_gate_call_with_params_and_callee, build_if_expr_then_block, build_if_expr_then_block_else_block, build_if_expr_then_block_else_expr, build_if_expr_then_expr_else_expr, @@ -39,7 +41,7 @@ use crate::{ wrap_expr_in_parens, }, io::SourceResolver, - parser::ast::{List, list_from_iter}, + parser::ast::{List, PathKind, list_from_iter}, semantic::{ QasmSemanticParseResult, ast::{ @@ -97,11 +99,52 @@ pub fn compile_to_qsharp_ast_with_config( stmts: vec![], symbols: res.symbols, errors: res.errors, + pragma_config: PragmaConfig::default(), }; compiler.compile(&program) } +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] +pub enum PragmaKind { + QdkBoxOpen, + QdkBoxClose, +} + +impl FromStr for PragmaKind { + type Err = (); + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "qdk.box.open" => Ok(PragmaKind::QdkBoxOpen), + "qdk.box.close" => Ok(PragmaKind::QdkBoxClose), + _ => Err(()), + } + } +} + +#[derive(Eq, PartialEq, Default)] +pub struct PragmaConfig { + pub pragmas: FxHashMap>, +} + +impl PragmaConfig { + pub fn is_supported>(&self, pragma: S) -> bool { + PragmaKind::from_str(pragma.as_ref()).is_ok() + } + + /// Inserts a pragma into the configuration. + /// If the pragma already exists, it will be overwritten. + pub fn insert>>(&mut self, pragma: PragmaKind, value: V) { + self.pragmas.insert(pragma, value.into()); + } + + #[must_use] + pub fn get(&self, key: PragmaKind) -> Option<&Rc> { + self.pragmas.get(&key) + } +} + pub struct QasmCompiler { /// The source map of QASM sources for error reporting. pub source_map: SourceMap, @@ -114,6 +157,7 @@ pub struct QasmCompiler { pub stmts: Vec, pub symbols: SymbolTable, pub errors: Vec>, + pub pragma_config: PragmaConfig, } impl QasmCompiler { @@ -132,7 +176,9 @@ impl QasmCompiler { if !matches!(program_ty, ProgramType::File) { self.append_runtime_import_decls(); } - + for pragma in &program.pragmas { + self.compile_pragma_stmt(pragma); + } self.compile_stmts(&program.statements); let (package, signature) = match program_ty { ProgramType::File => self.build_file(), @@ -407,8 +453,8 @@ impl QasmCompiler { } } - fn compile_stmts(&mut self, smtms: &[Box]) { - for stmt in smtms { + fn compile_stmts(&mut self, stmts: &[Box]) { + for stmt in stmts { let compiled_stmt = self.compile_stmt(stmt.as_ref()); if let Some(stmt) = compiled_stmt { self.stmts.push(stmt); @@ -458,7 +504,9 @@ impl QasmCompiler { semast::StmtKind::InputDeclaration(stmt) => self.compile_input_decl_stmt(stmt), semast::StmtKind::OutputDeclaration(stmt) => self.compile_output_decl_stmt(stmt), semast::StmtKind::MeasureArrow(stmt) => self.compile_measure_stmt(stmt), - semast::StmtKind::Pragma(stmt) => self.compile_pragma_stmt(stmt), + semast::StmtKind::Pragma(_) => { + unreachable!("pragma should have been removed in the lowerer") + } semast::StmtKind::QuantumGateDefinition(gate_stmt) => { self.compile_gate_decl_stmt(gate_stmt, &stmt.annotations) } @@ -580,8 +628,37 @@ impl QasmCompiler { } fn compile_box_stmt(&mut self, stmt: &semast::BoxStmt) -> Option { - self.push_unimplemented_error_message("box statements", stmt.span); - None + let open = self + .pragma_config + .get(PragmaKind::QdkBoxOpen) + .map(|name| build_call_stmt_no_params(name, &[], Span::default(), Span::default())); + let close = self + .pragma_config + .get(PragmaKind::QdkBoxClose) + .map(|name| build_call_stmt_no_params(name, &[], Span::default(), Span::default())); + + let body = stmt + .body + .iter() + .filter_map(|stmt| self.compile_stmt(stmt)) + .collect::>(); + + let mut stmts = vec![]; + if let Some(open) = open { + stmts.push(open); + } + stmts.extend(body); + if let Some(close) = close { + stmts.push(close); + } + + let block = qsast::Block { + id: qsast::NodeId::default(), + stmts: list_from_iter(stmts), + span: stmt.span, + }; + + Some(build_stmt_semi_from_expr(build_wrapped_block_expr(block))) } fn compile_block(&mut self, block: &semast::Block) -> qsast::Block { @@ -666,7 +743,11 @@ impl QasmCompiler { let body = Some(self.compile_block(&stmt.body)); let return_type = map_qsharp_type_to_ast_ty(&stmt.return_type); - let kind = if stmt.has_qubit_params { + let kind = if stmt.has_qubit_params + || annotations + .iter() + .any(|a| a.identifier == "SimulatableIntrinsic".into()) + { qsast::CallableKind::Operation } else { qsast::CallableKind::Function @@ -934,9 +1015,61 @@ impl QasmCompiler { None } - fn compile_pragma_stmt(&mut self, stmt: &semast::Pragma) -> Option { - self.push_unimplemented_error_message("pragma statements", stmt.span); - None + fn compile_pragma_stmt(&mut self, stmt: &semast::Pragma) { + fn is_parameterless_and_returns_void(args: &Arc<[Type]>, return_ty: &Arc) -> bool { + args.is_empty() && matches!(&**return_ty, crate::semantic::types::Type::Void) + } + + let name_str = stmt + .identifier + .as_ref() + .map_or_else(String::new, PathKind::as_string); + + // Check if the pragma is supported by the compiler. + // If not, we push an error message and return. + if !self.pragma_config.is_supported(&name_str) { + self.push_unsupported_error_message(format!("pragma statement: {name_str}"), stmt.span); + return; + } + + // The pragma is supported, so we get the pragma kind. + let pragma = PragmaKind::from_str(&name_str).expect("valid pragma"); + + match (pragma, stmt.value.as_ref()) { + (PragmaKind::QdkBoxOpen, Some(value)) => { + if let Some(symbol) = self.symbols.get_symbol_by_name(value) { + if let crate::semantic::types::Type::Function(args, return_ty) = &symbol.1.ty { + if is_parameterless_and_returns_void(args, return_ty) { + self.pragma_config + .insert(PragmaKind::QdkBoxOpen, value.clone()); + return; + } + } + } + self.push_compiler_error(CompilerErrorKind::InvalidBoxPragmaTarget( + value.to_string(), + stmt.value_span.unwrap_or(stmt.span), + )); + } + (PragmaKind::QdkBoxClose, Some(value)) => { + if let Some(symbol) = self.symbols.get_symbol_by_name(value) { + if let crate::semantic::types::Type::Function(args, return_ty) = &symbol.1.ty { + if is_parameterless_and_returns_void(args, return_ty) { + self.pragma_config + .insert(PragmaKind::QdkBoxClose, value.clone()); + return; + } + } + } + self.push_compiler_error(CompilerErrorKind::InvalidBoxPragmaTarget( + value.to_string(), + stmt.value_span.unwrap_or(stmt.span), + )); + } + (PragmaKind::QdkBoxOpen | PragmaKind::QdkBoxClose, None) => { + self.push_compiler_error(CompilerErrorKind::MissingBoxPragmaTarget(stmt.span)); + } + } } fn compile_gate_decl_stmt( diff --git a/source/compiler/qsc_qasm/src/compiler/error.rs b/source/compiler/qsc_qasm/src/compiler/error.rs index b0a70b160a..72ca3c272a 100644 --- a/source/compiler/qsc_qasm/src/compiler/error.rs +++ b/source/compiler/qsc_qasm/src/compiler/error.rs @@ -20,6 +20,13 @@ pub enum CompilerErrorKind { #[error("gate expects {0} qubit arguments, but {1} were provided")] #[diagnostic(code("Qasm.Compiler.InvalidNumberOfQubitArgs"))] InvalidNumberOfQubitArgs(usize, usize, #[label] Span), + #[error("{0} is not defined or is not a valid target for box usage")] + #[help("Box pragmas can only be used with functions that have no parameters and return void.")] + #[diagnostic(code("Qasm.Compiler.InvalidBoxPragmaTarget"))] + InvalidBoxPragmaTarget(String, #[label] Span), + #[error("Box pragma is missing target")] + #[diagnostic(code("Qasm.Compiler.MissingBoxPragmaTarget"))] + MissingBoxPragmaTarget(#[label] Span), #[error("{0} are not supported")] #[diagnostic(code("Qasm.Compiler.NotSupported"))] NotSupported(String, #[label] Span), diff --git a/source/compiler/qsc_qasm/src/parser/ast.rs b/source/compiler/qsc_qasm/src/parser/ast.rs index d34cb76929..ff6d7118d8 100644 --- a/source/compiler/qsc_qasm/src/parser/ast.rs +++ b/source/compiler/qsc_qasm/src/parser/ast.rs @@ -99,6 +99,71 @@ impl Display for PathKind { } } +impl PathKind { + /// Returns the span of the path, if it exists. + #[must_use] + pub fn span(&self) -> Option { + match self { + PathKind::Ok(path) => Some(path.span), + PathKind::Err(Some(incomplete_path)) => Some(incomplete_path.span), + PathKind::Err(None) => None, + } + } + + #[must_use] + pub fn segments(&self) -> Option> { + match self { + PathKind::Ok(path) => path.segments.as_ref().map(|s| s.to_vec()), + PathKind::Err(incomplete_path) => { + incomplete_path.as_ref().map(|path| path.segments.to_vec()) + } + } + } + + pub fn offset(&mut self, offset: u32) { + match self { + PathKind::Ok(path) => path.offset(offset), + PathKind::Err(Some(incomplete_path)) => incomplete_path.offset(offset), + PathKind::Err(None) => {} + } + } + + #[must_use] + pub fn as_string(&self) -> String { + match self { + PathKind::Ok(path) => match &path.segments { + Some(segments) => { + if segments.is_empty() { + return path.name.to_string(); + } + let mut value = String::new(); + for segment in segments { + if !value.is_empty() { + value.push('.'); + } + value.push_str(&segment.name); + } + value.push('.'); + value.push_str(&path.name.name); + value + } + None => path.name.to_string(), + }, + PathKind::Err(Some(path)) => { + let mut value = String::new(); + for segment in &path.segments { + if !value.is_empty() { + value.push('.'); + } + value.push_str(&segment.name); + } + value + } + PathKind::Err(None) => "Err".to_string(), + } + } +} + /// A path that was successfully parsed up to a certain `.`, /// but is missing its final identifier. #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -114,6 +179,17 @@ pub struct IncompletePath { pub keyword: bool, } +impl IncompletePath { + pub fn offset(&mut self, offset: u32) { + self.span.lo += offset; + self.span.hi += offset; + for segment in &mut self.segments { + segment.span.lo += offset; + segment.span.hi += offset; + } + } +} + /// A path to a declaration or a field access expression, /// to be disambiguated during name resolution. #[derive(Clone, Debug, Hash, PartialEq, Eq)] @@ -140,6 +216,17 @@ impl WithSpan for Path { } } +impl Path { + pub fn offset(&mut self, offset: u32) { + self.span.lo += offset; + self.span.hi += offset; + for segment in self.segments.iter_mut().flatten() { + segment.span.lo += offset; + segment.span.hi += offset; + } + } +} + #[derive(Clone, Debug)] pub struct MeasureExpr { pub span: Span, @@ -1109,17 +1196,22 @@ impl Display for QuantumArgument { #[derive(Clone, Debug)] pub struct Pragma { pub span: Span, - pub identifier: Rc, + pub identifier: Option, pub value: Option>, + pub value_span: Option, } impl Display for Pragma { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let identifier = format!("\"{}\"", self.identifier); let value = self.value.as_ref().map(|val| format!("\"{val}\"")); writeln_header(f, "Pragma", self.span)?; - writeln_field(f, "identifier", &identifier)?; - write_opt_field(f, "value", value.as_ref()) + writeln_opt_field( + f, + "identifier", + self.identifier.as_ref().map(PathKind::as_string).as_ref(), + )?; + writeln_opt_field(f, "value", value.as_ref())?; + write_opt_field(f, "value_span", self.value_span.as_ref()) } } diff --git a/source/compiler/qsc_qasm/src/parser/prim.rs b/source/compiler/qsc_qasm/src/parser/prim.rs index 2804d0cd09..9c24e521ec 100644 --- a/source/compiler/qsc_qasm/src/parser/prim.rs +++ b/source/compiler/qsc_qasm/src/parser/prim.rs @@ -12,6 +12,7 @@ use super::{ scan::ParserContext, }; use crate::lex::TokenKind; +use crate::parser::ast::{IncompletePath, Path, PathKind}; use qsc_data_structures::span::{Span, WithSpan}; @@ -57,6 +58,25 @@ pub(super) fn ident(s: &mut ParserContext) -> Result { } } +pub(super) fn ident_or_kw_as_ident(s: &mut ParserContext) -> Result { + s.expect(WordKinds::PathExpr); + let peek = s.peek(); + if matches!(peek.kind, TokenKind::Identifier | TokenKind::Keyword(..)) { + let name = s.read().into(); + s.advance(); + Ok(Ident { + span: peek.span, + name, + }) + } else { + Err(Error::new(ErrorKind::Rule( + "identifier", + peek.kind, + peek.span, + ))) + } +} + /// Optionally parse with the given parser. /// Returns Ok(Some(value)) if the parser succeeded, /// Ok(None) if the parser failed on the first token, @@ -206,6 +226,21 @@ pub(super) fn recovering( } } +/// Recovering [`Path`] parser. Parsing only fails if no segments +/// were successfully parsed. If any segments were successfully parsed, +/// returns a [`PathKind::Err`] containing the segments that were +/// successfully parsed up to the final `.` token. +pub(super) fn recovering_path(s: &mut ParserContext, kind: WordKinds) -> Result { + match path(s, kind) { + Ok(path) => Ok(PathKind::Ok(path)), + Err((error, Some(incomplete_path))) => { + s.push_error(error); + Ok(PathKind::Err(Some(incomplete_path))) + } + Err((error, None)) => Err(error), + } +} + pub(super) fn recovering_semi(s: &mut ParserContext) { if let Err(error) = token(s, TokenKind::Semicolon) { // no recovery, just move on to the next token @@ -235,6 +270,69 @@ pub(super) fn shorten(from_start: usize, from_end: usize, s: &str) -> &str { &s[from_start..s.len() - from_end] } +pub(super) fn trim_front_safely(from_start: usize, s: &str) -> &str { + if from_start >= s.len() { + return ""; + } + &s[from_start..s.len()] +} + fn advanced(s: &ParserContext, from: u32) -> bool { s.peek().span.lo > from } + +/// A `path` is a dot-separated list of idents like "Foo.Bar.Baz" +/// This is used in pragmas, annotations, and other places where a +/// path-like identifier is expected. +/// +/// Path parser. If parsing fails, also returns any valid segments +/// that were parsed up to the final `.` token. +pub(super) fn path( + s: &mut ParserContext, + kind: WordKinds, +) -> std::result::Result, (Error, Option>)> { + s.expect(kind); + + let lo = s.peek().span.lo; + let i = ident_or_kw_as_ident(s).map_err(|e| (e, None))?; + + let mut parts = vec![i]; + while token(s, TokenKind::Dot).is_ok() { + s.expect(WordKinds::PathSegment); + match ident_or_kw_as_ident(s) { + Ok(ident) => parts.push(ident), + Err(error) => { + let trivia_span = s.skip_trivia(); + let keyword = trivia_span.hi == trivia_span.lo + && matches!(s.peek().kind, TokenKind::Keyword(_)); + if keyword { + // Consume any keyword that comes immediately after the final + // dot, assuming it was intended to be part of the path. + s.advance(); + } + + return Err(( + error, + Some(Box::new(IncompletePath { + span: s.span(lo), + segments: parts.into(), + keyword, + })), + )); + } + } + } + + let name = parts.pop().expect("path should have at least one part"); + let segments = if parts.is_empty() { + None + } else { + Some(parts.into()) + }; + + Ok(Box::new(Path { + span: s.span(lo), + segments, + name: name.into(), + })) +} diff --git a/source/compiler/qsc_qasm/src/parser/scan.rs b/source/compiler/qsc_qasm/src/parser/scan.rs index 2e00156207..40a9bcff80 100644 --- a/source/compiler/qsc_qasm/src/parser/scan.rs +++ b/source/compiler/qsc_qasm/src/parser/scan.rs @@ -74,7 +74,6 @@ impl<'a> ParserContext<'a> { /// Moves the scanner to the start of the current token, /// returning the span of the skipped trivia. - #[cfg(test)] pub(super) fn skip_trivia(&mut self) -> Span { self.scanner.skip_trivia() } @@ -151,8 +150,7 @@ impl<'a> Scanner<'a> { /// Moves the scanner to the start of the current token, /// returning the span of the skipped trivia. - #[cfg(test)] - pub(super) fn skip_trivia(&mut self) -> Span { + pub(crate) fn skip_trivia(&mut self) -> Span { let lo = self.offset; self.offset = self.peek.span.lo; let hi = self.offset; diff --git a/source/compiler/qsc_qasm/src/parser/stmt.rs b/source/compiler/qsc_qasm/src/parser/stmt.rs index 0692dcd1ac..35d80beaaa 100644 --- a/source/compiler/qsc_qasm/src/parser/stmt.rs +++ b/source/compiler/qsc_qasm/src/parser/stmt.rs @@ -20,8 +20,12 @@ use super::{ use crate::{ keyword::Keyword, lex::{Delim, TokenKind, cooked::Type}, - parser::ast::{ - DefParameter, DefParameterType, DynArrayReferenceType, QubitType, StaticArrayReferenceType, + parser::{ + ast::{ + DefParameter, DefParameterType, DynArrayReferenceType, QubitType, + StaticArrayReferenceType, + }, + prim::{recovering_path, trim_front_safely}, }, }; @@ -408,49 +412,138 @@ fn parse_include(s: &mut ParserContext) -> Result { /// Grammar: `PRAGMA RemainingLineContent`. fn parse_pragma(s: &mut ParserContext) -> Result { - let lo = s.peek().span.lo; - s.expect(WordKinds::Pragma); - let token = s.peek(); + let stmt_lo = token.span.lo; + s.expect(WordKinds::Pragma); - let parts: Vec<&str> = if token.kind == TokenKind::Pragma { - let lexeme = s.read(); - s.advance(); - // remove pragma keyword and any leading whitespace - // split lexeme at first space/tab collecting each side - let pat = &['\t', ' ']; - shorten(6, 0, lexeme) - .trim_start_matches(pat) - .splitn(2, pat) - .collect() - } else { + if token.kind != TokenKind::Pragma { return Err(Error::new(ErrorKind::Rule( "pragma", token.kind, token.span, ))); + } + + // read the pragma lexeme, which is the whole line + // including the `#pragma` or `pragma` keyword + // and the rest of the line content. + let pragma_line_content = s.read(); + let pragma_kw_offset = if pragma_line_content.starts_with('#') { + 7 // length of "#pragma" + } else { + 6 // length of "pragma" }; + let ident_lo = token.span.lo + pragma_kw_offset; + let stmt_hi = token.span.hi; + + // pragma_line_content: + // #pragma a.b.c "some value" more value \nmore content + // |. | | | + // |. | | | + // |. | ^--------- value ------| + // |. ^-- ident_lo ^-- stmt_hi + // | | | + // | ^-- pragma_content ----------^ + // | ^-- pragma_kw_offset + // ^-- stmt_lo + + let from_start = pragma_kw_offset.try_into().expect("valid size"); + let pragma_content = shorten(from_start, 0, pragma_line_content); + + // pragma_content + // a.b.c "some value" more value + // ^-- value_lo + + // advance the parser to the next token for the next token in the program + s.advance(); + + // create a sub-parser context just for the line content + // This will tokenize the rest of the line which should be the identifier + // and the value, if any. + + let mut c = ParserContext::new(pragma_content); + let content_lo = c.skip_trivia().hi; + // parse the dotted path identifier + let Ok(mut path) = recovering_path(&mut c, WordKinds::PathExpr) else { + // We only fail if no parts were parsed, which means + // - the pragma line was empty or only contained whitespace + // In that case, we return an empty pragma + // - line contained odd characters that couldn't be ident/kw + // in that case we return value only pragma + + let trimmed_content = pragma_content.trim(); + if trimmed_content.is_empty() { + return Ok(Pragma { + span: token.span, + identifier: None, + value: None, + value_span: None, + }); + } - let identifier = parts.first().map_or_else( - || { - Err(Error::new(ErrorKind::Rule( - "pragma", token.kind, token.span, - ))) - }, - |s| Ok(Into::>::into(*s)), - )?; + let value = trim_front_safely(content_lo.try_into().expect("valid size"), pragma_content); + let value = if value.is_empty() { + None + } else { + Some(Rc::from(value)) + }; + let value_span = value.as_ref().map(|_| Span { + lo: stmt_lo + ident_lo + content_lo, + hi: stmt_hi, + }); + return Ok(Pragma { + span: token.span, + identifier: None, + value, + value_span, + }); + }; - if identifier.is_empty() { - s.push_error(Error::new(ErrorKind::Rule( - "pragma missing identifier", - token.kind, - token.span, - ))); + // update the path span based on the original lo + path.offset(ident_lo); + + if path.segments().iter().len() == 0 { + // name with no segments + // any pragma with a dotted name requires at least one segment. + // So this is not a namespaced pragma and is just a value pragma + let value = trim_front_safely(content_lo.try_into().expect("valid size"), pragma_content); + let value = if value.is_empty() { + None + } else { + Some(Rc::from(value)) + }; + let value_span = value.as_ref().map(|_| Span { + lo: stmt_lo + ident_lo + content_lo, + hi: stmt_hi, + }); + return Ok(Pragma { + span: s.span(stmt_lo), + identifier: None, + value, + value_span, + }); } - let value = parts.get(1).map(|s| Into::>::into(*s)); + + // we need to get to the first non-whitespace token + // after the identifier, which should be the value. + + // This value_lo offset is the start of the value in the pragma line content. + let value_lo = c.skip_trivia().hi; + let value = trim_front_safely(value_lo.try_into().expect("valid size"), pragma_content); + let value = if value.is_empty() { + None + } else { + Some(Rc::from(value)) + }; + + let value_span = value.as_ref().map(|_| Span { + lo: value_lo + ident_lo, + hi: stmt_hi, + }); Ok(Pragma { - span: s.span(lo), - identifier, + span: s.span(stmt_lo), + identifier: Some(path), value, + value_span, }) } diff --git a/source/compiler/qsc_qasm/src/parser/stmt/tests/pragma.rs b/source/compiler/qsc_qasm/src/parser/stmt/tests/pragma.rs index 42abef06cb..6609eff5c5 100644 --- a/source/compiler/qsc_qasm/src/parser/stmt/tests/pragma.rs +++ b/source/compiler/qsc_qasm/src/parser/stmt/tests/pragma.rs @@ -16,8 +16,24 @@ fn pragma_decl() { Stmt [0-15]: annotations: kind: Pragma [0-15]: - identifier: "a.b.d" - value: "23""#]], + identifier: a.b.d + value: "23" + value_span: [13-15]"#]], + ); +} + +#[test] +fn pragma_decl_complex_value_stops_at_newline() { + check( + parse, + "pragma a.b.d 23 or \"value\" or 'other' or // comment\n 42", + &expect![[r#" + Stmt [0-51]: + annotations: + kind: Pragma [0-51]: + identifier: a.b.d + value: "23 or "value" or 'other' or // comment" + value_span: [13-51]"#]], ); } @@ -30,8 +46,9 @@ fn pragma_decl_ident_only() { Stmt [0-12]: annotations: kind: Pragma [0-12]: - identifier: "a.b.d" - value: "#]], + identifier: a.b.d + value: + value_span: "#]], ); } @@ -44,21 +61,24 @@ fn pragma_decl_missing_ident() { Stmt [0-7]: annotations: kind: Pragma [0-7]: - identifier: "" + identifier: value: + value_span: "#]], + ); +} - [ - Error( - Rule( - "pragma missing identifier", - Pragma, - Span { - lo: 0, - hi: 7, - }, - ), - ), - ]"#]], +#[test] +fn pragma_decl_incomplete_ident_is_value_only() { + check( + parse, + "pragma name rest of line content", + &expect![[r#" + Stmt [0-32]: + annotations: + kind: Pragma [0-32]: + identifier: + value: "name rest of line content" + value_span: [7-32]"#]], ); } @@ -66,13 +86,14 @@ fn pragma_decl_missing_ident() { fn legacy_pragma_decl() { check( parse, - "#pragma a.b.d 23", + "#pragma a.b 23", &expect![[r#" - Stmt [0-16]: + Stmt [0-14]: annotations: - kind: Pragma [0-16]: - identifier: "a" - value: "a.b.d 23""#]], + kind: Pragma [0-14]: + identifier: a.b + value: "23" + value_span: [12-14]"#]], ); } @@ -85,8 +106,9 @@ fn legacy_pragma_decl_ident_only() { Stmt [0-13]: annotations: kind: Pragma [0-13]: - identifier: "a" - value: "a.b.d""#]], + identifier: a.b.d + value: + value_span: "#]], ); } @@ -99,8 +121,9 @@ fn legacy_pragma_ws_after_hash() { Stmt [2-14]: annotations: kind: Pragma [2-14]: - identifier: "a.b.d" + identifier: a.b.d value: + value_span: [ Error( @@ -129,7 +152,53 @@ fn legacy_pragma_decl_missing_ident() { Stmt [0-8]: annotations: kind: Pragma [0-8]: - identifier: "a" - value: """#]], + identifier: + value: + value_span: "#]], + ); +} + +#[test] +fn spec_example_1() { + check( + parse, + r#"pragma qiskit.simulator noise model "qpu1.noise""#, + &expect![[r#" + Stmt [0-48]: + annotations: + kind: Pragma [0-48]: + identifier: qiskit.simulator + value: "noise model "qpu1.noise"" + value_span: [24-48]"#]], + ); +} + +#[test] +fn spec_example_2() { + check( + parse, + r#"pragma ibm.user alice account 12345678"#, + &expect![[r#" + Stmt [0-38]: + annotations: + kind: Pragma [0-38]: + identifier: ibm.user + value: "alice account 12345678" + value_span: [16-38]"#]], + ); +} + +#[test] +fn spec_example_3() { + check( + parse, + r#"pragma ibm.max_temp qpu 0.4"#, + &expect![[r#" + Stmt [0-27]: + annotations: + kind: Pragma [0-27]: + identifier: ibm.max_temp + value: "qpu 0.4" + value_span: [20-27]"#]], ); } diff --git a/source/compiler/qsc_qasm/src/semantic/ast.rs b/source/compiler/qsc_qasm/src/semantic/ast.rs index c139923813..1aea2a4ab5 100644 --- a/source/compiler/qsc_qasm/src/semantic/ast.rs +++ b/source/compiler/qsc_qasm/src/semantic/ast.rs @@ -14,7 +14,7 @@ use crate::{ write_field, write_header, write_indented_list, write_list_field, write_opt_field, writeln_field, writeln_header, writeln_list_field, writeln_opt_field, }, - parser::ast::List, + parser::ast::{List, PathKind}, semantic::symbols::SymbolId, stdlib::{angle::Angle, complex::Complex}, }; @@ -25,14 +25,16 @@ use super::types::ArrayDimensions; #[derive(Clone, Debug)] pub struct Program { - pub statements: List, pub version: Option, + pub pragmas: List, + pub statements: List, } impl Display for Program { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { writeln!(f, "Program:")?; writeln_opt_field(f, "version", self.version.as_ref())?; + writeln_list_field(f, "pragmas", &self.pragmas)?; write_list_field(f, "statements", &self.statements) } } @@ -707,17 +709,22 @@ impl Display for QuantumArgument { #[derive(Clone, Debug)] pub struct Pragma { pub span: Span, - pub identifier: Rc, + pub identifier: Option, pub value: Option>, + pub value_span: Option, } impl Display for Pragma { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let identifier = format!("\"{}\"", self.identifier); let value = self.value.as_ref().map(|val| format!("\"{val}\"")); writeln_header(f, "Pragma", self.span)?; - writeln_field(f, "identifier", &identifier)?; - write_opt_field(f, "value", value.as_ref()) + writeln_opt_field( + f, + "identifier", + self.identifier.as_ref().map(PathKind::as_string).as_ref(), + )?; + writeln_opt_field(f, "value", value.as_ref())?; + write_opt_field(f, "value_span", self.value_span.as_ref()) } } diff --git a/source/compiler/qsc_qasm/src/semantic/lowerer.rs b/source/compiler/qsc_qasm/src/semantic/lowerer.rs index ee0873fa21..2836ba446a 100644 --- a/source/compiler/qsc_qasm/src/semantic/lowerer.rs +++ b/source/compiler/qsc_qasm/src/semantic/lowerer.rs @@ -90,6 +90,7 @@ pub(crate) struct Lowerer { /// and other features. pub version: Option, pub stmts: Vec, + pub pragmas: Vec, } impl Lowerer { @@ -119,6 +120,7 @@ impl Lowerer { symbols, version, stmts, + pragmas: Vec::new(), } } @@ -137,6 +139,7 @@ impl Lowerer { let program = semantic::Program { version: self.version, statements: syntax::list_from_iter(self.stmts), + pragmas: syntax::list_from_iter(self.pragmas), }; super::QasmSemanticParseResult { @@ -184,50 +187,61 @@ impl Lowerer { let mut includes = source.includes().iter(); for stmt in &source.program().statements { - if let syntax::StmtKind::Include(include) = &*stmt.kind { - // if we are not in the root we should not be able to include - // as this is a limitation of the QASM3 language - if !self.symbols.is_current_scope_global() { - let kind = SemanticErrorKind::IncludeNotInGlobalScope( - include.filename.to_string(), - include.span, - ); - self.push_semantic_error(kind); - continue; - } - - // special case for stdgates.inc - // it won't be in the includes list - if include.filename.to_lowercase() == "stdgates.inc" { - if self.version == Some(QASM2_VERSION) { - self.push_semantic_error(SemanticErrorKind::IncludeNotInLanguageVersion( + match &*stmt.kind { + syntax::StmtKind::Include(include) => { + // if we are not in the root we should not be able to include + // as this is a limitation of the QASM3 language + if !self.symbols.is_current_scope_global() { + let kind = SemanticErrorKind::IncludeNotInGlobalScope( include.filename.to_string(), - "3.0".to_string(), include.span, - )); + ); + self.push_semantic_error(kind); + continue; } - self.define_stdgates(include.span); - continue; - } else if include.filename.to_lowercase() == "qelib1.inc" { - if self.version != Some(QASM2_VERSION) { - self.push_semantic_error(SemanticErrorKind::IncludeNotInLanguageVersion( - include.filename.to_string(), - "2.0".to_string(), - include.span, - )); + + // special case for stdgates.inc + // it won't be in the includes list + if include.filename.to_lowercase() == "stdgates.inc" { + if self.version == Some(QASM2_VERSION) { + self.push_semantic_error( + SemanticErrorKind::IncludeNotInLanguageVersion( + include.filename.to_string(), + "3.0".to_string(), + include.span, + ), + ); + } + self.define_stdgates(include.span); + continue; + } else if include.filename.to_lowercase() == "qelib1.inc" { + if self.version != Some(QASM2_VERSION) { + self.push_semantic_error( + SemanticErrorKind::IncludeNotInLanguageVersion( + include.filename.to_string(), + "2.0".to_string(), + include.span, + ), + ); + } + self.define_qelib1_gates(include.span); + continue; + } else if include.filename.to_lowercase() == "qdk.inc" { + self.define_mresetzchecked(); + continue; } - self.define_qelib1_gates(include.span); - continue; - } else if include.filename.to_lowercase() == "qdk.inc" { - self.define_mresetzchecked(); - continue; - } - let include = includes.next().expect("missing include"); - self.lower_source(include); - } else { - let mut stmts = self.lower_stmt(stmt); - self.stmts.append(&mut stmts); + let include = includes.next().expect("missing include"); + self.lower_source(include); + } + syntax::StmtKind::Pragma(stmt) => { + let pragma = Self::lower_pragma(stmt); + self.pragmas.push(pragma); + } + _ => { + let mut stmts = self.lower_stmt(stmt); + self.stmts.append(&mut stmts); + } } } } @@ -266,7 +280,9 @@ impl Lowerer { syntax::StmtKind::Include(stmt) => self.lower_include(stmt), syntax::StmtKind::IODeclaration(stmt) => self.lower_io_decl(stmt), syntax::StmtKind::Measure(stmt) => self.lower_measure_arrow_stmt(stmt), - syntax::StmtKind::Pragma(stmt) => self.lower_pragma(stmt), + syntax::StmtKind::Pragma(..) => { + unreachable!("pragma should be handled in lower_source") + } syntax::StmtKind::QuantumGateDefinition(stmt) => self.lower_gate_def(stmt), syntax::StmtKind::QuantumDecl(stmt) => self.lower_quantum_decl(stmt), syntax::StmtKind::Reset(stmt) => self.lower_reset(stmt), @@ -1227,11 +1243,13 @@ impl Lowerer { /// Search for the definition of `Box` there, and then for all the classes /// inhereting from `QuantumStatement`. fn lower_box(&mut self, stmt: &syntax::BoxStmt) -> semantic::StmtKind { - let _stmts = stmt + self.symbols.push_scope(ScopeKind::Block); + let stmts = stmt .body .iter() - .map(|stmt| self.lower_stmt(stmt)) + .flat_map(|stmt| self.lower_stmt(stmt)) .collect::>(); + self.symbols.pop_scope(); let mut _has_invalid_stmt_kinds = false; for stmt in &stmt.body { @@ -1255,10 +1273,14 @@ impl Lowerer { self.push_unsupported_error_message("Box with duration", duration.span); } - // we semantically checked the stmts, but we still need to lower them - // with the correct behavior based on any pragmas that might be present - self.push_unimplemented_error_message("box stmt", stmt.span); - semantic::StmtKind::Err + semantic::StmtKind::Box(semantic::BoxStmt { + span: stmt.span, + duration: stmt + .duration + .as_ref() + .map(|duration| self.lower_expr(duration)), + body: list_from_iter(stmts), + }) } fn lower_break(&mut self, stmt: &syntax::BreakStmt) -> semantic::StmtKind { @@ -2384,9 +2406,13 @@ impl Lowerer { } } - fn lower_pragma(&mut self, stmt: &syntax::Pragma) -> semantic::StmtKind { - self.push_unimplemented_error_message("pragma stmt", stmt.span); - semantic::StmtKind::Err + fn lower_pragma(stmt: &syntax::Pragma) -> semantic::Pragma { + semantic::Pragma { + span: stmt.span, + identifier: stmt.identifier.clone(), + value: stmt.value.clone(), + value_span: stmt.value_span, + } } fn lower_gate_def(&mut self, stmt: &syntax::QuantumGateDefinition) -> semantic::StmtKind { diff --git a/source/compiler/qsc_qasm/src/semantic/tests.rs b/source/compiler/qsc_qasm/src/semantic/tests.rs index 858ffd6363..035b895f81 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests.rs @@ -196,6 +196,7 @@ fn semantic_errors_map_to_their_corresponding_file_specific_spans() { &expect![[r#" Program: version: 3.0 + pragmas: statements: Stmt [196-206]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/assignment.rs b/source/compiler/qsc_qasm/src/semantic/tests/assignment.rs index aa11a6c430..b8d958e15c 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/assignment.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/assignment.rs @@ -16,6 +16,7 @@ fn too_many_indices_in_indexed_assignment() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-80]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls.rs index 4aea79d9b0..3cc9fd849c 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls.rs @@ -59,6 +59,7 @@ fn scalar_ty_designator_must_be_positive() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-10]: annotations: @@ -87,6 +88,7 @@ fn scalar_ty_designator_must_be_castable_to_const_int() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-23]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/angle.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/angle.rs index b56a0852ca..bf1f940fe2 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/angle.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/angle.rs @@ -391,6 +391,7 @@ fn const_lit_decl_signed_int_lit_cast_neg_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-19]: annotations: @@ -424,6 +425,7 @@ fn explicit_zero_width_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-18]: annotations: @@ -452,6 +454,7 @@ fn explicit_width_over_64_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-25]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/duration.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/duration.rs index 9fd49e5819..4d6c1884e4 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/duration.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/duration.rs @@ -12,6 +12,7 @@ fn with_no_init_expr_has_generated_lit_expr() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-11]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/extern_decl.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/extern_decl.rs index 946ab03779..75f09368f3 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/extern_decl.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/extern_decl.rs @@ -65,6 +65,7 @@ fn no_allowed_in_non_global_scope() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-15]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/float.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/float.rs index c9667d878e..18453930bb 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/float.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/float.rs @@ -437,6 +437,7 @@ fn init_float_with_int_value_greater_than_safely_representable_values() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-27]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/qreg.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/qreg.rs index 06e1a7712a..bc9e814da8 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/qreg.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/qreg.rs @@ -22,6 +22,7 @@ fn with_no_init_expr_in_non_global_scope() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-9]: annotations: @@ -64,6 +65,7 @@ fn array_with_no_init_expr_in_non_global_scope() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-12]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/qubit.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/qubit.rs index d2fceba056..a2085024f7 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/qubit.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/qubit.rs @@ -22,6 +22,7 @@ fn with_no_init_expr_in_non_global_scope() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-10]: annotations: @@ -64,6 +65,7 @@ fn array_with_no_init_expr_in_non_global_scope() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-13]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/decls/stretch.rs b/source/compiler/qsc_qasm/src/semantic/tests/decls/stretch.rs index a700899579..3c2af1da27 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/decls/stretch.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/decls/stretch.rs @@ -12,6 +12,7 @@ fn with_no_init_expr_has_generated_lit_expr() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-10]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/binary/complex.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/binary/complex.rs index 7adb2ddf18..7f3094b80c 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/binary/complex.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/binary/complex.rs @@ -414,6 +414,7 @@ fn modulo_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-32]: annotations: @@ -458,6 +459,7 @@ fn modulo_non_complex_type_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-32]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions.rs index 82236ea6fb..d1cd9760b8 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions.rs @@ -33,6 +33,7 @@ fn builtin_call_with_invalid_input_types_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-22]: annotations: @@ -65,6 +66,7 @@ fn builtin_call_with_zero_arguments_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -97,6 +99,7 @@ fn builtin_call_with_lower_arity_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -129,6 +132,7 @@ fn builtin_call_with_higher_arity_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-22]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arccos.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arccos.rs index 38fc4aa2a7..08f8039590 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arccos.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arccos.rs @@ -95,23 +95,24 @@ fn arccos_negative_domain_error() { check_stmt_kinds( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-23]: - annotations: - kind: Err + Program: + version: + pragmas: + statements: + Stmt [9-23]: + annotations: + kind: Err - [Qasm.Lowerer.DomainError + [Qasm.Lowerer.DomainError - x arccos input should be in the range [-1.0, 1.0] - ,-[test:2:9] - 1 | - 2 | arccos(-1.01); - : ^^^^^^^^^^^^^ - 3 | - `---- - ]"#]], + x arccos input should be in the range [-1.0, 1.0] + ,-[test:2:9] + 1 | + 2 | arccos(-1.01); + : ^^^^^^^^^^^^^ + 3 | + `---- + ]"#]], ); } @@ -124,22 +125,23 @@ fn arccos_positive_domain_error() { check_stmt_kinds( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-22]: - annotations: - kind: Err + Program: + version: + pragmas: + statements: + Stmt [9-22]: + annotations: + kind: Err - [Qasm.Lowerer.DomainError + [Qasm.Lowerer.DomainError - x arccos input should be in the range [-1.0, 1.0] - ,-[test:2:9] - 1 | - 2 | arccos(1.01); - : ^^^^^^^^^^^^ - 3 | - `---- - ]"#]], + x arccos input should be in the range [-1.0, 1.0] + ,-[test:2:9] + 1 | + 2 | arccos(1.01); + : ^^^^^^^^^^^^ + 3 | + `---- + ]"#]], ); } diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arcsin.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arcsin.rs index 9145a5ec7d..85a669dda7 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arcsin.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/arcsin.rs @@ -95,23 +95,24 @@ fn arcsin_negative_domain_error() { check_stmt_kinds( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-23]: - annotations: - kind: Err + Program: + version: + pragmas: + statements: + Stmt [9-23]: + annotations: + kind: Err - [Qasm.Lowerer.DomainError + [Qasm.Lowerer.DomainError - x arcsin input should be in the range [-1.0, 1.0] - ,-[test:2:9] - 1 | - 2 | arcsin(-1.01); - : ^^^^^^^^^^^^^ - 3 | - `---- - ]"#]], + x arcsin input should be in the range [-1.0, 1.0] + ,-[test:2:9] + 1 | + 2 | arcsin(-1.01); + : ^^^^^^^^^^^^^ + 3 | + `---- + ]"#]], ); } @@ -124,22 +125,23 @@ fn arcsin_positive_domain_error() { check_stmt_kinds( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-22]: - annotations: - kind: Err + Program: + version: + pragmas: + statements: + Stmt [9-22]: + annotations: + kind: Err - [Qasm.Lowerer.DomainError + [Qasm.Lowerer.DomainError - x arcsin input should be in the range [-1.0, 1.0] - ,-[test:2:9] - 1 | - 2 | arcsin(1.01); - : ^^^^^^^^^^^^ - 3 | - `---- - ]"#]], + x arcsin input should be in the range [-1.0, 1.0] + ,-[test:2:9] + 1 | + 2 | arcsin(1.01); + : ^^^^^^^^^^^^ + 3 | + `---- + ]"#]], ); } diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/mod_.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/mod_.rs index dc473e86d4..bacd85b2c3 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/mod_.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/mod_.rs @@ -45,6 +45,7 @@ fn mod_int_divide_by_zero_error() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -104,6 +105,7 @@ fn mod_float_divide_by_zero_error() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/popcount.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/popcount.rs index bff4e6d449..808f9d3218 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/popcount.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/popcount.rs @@ -75,6 +75,7 @@ fn popcount_unsized_type_error() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotl.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotl.rs index b1fc3fb426..4ef85f9b93 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotl.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotl.rs @@ -251,6 +251,7 @@ fn rotl_unsized_type_error() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotr.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotr.rs index ab0bb8e491..e34bf2cf77 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotr.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/rotr.rs @@ -251,6 +251,7 @@ fn rotr_unsized_type_error() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sizeof.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sizeof.rs index ca2dbdff15..b462aadc1d 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sizeof.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sizeof.rs @@ -15,6 +15,7 @@ fn sizeof_no_args_errors() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-40]: annotations: @@ -52,6 +53,7 @@ fn sizeof_too_many_args_errors() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-47]: annotations: @@ -90,6 +92,7 @@ fn sizeof_non_array_errors() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-41]: annotations: @@ -166,81 +169,82 @@ fn sizeof_array_invalid_dimension_errors() { check( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-31]: - annotations: - kind: ClassicalDeclarationStmt [9-31]: - symbol_id: 8 - ty_span: [9-26] - init_expr: Expr [9-31]: - ty: array[bool, 3, 4] - kind: Lit: array: - Expr [0-0]: - ty: array[bool, 4] - kind: Lit: array: - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [0-0]: - ty: array[bool, 4] - kind: Lit: array: - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [0-0]: - ty: array[bool, 4] - kind: Lit: array: - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Stmt [40-77]: - annotations: - kind: ClassicalDeclarationStmt [40-77]: - symbol_id: 9 - ty_span: [46-50] - init_expr: Expr [62-76]: - ty: unknown - kind: Err - - [Qasm.Lowerer.SizeofInvalidDimension - - x requested dimension 2 but array has 2 dimensions - ,-[test:3:31] - 2 | array[bool, 3, 4] arr; - 3 | const uint arr_size = sizeof(arr, 2); - : ^^^^^^^^^^^^^^ - 4 | - `---- - ]"#]], + Program: + version: + pragmas: + statements: + Stmt [9-31]: + annotations: + kind: ClassicalDeclarationStmt [9-31]: + symbol_id: 8 + ty_span: [9-26] + init_expr: Expr [9-31]: + ty: array[bool, 3, 4] + kind: Lit: array: + Expr [0-0]: + ty: array[bool, 4] + kind: Lit: array: + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [0-0]: + ty: array[bool, 4] + kind: Lit: array: + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [0-0]: + ty: array[bool, 4] + kind: Lit: array: + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Stmt [40-77]: + annotations: + kind: ClassicalDeclarationStmt [40-77]: + symbol_id: 9 + ty_span: [46-50] + init_expr: Expr [62-76]: + ty: unknown + kind: Err + + [Qasm.Lowerer.SizeofInvalidDimension + + x requested dimension 2 but array has 2 dimensions + ,-[test:3:31] + 2 | array[bool, 3, 4] arr; + 3 | const uint arr_size = sizeof(arr, 2); + : ^^^^^^^^^^^^^^ + 4 | + `---- + ]"#]], ); } @@ -321,90 +325,91 @@ fn sizeof_static_array_ref_invalid_dimension_errors() { check( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-31]: - annotations: - kind: ClassicalDeclarationStmt [9-31]: - symbol_id: 8 - ty_span: [9-26] - init_expr: Expr [9-31]: - ty: array[bool, 3, 4] - kind: Lit: array: - Expr [0-0]: - ty: array[bool, 4] - kind: Lit: array: - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [0-0]: - ty: array[bool, 4] - kind: Lit: array: - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [0-0]: - ty: array[bool, 4] - kind: Lit: array: - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Expr [9-31]: - ty: const bool - kind: Lit: Bool(false) - Stmt [41-136]: - annotations: - kind: DefStmt [41-136]: - symbol_id: 9 - has_qubit_params: false - parameters: - 10 - return_type: () - body: Block [77-136]: - Stmt [91-126]: - annotations: - kind: ClassicalDeclarationStmt [91-126]: - symbol_id: 11 - ty_span: [97-101] - init_expr: Expr [113-125]: - ty: unknown - kind: Err - - [Qasm.Lowerer.SizeofInvalidDimension - - x requested dimension 2 but array has 2 dimensions - ,-[test:5:35] - 4 | def f(readonly array[bool, 3, 4] a) { - 5 | const uint arr_size = sizeof(a, 2); - : ^^^^^^^^^^^^ - 6 | } - `---- - ]"#]], + Program: + version: + pragmas: + statements: + Stmt [9-31]: + annotations: + kind: ClassicalDeclarationStmt [9-31]: + symbol_id: 8 + ty_span: [9-26] + init_expr: Expr [9-31]: + ty: array[bool, 3, 4] + kind: Lit: array: + Expr [0-0]: + ty: array[bool, 4] + kind: Lit: array: + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [0-0]: + ty: array[bool, 4] + kind: Lit: array: + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [0-0]: + ty: array[bool, 4] + kind: Lit: array: + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Expr [9-31]: + ty: const bool + kind: Lit: Bool(false) + Stmt [41-136]: + annotations: + kind: DefStmt [41-136]: + symbol_id: 9 + has_qubit_params: false + parameters: + 10 + return_type: () + body: Block [77-136]: + Stmt [91-126]: + annotations: + kind: ClassicalDeclarationStmt [91-126]: + symbol_id: 11 + ty_span: [97-101] + init_expr: Expr [113-125]: + ty: unknown + kind: Err + + [Qasm.Lowerer.SizeofInvalidDimension + + x requested dimension 2 but array has 2 dimensions + ,-[test:5:35] + 4 | def f(readonly array[bool, 3, 4] a) { + 5 | const uint arr_size = sizeof(a, 2); + : ^^^^^^^^^^^^ + 6 | } + `---- + ]"#]], ); } diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sqrt.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sqrt.rs index c757056474..a886056de6 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sqrt.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/builtin_functions/sqrt.rs @@ -39,23 +39,24 @@ fn sqrt_float_domain_error() { check_stmt_kinds( source, &expect![[r#" - Program: - version: - statements: - Stmt [9-19]: - annotations: - kind: Err + Program: + version: + pragmas: + statements: + Stmt [9-19]: + annotations: + kind: Err - [Qasm.Lowerer.DomainError + [Qasm.Lowerer.DomainError - x cannot compute square root of negative floats - ,-[test:2:9] - 1 | - 2 | sqrt(-4.); - : ^^^^^^^^^ - 3 | - `---- - ]"#]], + x cannot compute square root of negative floats + ,-[test:2:9] + 1 | + 2 | sqrt(-4.); + : ^^^^^^^^^ + 3 | + `---- + ]"#]], ); } diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_angle.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_angle.rs index 59f2a66da1..3a90cb57c5 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_angle.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_angle.rs @@ -87,6 +87,7 @@ fn angle_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -127,6 +128,7 @@ fn sized_angle_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -171,6 +173,7 @@ fn angle_to_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -211,6 +214,7 @@ fn angle_to_sized_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -251,6 +255,7 @@ fn sized_angle_to_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -291,6 +296,7 @@ fn sized_angle_to_sized_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -331,6 +337,7 @@ fn sized_angle_to_sized_int_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -371,6 +378,7 @@ fn sized_angle_to_sized_int_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -415,6 +423,7 @@ fn angle_to_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -455,6 +464,7 @@ fn angle_to_sized_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -495,6 +505,7 @@ fn sized_angle_to_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -535,6 +546,7 @@ fn sized_angle_to_sized_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -575,6 +587,7 @@ fn sized_angle_to_sized_uint_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -615,6 +628,7 @@ fn sized_angle_to_sized_uint_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -659,6 +673,7 @@ fn angle_to_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -699,6 +714,7 @@ fn angle_to_sized_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -739,6 +755,7 @@ fn sized_angle_to_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -779,6 +796,7 @@ fn sized_angle_to_sized_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -819,6 +837,7 @@ fn sized_angle_to_sized_float_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -859,6 +878,7 @@ fn sized_angle_to_sized_float_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1061,6 +1081,7 @@ fn angle_to_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -1101,6 +1122,7 @@ fn angle_to_sized_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -1141,6 +1163,7 @@ fn sized_angle_to_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1181,6 +1204,7 @@ fn sized_angle_to_sized_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1221,6 +1245,7 @@ fn sized_angle_to_sized_complex_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1261,6 +1286,7 @@ fn sized_angle_to_sized_complex_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1332,6 +1358,7 @@ fn angle_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -1426,6 +1453,7 @@ fn sized_angle_to_bitarray_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1466,6 +1494,7 @@ fn sized_angle_to_bitarray_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bit.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bit.rs index 3aad0b2193..bd9bc37838 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bit.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bit.rs @@ -87,6 +87,7 @@ fn bit_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -127,6 +128,7 @@ fn bitarray_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -294,6 +296,7 @@ fn bitarray_to_sized_int_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -334,6 +337,7 @@ fn bitarray_to_sized_int_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -501,6 +505,7 @@ fn bitarray_to_sized_uint_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -541,6 +546,7 @@ fn bitarray_to_sized_uint_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -639,6 +645,7 @@ fn bitarray_to_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -679,6 +686,7 @@ fn bitarray_to_sized_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -719,6 +727,7 @@ fn bitarray_to_sized_float_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -759,6 +768,7 @@ fn bitarray_to_sized_float_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -803,6 +813,7 @@ fn bit_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -843,6 +854,7 @@ fn bit_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -883,6 +895,7 @@ fn bitarray_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -950,6 +963,7 @@ fn bitarray_to_sized_angle_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -990,6 +1004,7 @@ fn bitarray_to_sized_angle_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1034,6 +1049,7 @@ fn bit_to_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -1074,6 +1090,7 @@ fn bit_to_sized_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -1114,6 +1131,7 @@ fn bitarray_to_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1154,6 +1172,7 @@ fn bitarray_to_sized_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1194,6 +1213,7 @@ fn bitarray_to_sized_complex_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1234,6 +1254,7 @@ fn bitarray_to_sized_complex_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1378,6 +1399,7 @@ fn bitarray_to_bitarray_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1418,6 +1440,7 @@ fn bitarray_to_bitarray_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bool.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bool.rs index 6f32bdcea6..8f92e33236 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bool.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_bool.rs @@ -56,6 +56,7 @@ fn bool_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -274,6 +275,7 @@ fn bool_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -314,6 +316,7 @@ fn bool_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -358,6 +361,7 @@ fn bool_to_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -398,6 +402,7 @@ fn bool_to_sized_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_complex.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_complex.rs index 61627fa665..f5819e5b6c 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_complex.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_complex.rs @@ -29,6 +29,7 @@ fn complex_to_bool_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -69,6 +70,7 @@ fn sized_complex_to_bool_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -113,6 +115,7 @@ fn complex_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -153,6 +156,7 @@ fn sized_complex_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -197,6 +201,7 @@ fn complex_to_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -237,6 +242,7 @@ fn complex_to_sized_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -277,6 +283,7 @@ fn sized_complex_to_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -317,6 +324,7 @@ fn sized_complex_to_sized_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -357,6 +365,7 @@ fn sized_complex_to_sized_int_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -397,6 +406,7 @@ fn sized_complex_to_sized_int_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -441,6 +451,7 @@ fn complex_to_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -481,6 +492,7 @@ fn complex_to_sized_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -521,6 +533,7 @@ fn sized_complex_to_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -561,6 +574,7 @@ fn sized_complex_to_sized_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -601,6 +615,7 @@ fn sized_complex_to_sized_uint_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -641,6 +656,7 @@ fn sized_complex_to_sized_uint_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -685,6 +701,7 @@ fn complex_to_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -725,6 +742,7 @@ fn complex_to_sized_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -765,6 +783,7 @@ fn sized_complex_to_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -805,6 +824,7 @@ fn sized_complex_to_sized_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -845,6 +865,7 @@ fn sized_complex_to_sized_float_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -885,6 +906,7 @@ fn sized_complex_to_sized_float_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -929,6 +951,7 @@ fn complex_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -969,6 +992,7 @@ fn complex_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1009,6 +1033,7 @@ fn sized_complex_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1049,6 +1074,7 @@ fn sized_complex_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1089,6 +1115,7 @@ fn sized_complex_to_sized_angle_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1129,6 +1156,7 @@ fn sized_complex_to_sized_angle_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1327,6 +1355,7 @@ fn complex_to_bit_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1367,6 +1396,7 @@ fn complex_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1407,6 +1437,7 @@ fn sized_complex_to_bit_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1447,6 +1478,7 @@ fn sized_complex_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1487,6 +1519,7 @@ fn sized_complex_to_bitarray_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: @@ -1527,6 +1560,7 @@ fn sized_complex_to_bitarray_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-30]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_duration.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_duration.rs index 9ff4648d5a..0f11e34e49 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_duration.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_duration.rs @@ -29,6 +29,7 @@ fn duration_to_bool_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -82,6 +83,7 @@ fn duration_to_duration() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -126,6 +128,7 @@ fn duration_to_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -175,6 +178,7 @@ fn duration_to_sized_int_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -228,6 +232,7 @@ fn duration_to_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -277,6 +282,7 @@ fn duration_to_sized_uint_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -330,6 +336,7 @@ fn duration_to_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -379,6 +386,7 @@ fn duration_to_sized_float_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -432,6 +440,7 @@ fn duration_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -481,6 +490,7 @@ fn duration_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -534,6 +544,7 @@ fn duration_to_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -583,6 +594,7 @@ fn duration_to_sized_complex_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -636,6 +648,7 @@ fn duration_to_bit_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -685,6 +698,7 @@ fn duration_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_float.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_float.rs index a9b18ae686..da0922e236 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_float.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_float.rs @@ -87,6 +87,7 @@ fn float_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -127,6 +128,7 @@ fn sized_float_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1020,6 +1022,7 @@ fn float_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-17]: annotations: @@ -1087,6 +1090,7 @@ fn sized_float_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1127,6 +1131,7 @@ fn sized_float_to_bitarray_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: @@ -1167,6 +1172,7 @@ fn sized_float_to_bitarray_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-21]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_int.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_int.rs index 05a87ff3b9..c9f8c245f1 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_int.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_int.rs @@ -87,6 +87,7 @@ fn int_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -127,6 +128,7 @@ fn sized_int_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -661,6 +663,7 @@ fn int_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -701,6 +704,7 @@ fn int_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -741,6 +745,7 @@ fn sized_int_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -781,6 +786,7 @@ fn sized_int_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -821,6 +827,7 @@ fn sized_int_to_sized_angle_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -861,6 +868,7 @@ fn sized_int_to_sized_angle_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1098,6 +1106,7 @@ fn int_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-15]: annotations: @@ -1192,6 +1201,7 @@ fn sized_int_to_bitarray_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: @@ -1232,6 +1242,7 @@ fn sized_int_to_bitarray_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-19]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_uint.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_uint.rs index 7ff75b935d..f03f81a381 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_uint.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/explicit_cast_from_uint.rs @@ -87,6 +87,7 @@ fn uint_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -127,6 +128,7 @@ fn sized_uint_to_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -661,6 +663,7 @@ fn uint_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -701,6 +704,7 @@ fn uint_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -741,6 +745,7 @@ fn sized_uint_to_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -781,6 +786,7 @@ fn sized_uint_to_sized_angle_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -821,6 +827,7 @@ fn sized_uint_to_sized_angle_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -861,6 +868,7 @@ fn sized_uint_to_sized_angle_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -1098,6 +1106,7 @@ fn uint_to_bitarray_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-16]: annotations: @@ -1192,6 +1201,7 @@ fn sized_uint_to_bitarray_truncating_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -1232,6 +1242,7 @@ fn sized_uint_to_bitarray_expanding_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_angle.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_angle.rs index 86cb602780..58f3a21222 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_angle.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_angle.rs @@ -136,6 +136,7 @@ fn to_implicit_int_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -179,6 +180,7 @@ fn to_explicit_int_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -222,6 +224,7 @@ fn to_implicit_uint_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -265,6 +268,7 @@ fn negative_lit_to_implicit_uint_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-24]: annotations: @@ -316,6 +320,7 @@ fn to_explicit_uint_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -359,6 +364,7 @@ fn to_explicit_bigint_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -402,6 +408,7 @@ fn to_implicit_float_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -445,6 +452,7 @@ fn to_explicit_float_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -488,6 +496,7 @@ fn to_implicit_complex_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: @@ -531,6 +540,7 @@ fn to_explicit_complex_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bit.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bit.rs index bb7b57eaf3..3b5ff66108 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bit.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bit.rs @@ -17,6 +17,7 @@ fn to_angle_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [10-20]: annotations: @@ -60,6 +61,7 @@ fn to_explicit_angle_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [10-20]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bitarray.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bitarray.rs index 919b334655..a8e775f138 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bitarray.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/implicit_cast_from_bitarray.rs @@ -174,6 +174,7 @@ fn to_int_with_higher_width_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-18]: annotations: @@ -225,6 +226,7 @@ fn to_int_with_higher_width_decl_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: @@ -269,6 +271,7 @@ fn to_int_with_lower_width_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-24]: annotations: @@ -317,6 +320,7 @@ fn to_int_with_lower_width_decl_implicitly_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-20]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/expression/indexing.rs b/source/compiler/qsc_qasm/src/semantic/tests/expression/indexing.rs index 03a7f68a46..96dac666bc 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/expression/indexing.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/expression/indexing.rs @@ -233,6 +233,7 @@ fn array_slice_with_zero_step_errors() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-23]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/lowerer_errors.rs b/source/compiler/qsc_qasm/src/semantic/tests/lowerer_errors.rs index 859cf2adbf..69f3c68e74 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/lowerer_errors.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/lowerer_errors.rs @@ -30,16 +30,6 @@ fn check_lowerer_error_spans_are_correct() { 5 | `---- - Qasm.Lowerer.Unimplemented - - x this statement is not yet handled during OpenQASM 3 import: pragma stmt - ,-[Test.qasm:7:1] - 6 | // Unimplemented pragma - 7 | pragma my_pragma; - : ^^^^^^^^^^^^^^^^^ - 8 | - `---- - Qasm.Lowerer.IncludeNotInGlobalScope x include stdgates.inc must be declared in global scope @@ -248,18 +238,6 @@ fn check_lowerer_error_spans_are_correct() { 89 | } `---- - Qasm.Lowerer.Unimplemented - - x this statement is not yet handled during OpenQASM 3 import: box stmt - ,-[Test.qasm:86:1] - 85 | // Unimplemented box - 86 | ,-> box { - 87 | | // ClassicalStmtInBox - 88 | | 2; - 89 | `-> } - 90 | - `---- - Qasm.Lowerer.InvalidScope x break can only appear in loop scopes diff --git a/source/compiler/qsc_qasm/src/semantic/tests/statements/box_stmt.rs b/source/compiler/qsc_qasm/src/semantic/tests/statements/box_stmt.rs index 6383192124..8b1f62b2c9 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/statements/box_stmt.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/statements/box_stmt.rs @@ -4,6 +4,267 @@ use crate::semantic::tests::check_stmt_kinds; use expect_test::expect; +#[test] +fn box_can_contain_barrier() { + check_stmt_kinds( + r#" + qubit q; + box { + barrier q; + } + "#, + &expect![[r#" + QubitDeclaration [13-21]: + symbol_id: 8 + BoxStmt [34-78]: + duration: + body: + Stmt [54-64]: + annotations: + kind: BarrierStmt [54-64]: + operands: + GateOperand [62-63]: + kind: Expr [62-63]: + ty: qubit + kind: SymbolId(8) + "#]], + ); +} + +#[test] +#[ignore = "Duration type, stretch type, and delay are not supported yet"] +fn box_can_contain_delay() { + check_stmt_kinds( + r#" + include "stdgates.inc"; + qubit q; + duration a = 300ns; + stretch c = 2 * a; + box { + delay[a] q; + } + "#, + &expect![[r#" + Program: + version: + pragmas: + statements: + Stmt [49-57]: + annotations: + kind: QubitDeclaration [49-57]: + symbol_id: 40 + Stmt [70-89]: + annotations: + kind: ClassicalDeclarationStmt [70-89]: + symbol_id: 41 + ty_span: [70-78] + init_expr: Expr [83-88]: + ty: duration + kind: Lit: Duration(300.0, Ns) + Stmt [102-120]: + annotations: + kind: ClassicalDeclarationStmt [102-120]: + symbol_id: 42 + ty_span: [102-109] + init_expr: Expr [114-119]: + ty: const float + kind: BinaryOpExpr: + op: Mul + lhs: Expr [114-115]: + ty: const float + kind: Lit: Float(2.0) + rhs: Expr [118-119]: + ty: duration + kind: SymbolId(41) + Stmt [133-178]: + annotations: + kind: BoxStmt [133-178]: + duration: + body: + Stmt [153-164]: + annotations: + kind: Err + + [Qasm.Lowerer.NotSupported + + x duration type values are not supported + ,-[test:4:13] + 3 | qubit q; + 4 | duration a = 300ns; + : ^^^^^^^^ + 5 | stretch c = 2 * a; + `---- + , Qasm.Lowerer.NotSupported + + x stretch type values are not supported + ,-[test:5:13] + 4 | duration a = 300ns; + 5 | stretch c = 2 * a; + : ^^^^^^^ + 6 | box { + `---- + , Qasm.Lowerer.CannotCast + + x cannot cast expression of type duration to type const float + ,-[test:5:29] + 4 | duration a = 300ns; + 5 | stretch c = 2 * a; + : ^ + 6 | box { + `---- + , Qasm.Lowerer.CannotCast + + x cannot cast expression of type const float to type stretch + ,-[test:5:25] + 4 | duration a = 300ns; + 5 | stretch c = 2 * a; + : ^^^^^ + 6 | box { + `---- + , Qasm.Lowerer.Unimplemented + + x this statement is not yet handled during OpenQASM 3 import: delay stmt + ,-[test:7:15] + 6 | box { + 7 | delay[a] q; + : ^^^^^^^^^^^ + 8 | } + `---- + ]"#]], + ); +} + +#[test] +fn box_can_contain_reset() { + check_stmt_kinds( + r#" + include "stdgates.inc"; + qubit q; + box { + reset q; + } + "#, + &expect![[r#" + QubitDeclaration [49-57]: + symbol_id: 40 + BoxStmt [70-112]: + duration: + body: + Stmt [90-98]: + annotations: + kind: ResetStmt [90-98]: + reset_token_span: [90-95] + operand: GateOperand [96-97]: + kind: Expr [96-97]: + ty: qubit + kind: SymbolId(40) + "#]], + ); +} + +#[test] +fn box_can_contain_gate_call() { + check_stmt_kinds( + r#" + include "stdgates.inc"; + qubit q; + box { + x q; + } + "#, + &expect![[r#" + QubitDeclaration [49-57]: + symbol_id: 40 + BoxStmt [70-108]: + duration: + body: + Stmt [90-94]: + annotations: + kind: GateCall [90-94]: + modifiers: + symbol_id: 9 + gate_name_span: [90-91] + args: + qubits: + GateOperand [92-93]: + kind: Expr [92-93]: + ty: qubit + kind: SymbolId(40) + duration: + classical_arity: 0 + quantum_arity: 1 + "#]], + ); +} + +#[test] +fn box_can_contain_gphase() { + check_stmt_kinds( + r#" + box { + gphase(pi); + } + "#, + &expect![[r#" + BoxStmt [13-58]: + duration: + body: + Stmt [33-44]: + annotations: + kind: GateCall [33-44]: + modifiers: + symbol_id: 1 + gate_name_span: [33-39] + args: + Expr [40-42]: + ty: angle + kind: Cast [0-0]: + ty: angle + expr: Expr [40-42]: + ty: const float + kind: SymbolId(2) + qubits: + duration: + classical_arity: 1 + quantum_arity: 0 + "#]], + ); +} + +#[test] +fn box_can_contain_box() { + check_stmt_kinds( + r#" + qubit q; + box { + box { + barrier q; + } + } + "#, + &expect![[r#" + QubitDeclaration [13-21]: + symbol_id: 8 + BoxStmt [34-116]: + duration: + body: + Stmt [54-102]: + annotations: + kind: BoxStmt [54-102]: + duration: + body: + Stmt [76-86]: + annotations: + kind: BarrierStmt [76-86]: + operands: + GateOperand [84-85]: + kind: Expr [84-85]: + ty: qubit + kind: SymbolId(8) + "#]], + ); +} + #[test] fn with_invalid_instruction_fails() { check_stmt_kinds( @@ -13,10 +274,26 @@ fn with_invalid_instruction_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-26]: annotations: - kind: Err + kind: BoxStmt [0-26]: + duration: + body: + Stmt [14-20]: + annotations: + kind: ExprStmt [14-20]: + expr: Expr [14-19]: + ty: const int + kind: BinaryOpExpr: + op: Add + lhs: Expr [14-15]: + ty: const int + kind: Lit: Int(2) + rhs: Expr [18-19]: + ty: const int + kind: Lit: Int(4) [Qasm.Lowerer.ClassicalStmtInBox @@ -27,14 +304,6 @@ fn with_invalid_instruction_fails() { : ^^^^^^ 3 | } `---- - , Qasm.Lowerer.Unimplemented - - x this statement is not yet handled during OpenQASM 3 import: box stmt - ,-[test:1:1] - 1 | ,-> box { - 2 | | 2 + 4; - 3 | `-> } - `---- ]"#]], ); } @@ -46,10 +315,15 @@ fn with_duration_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-13]: annotations: - kind: Err + kind: BoxStmt [0-13]: + duration: Expr [5-8]: + ty: const duration + kind: Lit: Duration(4.0, Us) + body: [Qasm.Lowerer.NotSupported @@ -58,13 +332,6 @@ fn with_duration_fails() { 1 | box [4us] { } : ^^^ `---- - , Qasm.Lowerer.Unimplemented - - x this statement is not yet handled during OpenQASM 3 import: box stmt - ,-[test:1:1] - 1 | box [4us] { } - : ^^^^^^^^^^^^^ - `---- ]"#]], ); } diff --git a/source/compiler/qsc_qasm/src/semantic/tests/statements/break_stmt.rs b/source/compiler/qsc_qasm/src/semantic/tests/statements/break_stmt.rs index 3eedebf2a9..289ae69ac9 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/statements/break_stmt.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/statements/break_stmt.rs @@ -80,6 +80,7 @@ fn break_in_non_loop_scope_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-6]: annotations: @@ -107,6 +108,7 @@ fn intermediate_def_scope_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-64]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/statements/continue_stmt.rs b/source/compiler/qsc_qasm/src/semantic/tests/statements/continue_stmt.rs index aee3854cd9..9ca28abb7e 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/statements/continue_stmt.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/statements/continue_stmt.rs @@ -80,6 +80,7 @@ fn continue_in_non_loop_scope_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-9]: annotations: @@ -107,6 +108,7 @@ fn intermediate_def_scope_fails() { &expect![[r#" Program: version: + pragmas: statements: Stmt [9-67]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/statements/reset_stmt.rs b/source/compiler/qsc_qasm/src/semantic/tests/statements/reset_stmt.rs index b9db21412d..656a6a811c 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/statements/reset_stmt.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/statements/reset_stmt.rs @@ -93,6 +93,7 @@ fn on_a_zero_len_qubit_register() { &expect![[r#" Program: version: + pragmas: statements: Stmt [0-11]: annotations: diff --git a/source/compiler/qsc_qasm/src/semantic/tests/statements/switch_stmt.rs b/source/compiler/qsc_qasm/src/semantic/tests/statements/switch_stmt.rs index f0612b0520..abe20fa9f2 100644 --- a/source/compiler/qsc_qasm/src/semantic/tests/statements/switch_stmt.rs +++ b/source/compiler/qsc_qasm/src/semantic/tests/statements/switch_stmt.rs @@ -14,6 +14,7 @@ fn not_supported_before_version_3_1() { &expect![[r#" Program: version: 3.0 + pragmas: statements: Stmt [23-47]: annotations: diff --git a/source/compiler/qsc_qasm/src/tests.rs b/source/compiler/qsc_qasm/src/tests.rs index ba13cafea4..a930fc1079 100644 --- a/source/compiler/qsc_qasm/src/tests.rs +++ b/source/compiler/qsc_qasm/src/tests.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use crate::compiler::parse_and_compile_to_qsharp_ast_with_config; +use crate::compiler::{PragmaConfig, parse_and_compile_to_qsharp_ast_with_config}; use crate::io::{InMemorySourceResolver, SourceResolver}; use crate::semantic::{QasmSemanticParseResult, parse_source}; use crate::{CompilerConfig, OutputSemantics, ProgramType, QasmCompileUnit, QubitSemantics}; @@ -100,6 +100,7 @@ fn compile_with_config>>( stmts: vec![], symbols: res.symbols, errors: res.errors, + pragma_config: PragmaConfig::default(), }; let unit = compiler.compile(&program); @@ -162,6 +163,7 @@ pub fn compile_all_with_config>>( stmts: vec![], symbols: res.symbols, errors: res.errors, + pragma_config: PragmaConfig::default(), }; let unit = compiler.compile(&program); diff --git a/source/compiler/qsc_qasm/src/tests/output.rs b/source/compiler/qsc_qasm/src/tests/output.rs index adb3c65395..5a8b4555a3 100644 --- a/source/compiler/qsc_qasm/src/tests/output.rs +++ b/source/compiler/qsc_qasm/src/tests/output.rs @@ -312,3 +312,68 @@ c2[2] = measure q[4]; Ok(()) } + +#[test] +fn qir_generation_for_box_with_simulatable_intrinsic() -> miette::Result<(), Vec> { + let source = r#" + OPENQASM 3.0; + include "stdgates.inc"; + #pragma qdk.box.open box_begin + #pragma qdk.box.close box_end + + @SimulatableIntrinsic + def box_begin() {} + + @SimulatableIntrinsic + def box_end() {} + + qubit q; + box { + x q; + } + output bit c; + c = measure q; + "#; + + let qir = compile_qasm_to_qir(source, Profile::AdaptiveRI)?; + expect![[r#" + %Result = type opaque + %Qubit = type opaque + + define void @ENTRYPOINT__main() #0 { + block_0: + call void @box_begin() + call void @__quantum__qis__x__body(%Qubit* inttoptr (i64 0 to %Qubit*)) + call void @box_end() + call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) + call void @__quantum__rt__tuple_record_output(i64 0, i8* null) + ret void + } + + declare void @box_begin() + + declare void @__quantum__qis__x__body(%Qubit*) + + declare void @box_end() + + declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1 + + declare void @__quantum__rt__tuple_record_output(i64, i8*) + + attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } + attributes #1 = { "irreversible" } + + ; module flags + + !llvm.module.flags = !{!0, !1, !2, !3, !4} + + !0 = !{i32 1, !"qir_major_version", i32 1} + !1 = !{i32 7, !"qir_minor_version", i32 0} + !2 = !{i32 1, !"dynamic_qubit_management", i1 false} + !3 = !{i32 1, !"dynamic_result_management", i1 false} + !4 = !{i32 1, !"int_computations", !"i64"} + "#]] + .assert_eq(&qir); + + Ok(()) +} diff --git a/source/compiler/qsc_qasm/src/tests/statement.rs b/source/compiler/qsc_qasm/src/tests/statement.rs index 495d7df324..d57803e38a 100644 --- a/source/compiler/qsc_qasm/src/tests/statement.rs +++ b/source/compiler/qsc_qasm/src/tests/statement.rs @@ -11,6 +11,7 @@ mod implicit_modified_gate_call; mod include; mod measure; mod modified_gate_call; +mod pragma; mod reset; mod switch; mod while_loop; diff --git a/source/compiler/qsc_qasm/src/tests/statement/pragma.rs b/source/compiler/qsc_qasm/src/tests/statement/pragma.rs new file mode 100644 index 0000000000..056227c058 --- /dev/null +++ b/source/compiler/qsc_qasm/src/tests/statement/pragma.rs @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +pub mod r#box; diff --git a/source/compiler/qsc_qasm/src/tests/statement/pragma/box.rs b/source/compiler/qsc_qasm/src/tests/statement/pragma/box.rs new file mode 100644 index 0000000000..f2245eeea9 --- /dev/null +++ b/source/compiler/qsc_qasm/src/tests/statement/pragma/box.rs @@ -0,0 +1,255 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::tests::compile_qasm_to_qsharp; +use expect_test::expect; +use miette::Report; + +#[test] +fn pragma_target_can_be_defined_before_pragma() -> miette::Result<(), Vec> { + let source = r#" + def sample_box_target() {} + pragma qdk.box.open sample_box_target + box {} + "#; + + let qsharp = compile_qasm_to_qsharp(source)?; + expect![[r#" + import Std.OpenQASM.Intrinsic.*; + function sample_box_target() : Unit {} + { + sample_box_target(); + }; + "#]] + .assert_eq(&qsharp); + Ok(()) +} + +#[test] +fn pragma_target_can_be_defined_after_pragma() -> miette::Result<(), Vec> { + let source = r#" + pragma qdk.box.open sample_box_target + def sample_box_target() {} + box {} + "#; + + let qsharp = compile_qasm_to_qsharp(source)?; + expect![[r#" + import Std.OpenQASM.Intrinsic.*; + function sample_box_target() : Unit {} + { + sample_box_target(); + }; + "#]] + .assert_eq(&qsharp); + Ok(()) +} + +#[test] +fn pragma_target_can_be_used_by_multilple_pragmas() -> miette::Result<(), Vec> { + let source = r#" + pragma qdk.box.open sample_box_target + pragma qdk.box.close sample_box_target + def sample_box_target() {} + box {} + "#; + + let qsharp = compile_qasm_to_qsharp(source)?; + expect![[r#" + import Std.OpenQASM.Intrinsic.*; + function sample_box_target() : Unit {} + { + sample_box_target(); + sample_box_target(); + }; + "#]] + .assert_eq(&qsharp); + Ok(()) +} + +#[test] +fn pragmas_can_have_separate_targets() -> miette::Result<(), Vec> { + let source = r#" + pragma qdk.box.open box_open + pragma qdk.box.close box_close + def box_open() {} + def box_close() {} + box {} + "#; + + let qsharp = compile_qasm_to_qsharp(source)?; + expect![[r#" + import Std.OpenQASM.Intrinsic.*; + function box_open() : Unit {} + function box_close() : Unit {} + { + box_open(); + box_close(); + }; + "#]] + .assert_eq(&qsharp); + Ok(()) +} + +#[test] +fn nested_boxes_call_separately() -> miette::Result<(), Vec> { + let source = r#" + pragma qdk.box.open box_open + pragma qdk.box.close box_close + def box_open() {} + def box_close() {} + box {box {}} + "#; + + let qsharp = compile_qasm_to_qsharp(source)?; + expect![[r#" + import Std.OpenQASM.Intrinsic.*; + function box_open() : Unit {} + function box_close() : Unit {} + { + box_open(); + { + box_open(); + box_close(); + }; + box_close(); + }; + "#]] + .assert_eq(&qsharp); + Ok(()) +} + +#[test] +fn last_pragma_overwrites_previous() -> miette::Result<(), Vec> { + let source = r#" + pragma qdk.box.open first + pragma qdk.box.open second + pragma qdk.box.close third + pragma qdk.box.close fourth + def first() {} + def second() {} + def third() {} + def fourth() {} + box {box {}} + "#; + + let qsharp = compile_qasm_to_qsharp(source)?; + expect![[r#" + import Std.OpenQASM.Intrinsic.*; + function first() : Unit {} + function second() : Unit {} + function third() : Unit {} + function fourth() : Unit {} + { + second(); + { + second(); + fourth(); + }; + fourth(); + }; + "#]] + .assert_eq(&qsharp); + Ok(()) +} + +#[test] +fn target_with_param_raises_error() { + let source = r#" + pragma qdk.box.open sample_box_target + def sample_box_target(int i) {} + box {} + "#; + + let Err(errors) = compile_qasm_to_qsharp(source) else { + panic!("Expected an error"); + }; + expect![[r#" + Qasm.Compiler.InvalidBoxPragmaTarget + + x sample_box_target is not defined or is not a valid target for box usage + ,-[Test.qasm:2:29] + 1 | + 2 | pragma qdk.box.open sample_box_target + : ^^^^^^^^^^^^^^^^^ + 3 | def sample_box_target(int i) {} + `---- + "#]] + .assert_eq(&format!("{:?}", &errors[0])); +} + +#[test] +fn unknown_pragma_raises_error() { + let source = r#" + pragma qdk.box.unknown sample_box_target + def sample_box_target(int i) {} + box {} + "#; + + let Err(errors) = compile_qasm_to_qsharp(source) else { + panic!("Expected an error"); + }; + expect![[r#" + Qasm.Compiler.NotSupported + + x pragma statement: qdk.box.unknown are not supported + ,-[Test.qasm:2:9] + 1 | + 2 | pragma qdk.box.unknown sample_box_target + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 3 | def sample_box_target(int i) {} + `---- + "#]] + .assert_eq(&format!("{:?}", &errors[0])); +} + +#[test] +fn target_with_return_value_raises_error() { + let source = r#" + pragma qdk.box.open sample_box_target + def sample_box_target() -> int { + return 42; + } + box {} + "#; + + let Err(errors) = compile_qasm_to_qsharp(source) else { + panic!("Expected an error"); + }; + expect![[r#" + Qasm.Compiler.InvalidBoxPragmaTarget + + x sample_box_target is not defined or is not a valid target for box usage + ,-[Test.qasm:2:29] + 1 | + 2 | pragma qdk.box.open sample_box_target + : ^^^^^^^^^^^^^^^^^ + 3 | def sample_box_target() -> int { + `---- + "#]] + .assert_eq(&format!("{:?}", &errors[0])); +} + +#[test] +fn unknown_target_with_return_value_raises_error() { + let source = r#" + pragma qdk.box.open sample_box_target + box {} + "#; + + let Err(errors) = compile_qasm_to_qsharp(source) else { + panic!("Expected an error"); + }; + expect![[r#" + Qasm.Compiler.InvalidBoxPragmaTarget + + x sample_box_target is not defined or is not a valid target for box usage + ,-[Test.qasm:2:29] + 1 | + 2 | pragma qdk.box.open sample_box_target + : ^^^^^^^^^^^^^^^^^ + 3 | box {} + `---- + "#]] + .assert_eq(&format!("{:?}", &errors[0])); +} diff --git a/source/vscode/syntaxes/openqasm.tmLanguage.json b/source/vscode/syntaxes/openqasm.tmLanguage.json index 1e75c6bb18..d8d54edd8e 100644 --- a/source/vscode/syntaxes/openqasm.tmLanguage.json +++ b/source/vscode/syntaxes/openqasm.tmLanguage.json @@ -47,11 +47,11 @@ "patterns": [ { "name": "keyword.control.openqasm", - "match": "\\b(in|for|return|if|else|switch|while)\\b" + "match": "(?