Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into swernli/python-interop
Browse files Browse the repository at this point in the history
  • Loading branch information
swernli committed Dec 6, 2024
2 parents d06cff4 + f026774 commit c444928
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 29 deletions.
2 changes: 1 addition & 1 deletion compiler/qsc_frontend/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub(super) fn lift(
name: Ident {
id: assigner.next_node(),
span,
name: "lambda".into(),
name: "<lambda>".into(),
},
generics: Vec::new(),
input,
Expand Down
4 changes: 3 additions & 1 deletion compiler/qsc_frontend/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ use self::convert::TyConversionError;
#[derive(Clone, Debug, Diagnostic, Error)]
pub(super) enum Error {
#[error("unknown attribute {0}")]
#[diagnostic(help("supported attributes are: EntryPoint, Config"))]
#[diagnostic(help(
"supported attributes are: EntryPoint, Config, SimulatableIntrinsic, Measurement, Reset"
))]
#[diagnostic(code("Qsc.LowerAst.UnknownAttr"))]
UnknownAttr(String, #[label] Span),
#[error("invalid attribute arguments: expected {0}")]
Expand Down
32 changes: 16 additions & 16 deletions compiler/qsc_frontend/src/lower/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,7 @@ fn lambda_function_empty_closure() {
Item 2 [57-67] (Internal):
Parent: 1
Callable 15 [57-67] (function):
name: Ident 16 [57-67] "lambda"
name: Ident 16 [57-67] "<lambda>"
input: Pat 14 [57-67] [Type (Int,)]: Tuple:
Pat 9 [57-58] [Type Int]: Bind: Ident 10 [57-58] "x"
output: Int
Expand Down Expand Up @@ -1025,7 +1025,7 @@ fn lambda_function_empty_closure_passed() {
Item 3 [93-103] (Internal):
Parent: 2
Callable 25 [93-103] (function):
name: Ident 26 [93-103] "lambda"
name: Ident 26 [93-103] "<lambda>"
input: Pat 24 [93-103] [Type (Int,)]: Tuple:
Pat 19 [93-94] [Type Int]: Bind: Ident 20 [93-94] "x"
output: Int
Expand Down Expand Up @@ -1081,7 +1081,7 @@ fn lambda_function_closure() {
Item 2 [76-86] (Internal):
Parent: 1
Callable 21 [76-86] (function):
name: Ident 22 [76-86] "lambda"
name: Ident 22 [76-86] "<lambda>"
input: Pat 19 [76-86] [Type (Int, Int)]: Tuple:
Pat 20 [53-54] [Type Int]: Bind: Ident 18 [53-54] "x"
Pat 13 [76-77] [Type Int]: Bind: Ident 14 [76-77] "y"
Expand Down Expand Up @@ -1138,7 +1138,7 @@ fn lambda_function_closure_repeated_var() {
Item 2 [76-90] (Internal):
Parent: 1
Callable 23 [76-90] (function):
name: Ident 24 [76-90] "lambda"
name: Ident 24 [76-90] "<lambda>"
input: Pat 21 [76-90] [Type (Int, Int)]: Tuple:
Pat 22 [53-54] [Type Int]: Bind: Ident 20 [53-54] "x"
Pat 13 [76-77] [Type Int]: Bind: Ident 14 [76-77] "y"
Expand Down Expand Up @@ -1209,7 +1209,7 @@ fn lambda_function_closure_passed() {
Item 3 [120-130] (Internal):
Parent: 2
Callable 31 [120-130] (function):
name: Ident 32 [120-130] "lambda"
name: Ident 32 [120-130] "<lambda>"
input: Pat 29 [120-130] [Type (Int, Int)]: Tuple:
Pat 30 [101-102] [Type Int]: Bind: Ident 28 [101-102] "x"
Pat 23 [120-121] [Type Int]: Bind: Ident 24 [120-121] "y"
Expand Down Expand Up @@ -1283,7 +1283,7 @@ fn lambda_function_nested_closure() {
Item 3 [172-190] (Internal):
Parent: 2
Callable 51 [172-190] (function):
name: Ident 52 [172-190] "lambda"
name: Ident 52 [172-190] "<lambda>"
input: Pat 47 [172-190] [Type (Int, Int, Int, Int)]: Tuple:
Pat 48 [111-112] [Type Int]: Bind: Ident 44 [111-112] "a"
Pat 49 [130-131] [Type Int]: Bind: Ident 45 [130-131] "b"
Expand All @@ -1306,7 +1306,7 @@ fn lambda_function_nested_closure() {
Item 4 [130-200] (Internal):
Parent: 2
Callable 59 [130-200] (function):
name: Ident 60 [130-200] "lambda"
name: Ident 60 [130-200] "<lambda>"
input: Pat 57 [130-200] [Type (Int, Int)]: Tuple:
Pat 58 [111-112] [Type Int]: Bind: Ident 56 [111-112] "a"
Pat 25 [130-131] [Type Int]: Bind: Ident 26 [130-131] "b"
Expand Down Expand Up @@ -1382,7 +1382,7 @@ fn lambda_operation_empty_closure() {
Item 3 [137-144] (Internal):
Parent: 2
Callable 27 [137-144] (operation):
name: Ident 28 [137-144] "lambda"
name: Ident 28 [137-144] "<lambda>"
input: Pat 26 [137-144] [Type (Qubit,)]: Tuple:
Pat 23 [137-138] [Type Qubit]: Bind: Ident 24 [137-138] "q"
output: Unit
Expand Down Expand Up @@ -1465,7 +1465,7 @@ fn lambda_operation_closure() {
Item 4 [199-215] (Internal):
Parent: 3
Callable 35 [199-215] (operation):
name: Ident 36 [199-215] "lambda"
name: Ident 36 [199-215] "<lambda>"
input: Pat 33 [199-215] [Type (Qubit, Unit)]: Tuple:
Pat 34 [174-175] [Type Qubit]: Bind: Ident 32 [174-175] "q"
Pat 28 [199-201] [Type Unit]: Unit
Expand Down Expand Up @@ -1543,7 +1543,7 @@ fn lambda_adj() {
Item 4 [138-147] (Internal):
Parent: 3
Callable 27 [138-147] (operation):
name: Ident 28 [138-147] "lambda"
name: Ident 28 [138-147] "<lambda>"
input: Pat 26 [138-147] [Type (Qubit,)]: Tuple:
Pat 21 [138-139] [Type Qubit]: Bind: Ident 22 [138-139] "q"
output: Unit
Expand Down Expand Up @@ -1611,7 +1611,7 @@ fn partial_app_one_hole() {
Item 3 [99-108] (Internal):
Parent: 2
Callable 37 [99-108] (function):
name: Ident 38 [99-108] "lambda"
name: Ident 38 [99-108] "<lambda>"
input: Pat 35 [99-108] [Type (Int, Int)]: Tuple:
Pat 36 [106-107] [Type Int]: Bind: Ident 34 [106-107] "arg"
Pat 24 [103-104] [Type Int]: Bind: Ident 23 [103-104] "hole"
Expand Down Expand Up @@ -1679,7 +1679,7 @@ fn partial_app_two_holes() {
Item 3 [99-108] (Internal):
Parent: 2
Callable 33 [99-108] (function):
name: Ident 34 [99-108] "lambda"
name: Ident 34 [99-108] "<lambda>"
input: Pat 32 [99-108] [Type ((Int, Int),)]: Tuple:
Pat 30 [102-108] [Type (Int, Int)]: Tuple:
Pat 24 [103-104] [Type Int]: Bind: Ident 23 [103-104] "hole"
Expand Down Expand Up @@ -1752,7 +1752,7 @@ fn partial_app_nested_tuple() {
Item 3 [130-152] (Internal):
Parent: 2
Callable 52 [130-152] (function):
name: Ident 53 [130-152] "lambda"
name: Ident 53 [130-152] "<lambda>"
input: Pat 50 [130-152] [Type (Double, (Int, (Bool, String), Result))]: Tuple:
Pat 51 [141-144] [Type Double]: Bind: Ident 49 [141-144] "arg"
Pat 47 [133-152] [Type (Int, (Bool, String), Result)]: Tuple:
Expand Down Expand Up @@ -1836,7 +1836,7 @@ fn partial_app_nested_tuple_singleton_unwrap() {
Item 3 [130-155] (Internal):
Parent: 2
Callable 56 [130-155] (function):
name: Ident 57 [130-155] "lambda"
name: Ident 57 [130-155] "<lambda>"
input: Pat 53 [130-155] [Type (Bool, Double, (Int, String, Result))]: Tuple:
Pat 54 [138-142] [Type Bool]: Bind: Ident 51 [138-142] "arg"
Pat 55 [144-147] [Type Double]: Bind: Ident 52 [144-147] "arg"
Expand Down Expand Up @@ -2091,7 +2091,7 @@ fn partial_app_bound_to_non_arrow_ty() {
Item 3 [113-122] (Internal):
Parent: 2
Callable 37 [113-122] (function):
name: Ident 38 [113-122] "lambda"
name: Ident 38 [113-122] "<lambda>"
input: Pat 35 [113-122] [Type (Int, Int)]: Tuple:
Pat 36 [117-118] [Type Int]: Bind: Ident 34 [117-118] "arg"
Pat 30 [120-121] [Type Int]: Bind: Ident 29 [120-121] "hole"
Expand Down Expand Up @@ -2366,7 +2366,7 @@ fn lambda_with_invalid_free_variable() {
Item 2 [52-67] (Internal):
Parent: 1
Callable 12 [52-67] (operation):
name: Ident 13 [52-67] "lambda"
name: Ident 13 [52-67] "<lambda>"
input: Pat 11 [52-67] [Type (Unit,)]: Tuple:
Pat 7 [52-54] [Type Unit]: Unit
output: Unit
Expand Down
31 changes: 25 additions & 6 deletions compiler/qsc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1344,23 +1344,42 @@ impl Display for Ident {
/// An attribute.
#[derive(Clone, Debug, PartialEq)]
pub enum Attr {
/// Provide pre-processing information about when an item should be included in compilation.
/// Provides pre-processing information about when an item should be included in compilation.
Config,
/// Indicates that a callable is an entry point to a program.
/// Indicates that the callable is the entry point to a program.
EntryPoint,
/// Indicates that an item does not have an implementation available for use.
/// Indicates that an item is not yet implemented.
Unimplemented,
/// Indicates that an item should be treated as an intrinsic callable for QIR code generation
/// and any implementation should be ignored.
/// and any implementation should only be used during simulation.
SimulatableIntrinsic,
/// Indicates that a callable is a measurement. This means that the operation will be marked as
/// Indicates that an intrinsic callable is a measurement. This means that the operation will be marked as
/// "irreversible" in the generated QIR, and output Result types will be moved to the arguments.
Measurement,
/// Indicates that a callable is a reset. This means that the operation will be marked as
/// Indicates that an intrinsic callable is a reset. This means that the operation will be marked as
/// "irreversible" in the generated QIR.
Reset,
}

impl Attr {
/// Gets the string description of the attribute.
#[must_use]
pub fn description(&self) -> &'static str {
match self {
Attr::Config => "Provides pre-processing information about when an item should be included in compilation.
Valid arguments are `Base`, `Adaptive`, `IntegerComputations`, `FloatingPointComputations`, `BackwardsBranching`, `HigherLevelConstructs`, `QubitReset`, and `Unrestricted`.
The `not` operator is also supported to negate the attribute, e.g. `not Adaptive`.",
Attr::EntryPoint => "Indicates that the callable is the entry point to a program.",
Attr::Unimplemented => "Indicates that an item is not yet implemented.",
Attr::SimulatableIntrinsic => "Indicates that an item should be treated as an intrinsic callable for QIR code generation and any implementation should only be used during simulation.",
Attr::Measurement => "Indicates that an intrinsic callable is a measurement. This means that the operation will be marked as \"irreversible\" in the generated QIR, and output Result types will be moved to the arguments.",
Attr::Reset => "Indicates that an intrinsic callable is a reset. This means that the operation will be marked as \"irreversible\" in the generated QIR.",
}
}
}

impl FromStr for Attr {
type Err = ();

Expand Down
6 changes: 3 additions & 3 deletions compiler/qsc_passes/src/spec_gen/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1906,7 +1906,7 @@ fn lambda_adj_calls_adj() {
Item 4 [138-147] (Internal):
Parent: 3
Callable 27 [138-147] (operation):
name: Ident 28 [138-147] "lambda"
name: Ident 28 [138-147] "<lambda>"
input: Pat 26 [138-147] [Type (Qubit,)]: Tuple:
Pat 21 [138-139] [Type Qubit]: Bind: Ident 22 [138-139] "q"
output: Unit
Expand Down Expand Up @@ -2032,7 +2032,7 @@ fn op_array_forget_functors_with_lambdas() {
Item 5 [270-281] (Internal):
Parent: 4
Callable 35 [270-281] (operation):
name: Ident 36 [270-281] "lambda"
name: Ident 36 [270-281] "<lambda>"
input: Pat 34 [270-281] [Type (Qubit,)]: Tuple:
Pat 29 [270-271] [Type Qubit]: Bind: Ident 30 [270-271] "q"
output: Unit
Expand All @@ -2048,7 +2048,7 @@ fn op_array_forget_functors_with_lambdas() {
Item 6 [283-294] (Internal):
Parent: 4
Callable 47 [283-294] (operation):
name: Ident 48 [283-294] "lambda"
name: Ident 48 [283-294] "<lambda>"
input: Pat 46 [283-294] [Type (Qubit,)]: Tuple:
Pat 41 [283-284] [Type Qubit]: Bind: Ident 42 [283-284] "q"
output: Unit
Expand Down
4 changes: 4 additions & 0 deletions language_service/src/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ struct DefinitionFinder<'a> {
}

impl<'a> Handler<'a> for DefinitionFinder<'a> {
fn at_attr_ref(&mut self, _: &'a ast::Ident) {
// We don't support goto def for attributes.
}

fn at_callable_def(
&mut self,
_: &LocatorContext<'a>,
Expand Down
15 changes: 15 additions & 0 deletions language_service/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ use crate::protocol::Hover;
use crate::qsc_utils::into_range;
use qsc::ast::visit::Visitor;
use qsc::display::{parse_doc_for_param, parse_doc_for_summary, CodeDisplay, Lookup};
use qsc::hir::Attr;
use qsc::line_column::{Encoding, Position, Range};
use qsc::{ast, hir, Span};
use std::fmt::Display;
use std::rc::Rc;
use std::str::FromStr;

pub(crate) fn get_hover(
compilation: &Compilation,
Expand Down Expand Up @@ -43,6 +45,7 @@ enum LocalKind {
LambdaParam,
Local,
}

struct HoverGenerator<'a> {
position_encoding: Encoding,
hover: Option<Hover>,
Expand All @@ -51,6 +54,18 @@ struct HoverGenerator<'a> {
}

impl<'a> Handler<'a> for HoverGenerator<'a> {
fn at_attr_ref(&mut self, name: &'a ast::Ident) {
let description = match Attr::from_str(&name.name) {
Ok(attr) => attr.description(),
Err(()) => return, // No hover information for unsupported attributes.
};

self.hover = Some(Hover {
contents: format!("attribute ```{}```\n\n{}", name.name, description),
span: self.range(name.span),
});
}

fn at_callable_def(
&mut self,
context: &LocatorContext<'a>,
Expand Down
36 changes: 36 additions & 0 deletions language_service/src/hover/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,42 @@ fn check_notebook_none(cells_with_markers: &[(&str, &str)]) {
assert!(actual.is_none());
}

#[test]
fn attr() {
check(
indoc! {r#"
namespace Test {
@◉Entr↘yPoint◉()
operation Bar() : Unit {}
}
"#},
&expect![[r#"
attribute ```EntryPoint```
Indicates that the callable is the entry point to a program."#]],
);
}

#[test]
fn attr_with_arg() {
check(
indoc! {r#"
namespace Test {
@◉Con↘fig◉(BackwardsBranching)
operation Bar() : Unit {}
}
"#},
&expect![[r#"
attribute ```Config```
Provides pre-processing information about when an item should be included in compilation.
Valid arguments are `Base`, `Adaptive`, `IntegerComputations`, `FloatingPointComputations`, `BackwardsBranching`, `HigherLevelConstructs`, `QubitReset`, and `Unrestricted`.
The `not` operator is also supported to negate the attribute, e.g. `not Adaptive`."#]],
);
}

#[test]
fn callable_unit_types() {
check(
Expand Down
16 changes: 14 additions & 2 deletions language_service/src/name_locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,23 @@ use std::mem::replace;
use std::rc::Rc;

use crate::compilation::Compilation;
use qsc::ast::visit::{walk_expr, walk_namespace, walk_pat, walk_ty, walk_ty_def, Visitor};
use qsc::ast::visit::{
walk_attr, walk_expr, walk_namespace, walk_pat, walk_ty, walk_ty_def, Visitor,
};
use qsc::ast::{FieldAccess, Idents, PathKind};
use qsc::display::Lookup;
use qsc::{ast, hir, resolve};

#[allow(unused_variables)]
pub(crate) trait Handler<'package> {
fn at_attr_ref(&mut self, name: &'package ast::Ident);

fn at_callable_def(
&mut self,
context: &LocatorContext<'package>,
name: &'package ast::Ident,
decl: &'package ast::CallableDecl,
);

fn at_callable_ref(
&mut self,
path: &'package ast::Path,
Expand Down Expand Up @@ -166,6 +170,13 @@ impl<'inner, 'package, T: Handler<'package>> Locator<'inner, 'package, T> {
}

impl<'inner, 'package, T: Handler<'package>> Visitor<'package> for Locator<'inner, 'package, T> {
fn visit_attr(&mut self, attr: &'package ast::Attr) {
if attr.name.span.contains(self.offset) {
self.inner.at_attr_ref(&attr.name);
}
walk_attr(self, attr);
}

fn visit_namespace(&mut self, namespace: &'package ast::Namespace) {
if namespace.span.contains(self.offset) {
self.context.current_namespace = namespace.name.full_name();
Expand All @@ -177,6 +188,7 @@ impl<'inner, 'package, T: Handler<'package>> Visitor<'package> for Locator<'inne
fn visit_item(&mut self, item: &'package ast::Item) {
if item.span.contains(self.offset) {
let context = replace(&mut self.context.current_item_doc, item.doc.clone());
item.attrs.iter().for_each(|a| self.visit_attr(a));
match &*item.kind {
ast::ItemKind::Callable(decl) => {
if decl.name.span.touches(self.offset) {
Expand Down
4 changes: 4 additions & 0 deletions language_service/src/references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ struct NameHandler<'a> {
}

impl<'a> Handler<'a> for NameHandler<'a> {
fn at_attr_ref(&mut self, _: &'a ast::Ident) {
// We don't support find all refs for attributes.
}

fn at_callable_def(
&mut self,
_: &LocatorContext<'a>,
Expand Down
Loading

0 comments on commit c444928

Please sign in to comment.