-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!: Make linear types @inout by default; add @owned annotation #486
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #486 +/- ##
==========================================
- Coverage 92.01% 91.99% -0.03%
==========================================
Files 58 59 +1
Lines 5914 5921 +7
==========================================
+ Hits 5442 5447 +5
- Misses 472 474 +2 ☔ View full report in Codecov by Sentry. |
def rz(q: qubit @ owned, angle: angle) -> qubit: ... | ||
|
||
|
||
@guppy.hugr_op(quantum, quantum_op("Rx")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
N.B. This is broken in main. Both rz
and rx
are annoted with quantum_op("Rz")
@@ -163,7 +163,9 @@ def check_signature(func_def: ast.FunctionDef, globals: Globals) -> FunctionType | |||
) | |||
|
|||
|
|||
def parse_docstring(func_ast: ast.FunctionDef) -> tuple[ast.FunctionDef, str | None]: | |||
def parse_function_with_docstring( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive-by: I updated the name of this function because I found it too confusing
guppylang/tys/parsing.py
Outdated
@@ -82,11 +82,11 @@ def _try_parse_defn(node: AstNode, globals: Globals) -> Definition | None: | |||
match node: | |||
case ast.Name(id=x): | |||
if x not in globals: | |||
raise GuppyError("Unknown identifier", node) | |||
raise GuppyError(f"Unknown identifier: {x}", node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive-by: Printing the unknown identifiers here and on line 89
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #479. It also makes the printed id show the module name instead of the object repr.
@@ -1,6 +1,7 @@ | |||
import guppylang.prelude.quantum as quantum | |||
from guppylang.decorator import guppy | |||
from guppylang.module import GuppyModule | |||
from guppylang.prelude.builtins import owned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this file from copy.py
to copy_qubit.py
because of some weird case where it was being imported by the guppy prelude instead of the python copy
library. Not 100% sure what was going on there but I don't want to touch it with a 10ft pole.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! 🎉
I think you also need to update the autogenerated constructors for structs (see guppylang/definition/structs.py
) to take ownership of linear arguments. Surprising that this wasn't caught by the tests :/
@@ -74,7 +74,14 @@ def __rmatmul__(self, other: Any) -> Any: | |||
return other | |||
|
|||
|
|||
inout = _Inout() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also remove the _Inout
class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
guppylang/tys/parsing.py
Outdated
@@ -252,8 +256,11 @@ def type_from_ast( | |||
) -> Type: | |||
"""Turns an AST expression into a Guppy type.""" | |||
ty, flags = type_with_flags_from_ast(node, globals, param_var_mapping) | |||
if flags != InputFlags.NoFlags: | |||
raise GuppyError("`@` type annotations are not allowed in this position", node) | |||
if flags != InputFlags.NoFlags and flags != InputFlags.Inout: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why exclude InputFlags.Inout
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a linear variable has InputFlags.Inout
, it's because we set it - it can't have been done via an annotation from the user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if it were set, this would be a compiler bug, right? Maybe do an assert
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to an assert
pyproject.toml
Outdated
disable_error_code = ['valid-type' # Otherwise mypy will complain about @owned annotations | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we shouldn't disable this globally, only for files that actually contain Guppy code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed and readded locally to the definitions in quantum.py and quantum_functional.py
17: def foo(qs: linst[qubit]) -> linst[qubit]: | ||
17: def foo(qs: linst[qubit] @owned) -> linst[qubit]: | ||
18: return [q for q in qs if bar(q)] | ||
^ | ||
GuppyError: Variable `q` with linear type `qubit` was already used (at 18:33) | ||
^ | ||
GuppyTypeError: Variable `q` with linear type `qubit` is not used on all control-flow paths of the list comprehension |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to annotate bar
as owned
as well to reproduce the old error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good spot! Updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you delete this file? Same for __pycache__.err
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
^^^^^^ | ||
GuppyTypeError: Cannot instantiate non-linear type variable `T` in type `forall T. (T -> T) -> None` with linear type `qubit` | ||
^ | ||
GuppyTypeError: Expected argument of type `?T -> ?T`, got `qubit -> qubit` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this error get worse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's failing comparing T
with NoFlags
against qubit
with Inout
before it can get to the linearity check. I'll add a better error message for these flag mismatches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this is clearer after I fixed a bug locally - will push now. The printing code was hiding @owned
flags. Now we get ?T -> ?T
vs qubit @owned -> qubit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BUT the case I was thinking of in my first comment also happens. I've just added poly_errors/non_linear3.py
to demonstrate this. @inout
flags are silent during printing because they're not user-facing, but they still mess up unification. I'll add an issue for this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added #487
I've added a test and the logic for this, but it seems like it was working by accident! Something's a bit fishy there... |
@croyzor could you also resolve the conflicts that github is pointing out in |
Some leftover skips from the hugr update, and from #343 Also adds some extra info on the remaining skips. --------- Co-authored-by: Agustin Borgna <[email protected]>
guppylang/prelude/quantum.py
Outdated
@@ -29,12 +29,12 @@ def dirty_qubit() -> qubit: ... | |||
|
|||
|
|||
@guppy.hugr_op(quantum, quantum_op("Measure")) | |||
def measure_return(q: qubit @ owned) -> tuple[qubit, bool]: ... | |||
def measure_return(q: qubit @ owned) -> tuple[qubit, bool]: ... # type: ignore[valid-type] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also add valid-type
to the mypy: disable-error-code
pragma at the start of the file.
Same in quantum_functional.py
Co-authored-by: Mark Koch <[email protected]>
Co-authored-by: Mark Koch <[email protected]>
Co-authored-by: Mark Koch <[email protected]>
🤖 I have created a release *beep* *boop* --- ## [0.12.0](v0.11.0...v0.12.0) (2024-09-18) ### ⚠ BREAKING CHANGES * Pytket circuits loaded via a `py` expression no longer take ownership of the passed qubits. * Lists and function tensors are no longer available by default. `guppylang.enable_experimental_features()` must be called before compilation to enable them. * The `GuppyModule` argument is now optional for all decorators and no longer the first positional argument. Removed the explicit module objects `builtins`, `quantum`, and `angle`. * `quantum_functional` is now its own Guppy module and no longer implicitly comes with `quantum`. * Linear function arguments are now borrowed by default; removed the now redundant `@inout` annotation ### Features * Add functions to quantum module and make quantum_functional independent ([#494](#494)) ([0b0b1af](0b0b1af)) * Hide lists and function tensors behind experimental flag ([#501](#501)) ([c867f48](c867f48)) * Make linear types [@inout](https://github.com/inout) by default; add [@owned](https://github.com/owned) annotation ([#486](#486)) ([e900c96](e900c96)) * Only lower definitions to Hugr if they are used ([#496](#496)) ([cc2c8a4](cc2c8a4)) * Support implicit modules for all decorators and turn builtins into implicit module ([#476](#476)) ([cc8a424](cc8a424)) * Use inout for pytket circuits ([#500](#500)) ([a980ec2](a980ec2)) ### Bug Fixes * `angle` is now a struct and emitted as a rotation ([#485](#485)) ([992b138](992b138)) * Evade false positives for inout variable usage ([#493](#493)) ([6fdb5d6](6fdb5d6)) * Fix redefinition of structs ([#499](#499)) ([0b156e9](0b156e9)) * Initialise _checked in GuppyModule ([#491](#491)) ([3dd5dd3](3dd5dd3)), closes [#489](#489) * use correct array ops ([#503](#503)) ([720d8b8](720d8b8)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Resolves #413 and #414.
BREAKING CHANGE: Linear function arguments are now borrowed by default; removed the now redundant
@inout
annotation