public function visitTupleType(TupleType $type)
    {
        $this->typeCheck->visitTupleType(func_get_args());

        $tupleSize = count($type->types());
        $isArrayCall = new Call(QualifiedIdentifier::fromString('\is_array'));
        $isArrayCall->add($this->valueExpression());
        $arrayKeysCall = new Call(QualifiedIdentifier::fromString('\array_keys'));
        $arrayKeysCall->add($this->valueExpression());
        $rangeCall = new Call(QualifiedIdentifier::fromString('\range'));
        $rangeCall->add(new Literal(0));
        $rangeCall->add(new Literal($tupleSize - 1));
        $sequentialKeyExpression = new StrictEquals(
            $arrayKeysCall,
            $rangeCall
        );
        $expressions = array(
            $isArrayCall,
            $sequentialKeyExpression
        );

        $closures = array();
        $closureCalls = array();
        $checkVariable = new Variable(new Identifier('check'));
        foreach ($type->types() as $index => $subType) {
            $this->valueIndex = $index;

            $expression = $subType->accept($this);
            if ($expression instanceof Closure) {
                $closures[] = $expression;
                $checkCall = new Call($checkVariable);
                $checkCall->add($this->valueExpression());
                $closureCalls[] = $checkCall;
            } else {
                $expressions[] = $expression;
            }
        }
        $this->valueIndex = null;

        $tupleExpression = null;
        foreach ($expressions as $expression) {
            if ($tupleExpression) {
                $tupleExpression->add($expression);
            } else {
                $tupleExpression = new LogicalAnd($expression);
            }
        }

        $numClosures = count($closures);
        if ($numClosures < 1) {
            return $tupleExpression;
        }

        $closure = new Closure;
        $closure->addParameter(new Parameter($this->valueIdentifier));

        $ifStatement = new IfStatement(new LogicalNot($tupleExpression));
        $ifStatement->trueBranch()->add(
            new ReturnStatement(new Literal(false))
        );
        $closure->statementBlock()->add($ifStatement);

        $lastClosureIndex = $numClosures - 1;
        for ($i = 0; $i < $lastClosureIndex; $i ++) {
            $closure->statementBlock()->add(new ExpressionStatement(new Assign(
                $checkVariable,
                $closures[$i]
            )));
            $ifStatement = new IfStatement(new LogicalNot($closureCalls[$i]));
            $ifStatement->trueBranch()->add(
                new ReturnStatement(new Literal(false))
            );
            $closure->statementBlock()->add($ifStatement);
        }

        $closure->statementBlock()->add(new ExpressionStatement(new Assign(
            $checkVariable,
            $closures[$lastClosureIndex]
        )));
        $closure->statementBlock()->add(new ReturnStatement($closureCalls[$lastClosureIndex]));

        return $closure;
    }
public function visitTupleType(TupleType $type)
    {
        $this->typeCheck->visitTupleType(func_get_args());

        $tupleSize = count($type->types());
        $isArrayCall = new Call(QualifiedIdentifier::fromString('\is_array'));
        $isArrayCall->add($this->valueExpression());
        $arrayKeysCall = new Call(QualifiedIdentifier::fromString('\array_keys'));
        $arrayKeysCall->add($this->valueExpression());
        $rangeCall = new Call(QualifiedIdentifier::fromString('\range'));
        $rangeCall->add(new Literal(0));
        $rangeCall->add(new Literal($tupleSize - 1));
        $sequentialKeyExpression = new StrictEquals(
            $arrayKeysCall,
            $rangeCall
        );
        $expressions = array(
            $isArrayCall,
            $sequentialKeyExpression
        );

        $closures = array();
        $closureCalls = array();
        $checkVariable = new Variable(new Identifier('check'));
        foreach ($type->types() as $index => $subType) {
            $this->valueIndex = $index;

            $expression = $subType->accept($this);
            if ($expression instanceof Closure) {
                $closures[] = $expression;
                $checkCall = new Call($checkVariable);
                $checkCall->add($this->valueExpression());
                $closureCalls[] = $checkCall;
            } else {
                $expressions[] = $expression;
            }
        }
        $this->valueIndex = null;

        $tupleExpression = null;
        foreach ($expressions as $expression) {
            if ($tupleExpression) {
                $tupleExpression->add($expression);
            } else {
                $tupleExpression = new LogicalAnd($expression);
            }
        }

        $numClosures = count($closures);
        if ($numClosures < 1) {
            return $tupleExpression;
        }

        $closure = new Closure;
        $closure->addParameter(new Parameter($this->valueIdentifier));

        $ifStatement = new IfStatement(new LogicalNot($tupleExpression));
        $ifStatement->trueBranch()->add(
            new ReturnStatement(new Literal(false))
        );
        $closure->statementBlock()->add($ifStatement);

        $lastClosureIndex = $numClosures - 1;
        for ($i = 0; $i < $lastClosureIndex; $i ++) {
            $closure->statementBlock()->add(new ExpressionStatement(new Assign(
                $checkVariable,
                $closures[$i]
            )));
            $ifStatement = new IfStatement(new LogicalNot($closureCalls[$i]));
            $ifStatement->trueBranch()->add(
                new ReturnStatement(new Literal(false))
            );
            $closure->statementBlock()->add($ifStatement);
        }

        $closure->statementBlock()->add(new ExpressionStatement(new Assign(
            $checkVariable,
            $closures[$lastClosureIndex]
        )));
        $closure->statementBlock()->add(new ReturnStatement($closureCalls[$lastClosureIndex]));

        return $closure;
    }
@param TupleType $type

@return LogicalAnd|Closure