This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
/
SyntaxGenerator.fs
500 lines (405 loc) · 26 KB
/
SyntaxGenerator.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.QsCompiler
open System
open System.Collections.Immutable
open System.Text.RegularExpressions
open Microsoft.Quantum.QsCompiler.DataTypes
open Microsoft.Quantum.QsCompiler.ReservedKeywords
open Microsoft.Quantum.QsCompiler.SyntaxExtensions
open Microsoft.Quantum.QsCompiler.SyntaxTokens
open Microsoft.Quantum.QsCompiler.SyntaxTree
open Microsoft.Quantum.QsCompiler.Transformations.Core
// transformations used to strip range information for auto-generated syntax
type private StripPositionInfoFromType(parent: StripPositionInfo) =
inherit TypeTransformation(parent)
override this.OnTypeRange _ = TypeRange.Generated
override this.OnRangeInformation _ = Null
and private StripPositionInfoFromExpression(parent: StripPositionInfo) =
inherit ExpressionTransformation(parent)
override this.OnRangeInformation _ = Null
and private StripPositionInfoFromStatement(parent: StripPositionInfo) =
inherit StatementTransformation(parent)
override this.OnLocation _ = Null
and private StripPositionInfoFromNamespace(parent: StripPositionInfo) =
inherit NamespaceTransformation(parent)
override this.OnLocation _ = Null
and public StripPositionInfo private (_internal_) =
inherit SyntaxTreeTransformation()
static let defaultInstance = new StripPositionInfo()
new() as this =
StripPositionInfo("_internal_")
then
this.Types <- new StripPositionInfoFromType(this)
this.Expressions <- new StripPositionInfoFromExpression(this)
this.Statements <- new StripPositionInfoFromStatement(this)
this.Namespaces <- new StripPositionInfoFromNamespace(this)
static member public Default = defaultInstance
static member public Apply t = defaultInstance.Types.OnType t
static member public Apply e =
defaultInstance.Expressions.OnTypedExpression e
static member public Apply s = defaultInstance.Statements.OnScope s
static member public Apply a =
defaultInstance.Namespaces.OnNamespace a
module SyntaxGenerator =
/// Matches only if the string consists of a fully qualified name and nothing else.
let internal FullyQualifiedName = new Regex(@"^[\p{L}_][\p{L}\p{Nd}_]*(\.[\p{L}_][\p{L}\p{Nd}_]*)+$")
// literal expressions
/// Builds an immutable typed expression of the given kind and type kind,
/// setting the quantum dependency to the given value and assuming no type parameter resolutions.
/// Sets the range information for the built expression to Null.
let AutoGeneratedExpression kind exTypeKind qDep =
let inferredInfo = InferredExpressionInformation.New(false, quantumDep = qDep)
TypedExpression.New(kind, ImmutableDictionary.Empty, exTypeKind |> ResolvedType.New, inferredInfo, Null)
/// Creates a typed expression that represents an invalid expression of invalid type.
/// Sets the range information for the built expression to Null.
let InvalidExpression = AutoGeneratedExpression InvalidExpr QsTypeKind.InvalidType false
/// Creates a typed expression that corresponds to a Unit value.
/// Sets the range information for the built expression to Null.
let UnitValue = AutoGeneratedExpression UnitValue QsTypeKind.UnitType false
/// Creates a typed expression that corresponds to a Bool literal with the given value.
/// Sets the range information for the built expression to Null.
let BoolLiteral value =
AutoGeneratedExpression(BoolLiteral value) QsTypeKind.Bool false
/// Creates a typed expression that corresponds to an Int literal with the given value.
/// Sets the range information for the built expression to Null.
let IntLiteral v =
AutoGeneratedExpression(IntLiteral v) QsTypeKind.Int false
/// Creates a typed expression that corresponds to a BigInt literal with the given value.
/// Sets the range information for the built expression to Null.
let BigIntLiteral (v: int) =
AutoGeneratedExpression(BigIntLiteral(bigint v)) QsTypeKind.BigInt false
/// Creates a typed expression that corresponds to a Double literal with the given value.
/// Sets the range information for the built expression to Null.
let DoubleLiteral v =
AutoGeneratedExpression(DoubleLiteral v) QsTypeKind.Double false
/// Creates a typed expression that corresponds to a String literal with the given value and interpolation arguments.
/// Sets the range information for the built expression to Null.
let StringLiteral (s, interpolArgs) =
AutoGeneratedExpression(StringLiteral(s, interpolArgs)) QsTypeKind.String false
/// Creates a typed expression that corresponds to a Range literal with the given left hand side and right hand side.
/// Sets the range information for the built expression to Null.
/// Does *not* verify the given left and right hand side.
let RangeLiteral (lhs, rhs) =
AutoGeneratedExpression(RangeLiteral(lhs, rhs)) QsTypeKind.Range false
/// Creates a typed expression that corresponds to a value tuple with the given items.
/// Sets the range information for the built expression to Null.
/// Does *not* strip positional information from the given items; the responsibility to do so is with the caller.
let TupleLiteral (items: TypedExpression seq) =
let qdep = items |> Seq.exists (fun item -> item.InferredInformation.HasLocalQuantumDependency)
let tupleType =
items |> Seq.map (fun item -> item.ResolvedType) |> ImmutableArray.CreateRange |> TupleType
AutoGeneratedExpression(ValueTuple(items.ToImmutableArray())) tupleType qdep
// utils for assignments
/// Given a typed expression that consists only of local variables, missing or invalid expressions, and tuples thereof,
/// returns the corresponding symbol tuple. Throws an ArgumentException if the expression contains anything else.
let rec ExpressionAsSymbolTuple (ex: TypedExpression) : SymbolTuple =
match ex.Expression with
| ValueTuple items ->
items |> Seq.map ExpressionAsSymbolTuple |> ImmutableArray.CreateRange |> VariableNameTuple
| Identifier (LocalVariable varName, tArgs) when tArgs = Null -> VariableName varName
| Identifier (InvalidIdentifier, tArgs) when tArgs = Null -> InvalidItem
| InvalidExpr -> InvalidItem
| MissingExpr -> DiscardedItem
| _ ->
ArgumentException "the given expression contains items that do not represent a valid symbol name"
|> raise
/// Given the argument tuple of a callable or a provided specialization declaration, returns the corresponding symbol tuple.
/// Throws an ArgumentExecption if the outermost tuple is empty or if it is not a QsTuple, or if an inner tuple is empty.
let ArgumentTupleAsSymbolTuple (argTuple: QsTuple<LocalVariableDeclaration<QsLocalSymbol>>) : SymbolTuple =
let rec resolveArgTupleItem =
function
| QsTupleItem (decl: LocalVariableDeclaration<QsLocalSymbol>) ->
decl.VariableName
|> function
| ValidName varName -> varName |> VariableName
| InvalidName -> DiscardedItem
| QsTuple elements when elements.Length = 0 ->
ArgumentException "argument tuple items cannot be empty tuples" |> raise
| QsTuple elements when elements.Length = 1 -> resolveArgTupleItem elements.[0]
| QsTuple elements -> buildTuple elements
and buildTuple elements =
let items = elements |> Seq.map resolveArgTupleItem |> ImmutableArray.CreateRange
items |> VariableNameTuple
match argTuple with
| QsTuple elements when elements.Length = 0 ->
ArgumentException "cannot construct symbol tuple for empty argument tuple" |> raise
| QsTuple elements when elements.Length = 1 -> resolveArgTupleItem elements.[0]
| QsTuple elements -> buildTuple elements
| _ -> ArgumentException "the argument tuple needs to be a QsTuple" |> raise
/// Given the argument tuple of a callable or a provided specialization declaration,
/// returns the corresponding typed expression.
/// Throws an ArgumentExecption if the outermost tuple is not a QsTuple, or if an inner tuple is empty.
let ArgumentTupleAsExpression (argTuple: QsTuple<LocalVariableDeclaration<QsLocalSymbol>>) =
let rec resolveArgTupleItem =
function
| QsTupleItem (decl: LocalVariableDeclaration<QsLocalSymbol>) ->
decl.VariableName
|> function
| ValidName varName ->
let exKind = (LocalVariable varName, Null) |> Identifier
AutoGeneratedExpression exKind decl.Type.Resolution false
| InvalidName -> InvalidExpression
| QsTuple elements when elements.Length = 0 ->
ArgumentException "argument tuple items cannot be empty tuples" |> raise
| QsTuple elements when elements.Length = 1 -> resolveArgTupleItem elements.[0]
| QsTuple elements -> buildTuple elements
and buildTuple elements =
let items = elements |> Seq.map resolveArgTupleItem |> ImmutableArray.CreateRange
let exType = items |> Seq.map (fun ex -> ex.ResolvedType) |> ImmutableArray.CreateRange |> TupleType
AutoGeneratedExpression(ValueTuple items) exType false
match argTuple with
| QsTuple elements when elements.Length = 0 -> UnitValue
| QsTuple elements when elements.Length = 1 -> resolveArgTupleItem elements.[0]
| QsTuple elements -> buildTuple elements
| _ -> ArgumentException "the argument tuple needs to be a QsTuple" |> raise
// utils to for building typed expressions and iterable inversions
/// Creates a typed expression corresponding to a call to a non-type-parametrized callable.
/// Only verifies the type of <paramref name="lhs"/>.
/// </summary>
/// <exception cref="ArgumentException">The type of <paramref name="lhs"/> is valid but not a <see cref="QsTypeKind.Function"/> or <see cref="QsTypeKind.Operation"/> type.</exception>.
let CallNonGeneric (lhs: TypedExpression, rhs: TypedExpression) =
let kind = CallLikeExpression(lhs, rhs)
let quantumDep =
lhs.InferredInformation.HasLocalQuantumDependency
|| rhs.InferredInformation.HasLocalQuantumDependency
match lhs.ResolvedType.Resolution with
| QsTypeKind.InvalidType -> AutoGeneratedExpression kind InvalidType quantumDep
| QsTypeKind.Operation ((_, ot), _)
| QsTypeKind.Function (_, ot) -> AutoGeneratedExpression kind ot.Resolution quantumDep
| _ -> ArgumentException "given lhs is not callable" |> raise
/// <summary>
/// Given a typed expression of type range,
/// creates a typed expression that when executed will generate the reverse sequence for the given range.
/// Assumes that the RangeReverse function is part of the standard library.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is of a valid type but not of type <see cref="QsTypeKind.Range"/>.</exception>
let private ReverseRange (ex: TypedExpression) =
let buildCallToReverse ex =
let kind = Identifier.GlobalCallable BuiltIn.RangeReverse.FullName
let exTypeKind =
QsTypeKind.Function(QsTypeKind.Range |> ResolvedType.New, QsTypeKind.Range |> ResolvedType.New)
let reverse = AutoGeneratedExpression(QsExpressionKind.Identifier(kind, Null)) exTypeKind false
CallNonGeneric(reverse, ex)
match ex.ResolvedType.Resolution with
| QsTypeKind.InvalidType
| QsTypeKind.Range _ -> buildCallToReverse ex
| _ -> ArgumentException "given expression is not a range" |> raise
/// Builds a range expression for the given lhs and rhs of the range operator.
/// Does *not* verify the type of the given lhs or rhs.
let private RangeExpression (lhs: TypedExpression, rhs: TypedExpression) =
let kind = QsExpressionKind.RangeLiteral(lhs, rhs)
let quantumDep =
lhs.InferredInformation.HasLocalQuantumDependency
|| rhs.InferredInformation.HasLocalQuantumDependency
AutoGeneratedExpression kind QsTypeKind.Range quantumDep
/// <summary>
/// Creates a typed expression that corresponds to a call to the Length function.
/// The Length function needs to be part of the QsCore library, and its type parameter name needs to match the one here.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is not of type array or is of an invalid type.</exception>
let Length (ex: TypedExpression) =
let callableName = BuiltIn.Length.FullName
let kind = Identifier.GlobalCallable callableName
let typeParameterName =
match BuiltIn.Length.Kind with
| BuiltInKind.Function typeParams -> typeParams.[0]
| _ -> ArgumentException "Length is expected to be a function" |> raise
let typeParameter = QsTypeParameter.New(callableName, typeParameterName)
let genArrayType =
QsTypeKind.ArrayType(QsTypeKind.TypeParameter typeParameter |> ResolvedType.New) |> ResolvedType.New
let exTypeKind = QsTypeKind.Function(genArrayType, QsTypeKind.Int |> ResolvedType.New)
let length = AutoGeneratedExpression(QsExpressionKind.Identifier(kind, Null)) exTypeKind false
let callToLength tpRes =
let resolutions = ImmutableArray.Create((typeParameter.Origin, typeParameter.TypeName, tpRes))
{ CallNonGeneric(length, ex) with TypeArguments = resolutions }
match ex.ResolvedType.Resolution with
| ArrayType b -> callToLength b
| InvalidType -> callToLength ex.ResolvedType
| _ -> ArgumentException "the given expression is not of array type" |> raise
/// <summary>
/// Creates a typed expression that corresponds to subtracting one from the call to the Length function.
/// Sets any range information in the built expression to Null, including inner expressions.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is not of type array or is of an invalid type.</exception>
let LengthMinusOne (ex: TypedExpression) =
let callToLength = ex |> StripPositionInfo.Apply |> Length
let kind = QsExpressionKind.SUB(callToLength, IntLiteral 1L)
AutoGeneratedExpression kind QsTypeKind.Int callToLength.InferredInformation.HasLocalQuantumDependency
/// <summary>
/// Given a typed expression of array type,
/// creates a typed expression that when evaluated returns a new array with the order of the elements reversed.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is not of type array or is of an invalid type.</exception>
let private ReverseArray (ex: TypedExpression) =
let built =
let reversingRange = RangeExpression(RangeExpression(LengthMinusOne ex, IntLiteral -1L), IntLiteral 0L)
let kind = ArrayItem(ex, reversingRange)
AutoGeneratedExpression kind ex.ResolvedType.Resolution ex.InferredInformation.HasLocalQuantumDependency
match ex.ResolvedType.Resolution with
| ArrayType _
| InvalidType -> built
| _ -> ArgumentException "the given expression is not of array type" |> raise
/// <summary>
/// Given a typed expression of a type that supports iteration,
/// creates a typed expression that when evaluated returns the reversed sequence.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is of a valid type but not either of type <see cref="QsTypeKind.Range"/> or of array type.</exception>
let ReverseIterable (ex: TypedExpression) =
let ex = StripPositionInfo.Apply ex
match ex.ResolvedType.Resolution with
| QsTypeKind.Range -> ReverseRange ex
| QsTypeKind.ArrayType _ -> ReverseArray ex
| QsTypeKind.InvalidType -> ex
| _ -> ArgumentException "the given expression is not iterable" |> raise
/// <summary>
/// Returns a boolean expression that evaluates to true if the given expression is negative.
/// Returns an invalid expression of type Bool if the given expression is invalid.
/// </summary>
/// <exception cref="ArgumentException">The type of <paramref name="ex"/> does not support arithmetic.</exception>
let IsNegative (ex: TypedExpression) =
let kind =
match ex.ResolvedType.Resolution with
| Int -> LT(ex, IntLiteral 0L)
| BigInt -> LT(ex, BigIntLiteral 0)
| Double -> LT(ex, DoubleLiteral 0.)
| InvalidType -> InvalidExpr
| _ -> ArgumentException "the type of the given expression does not support arithmetic operations" |> raise
AutoGeneratedExpression kind Bool ex.InferredInformation.HasLocalQuantumDependency
/// Returns an expression that adds the two expression.
/// The type of the expression is set to the given type and the position information is set to null.
/// Does not validate type compatibility.
let AddExpressions exType (lhs: TypedExpression, rhs: TypedExpression) =
let kind = QsExpressionKind.ADD(lhs, rhs)
let quantumDep =
lhs.InferredInformation.HasLocalQuantumDependency
|| rhs.InferredInformation.HasLocalQuantumDependency
AutoGeneratedExpression kind exType quantumDep
// utils related to building and generating functor specializations
let QubitArrayType = Qubit |> ResolvedType.New |> ArrayType |> ResolvedType.New
/// Recursively extracts and returns all tuple items in the given tuple.
let ExtractInnerItems (this: ITuple) =
let rec extractAll =
function
| Tuple items -> items |> Seq.collect extractAll
| Item item -> seq { yield item }
| Missing -> ArgumentException "missing item in tuple" |> raise
| _ -> ArgumentException "invalid item in tuple" |> raise
this |> extractAll
/// Given a QsTuple, recursively extracts and returns all of its items.
let ExtractItems (this: QsTuple<_>) = this.Items.ToImmutableArray()
/// Given an immutable array with local variable declarations returns an immutable array containing only the declarations with a valid name.
let ValidDeclarations (this: ImmutableArray<LocalVariableDeclaration<QsLocalSymbol>>) =
let withValidName (d: LocalVariableDeclaration<_>) =
match d.VariableName with
| ValidName name ->
let mut, qDep = d.InferredInformation.IsMutable, d.InferredInformation.HasLocalQuantumDependency
Some(LocalVariableDeclaration.New mut ((d.Position, d.Range), name, d.Type, qDep))
| _ -> None
(this |> Seq.choose withValidName).ToImmutableArray()
/// Strips all range information from the given signature.
let WithoutRangeInfo (signature: ResolvedSignature) =
let argType = signature.ArgumentType |> StripPositionInfo.Apply
let returnType = signature.ReturnType |> StripPositionInfo.Apply
ResolvedSignature.New((argType, returnType), signature.Information, signature.TypeParameters)
/// Given the resolved argument type of an operation, returns the argument type of its controlled version.
let AddControlQubits (argT: ResolvedType) =
[ QubitArrayType; argT ].ToImmutableArray() |> TupleType |> ResolvedType.New
/// Given a resolved signature, returns the corresponding signature for the controlled version.
let BuildControlled (this: ResolvedSignature) =
{ this with ArgumentType = this.ArgumentType |> AddControlQubits }
/// <summary>
/// Given an argument tuple of a callable, the name and the range of the control qubits symbol, as well as the position offset for that range,
/// builds and returns the argument tuple for the controlled specialization.
/// </summary>
/// <exception cref="ArgumentException">The given argument tuple is not a <see cref="QsTuple"/>.</exception>
let WithControlQubits arg offset (name, symRange: QsNullable<_>) =
let range = symRange.ValueOr Range.Zero
let ctlQs = LocalVariableDeclaration.New false ((offset, range), name, QubitArrayType, false)
let unitArg =
let argName = ValidName InternalUse.UnitArgument
let unitT = UnitType |> ResolvedType.New
LocalVariableDeclaration.New false ((offset, range), argName, unitT, false) |> QsTupleItem // the range is not accurate here, but also irrelevant
match arg with
| QsTuple ts when ts.Length = 0 -> [ ctlQs |> QsTupleItem; unitArg ].ToImmutableArray()
| QsTuple ts when ts.Length = 1 -> [ ctlQs |> QsTupleItem; ts.[0] ].ToImmutableArray()
| QsTuple _ -> [ ctlQs |> QsTupleItem; arg ].ToImmutableArray()
| _ -> ArgumentException "expecting the given argument tuple to be a QsTuple" |> raise
|> QsTuple
/// <summary>
/// Given a typed expression that is used as argument to an operation and a typed expression for the control qubits,
/// combines them to a suitable argument for the controlled version of the originally called operation under the assumption that the argument was correct.
/// The range information for the built expression is set to Null.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ctlQs"/> is a valid type, but not an <see cref="ArrayType"/> <see cref="Qubit"/>.</exception>
let ArgumentWithControlQubits (arg: TypedExpression) (ctlQs: TypedExpression) =
let isInvalid =
function
| Tuple _
| Item _
| Missing -> false
| _ -> true
if ctlQs.ResolvedType.Resolution <> QubitArrayType.Resolution && not (ctlQs.ResolvedType |> isInvalid) then
new ArgumentException "expression for the control qubits is valid but not of type Qubit[]" |> raise
TupleLiteral [ ctlQs; arg ]
/// Returns the name of the control qubits
/// if the given argument tuple is consistent with the argument tuple of a controlled specialization.
/// Return null otherwise, or if the name of the control qubits is invalid.
let ControlledFunctorArgument arg =
let getItemName =
function
| QsTupleItem (item: LocalVariableDeclaration<QsLocalSymbol>) ->
match item.VariableName with
| ValidName name -> name
| InvalidName -> null
| _ -> null
match arg with
| QsTuple ts when ts.Length = 2 -> ts.[0] |> getItemName
| _ -> null
/// Creates a typed expression that corresponds to an immutable local variable with the given name
/// that contains an expression of type Qubit[] and has no quantum dependencies.
let ImmutableQubitArrayWithName name =
let kind = (Identifier.LocalVariable name, Null) |> QsExpressionKind.Identifier
let exTypeKind = QsTypeKind.ArrayType(QsTypeKind.Qubit |> ResolvedType.New)
AutoGeneratedExpression kind exTypeKind false
/// <summary>
/// Given a typed expression of operation type, creates a typed expression corresponding to a Controlled application on that operation.
/// Creates an expression of invalid type if the given expression is invalid.
/// Blindly builds the controlled application if the characteristics of the given operation are invalid.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is valid but not of type <see cref="QsTypeKind.Operation"/>, or does not support the <see cref="Controlled"/> functor.</exception>
let ControlledOperation (ex: TypedExpression) =
let ex = StripPositionInfo.Apply ex
let kind = QsExpressionKind.ControlledApplication ex
let built exTypeKind =
AutoGeneratedExpression kind exTypeKind ex.InferredInformation.HasLocalQuantumDependency
let ctlOpType ((it, ot), opInfo) =
QsTypeKind.Operation((AddControlQubits it, ot), opInfo)
match ex.ResolvedType.Resolution with
| QsTypeKind.InvalidType -> built InvalidType
| QsTypeKind.Operation ((it, ot), opInfo) when opInfo.Characteristics.AreInvalid ->
ctlOpType ((it, ot), opInfo) |> built
| QsTypeKind.Operation ((it, ot), opInfo) ->
match opInfo.Characteristics.SupportedFunctors with
| Value functors when functors.Contains Controlled -> ctlOpType ((it, ot), opInfo) |> built
| _ -> ArgumentException "given expression does not correspond to a suitable operation" |> raise
| _ -> ArgumentException "given expression does not correspond to a suitable operation" |> raise
/// <summary>
/// Given a typed expression of operation type, creates a typed expression corresponding to a Adjoint application on that operation.
/// Creates an expression of invalid type if the given expression is invalid.
/// Blindly builds the adjoint application if the characteristics of the given operation are invalid.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="ex"/> is valid but not of type <see cref="QsTypeKind.Operation"/>, or does not support the <see cref="Adjoint"/> functor.</exception>
let AdjointOperation (ex: TypedExpression) =
let ex = StripPositionInfo.Apply ex
let kind = QsExpressionKind.AdjointApplication(ex)
let built =
AutoGeneratedExpression kind ex.ResolvedType.Resolution ex.InferredInformation.HasLocalQuantumDependency
match ex.ResolvedType.Resolution with
| QsTypeKind.InvalidType -> built
| QsTypeKind.Operation (_, opInfo) when opInfo.Characteristics.AreInvalid -> built
| QsTypeKind.Operation (_, opInfo) ->
match opInfo.Characteristics.SupportedFunctors with
| Value functors when functors.Contains Adjoint -> built
| _ -> ArgumentException "given expression does not correspond to a suitable operation" |> raise
| _ -> ArgumentException "given expression does not correspond to a suitable operation" |> raise