// Takes a single TypedExpression of type Result and puts in into a
 // value array expression with the given expression as its only item.
 static TypedExpression BoxResultInArray(TypedExpression expression) =>
 new TypedExpression(
     ExpressionKind.NewValueArray(ImmutableArray.Create(expression)),
     TypeArgsResolution.Empty,
     ResolvedType.New(ResolvedTypeKind.NewArrayType(ResolvedType.New(ResolvedTypeKind.Result))),
     new InferredExpressionInformation(false, expression.InferredInformation.HasLocalQuantumDependency),
     QsNullable <Range> .Null);
        /// <summary>
        /// Creates an array literal with the given items, setting the range information to Null.
        /// If no items are given, creates an empty array of type Unit[].
        /// The resolved types for all of the given expressions must match,
        /// none of the given expressions should have a local quantum dependency,
        /// and all range information should be stripped from each given expression.
        /// </summary>
        internal static TypedExpression CreateValueArray(params TypedExpression[] expressions)
        {
            ResolvedType type = null;

            if (expressions.Any())
            {
                type = expressions.First().ResolvedType;
                QsCompilerError.Verify(expressions.All(expr => expr.ResolvedType.Equals(type)));
            }
            else
            {
                type = ResolvedType.New(ResolvedTypeKind.UnitType);
            }

            return(new TypedExpression
                   (
                       ExpressionKind.NewValueArray(expressions.ToImmutableArray()),
                       TypeArgsResolution.Empty,
                       ResolvedType.New(ResolvedTypeKind.NewArrayType(type)),
                       new InferredExpressionInformation(false, false),
                       QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null
                   ));
        }
                /// <summary>
                /// Creates an operation call from the conditional control API for non-literal Result comparisons.
                /// The equalityScope and inequalityScope cannot both be null.
                /// </summary>
                private TypedExpression CreateApplyConditionallyExpression(TypedExpression conditionExpr1, TypedExpression conditionExpr2, QsScope equalityScope, QsScope inequalityScope)
                {
                    QsCompilerError.Verify(equalityScope != null || inequalityScope != null, $"Cannot have null for both equality and inequality scopes when creating ApplyConditionally expressions.");

                    var(isEqualityValid, equalityId, equalityArgs)       = this.IsValidScope(equalityScope);
                    var(isInequaltiyValid, inequalityId, inequalityArgs) = this.IsValidScope(inequalityScope);

                    if (!isEqualityValid && equalityScope != null)
                    {
                        return(null); // ToDo: Diagnostic message - equality block exists, but is not valid
                    }

                    if (!isInequaltiyValid && inequalityScope != null)
                    {
                        return(null); // ToDo: Diagnostic message - inequality block exists, but is not valid
                    }

                    if (equalityScope == null)
                    {
                        (equalityId, equalityArgs) = this.GetNoOp();
                    }
                    else if (inequalityScope == null)
                    {
                        (inequalityId, inequalityArgs) = this.GetNoOp();
                    }

                    // Get characteristic properties from global id
                    var props = ImmutableHashSet <OpProperty> .Empty;

                    if (equalityId.ResolvedType.Resolution is ResolvedTypeKind.Operation op)
                    {
                        props = op.Item2.Characteristics.GetProperties();
                        if (inequalityId != null && inequalityId.ResolvedType.Resolution is ResolvedTypeKind.Operation defaultOp)
                        {
                            props = props.Intersect(defaultOp.Item2.Characteristics.GetProperties());
                        }
                    }

                    BuiltIn controlOpInfo;

                    (bool adj, bool ctl) = (props.Contains(OpProperty.Adjointable), props.Contains(OpProperty.Controllable));
                    if (adj && ctl)
                    {
                        controlOpInfo = BuiltIn.ApplyConditionallyCA;
                    }
                    else if (adj)
                    {
                        controlOpInfo = BuiltIn.ApplyConditionallyA;
                    }
                    else if (ctl)
                    {
                        controlOpInfo = BuiltIn.ApplyConditionallyC;
                    }
                    else
                    {
                        controlOpInfo = BuiltIn.ApplyConditionally;
                    }

                    // Takes a single TypedExpression of type Result and puts in into a
                    // value array expression with the given expression as its only item.
                    TypedExpression BoxResultInArray(TypedExpression expression) =>
                    new TypedExpression(
                        ExpressionKind.NewValueArray(ImmutableArray.Create(expression)),
                        TypeArgsResolution.Empty,
                        ResolvedType.New(ResolvedTypeKind.NewArrayType(ResolvedType.New(ResolvedTypeKind.Result))),
                        new InferredExpressionInformation(false, expression.InferredInformation.HasLocalQuantumDependency),
                        QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);

                    var equality    = this.CreateValueTupleExpression(equalityId, equalityArgs);
                    var inequality  = this.CreateValueTupleExpression(inequalityId, inequalityArgs);
                    var controlArgs = this.CreateValueTupleExpression(
                        BoxResultInArray(conditionExpr1),
                        BoxResultInArray(conditionExpr2),
                        equality,
                        inequality);
                    var targetArgsTypes = ImmutableArray.Create(equalityArgs.ResolvedType, inequalityArgs.ResolvedType);

                    return(this.CreateControlCall(controlOpInfo, props, controlArgs, targetArgsTypes));
                }