예제 #1
0
        public static DecomposeTupleNode CreateDecomposeTupleNodeWithFacades(Diagram parentDiagram, int elementCount, DecomposeMode decomposeMode)
        {
            var decomposeTupleNode = new DecomposeTupleNode(parentDiagram, elementCount, decomposeMode);

            decomposeTupleNode.CreateFacadesForDecomposeTupleNode(parentDiagram.GetTypeVariableSet());
            return(decomposeTupleNode);
        }
예제 #2
0
        public void DecomposeTupleNodeWithUnwiredInput_ValidateVariableUsages_ErrorOnUnwiredInput()
        {
            DfirRoot function       = DfirRoot.Create();
            var      decomposeTuple = new DecomposeTupleNode(function.BlockDiagram, 2, DecomposeMode.Borrow);

            RunSemanticAnalysisUpToValidation(function);

            AssertTerminalHasRequiredTerminalUnconnectedMessage(decomposeTuple.InputTerminals[0]);
        }
예제 #3
0
        internal static DecomposeTupleNode InsertDecompositionForTupleVariable(Diagram parentDiagram, LiveVariable liveTupleVariable, ITypeUnificationResultFactory unificationResultFactory)
        {
            NIType             variableType   = liveTupleVariable.Variable.Type;
            DecomposeTupleNode decomposeTuple = TupleNodeHelpers.CreateDecomposeTupleNodeWithFacades(
                parentDiagram,
                variableType.GetFields().Count(),
                DecomposeMode.Move);

            Terminal tupleInputTerminal = decomposeTuple.InputTerminals[0];

            liveTupleVariable.ConnectToTerminalAsInputAndUnifyVariables(
                tupleInputTerminal,
                unificationResultFactory);
            return(decomposeTuple);
        }
        bool IDfirNodeVisitor <bool> .VisitDecomposeTupleNode(DecomposeTupleNode decomposeTupleNode)
        {
            Terminal inputTerminal = decomposeTupleNode.InputTerminals[0];

            if (decomposeTupleNode.DecomposeMode == DecomposeMode.Borrow)
            {
                MarkFacadeVariableOfTerminalInterrupted(inputTerminal);
            }
            MarkTrueVariableOfTerminalConsumed(inputTerminal);
            foreach (Terminal outputTerminal in decomposeTupleNode.OutputTerminals)
            {
                MarkFacadeVariableOfTerminalLive(outputTerminal);
            }
            return(true);
        }
예제 #5
0
        bool IDfirNodeVisitor <bool> .VisitDecomposeTupleNode(DecomposeTupleNode decomposeTupleNode)
        {
            TypeVariableReference[]             elementTypes       = new TypeVariableReference[decomposeTupleNode.OutputTerminals.Count];
            TypeVariableReference               mutabilityType     = default(TypeVariableReference);
            ReferenceInputTerminalLifetimeGroup inputTerminalGroup = null;

            if (decomposeTupleNode.DecomposeMode == DecomposeMode.Borrow)
            {
                mutabilityType = _typeVariableSet.CreateReferenceToMutabilityType();
                var lifetimeVariableGroup = LifetimeTypeVariableGroup.CreateFromNode(decomposeTupleNode);
                inputTerminalGroup = _nodeFacade.CreateInputLifetimeGroup(
                    InputReferenceMutability.Polymorphic,
                    lifetimeVariableGroup.LazyNewLifetime,
                    lifetimeVariableGroup.LifetimeType);
            }

            for (int i = 0; i < decomposeTupleNode.OutputTerminals.Count; ++i)
            {
                Terminal outputTerminal                  = decomposeTupleNode.OutputTerminals[i];
                TypeVariableReference elementType        = _typeVariableSet.CreateReferenceToNewTypeVariable();
                TypeVariableReference outputTerminalType = decomposeTupleNode.DecomposeMode == DecomposeMode.Borrow
                    ? _typeVariableSet.CreateReferenceToPolymorphicReferenceType(
                    mutabilityType,
                    elementType,
                    inputTerminalGroup.LifetimeType)
                    : elementType;
                _nodeFacade[outputTerminal] = new SimpleTerminalFacade(outputTerminal, outputTerminalType);
                elementTypes[i]             = elementType;
            }

            TypeVariableReference tupleType = _typeVariableSet.CreateReferenceToTupleType(elementTypes);
            Terminal inputTerminal          = decomposeTupleNode.InputTerminals[0];

            if (decomposeTupleNode.DecomposeMode == DecomposeMode.Borrow)
            {
                inputTerminalGroup.AddTerminalFacade(
                    inputTerminal,
                    tupleType,
                    mutabilityType);
            }
            else
            {
                _nodeFacade[inputTerminal] = new SimpleTerminalFacade(inputTerminal, tupleType);
            }
            return(true);
        }
