Skip to content

Commit 8b35440

Browse files
authored
Add complete type validation for Go (#2101)
Behavior changes: - Go now supports generating self recurives types: ``` type Foo = Foo[] ``` This turns into in go: ``` type Foo = []any ``` - Enhanced unions - created a `{union}__New{variant}()` method - unions of literals don't take in any parameters for constructors. - Serialization/Deserialziation tests for various types (unions of literals, maps, lists, etc) - Removed excess logging Commands for testing: Command 1: ``` cd engine/language_client_cffi OPENAI_API_KEY="...." BAML_LOG=warn cargo make integ-tests-run-spec ``` Integ tests pass (compile and go build works!) <img width="1053" alt="Screenshot 2025-07-03 at 4 35 39 AM" src="https://github.com/user-attachments/assets/bf223bb0-ca63-4385-953c-4ac428084698" /> Command 2: ``` RUN_GENERATOR_TESTS=1 infisical run --env=test -- cargo test --lib -p generators-go --no-fail-fast ``` <img width="1069" alt="Screenshot 2025-07-03 at 4 36 24 AM" src="https://github.com/user-attachments/assets/e6a5c99b-8904-4068-8438-b880aa51713f" />
1 parent aedc87e commit 8b35440

520 files changed

Lines changed: 110480 additions & 2465 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-cli-release.reusable.yaml

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ on:
44
workflow_call:
55
inputs:
66
version:
7-
description: 'Release version'
7+
description: "Release version"
88
required: false
99
type: string
1010
package_for_release:
11-
description: 'Create archives for release instead of raw binaries'
11+
description: "Create archives for release instead of raw binaries"
1212
type: boolean
1313
default: true
1414
required: false
@@ -17,7 +17,6 @@ on:
1717
- protoc-fix
1818
env:
1919
MACOSX_DEPLOYMENT_TARGET: "10.13"
20-
2120

2221
concurrency:
2322
# suffix is important to prevent a concurrency deadlock with the calling workflow
@@ -55,15 +54,15 @@ jobs:
5554
# with a newer GLIBC version compatible with Node20 used by actions/checkout@v4
5655
# container: ${{ contains(matrix._.os, 'ubuntu') && (contains(matrix._.target, 'x86_64') && 'quay.io/pypa/manylinux_2_28_x86_64' || 'ghcr.io/rust-cross/manylinux_2_28-cross:aarch64') || '' }}
5756
runs-on: ${{ matrix._.os }}
58-
57+
5958
env:
6059
CROSS_VERSION: v0.2.5
6160
CARGO: cargo
6261
TARGET_FLAGS: ${{ matrix._.target != '' && format('--target {0}', matrix._.target) || '' }}
6362
RUST_BACKTRACE: 1
6463
# When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
6564
TARGET_DIR: ./engine/target
66-
65+
6766
steps:
6867
- uses: actions/checkout@v4
6968
# - name: Install packages (Ubuntu)
@@ -82,16 +81,17 @@ jobs:
8281
prefix-key: "v5-rust-${{ matrix._.target }}"
8382
- uses: actions/setup-go@v5
8483
with:
85-
go-version: '1.21'
86-
84+
go-version: "1.21"
85+
8786
- name: Install protoc-gen-go into .cargo/bin
8887
shell: bash
8988
run: |
9089
# The cross-compile environment sanitizes the PATH, so we install the plugin
9190
# directly into a directory that is guaranteed to be in the PATH for cargo.
9291
# We also create a symlink from the go/bin to the cargo/bin for consistency.
9392
mkdir -p .cargo/bin
94-
go install github.com/golang/protobuf/protoc-gen-go@latest
93+
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
94+
go install golang.org/x/tools/cmd/goimports@latest
9595
cp "$HOME/go/bin/protoc-gen-go" ".cargo/bin/"
9696
echo "Installed protoc-gen-go into .cargo/bin:"
9797
ls -la .cargo/bin
@@ -111,14 +111,12 @@ jobs:
111111
# Test that protoc can find the go plugin (this will show an error about missing .proto file, but that's expected)
112112
protoc --go_out=/tmp --help | grep -q "go_out" && echo "✅ protoc recognizes --go_out flag" || echo "❌ protoc does not recognize --go_out flag"
113113
114-
115-
116114
- name: Use Cross
117115
if: contains(matrix._.os, 'ubuntu')
118116
run: |
119117
cargo install cross
120118
echo 'CARGO=cross' >> "$GITHUB_ENV"
121-
119+
122120
- name: Set target variables
123121
shell: bash
124122
run: |
@@ -129,15 +127,14 @@ jobs:
129127
if: contains(matrix._.target, 'linux')
130128
run: |
131129
ldd --version
132-
130+
133131
- name: Show command used for Cargo
134132
shell: bash
135133
run: |
136134
echo "cargo command is: ${{ env.CARGO }}"
137135
echo "target flag is: ${{ env.TARGET_FLAGS }}"
138136
echo "target dir is: ${{ env.TARGET_DIR }}"
139137
140-
141138
# Build the CLI - Always use static-ssl features
142139
- name: Build CLI Binary
143140
# This single step now handles all builds
@@ -159,13 +156,13 @@ jobs:
159156
export PROTOC_GEN_GO_PATH="${{ steps.protoc_gen_go_setup.outputs.protoc_gen_go_path }}"
160157
fi
161158
echo "Using PROTOC_GEN_GO_PATH: $PROTOC_GEN_GO_PATH"
162-
159+
163160
# We must use PROTOC_GEN_GO_PATH to explicitly tell the build script
164161
# where to find the plugin, as the cross-compile environment is isolated.
165162
export GOPATH=$HOME/go
166163
export GOBIN=$GOPATH/bin
167164
export PATH=$PATH:$GOROOT:$GOPATH:$GOBIN
168-
165+
169166
${{ env.CARGO }} build --release -p baml_cffi ${{ env.TARGET_FLAGS }}
170167
working-directory: engine
171168
# Skip this step on Windows runners
@@ -201,17 +198,16 @@ jobs:
201198
echo "Original Filename: ${base_name}"
202199
echo "New Filename: ${new_name}"
203200
204-
205201
# List target directories to debug build outputs
206202
- name: List target directories
207203
shell: bash
208204
run: |
209205
echo "Listing target/ directory:"
210206
ls -la engine/target/
211-
207+
212208
echo "Listing target/${{ matrix._.target }} directory:"
213209
ls -la engine/target/${{ matrix._.target }}/
214-
210+
215211
echo "Listing target/${{ matrix._.target }}/release directory:"
216212
ls -la engine/target/${{ matrix._.target }}/release/
217213
@@ -257,7 +253,7 @@ jobs:
257253
# Path now points to the *renamed* library file
258254
path: engine/target/${{ matrix._.target }}/release/${{ steps.cffi_info.outputs.new_lib_name }}
259255
if-no-files-found: error # Fail if the library file doesn't exist
260-
256+
261257
# Determine binary path and archive name
262258
- name: Set binary and archive paths
263259
id: paths
@@ -281,7 +277,7 @@ jobs:
281277
archive_base="baml-cli-${version_name}-${{ matrix._.target }}"
282278
echo "archive_base=$archive_base" >> $GITHUB_OUTPUT
283279
# Directory to create for staging files
284-
echo "archive_dir=./${archive_base}" >> $GITHUB_OUTPUT
280+
echo "archive_dir=./${archive_base}" >> $GITHUB_OUTPUT
285281
286282
# Print determined paths for debugging
287283
- name: Print artifact details

.github/workflows/primary.yml

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ jobs:
4848
with:
4949
go-version: "1.24"
5050
- name: Install protoc-gen-go
51-
run: go install github.com/golang/protobuf/protoc-gen-go@latest
51+
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
52+
- name: Install goimports
53+
run: go install golang.org/x/tools/cmd/goimports@latest
5254
- uses: dtolnay/rust-toolchain@stable
5355
with:
5456
toolchain: stable
@@ -79,7 +81,9 @@ jobs:
7981
- uses: jdx/mise-action@v2
8082
- uses: actions/setup-go@v5
8183
- name: Install protoc-gen-go
82-
run: go install github.com/golang/protobuf/protoc-gen-go@latest
84+
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
85+
- name: Install goimports
86+
run: go install golang.org/x/tools/cmd/goimports@latest
8387
- uses: actions/setup-node@v4
8488
with:
8589
node-version: 20
@@ -138,20 +142,20 @@ jobs:
138142
run: |
139143
git diff --exit-code || (echo "::error:: merge canary and run codegen again" && exit 1)
140144
build-wasm:
141-
runs-on: ubuntu-latest
142-
steps:
143-
- uses: actions/checkout@v4
144-
- uses: jdx/mise-action@v2
145-
- uses: dtolnay/rust-toolchain@stable
146-
with:
147-
toolchain: stable
148-
- run: rustup target add wasm32-unknown-unknown
149-
- uses: Swatinem/rust-cache@v2
150-
with:
151-
workspaces: engine
152-
- name: Build rust for wasm32
153-
run: cargo build --target=wasm32-unknown-unknown
154-
working-directory: engine/baml-schema-wasm
145+
runs-on: ubuntu-latest
146+
steps:
147+
- uses: actions/checkout@v4
148+
- uses: jdx/mise-action@v2
149+
- uses: dtolnay/rust-toolchain@stable
150+
with:
151+
toolchain: stable
152+
- run: rustup target add wasm32-unknown-unknown
153+
- uses: Swatinem/rust-cache@v2
154+
with:
155+
workspaces: engine
156+
- name: Build rust for wasm32
157+
run: cargo build --target=wasm32-unknown-unknown
158+
working-directory: engine/baml-schema-wasm
155159
build:
156160
runs-on: ubuntu-latest
157161
steps:
@@ -166,19 +170,19 @@ jobs:
166170
workspaces: engine
167171
- uses: actions/setup-go@v4
168172
with:
169-
go-version: '1.24'
173+
go-version: "1.24"
170174
- name: Install protoc-gen-go
171-
run: go install github.com/golang/protobuf/protoc-gen-go@latest
175+
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
172176
- name: Install goimports
173177
run: go install golang.org/x/tools/cmd/goimports@latest
174178
- uses: actions/setup-python@v4
175179
with:
176-
python-version: '3.13'
180+
python-version: "3.13"
177181
- name: Install ruff
178182
run: pip install ruff
179183
- uses: actions/setup-node@v4
180184
with:
181-
node-version: '24.2.0'
185+
node-version: "24.2.0"
182186
- name: Install prettier
183187
run: npm install -g prettier
184188
- name: Install Biome
@@ -214,7 +218,9 @@ jobs:
214218
with:
215219
go-version: "1.21.x"
216220
- name: Install protoc-gen-go
217-
run: go install github.com/golang/protobuf/protoc-gen-go@latest
221+
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
222+
- name: Install goimports
223+
run: go install golang.org/x/tools/cmd/goimports@latest
218224
- uses: dtolnay/rust-toolchain@stable
219225
with:
220226
toolchain: stable

engine/Cross.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pre-build = [
88
"wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz",
99
"tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local",
1010
"export PATH=$PATH:/usr/local/go/bin",
11-
"/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest",
11+
"/usr/local/go/bin/go install google.golang.org/protobuf/protoc-gen-go@latest",
1212
"cp /root/go/bin/protoc-gen-go /usr/local/bin/",
1313
]
1414

@@ -18,7 +18,7 @@ pre-build = [
1818
"wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz",
1919
"tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local",
2020
"export PATH=$PATH:/usr/local/go/bin",
21-
"/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest",
21+
"/usr/local/go/bin/go install google.golang.org/protobuf/protoc-gen-go@latest",
2222
"cp /root/go/bin/protoc-gen-go /usr/local/bin/",
2323
]
2424

@@ -29,7 +29,7 @@ pre-build = [
2929
"wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz",
3030
"tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local",
3131
"export PATH=$PATH:/usr/local/go/bin",
32-
"/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest",
32+
"/usr/local/go/bin/go install google.golang.org/protobuf/protoc-gen-go@latest",
3333
"cp /root/go/bin/protoc-gen-go /usr/local/bin/",
3434
]
3535

@@ -39,6 +39,6 @@ pre-build = [
3939
"wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz",
4040
"tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local",
4141
"export PATH=$PATH:/usr/local/go/bin",
42-
"/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest",
42+
"/usr/local/go/bin/go install google.golang.org/protobuf/protoc-gen-go@latest",
4343
"cp /root/go/bin/protoc-gen-go /usr/local/bin/",
4444
]

engine/baml-lib/baml-core/src/ir/repr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ impl IntermediateRepr {
642642
let mut res = vec![];
643643
all_types.for_each(|t| {
644644
let found = t.to_non_streaming_type(self);
645-
res.extend(found.find_if(&is_union).into_iter().cloned());
645+
res.extend(found.find_if(&is_union, false).into_iter().cloned());
646646
});
647647

648648
res.into_iter()
@@ -677,7 +677,7 @@ impl IntermediateRepr {
677677
let mut res = vec![];
678678
all_types.for_each(|t| {
679679
let found = t.to_streaming_type(self);
680-
res.extend(found.find_if(&is_union).into_iter().cloned());
680+
res.extend(found.find_if(&is_union, false).into_iter().cloned());
681681
});
682682

683683
res.into_iter()

engine/baml-lib/baml-types/src/ir_type/mod.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ impl<T> TypeGeneric<T> {
356356
pub fn find_if<'a>(
357357
&'a self,
358358
predicate: &impl Fn(&TypeGeneric<T>) -> bool,
359+
ignore_map_keys: bool,
359360
) -> Vec<&'a TypeGeneric<T>> {
360361
if predicate(self) {
361362
return vec![self];
@@ -367,27 +368,31 @@ impl<T> TypeGeneric<T> {
367368
| TypeGeneric::Literal(..)
368369
| TypeGeneric::Class { .. }
369370
| TypeGeneric::RecursiveTypeAlias { .. } => vec![],
370-
TypeGeneric::List(inner, _) => inner.find_if(predicate),
371-
TypeGeneric::Map(type_generic, type_generic1, _) => {
372-
let mut res = type_generic.find_if(predicate);
373-
res.extend(type_generic1.find_if(predicate));
371+
TypeGeneric::List(inner, _) => inner.find_if(predicate, ignore_map_keys),
372+
TypeGeneric::Map(key_type, value_type, _) => {
373+
let mut res = value_type.find_if(predicate, ignore_map_keys);
374+
if !ignore_map_keys {
375+
res.extend(key_type.find_if(predicate, ignore_map_keys));
376+
}
374377
res
375378
}
376379
TypeGeneric::Tuple(type_generics, _) => type_generics
377380
.iter()
378-
.flat_map(|t| t.find_if(predicate))
381+
.flat_map(|t| t.find_if(predicate, ignore_map_keys))
379382
.collect(),
380383
TypeGeneric::Union(union_type_generic, _) => union_type_generic
381384
.iter_skip_null()
382385
.iter()
383-
.flat_map(|t| t.find_if(predicate))
386+
.flat_map(|t| t.find_if(predicate, ignore_map_keys))
384387
.collect(),
385388
TypeGeneric::Arrow(arrow_generic, _) => {
386389
let res = arrow_generic
387390
.param_types
388391
.iter()
389-
.flat_map(|t| t.find_if(predicate));
390-
let mut returned = arrow_generic.return_type.find_if(predicate);
392+
.flat_map(|t| t.find_if(predicate, ignore_map_keys));
393+
let mut returned = arrow_generic
394+
.return_type
395+
.find_if(predicate, ignore_map_keys);
391396
returned.extend(res);
392397
returned
393398
}

0 commit comments

Comments
 (0)