microsoft / qsharp-runtime

Runtime components for Q#
https://docs.microsoft.com/quantum
MIT License
285 stars 93 forks source link

Code gen failure when returning the value of a generic function #48

Open vadym-kl opened 5 years ago

vadym-kl commented 5 years ago

Describe the bug

Run-time failure related to use of type parameters and partial application

To Reproduce

Create project with Bug.qs with content below and run PrintAllPaulis() operation.

namespace Buggy {
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;

    operation PrintPaulies( paulis : Pauli[] ) : Unit { Message($"{paulis}"); }

    operation ApplyComposed<'U,'V>( op : ('U => Unit), fn : ('V -> 'U), arg : 'V) : Unit {
        op(fn(arg));
    }

    function ArrayFromIndicies<'T>( values : 'T[], indicies : Int[] ) : 'T[] {
        mutable arr = new 'T[Length(indicies)];
        for( i in 0 .. Length(indicies) - 1) {
            set arr w/= i <- values[indicies[i]];
        }
        return arr;
    }

    operation IterateThroughCartesianPowerT<'T> (power : Int, values : 'T[], op : ('T[] => Unit)) : Unit {
        let opInt = ApplyComposed(op, ArrayFromIndicies(values,_),_);
        IterateThroughCartesianPower(power, Length(values), opInt);
    }

    operation PrintAllPaulis() : Unit {
        IterateThroughCartesianPowerT(3, [PauliI,PauliX,PauliY,PauliZ], PrintPaulies);
    }
}

Expected behavior

64 lines of all possible combinations of 3 Pauli operators printed to console.

Actual behavior

Run-time failure with the following data:

  Message: 
    System.MissingMethodException : Constructor on type 'Microsoft.Quantum.Simulation.Core.IQArray`1[[System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' not found.
  Stack Trace: 
    at RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
    at PartialMapper.CastTuple(Type targetType, Object value)
    at PartialMapper.CastTuple(Type targetType, Object value)
    at <>c__DisplayClass9_0`2.<Create>b__0(P argTuple)
    at FunctionPartial`3.<get_Body>b__16_0(P a)
    at Function`2.Apply[GenO](Object args)
    at GenericCallable.Apply[O](Object args)
    at <>c.<get_Body>b__7_0(ValueTuple`3 __in__) in Bug.qs line: 8
    at OperationPartial`3.<get_Body>b__20_0(P a)
    at Operation`2.Apply(I a)
    at Operation`2.Apply[GenO](Object args)
    at GenericCallable.Apply[O](Object args)
    at <>c.<get_Body>b__11_0(ValueTuple`2 __in__)
    at Operation`2.Apply(I a)
    at ICallable<I,O>.Apply(I args)
    at IterateThroughCartesianPower.<get_Body>b__15_0(ValueTuple`3 __in__)
    at Operation`2.Apply(I a)
    at ICallable<I,O>.Apply(I args)
    at IterateThroughCartesianPowerT`1.<get_Body>b__23_0(ValueTuple`3 __in__) in Bug.qs line: 21

System information

anpaz commented 5 years ago

From the strack-trace, looks like:

ArrayFromIndicies is not figuring out that 'T is of type Pauli (which is strange, since 'T is in the values argument) so it defaults to object --> that causes that the resolved type for the array is object[], but looks like QArray doesn't support objects so it fails.

This seems related to #47, however, for this one I would start on GenericaCallable.FindCallable to figure out why the Type parameter 'T from ArrayFromIndicies is not correctly identified.

bettinaheim commented 5 years ago

I did a quick investigation and the problem is that IsValidValue(Type targetType, object partialValues) will fail for the target type being an IQArray of objects and the partialValues being a concrete array of something (Paulis in this case). This is unfortunately how ArrayFromIndicies(values,_) currently get's translated. To fix this we would need to construct the mapper at runtime in this case, i.e. whether or not to build the partial mapper on code gen has to be determined based on whether the original callable had type parameters (not the partially applied one), but then PartialApplicationTypes needs to be adapted I think.