Beispiel #1
0
        public void Execute(DfirRoot dfirRoot, CompileCancellationToken cancellationToken)
        {
            var lifetimeGraphTree = dfirRoot.GetLifetimeGraphTree();
            BoundedLifetimeLiveVariableSet boundedLifetimeLiveVariableSet;

            while (_lifetimeVariableAssociation.TryGetBoundedLifetimeWithLiveVariables(out boundedLifetimeLiveVariableSet))
            {
                if (lifetimeGraphTree.IsDiagramLifetimeOfAnyLifetimeGraph(boundedLifetimeLiveVariableSet.Lifetime))
                {
                    // Since we assume there are no semantic errors at this point, just mark any remaining live variables
                    // in a diagram lifetime as consumed.
                    boundedLifetimeLiveVariableSet.LiveVariables.Select(l => l.Variable).ForEach(_lifetimeVariableAssociation.MarkVariableConsumed);
                    continue;
                }

                int inputVariableCount = boundedLifetimeLiveVariableSet.LiveVariables.Count();
                IEnumerable <VariableReference> interruptedVariables = _lifetimeVariableAssociation.GetVariablesInterruptedByLifetime(boundedLifetimeLiveVariableSet.Lifetime);
                int outputVariableCount = interruptedVariables.Count();

                Diagram startSearch = boundedLifetimeLiveVariableSet.LiveVariables.First().Terminal.ParentDiagram;
                LifetimeGraphIdentifier originGraphIdentifier = lifetimeGraphTree.GetBoundedLifetimeGraphIdentifier(boundedLifetimeLiveVariableSet.Lifetime);
                Diagram originDiagram = originGraphIdentifier.FindDiagramForGraphIdentifier(startSearch);

                LiveVariable[] liveVariables = boundedLifetimeLiveVariableSet.LiveVariables.ToArray();
                for (int i = 0; i < liveVariables.Length; ++i)
                {
                    LiveVariable liveVariable = liveVariables[i];
                    while (liveVariable.Terminal.ParentDiagram != originDiagram)
                    {
                        liveVariable = PullLiveVariableUpToNextHigherDiagram(liveVariable);
                    }
                    liveVariables[i] = liveVariable;
                }

                TerminateLifetimeNode terminateLifetime = TerminateLifetimeNodeHelpers.CreateTerminateLifetimeWithFacades(originDiagram, inputVariableCount, outputVariableCount);
                int inputIndex = 0;
                foreach (LiveVariable liveVariable in liveVariables)
                {
                    // TODO: maybe assert that liveVariable.Terminal is unwired here?
                    Terminal terminateLifetimeInputTerminal = terminateLifetime.InputTerminals[inputIndex];
                    Wire.Create(originDiagram, liveVariable.Terminal, terminateLifetimeInputTerminal);
                    terminateLifetimeInputTerminal.GetFacadeVariable().MergeInto(liveVariable.Variable);
                    _lifetimeVariableAssociation.MarkVariableConsumed(liveVariable.Variable);

                    ++inputIndex;
                }
                int outputIndex = 0;
                foreach (VariableReference interruptedVariable in interruptedVariables)
                {
                    Terminal terminateLifetimeOutputTerminal = terminateLifetime.OutputTerminals[outputIndex];
                    terminateLifetimeOutputTerminal.GetFacadeVariable().MergeInto(interruptedVariable);
                    _lifetimeVariableAssociation.MarkVariableLive(interruptedVariable, terminateLifetimeOutputTerminal);

                    ++outputIndex;
                }
            }
        }
Beispiel #2
0
        internal static void InsertDropForVariable(Diagram parentDiagram, LiveVariable liveUnboundedLifetimeVariable, ITypeUnificationResultFactory unificationResultFactory)
        {
            var                  drop          = new DropNode(parentDiagram);
            Terminal             inputTerminal = drop.InputTerminals[0];
            AutoBorrowNodeFacade nodeFacade    = AutoBorrowNodeFacade.GetNodeFacade(drop);

            nodeFacade[inputTerminal] = new SimpleTerminalFacade(
                inputTerminal,
                parentDiagram.GetTypeVariableSet().CreateReferenceToNewTypeVariable());

            liveUnboundedLifetimeVariable.ConnectToTerminalAsInputAndUnifyVariables(inputTerminal, unificationResultFactory);
        }