예제 #6
0
        public void DecomposeTupleElementRefsNode_SetVariableTypes_OutputsAreElementRefTypes()
        {
            DfirRoot       function   = DfirRoot.Create();
            BuildTupleNode buildTuple = new BuildTupleNode(function.BlockDiagram, 2);

            ConnectConstantToInputTerminal(buildTuple.InputTerminals[0], NITypes.Int32, false);
            ConnectConstantToInputTerminal(buildTuple.InputTerminals[1], NITypes.Boolean, false);
            var decomposeTuple = new DecomposeTupleNode(function.BlockDiagram, 2, DecomposeMode.Borrow);

            Wire.Create(function.BlockDiagram, buildTuple.OutputTerminals[0], decomposeTuple.InputTerminals[0]);

            RunSemanticAnalysisUpToSetVariableTypes(function);

            VariableReference decomposeOutputVariable0 = decomposeTuple.OutputTerminals[0].GetTrueVariable(),
                              decomposeOutputVariable1 = decomposeTuple.OutputTerminals[1].GetTrueVariable();

            Assert.IsTrue(decomposeOutputVariable0.Type.GetReferentType().IsInt32());
            Assert.IsTrue(decomposeOutputVariable1.Type.GetReferentType().IsBoolean());
        }
예제 #7
0
        public void BuildTupleAndDecomposeTupleAsMove_Execute_CorrectElementValues()
        {
            DfirRoot       function   = DfirRoot.Create();
            BuildTupleNode buildTuple = new BuildTupleNode(function.BlockDiagram, 2);

            ConnectConstantToInputTerminal(buildTuple.InputTerminals[0], NITypes.Int32, 1, false);
            ConnectConstantToInputTerminal(buildTuple.InputTerminals[1], NITypes.Boolean, true, false);
            var decomposeTuple = new DecomposeTupleNode(function.BlockDiagram, 2, DecomposeMode.Move);

            Wire.Create(function.BlockDiagram, buildTuple.OutputTerminals[0], decomposeTuple.InputTerminals[0]);
            FunctionalNode inspect0 = ConnectInspectToOutputTerminal(decomposeTuple.OutputTerminals[0]),
                           inspect1 = ConnectInspectToOutputTerminal(decomposeTuple.OutputTerminals[1]);

            TestExecutionInstance executionInstance = CompileAndExecuteFunction(function);

            byte[] inspectValue = executionInstance.GetLastValueFromInspectNode(inspect0);
            AssertByteArrayIsInt32(inspectValue, 1);
            inspectValue = executionInstance.GetLastValueFromInspectNode(inspect1);
            AssertByteArrayIsBoolean(inspectValue, true);
        }
예제 #8
0
        public void UnconsumedTupleVariable_AutomaticNodeInsertion_TupleIsMoveDecomposedAndElementsAreDropped()
        {
            DfirRoot       function   = DfirRoot.Create();
            BuildTupleNode buildTuple = new BuildTupleNode(function.BlockDiagram, 2);

            ConnectConstantToInputTerminal(buildTuple.InputTerminals[0], NITypes.Int32, false);
            ConnectConstantToInputTerminal(buildTuple.InputTerminals[1], NITypes.Boolean, false);

            RunCompilationUpToAutomaticNodeInsertion(function);

            DecomposeTupleNode decomposeTuple = AssertDiagramContainsNodeWithSources <DecomposeTupleNode>(function.BlockDiagram, buildTuple.OutputTerminals[0]);

            Assert.AreEqual(DecomposeMode.Move, decomposeTuple.DecomposeMode);
            AssertVariablesReferenceSame(buildTuple.OutputTerminals[0].GetTrueVariable(), decomposeTuple.InputTerminals[0].GetTrueVariable());
            Assert.AreEqual(2, decomposeTuple.OutputTerminals.Count);
            DropNode drop0 = AssertDiagramContainsNodeWithSources <DropNode>(function.BlockDiagram, decomposeTuple.OutputTerminals[0]);

            AssertDropInputVariableHasType(drop0, NITypes.Int32);
            DropNode drop1 = AssertDiagramContainsNodeWithSources <DropNode>(function.BlockDiagram, decomposeTuple.OutputTerminals[1]);

            AssertDropInputVariableHasType(drop1, NITypes.Boolean);
        }
