в одном файле могут быть например несколько модулей. Или имя файла может не соответствовать имени модуля, описанного в нем. Поэтому он анализирует сначала все файлы, по ходу преобразовывая HDL, на котором написан файл, во внутренний формат логических выражений. В процессе этого анализа и ругается если что. Потом создает дерево проекта, и уже после этого синтезирует из внутреннего логического формата только дерево проекта в конкретные LUT/LCELL. Точно также работает и синтезатор у синопсиса например. Другое дело, что можно было бы в два прохода делать - в первом вычислить какие модули где описаны, но подробно не анализировать синтаксис (только module/endmodule и аналоги в других языках) и построить дерево, а во втором - собирать, но увы. Это не так.