Beispiel #3
0
        private LiveVariable PullLiveVariableUpToNextHigherDiagram(LiveVariable liveVariable)
        {
            Tunnel   outputTunnel   = liveVariable.Terminal.ParentDiagram.ParentStructure.CreateTunnel(Direction.Output, TunnelMode.LastValue, PFTypes.Void, PFTypes.Void);
            Terminal inputTerminal  = outputTunnel.InputTerminals[0],
                     outputTerminal = outputTunnel.OutputTerminals[0];

            CreateNodeFacadesTransform.CreateTunnelNodeFacade(outputTunnel);

            Wire.Create(liveVariable.Terminal.ParentDiagram, liveVariable.Terminal, inputTerminal);
            inputTerminal.GetFacadeVariable().MergeInto(liveVariable.Variable);
            _lifetimeVariableAssociation.MarkVariableConsumed(liveVariable.Variable);

            return(new LiveVariable(outputTerminal.GetFacadeVariable(), outputTerminal));
        }
        private LiveVariable PullLiveVariableUpToNextHigherDiagram(LiveVariable liveVariable)
        {
            Tunnel   outputTunnel   = liveVariable.Terminal.ParentDiagram.ParentStructure.CreateTunnel(Direction.Output, TunnelMode.LastValue, NITypes.Void, NITypes.Void);
            Terminal inputTerminal  = outputTunnel.InputTerminals[0],
                     outputTerminal = outputTunnel.OutputTerminals[0];

            CreateNodeFacadesTransform.CreateTunnelNodeFacade(outputTunnel);

            Wire.Create(liveVariable.Terminal.ParentDiagram, liveVariable.Terminal, inputTerminal);
            AutoBorrowNodeFacade.GetNodeFacade(outputTunnel)[inputTerminal].UnifyWithConnectedWireTypeAsNodeInput(
                liveVariable.Variable,
                new TerminalTypeUnificationResults());
            _lifetimeVariableAssociation.MarkVariableConsumed(liveVariable.Variable);

            return(new LiveVariable(outputTerminal.GetFacadeVariable(), outputTerminal));
        }
Beispiel #5
0
        internal static DecomposeStructNode InsertDecompositionForStructVariable(Diagram parentDiagram, LiveVariable liveStructVariable, ITypeUnificationResultFactory unificationResultFactory)
        {
            NIType variableType = liveStructVariable.Variable.Type;
            DecomposeStructNode decomposeStruct = TupleNodeHelpers.CreateDecomposeStructNodeWithFacades(
                parentDiagram,
                variableType);

            Terminal structInputTerminal = decomposeStruct.InputTerminals[0];

            liveStructVariable.ConnectToTerminalAsInputAndUnifyVariables(
                structInputTerminal,
                unificationResultFactory);
            return(decomposeStruct);
        }
Beispiel #6
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);
        }
Beispiel #7
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();
        }
Beispiel #8
0
        private void ConnectOutputTerminal(Terminal outputTerminal, Terminal newOutputTerminal)
        {
            AutoBorrowNodeFacade nodeToReplaceFacade   = AutoBorrowNodeFacade.GetNodeFacade(outputTerminal.ParentNode);
            AutoBorrowNodeFacade newTerminalNodeFacade = AutoBorrowNodeFacade.GetNodeFacade(newOutputTerminal.ParentNode);

            if (outputTerminal.IsConnected)
            {
                outputTerminal.ConnectedTerminal.ConnectTo(newOutputTerminal);
                newTerminalNodeFacade[newOutputTerminal] = nodeToReplaceFacade[outputTerminal];
            }
            else
            {
                InsertDropTransform.InsertDropForVariable(newOutputTerminal.ParentDiagram, LiveVariable.FromTerminal(newOutputTerminal), _unificationResultFactory);
            }
        }