Знакомо, узнали? Каждый раз когда вы пытались объявить опциональное замыкание @escaping в Swift компилятор ругался и писал непонятную ошибку @escaping attribute only applies to function types. Мне это не нравилось, и я решил это исправить. Теперь компилятор Swift 5.3 вместо этой ошибки напишет Closure is already escaping in optional type argument.  И сегодня мы разберемся, как сделать свой вклад в развитие языка Swift. Swift — огромный opensource-проект, и самый лучший способ с одной стороны разобраться в любимом инструменте, а с другой принести пользу и его улучшить — исправить один из многочисленных багов. К тому же вы получите опыт работы в огромном проекте и бейджик "contributed to Apple". Для сборки Swift понадобится компьютер под управлением macOS, Linux или Windows, а также 15-70 GB свободного места в зависимости от способа сборки Swift (об этом будет чуть дальше). Для внесения правок понадобятся знания Swift и представление о С++, однако это не обязательно, некоторые задачи требуют добавления тест-кейсов, где не нужны знания языка. Все очень просто и укладывается в 9 шагов: Рассмотрим некоторые пункты в деталях. Если вы уже работали с JIRA — то ничего сложного в поиске бага нет, открываете вкладку Issues и выбираете наиболее интересное среди бесконечного числа багов и тасков.  Также есть фильтр для Starter Bug-ов — специальных задач для тех, кто только начинает свой путь в разработке Swift. Этот фильтр помог мне найти задачу на исправление диагностики, которую я впоследствии сделал. Официальный Readme хорошо описывает процесс скачивания и сборки. Ниже пересказ, как это делать на macOS, но на Linux и Windows собрать Swift тоже можно. Устанавливаем зависимости или Создаем папку под проект и клонируем Также можно добавить environment variable для быстрой навигации. Есть несколько способов собрать Swift — для работы с ninja или для работы с Xcode. Сборка для Xcode медленнее, но можно будет ставить брейкпоинты и пользоваться привычным iOS разработчикам IDE.  Ninja — это легковесная C++ билд-система, которая работает быстрее чем Xcode и дает возможность делать быстрые инкрементальные билды, но нужно будет работать не в самом лучшем на свете IDE — Xcode. Разработчики Swift используют в основном ninja.  Все сборки делаются при помощи build-script — утилиты, которая умеет собирать LLDB для Swift, SPM, гонять тесты и т.д. Первым делом надо перейти в директорию для сборки: Сборка при помощи ninja: Чтобы собрать какие-то части для дебага можно добавить флагов, например: Но если вам очень хочется пожарить яичницу на макбуке или испытать на прочность Mac Pro, можно собрать весь Swift в дебаге: Предупреждение: это будет очень долго, лучше ставить эту сборку на ночь + это съест много места (~70 GB) После сборки можно добавить ещё одну environment переменную: После того как собрали весь проект, можно делать быстрые инкрементальные сборки при помощи ninja: То есть делаем какие-то фиксы, а потом быстро ребилдим при помощи команды ninja swift. Сборка при помощи Xcode Просто добавьте --xcode флажок к командам выше. Также после сборки можно добавить environment переменную: Вам соберется .xcodeproj файл, который можно просто открыть На старте он предложит вам создать схемы автоматически, соглашайтесь и ждите пока Xcode висит создает схемы.  После можно выбрать схему swift и спокойно нажимать Run. После этого запустится Swift, и можно будет пользоваться им через консоль Xcode. Xcode поддерживает брейкпоинты, это может пригодиться для дебага. То есть запускаем схему swift, ставим брейкпоинт в интересующей нас части кода и через консоль пытаемся набросать код, который приведет к вызову этого брейкпоинта. P.S Если возникли проблемы со сборкой, отладкой, тестированием или подобным — можно написать на forums.swift.org. Там достаточно оперативно помогают разобраться. Самая интересная и она же самая сложная часть для начинающих — как найти код, который нужно зафиксить. Чтобы сэкономить время при поиске бага, неплохо для начала ознакомиться немного с теорией. Все это может выглядеть сложно, если вы раньше не работали с компиляторами и не погружались в теорию того, как работают языки программирования. По правде говоря, для того чтобы внести свой вклад в Swift, совсем не обязательно знать, как работает каждый компонент языка, достаточно владеть некоторыми хитростями, о которых вы узнаете чуть ниже.  Тем не менее для тех, кто хочет погрузиться в детали, рекомендую прочесть цикл статей, подробно рассказывающий устройство компилятора Swift на русском. Также в репозитории Swift есть раздел документации, который содержит статьи по аспектам дизайна компонентов, их работе, эволюции языка, пояснения по работе различных частей и т.п.  Ниже проиллюстрирована архитектура компилятора и приведена выдержка из официального высокоуровневого описания архитектуры.  Взято из доклада Contributing to open source Swift by Jesse Squires 1) Парсинг (находится в lib/Parse) Парсер — это простой преобразователь исходного кода в AST (абстрактное синтаксическое дерево). В него встроен лексер — преобразователь потока символов исходного кода программы в слова, которые можно использовать в языке. То есть сначала лексер проверяет, что в исходном коде нет неожиданных символов, а потом парсер составляет из символов AST. Лексер выявляет ошибки типа использования неизвестных языку символов, а парсер ошибки несбалансированности открывающих/закрывающих скобок и т.п. 2) Семантический анализ (lib/Sema) Семантический анализатор отвечает за преобразование AST с предыдущего шага в типизированное AST. В основном он выявляет ошибки типизации. 3) Импорт Clang (lib/ClangImporter) На этом шаге импортируются Clang модули и мапятся C или Objective-C API в соответствующие Swift API. 4) Генерация SIL (lib/SILGen) Swift Intermediate Language (SIL) — это высокоуровневый промежуточный язык, необходимый для анализа и оптимизации Swift кода. В этой части типизированное AST преобразуется в так называемый "сырой" SIL. 5) SIL преобразование (lib/SILOptimizer/Mandatory) Тут происходят дополнительные проверки потока данных, например, использование не инициализированных переменных. Конечным результатом этого этапа является так называемый "каноничный" SIL. 6) SIL оптимизации (lib/SILOptimizer) На этом этапе происходят высокоуровневые оптимизации, включающие в себя девиртуализацию, специализация дженериков и оптимизации ARC. 7) LLVM IR генерация (lib/IRGen) Генерация IR (Intermediate Representation) преобразует SIL в LLVM IR, после которого LLVM может продолжить оптимизировать его и сгенерировать машинный код. Отталкиваясь от описания выше, можно примерно понять, где должна находиться та или иная правка для языка. Но чтобы немного упростить процесс поиска можно воспользоваться некоторыми хитростями: Мне повезло и человек в комментариях к моему таску прояснил многие моменты.  Тут мы можем узнать несколько лайфхаков для решения моей задачи и задач в Swift в целом: Что ж, поехали. Открываем Xcode с собранным Swift. Ищем текущую диагностику по строке, находим её в DiagnosticsSema.def под названием escaping_non_function_parameter, там же обнаруживаем, что нужна диагностика существует, но только как NOTE, поэтому нужно переделать на ERROR.  Также находим тесты которые проверяют эту ошибку. Добавляем по соседству свои тесты или исправляем текущие, запускаем, видим падающие тесты. Затем находим кусочек кода в TypeCheckType.cpp, который показывает первоначальную диагностику, ставим брейкпоинт чуть выше, запускаем. В консоли вводим пример кода, который должен вызывать новую диагностику. Смотрим, как код работает в этой части. Добавляем проверку, которую нам порекомендовали в комментариях в задаче. Запускаем, проверяем, видим зеленые тесты, радуемся. Пару слов о работе TypeCheckType.cpp: здесь проверяется использование типов и по сути это набор if-проверок, в который мы добавили новую. Важно: если вы делали правки в C++ коде, то перед коммитом нужно отформатировать код при помощи clang-format, иначе на ревью скорее всего не пропустят. В Swift куча разных тестов, и их обязательно нужно прогнать перед отправкой вашего кода. Для запуска тестов в основном используется утилита lit.py, но также можно вызывать их при помощи cmake. Более детально с подходами к тестированию можно ознакомиться тут. Я пользовался только lit.py, поэтому ниже приведу cheatsheet, который поможет запустить нужный вариант тестов.  Предупреждение: lit не умеет фильтровать по нескольким --filter флагам и берет только самый последний. Итак, после того как мы сделали все что нужно, можно отправлять пулл реквест. Если коммитов много, то следует сделать squash перед отправкой, чтобы отправлять все одним коммитом. Название ветки должно примерно описывать, что вы сделали. Например: fix-it-for-removing-escaping-from-optional-closure-parameter.  Ревьюеры в Swift очень внимательные и попросят вас исправить каждый лишний отступ и каждое несоответствие их идеям о том, как это должно работать. Тут у меня тоже возникли некоторые сложности, так как С++ разработчик из меня никакой. Но добрые люди в пулл реквесте подсказали, как можно написать код, чтобы все работало и было красиво. После того как все исправили, остается ждать аппрува от мемберов и соответственно мержа от них же. В этой статье я постарался показать весь процесс вклада в огромный opensource-проект Swift и поделился некоторыми лайфхаками, которые могут упростить вход в разработку и немного осветил теоретическую часть архитектуры компилятора.  Как оказалось, помочь развитию своего любимого языка не очень сложно, особенно при поддержке мощного и дружелюбного сообщества разработчиков. Поэтому не стесняйтесь браться за Starter Task-и и помогать развиваться Swift! iOS Developer