예제 #9
0
        private static void CreateFacadesForDecomposeTupleNode(this DecomposeTupleNode decomposeTupleNode, TypeVariableSet typeVariableSet)
        {
            if (decomposeTupleNode.DecomposeMode == DecomposeMode.Borrow)
            {
                throw new NotSupportedException();
            }
            TypeVariableReference[] elementTypes = new TypeVariableReference[decomposeTupleNode.OutputTerminals.Count];
            AutoBorrowNodeFacade    nodeFacade   = AutoBorrowNodeFacade.GetNodeFacade(decomposeTupleNode);

            for (int i = 0; i < decomposeTupleNode.OutputTerminals.Count; ++i)
            {
                Terminal outputTerminal           = decomposeTupleNode.OutputTerminals[i];
                TypeVariableReference elementType = typeVariableSet.CreateReferenceToNewTypeVariable();
                nodeFacade[outputTerminal] = new SimpleTerminalFacade(outputTerminal, elementType);
                elementTypes[i]            = elementType;
            }

            TypeVariableReference tupleType = typeVariableSet.CreateReferenceToTupleType(elementTypes);
            Terminal inputTerminal          = decomposeTupleNode.InputTerminals[0];

            nodeFacade[inputTerminal] = new SimpleTerminalFacade(inputTerminal, tupleType);
        }
예제 #10
0
        public void Execute(DfirRoot dfirRoot, CompileCancellationToken cancellationToken)
        {
            LiveVariable liveUnboundedLifetimeVariable;

            while (_lifetimeVariableAssociation.TryGetLiveVariableWithUnboundedLifetime(out liveUnboundedLifetimeVariable))
            {
                Diagram parentDiagram = liveUnboundedLifetimeVariable.Terminal.ParentDiagram;
                NIType  variableType  = liveUnboundedLifetimeVariable.Variable.Type;
                if (variableType.IsCluster())
                {
                    DecomposeTupleNode decomposeTuple = InsertDecompositionForTupleVariable(
                        parentDiagram,
                        liveUnboundedLifetimeVariable,
                        _unificationResultFactory);
                    foreach (Terminal outputTerminal in decomposeTuple.OutputTerminals)
                    {
                        _lifetimeVariableAssociation.MarkVariableLive(outputTerminal.GetFacadeVariable(), outputTerminal);
                    }
                    _lifetimeVariableAssociation.MarkVariableConsumed(liveUnboundedLifetimeVariable.Variable);
                    continue;
                }
                if (variableType.IsValueClass() && variableType.GetFields().Any())
                {
                    DecomposeStructNode decomposeStruct = InsertDecompositionForStructVariable(
                        parentDiagram,
                        liveUnboundedLifetimeVariable,
                        _unificationResultFactory);
                    foreach (Terminal outputTerminal in decomposeStruct.OutputTerminals)
                    {
                        _lifetimeVariableAssociation.MarkVariableLive(outputTerminal.GetFacadeVariable(), outputTerminal);
                    }
                    _lifetimeVariableAssociation.MarkVariableConsumed(liveUnboundedLifetimeVariable.Variable);
                    continue;
                }
                InsertDropForVariable(parentDiagram, liveUnboundedLifetimeVariable, _unificationResultFactory);
                _lifetimeVariableAssociation.MarkVariableConsumed(liveUnboundedLifetimeVariable.Variable);
            }
        }
 bool IDfirNodeVisitor <bool> .VisitDecomposeTupleNode(DecomposeTupleNode decomposeTupleNode)
 {
     ValidateRequiredInputTerminal(decomposeTupleNode.InputTerminals[0]);
     return(true);
 }
