короче я в целом придумал как сделать без дупликации кода, по заданным требованиям и без кодгенерации. Ну вернее я еще немного усложнил требования (у меня на самом деле они еще чуть более сложные, но это уже мелочи, адаптировать смогу) - вместо разных функций, которые требуют опции, у меня функция create, которая возвращает разные типы.
Вот код (он в плейграунде не компилится, потому что там старая версия, но на мастер бранче вполне) -
https://go2goplay.golang.org/p/-27Cyp-jauS .
К изначальной задаче это привести несложно: переименовать все эти foo/bar структуры в fooTag/barTag и опционируемые функции задавать как
func foo[Opt optionApplier[fooTag]](options ...Opt) {}