예제 #12
0
        private void DecomposeMethodCall(MethodCallNode methodCallNode, bool isYielding, bool mayPanic)
        {
            NIType outputType;
            // TODO: try to use something like Unit or Void
            NIType emptyOutputType = NITypes.Boolean;

            switch (methodCallNode.OutputTerminals.Count)
            {
            case 0:
                outputType = emptyOutputType;
                break;

            case 1:
                outputType = methodCallNode.OutputTerminals[0].GetTrueVariable().Type;
                break;

            default:
                outputType = methodCallNode.OutputTerminals.Select(t => t.GetTrueVariable().Type).DefineTupleType();
                break;
            }

            AutoBorrowNodeFacade methodCallNodeFacade = AutoBorrowNodeFacade.GetNodeFacade(methodCallNode);
            AwaitNode            awaitNode            = null;

            if (isYielding)
            {
                CreateMethodCallPromise createMethodCallPromise       = new CreateMethodCallPromise(methodCallNode.ParentDiagram, methodCallNode.Signature, methodCallNode.TargetName);
                AutoBorrowNodeFacade    createMethodCallPromiseFacade = AutoBorrowNodeFacade.GetNodeFacade(createMethodCallPromise);
                foreach (var terminalPair in methodCallNode.InputTerminals.Zip(createMethodCallPromise.InputTerminals))
                {
                    Terminal methodCallTerminal = terminalPair.Key, createMethodCallPromiseTerminal = terminalPair.Value;
                    methodCallTerminal.ConnectedTerminal.ConnectTo(createMethodCallPromiseTerminal);
                    createMethodCallPromiseFacade[createMethodCallPromiseTerminal] = methodCallNodeFacade[methodCallTerminal];
                }

                Terminal methodCallOutputTerminal = methodCallNode.OutputTerminals.FirstOrDefault();
                NIType   awaitOutputType          = mayPanic ? outputType.CreatePanicResult() : outputType;
                NIType   promiseType     = awaitOutputType.CreateMethodCallPromise();
                Terminal promiseTerminal = createMethodCallPromise.OutputTerminals[0];
                createMethodCallPromiseFacade[promiseTerminal] = new SimpleTerminalFacade(
                    promiseTerminal,
                    createMethodCallPromise.GetTypeVariableSet().CreateTypeVariableReferenceFromNIType(promiseType));

                awaitNode = ConnectNewNodeToOutputTerminalWithOutputFacade(createMethodCallPromise, diagram => new AwaitNode(diagram), awaitOutputType);
                VariableSet           variableSet            = awaitNode.GetVariableSet();
                TypeVariableReference outputTypeVariable     = awaitNode.OutputTerminal.GetTrueVariable().TypeVariableReference;
                TypeVariableReference pollResultTypeVariable = variableSet.TypeVariableSet.CreateReferenceToOptionType(outputTypeVariable);
                awaitNode.PollResultVariable = variableSet.CreateNewVariable(
                    diagramId: 0,
                    variableType: pollResultTypeVariable,
                    mutable: false);
            }

            Node outputNode = awaitNode;

            if (mayPanic)
            {
                Node panicOrContinueInput = awaitNode;
                if (!isYielding)
                {
                    // Create PanickingMethodCall as input to PanicOrContinue
                    throw new NotImplementedException("Calling non-yielding panicking methods not supported yet.");
                }
                outputNode = ConnectNewNodeToOutputTerminalWithOutputFacade(
                    panicOrContinueInput,
                    diagram => new PanicOrContinueNode(diagram),
                    outputType);
            }

            Terminal outputNodeTerminal = outputNode.OutputTerminals[0];

            switch (methodCallNode.OutputTerminals.Count)
            {
            case 0:
                // no method call output terminals; drop the result of the await
                InsertDropTransform.InsertDropForVariable(outputNode.ParentDiagram, LiveVariable.FromTerminal(outputNodeTerminal), _unificationResultFactory);
                break;

            case 1:
                ConnectOutputTerminal(methodCallNode.OutputTerminals[0], outputNodeTerminal);
                break;

            default:
            {
                // for >1 method call output terminals, decompose the tuple result of the await and match each
                // decomposed terminal to a method call terminal
                DecomposeTupleNode decomposeTupleNode = InsertDropTransform.InsertDecompositionForTupleVariable(
                    methodCallNode.ParentDiagram,
                    LiveVariable.FromTerminal(outputNodeTerminal),
                    _unificationResultFactory);
                foreach (var pair in methodCallNode.OutputTerminals.Zip(decomposeTupleNode.OutputTerminals))
                {
                    Terminal methodCallTerminal = pair.Key, decomposeTupleTerminal = pair.Value;
                    ConnectOutputTerminal(methodCallTerminal, decomposeTupleTerminal);
                }
                break;
            }
            }

            methodCallNode.RemoveFromGraph();
        }
 bool IDfirNodeVisitor <bool> .VisitDecomposeTupleNode(DecomposeTupleNode decomposeTupleNode)
 {
     decomposeTupleNode.UnifyNodeInputTerminalTypes(_typeUnificationResults);
     return(true);
 }