Skip to content

Kotlin/Android transpiler: production-grade codegen (runtime extraction + compiler-verified fixes)#92

Merged
abneeshsingh21 merged 12 commits into
mainfrom
fix/kotlin-swift-native-production
Jul 17, 2026
Merged

Kotlin/Android transpiler: production-grade codegen (runtime extraction + compiler-verified fixes)#92
abneeshsingh21 merged 12 commits into
mainfrom
fix/kotlin-swift-native-production

Conversation

@abneeshsingh21

@abneeshsingh21 abneeshsingh21 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Drives the Kotlin/Android transpiler toward production-grade: EPL programs generate Kotlin that actually compiles on a real kotlinc/gradlew toolchain and builds an installable APK. Extracts the runtime into a single source of truth and fixes a batch of codegen defects found by compiling the example corpus through the real Android compiler.

Architecture

  • epl/kotlin_runtime.py — the inline EPLRuntime shim extracted into one module, assembled per target:
    • android_runtime() — byte-identical to the historically verified APK runtime (SQLite db_*, android.util.Base64, org.json).
    • console_runtime() — plain-JVM slots + a dependency-free JsonMini, so a standalone epl kotlin transpile compiles and runs with only kotlin-stdlib.
  • generate(include_runtime=True) appends the shim only when referenced; golden tests (tests/test_kotlin_runtime_golden.py) lock the Android runtime against drift.

Compiler-verified codegen fixes

  • Division/power parity: eplDiv keeps evenly-divisible int/int integral (10/2 → 5, 10/4 → 2.5); **eplPow (int-preserving). Matches the interpreter/VM exactly.
  • for-each over a list-of-maps wrongly emitted .keys (matched "Map" as a substring of MutableList<Map<...>>); now checks the type prefix.
  • Display/Say of a dynamic value hit println(Any?) overload ambiguity → routes through EPLRuntime.toText.
  • Reassigning a function parameter violated Kotlin's immutable val params → emits a mutable shadow var p = p.
  • Math builtins on dynamic args (floor/sqrt/ceil/log/sin/cos) coerce via EPLRuntime.toDecimal; abs preserves int-vs-decimal via absNum.
  • Top-level constants were buried inside fun main(), unreachable from file-scope inlined stdlib functions → emitted at file scope.
  • not on a dynamic operand routes through EPLRuntime.truthy; Any?→non-null Any args get a non-null assertion.
  • Added native regex_replace / regex_split bridges (interpreter arg-order parity).

Verification (real toolchain)

  • 63 kotlin/native tests pass; golden fixtures regenerated.
  • database_appassembleDebug → 7.4 MB installable app-debug.apk.
  • Example compile sweep: 47/55 compile clean on real kotlinc; the remainder are legitimately non-portable (Python interop, gui_*, server real_db_*/web_*, csv_read) — surfaced by the porting report — or a known-malformed example.

Summary by CodeRabbit

  • New Features

    • Improved Kotlin and Android transpilation compatibility across arithmetic, collections, strings, lambdas, dynamic values, slicing, file access, and SQLite operations.
    • Added platform-appropriate runtime support for generated Kotlin applications.
    • Native builds now include only the standard-library code they use.
    • Added portability checks for unsupported Python and JavaScript interoperability.
  • Bug Fixes

    • Fixed variable scoping, return types, error handling, string interpolation, list mutations, and Kotlin keyword escaping.
    • Corrected behavior for dynamic operators, built-in functions, map methods, and negative-index slicing.
  • Tests

    • Expanded compiler-verified regression coverage for Kotlin generation and runtime behavior.

Found by building real APKs with the actual Kotlin/Gradle toolchain:

- db_create_table / db_tables / file_* now bridge to EPLRuntime methods
  instead of passing through as unresolved snake_case references
- ambiguous Any + Any lowers to eplAdd runtime helper (EPL + semantics)
- EPL / lowers to eplDiv (float division, raises on zero) instead of
  Kotlin integer division which gave wrong values
- class-method call sites resolve the receiver class's declared return
  type instead of the generic builtin .add => Unit map
- generate_android_activity now runs the symbol pre-pass so class/function
  type lookups resolve on the Android path
- variable reassignment emits one var + bare assignment, tracked per scope

Portability checker now flags Use python / Use javascript interop as
unportable to native targets instead of silently emitting broken code.
…oist, numeric coercion, function-scoped locals

Second compiler-verified pass over the example corpus (compileDebugKotlin):
- Map methods (keys/values/entries/has/get-default/merge/set/copy/remove) route
  through EPLRuntime helpers mirroring interpreter dict semantics; map-key field
  assignment and key-iteration fixed.
- Slicing (list/text [a:b:c]) now emits an EPLRuntime.slice helper with
  CPython-faithful negative-index/step semantics instead of null.
- round/type_of/typeof/abs builtins mapped; length() dispatches on runtime value.
- Top-level enums hoisted to file level (Kotlin forbids local enum classes).
- Mixed Int/Double comparisons, arithmetic, and function-call args widened.
- Function-scoped locals first assigned inside try/if/loop are hoisted to scope
  top so out-of-block uses resolve; float reassignment coercion.
… builtins

Third compiler-verified pass (compileDebugKotlin over strings/string_advanced/math_builtins):
- String receivers dispatch through a dedicated method map + EPLRuntime helpers
  (strCount/padLeft/padRight/charAt/toCharList/isNumberStr/isAlphaStr/strFormat)
  mirroring interpreter _call_string_method; find/count/reverse no longer bind to
  Kotlin CharSequence predicate overloads.
- Property-style accessors (.uppercase/.lowercase/.trim, .length on collections)
  emit method calls / .size instead of unresolved property reads.
- List mutation fixed: sort()/reverse() in-place (were sorted()/reversed(), which
  discarded the mutation); remove(x) by value (was removeAt index); split() yields
  MutableList.
- Added free-function builtins: range, sum, sorted, reversed, is_* type predicates,
  char_code, from_char_code, json_parse, json_stringify (JSON via org.json).
…amming

Emit EPL lambdas as (Any?...) -> Any? and route dynamic operators, higher-order
list methods (map/filter/reduce/find/every/some), and dynamic-callable invocation
through EPLRuntime helpers. Compiler-verified: lambdas example now compiles clean,
all prior-green examples still green.
…turn coercion

- String+String concat no longer routes through eplAdd (kept Any?), which broke
  chained concatenation; native + now preserves the String type.
- keys/values/random_integer/format resolve as free-function builtins.
- Double-returning functions widen Int-literal return paths (e.g. return 0 guard).
Compiler-verified: showcase, guessing_game, new_features now compile; no regressions.
…hs-return

Fourth compiler-verified pass. Every fix confirmed against compileDebugKotlin
over the killer_*, text_analyzer, and data-processing examples.

- stdlib_inliner: resolve plain `Import "<stdlib>"` for native targets by
  splicing reachable defs (callee-before-caller order); wired into the kotlin
  and android CLI paths. Aliased/namespaced imports left untouched.
- Dynamic (Any) receivers/args from iterate(): coerce string-only methods to
  String; route shared reverse/count/replace/contains/length via EPLRuntime.
- All-paths-return analysis (recurses if/else) replaces the shallow top-level
  return check, killing spurious `return Unit` under non-Unit signatures.
- Backtick-escape Kotlin hard keywords used as EPL identifiers (this/super
  pass through unchanged).
- Coerce dynamic values into Int/Double/String params, typed reassignments,
  and range bounds; `+` type inference now mirrors the emitter (dynamic left
  lowers to eplAdd => Any?, no longer mis-inferred as String).
- Add tests/test_stdlib_inliner.py (9 cases) covering reachability, ordering,
  import stripping, and the untouched-boundary cases.
…tdlib builtins

Splice reachable module-level Create state (e.g. testing.epl counters) so
inlined stdlib functions share it instead of re-declaring per-function locals.
Add Kotlin runtime + dispatch for crypto/encoding/datetime/regex/math native
builtins, list.pop/dynamic mutation, truthy coercion, and nullable-return
widening. native_stdlib_demo and stdlib_demo now compile to real Kotlin.
…ompiler-verified codegen bugs

Extract the inline EPLRuntime shim into epl/kotlin_runtime.py as a single
source of truth assembled per target: android_runtime() stays byte-identical
to the verified APK runtime; console_runtime() fills platform slots with
plain-JVM equivalents so a self-contained `epl kotlin` transpile compiles and
runs with only kotlin-stdlib. generate(include_runtime=True) appends the shim.

Compiler-verified codegen fixes (found via real kotlinc/gradlew):
- for-each over a list-of-maps emitted `.keys` (Map-only) because the type
  check matched the substring 'Map' in 'MutableList<Map<...>>'; now checks the
  type prefix in the correct order.
- Display/Say of a dynamic value hit println(Any?) overload ambiguity; routes
  through EPLRuntime.toText (also matches EPL display formatting).
- reassigning a function parameter redeclared it as `var` and violated Kotlin's
  immutable val params; now emits a mutable shadow `var p = p`.
- eplDiv/eplMul/etc. return Any, so math builtins' `{arg}.toDouble()` was
  unresolved; coerce via EPLRuntime.toDecimal; abs preserves int/decimal via
  new EPLRuntime.absNum.
- top-level constants were emitted inside fun main(), unreachable from
  file-scope inlined stdlib functions; now emitted at file scope.

Golden fixtures regenerated (division fix changes the runtime); stale test
assertions updated; regression tests added for the for-each and print fixes.
Verified: 60 kotlin/native tests pass; database_app assembleDebug -> 7.4MB APK;
41->44 of 55 example programs compile clean on real kotlinc.
…null Any params

- `not` on a dynamic operand (Any/Any?, e.g. a dynamic-lambda call result)
  now routes through EPLRuntime.truthy(); Kotlin's `!` only accepts Boolean.
- A nullable dynamic value (Any?) passed into a non-null Any param now gets a
  `!!` assertion so the call type-checks.

Refresh three stale test_kotlin_gen assertions to the current (correct) codegen:
toText-wrapped Print, main()-scoped var-count, and eplDiv line-number arg.
…es, unary-not truthiness

- math builtins (floor/sqrt/ceil/log/sin/cos) coerce args via EPLRuntime.toDecimal
  instead of `.toDouble()` on eplDiv's Any return (unresolved reference); abs
  preserves int-vs-decimal parity via new EPLRuntime.absNum.
- add native regex_replace/regex_split bridges (EPLRuntime.regexReplace/regexSplit),
  matching the interpreter's (pattern, replacement, text) / (pattern, text) arg order.
- unary `not` on a dynamic operand routes through EPLRuntime.truthy (Kotlin's !
  requires Boolean; a dynamic-call result is Any?).
- `Any?` arg into a non-null `Any` param gets a non-null assertion so calls type-check.

Regression tests added; golden fixtures regenerated (absNum). Verified on real
kotlinc: regex_demo/data_pipeline/text_analyzer now compile (47/55 examples clean;
remainder are legitimately non-portable — python interop, gui_*, server db, csv);
database_app assembleDebug -> 7.4MB APK; 63 kotlin/native tests pass.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
epl 565a2d0 Commit Preview URL

Branch Preview URL
Jul 17 2026, 09:13 PM

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@abneeshsingh21, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4447d86d-ade0-48bc-8d31-fe889d5d1291

📥 Commits

Reviewing files that changed from the base of the PR and between b43e535 and be5b6a4.

📒 Files selected for processing (4)
  • epl/kotlin_gen.py
  • epl/kotlin_runtime.py
  • tests/test_kotlin.py
  • tests/test_stdlib_inliner.py

Walkthrough

The PR expands Kotlin and Android transpilation with runtime-backed semantics, scope-aware code generation, native stdlib inlining, platform runtime shims, portability detection, compiler differential coverage, and regression fixtures.

Changes

Kotlin transpilation and stdlib integration

Layer / File(s) Summary
Stdlib resolution and native entry points
epl/stdlib_inliner.py, epl/cli.py, epl/native_portability.py, tests/test_stdlib_inliner.py
Bundled stdlib definitions are reachability-pruned, dependency-ordered, aliased imports are flattened, and native entry points pass the transformed AST to code generation.
Generator scope and control-flow emission
epl/kotlin_gen.py
Kotlin emission adds symbol tracking, hoisting, typed coercions, dynamic truthiness, return-path analysis, file operations, exception formatting, and file-scope enum constants.
Type inference and expression dispatch
epl/kotlin_gen.py
Operators, lambdas, calls, strings, slices, maps, lists, builtins, interpolation, and Kotlin keyword identifiers use expanded inference and runtime dispatch.
Shared runtime shims
epl/kotlin_runtime.py, scripts/_gen_kotlin_runtime.py, tests/fixtures/*
Android and console runtime sources provide EPL arithmetic, collections, strings, JSON, database, file, encoding, and slicing helpers.
Compiler parity and regression validation
scripts/kotlin_coverage.py, tests/test_kotlin.py, tests/test_kotlin_gen.py, tests/test_kotlin_runtime_golden.py
JVM differential coverage, generator assertions, portability checks, and byte-identical Android runtime fixtures are added or updated.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant EPLProgram
  participant CLI
  participant KotlinGenerator
  participant EPLRuntime
  participant KotlinCompiler
  EPLProgram->>CLI: load source program
  CLI->>KotlinGenerator: pass inlined Program
  KotlinGenerator->>EPLRuntime: emit referenced runtime helpers
  KotlinGenerator->>KotlinCompiler: produce Kotlin source
  KotlinCompiler-->>CLI: compiled JVM or Android-compatible output
Loading

Possibly related PRs

Poem

A rabbit hopped through Kotlin code,
And found runtime carrots where operators glowed.
Slices went negative, lambdas learned to play,
Stdlib imports found their proper way.
“Compile,” cried Bun, “and let tests sing—”
Then nibbled a golden fixture string.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: Kotlin/Android transpiler codegen improvements, runtime extraction, and compiler-verified fixes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/kotlin-swift-native-production

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b43e535f82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread epl/kotlin_gen.py
Comment on lines 1561 to +1562
'absolute': 'Int',
'abs': 'Int',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Widen abs/absolute result type to match the helper

When absolute()/abs() is used in an assignment or return, the generator still infers Int here, but the new lowering emits EPLRuntime.absNum(...), whose Kotlin signature returns Any. A simple program such as x = absolute(-5) now generates var x: Int = EPLRuntime.absNum(-5), which Kotlin rejects even though the previous kotlin.math.abs(-5) form compiled; infer Any/cast the helper result instead of declaring an Int destination.

Useful? React with 👍 / 👎.

Comment thread epl/stdlib_inliner.py
Comment on lines +51 to +52
if isinstance(node, (ast.FunctionDef, ast.ConstDeclaration, ast.VarDeclaration)):
return node.name

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Hoist inlined mutable stdlib state to file scope

The inliner now treats top-level Create statements from stdlib modules as definitions, but KotlinGenerator.generate() only hoists ConstDeclarations and leaves these VarDeclarations in fun main(). For Import "testing"; test_summary(), the inlined test_summary function is emitted at file scope and references _test_passed, _test_failed, and _test_errors before their local declarations inside main, so the generated Kotlin does not compile; these mutable module variables need to be emitted at file scope along with the functions that close over them.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/test_kotlin.py (1)

374-380: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Register all new regression tests in the explicit runner.

The six tests added at Lines 239–309 are never invoked by this runner.

Proposed fix
         test_throw,
+        test_for_each_over_list_of_maps_no_keys,
+        test_for_each_over_map_iterates_keys,
+        test_display_dynamic_value_routes_through_totext,
+        test_math_builtins_accept_dynamic_args,
+        test_regex_replace_and_split_bridges,
+        test_reassigned_param_shadowed_not_redeclared,
         test_map_literal,

As per path instructions, test files must ensure good regression coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_kotlin.py` around lines 374 - 380, Update the explicit test runner
list in tests/test_kotlin.py to include all six newly added regression test
functions from Lines 239–309, placing them alongside the existing test_*
entries. Ensure each new test is invoked when the runner executes, without
changing the tests themselves.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@epl/kotlin_gen.py`:
- Line 213: Update generate_compose_activity to call
_register_symbols(program.statements) before generating Compose code, matching
the pre-pass used by generate_android_activity. Ensure forward calls and
receiver types resolve correctly, then verify the generated Jetpack Compose
output is valid Kotlin.
- Around line 1561-1562: Update the type inference for abs and absolute in the
relevant generator logic to match absNum’s Any return behavior: infer the result
from the argument when possible or emit a typed expression so assignments such
as x = abs(-1) remain valid Kotlin. Apply the same correction at the additional
abs/absolute handling near the other referenced location, preserving valid
Kotlin type generation.
- Around line 999-1000: Update the incomplete-return handling around
_always_returns in the relevant code-generation paths so value-returning Kotlin
functions never emit return Unit. For nullable value-returning functions, emit
return null and ensure the generated return type permits null; otherwise reject
incomplete returns instead. Apply the same correction to the corresponding logic
at all referenced locations while preserving Unit returns for genuinely
Unit-returning functions.
- Around line 1154-1162: Update `_declare_hoisted` so the emitted Kotlin
declaration uses `_safe_ident(nm)` instead of the raw `nm` in the `var`
statement. Keep symbol-table operations keyed by the original name and preserve
the existing type/default-value logic.
- Around line 2484-2506: Extend the dynamic operator dispatch in the Kotlin
generation logic to handle `and` and `or` via EPLRuntime truthiness helpers,
rather than allowing dynamic operands to fall through to native Kotlin `&&` or
`||`. Update the `dyn` mapping or equivalent branch around the dynamic handling
block, using the existing runtime conventions and emitting valid Kotlin
expressions.

In `@epl/kotlin_runtime.py`:
- Line 1: Apply Ruff formatting to epl/kotlin_runtime.py using ruff format so
the file passes ruff format --check without changing its behavior.
- Line 28: Update dbCount to validate the table argument with the existing
DB_IDENT regex before building its SQL query, then quote the validated
identifier in the COUNT query. Preserve the current row-count extraction and
fallback behavior.
- Line 13: Update epl/kotlin_runtime.py at lines 13-13 in eplDiv to always
return decimal division as a Double, including evenly divisible numeric
operands. Update epl/kotlin_gen.py at lines 1486-1510 so the / operator is
inferred as Double rather than Any. Add coverage in tests/test_kotlin_gen.py at
lines 140-144 for divisible operands and assert the resulting decimal type
semantics.
- Line 30: Update the Android resolveFile function to enforce the filesDir
sandbox: reject absolute input paths, canonicalize the base and resolved
candidate, and reject candidates that do not remain beneath the canonical base
directory. Keep all fileExists, fileDelete, fileRead, fileWrite, and fileAppend
callers using resolveFile so traversal and absolute-path access are consistently
blocked.

In `@epl/native_portability.py`:
- Around line 238-251: The native interop diagnostics in
epl/native_portability.py, within the UseStatement and UseJSStatement handling,
expose None for aliasless imports; format both messages with node.alias or
node.library as the effective binding. Update tests/test_kotlin_gen.py at lines
178-187 to assert the library name for aliasless Python and JavaScript interop
diagnostics, covering both cases with meaningful edge-case assertions.

In `@epl/stdlib_inliner.py`:
- Around line 240-242: Update the inlining flow around user_stmts and the
import-resolution logic to track the specific ImportStatement nodes successfully
resolved, removing only those from the emitted statements. Preserve local,
native, unknown, unused-alias, and failed-to-parse imports, and add a regression
test covering a mixed bundled-stdlib and non-inlined import.
- Around line 27-32: Harden _module_path so resolution cannot escape
_STDLIB_DIR: reject absolute names and traversal components, resolve the
candidate path (including symlinks), and return it only when it remains within
the resolved _STDLIB_DIR and points to a file. Preserve the existing .epl
normalization and None result for invalid or missing modules.

In `@scripts/_gen_kotlin_runtime.py`:
- Around line 66-100: Harden the generated Kotlin JSON parser around
Parser.parseValue(), obj(), arr(), and parse(): check bounds before every s[i]
access, require ':' after object keys, and accept only ',' or the matching
closing delimiter after each value instead of blindly incrementing. Make parse()
skip trailing whitespace and reject any non-EOF input, while preserving valid
object and array parsing.

In `@scripts/kotlin_coverage.py`:
- Around line 218-226: Update the build-result classification around the
compiler result in the Kotlin coverage flow to check the compiler process exit
status before relying on diagnostic text or generated class files. Any nonzero
status must return 'buildfail', while preserving the existing error-message and
successful class-file handling for zero-status builds.

In `@tests/fixtures/android_epl_runtime__com_acme_demo.kt`:
- Around line 614-620: The resolveFile implementation generated by
scripts/_gen_kotlin_runtime.py must always confine paths beneath filesDir:
reject or safely normalize absolute paths and prevent .. traversal from escaping
the sandbox. Update the generator’s resolveFile logic, then regenerate both
tests/fixtures/android_epl_runtime__com_acme_demo.kt (lines 614-620) and
tests/fixtures/android_epl_runtime__com_epl_app.kt (lines 614-620) with the
hardened implementation.

In `@tests/test_kotlin_gen.py`:
- Around line 162-175: Strengthen test_class_method_call_return_type_resolved by
positively asserting that the generated Kotlin includes the expected Calc.addup
method signature returning the inferred numeric type and declares s with that
same type, rather than only checking that Unit is absent. Ensure the assertions
still verify the generated source contains the complete method and variable
declarations.

In `@tests/test_kotlin.py`:
- Around line 284-291: Simplify test_math_builtins_accept_dynamic_args by
removing the tautological assertion branch that checks '.toDouble()).toInt()'
with an always-satisfied 'or' condition. Keep meaningful assertions that verify
EPLRuntime.toDecimal is used for floor and EPLRuntime.absNum is used for
absolute.

In `@tests/test_stdlib_inliner.py`:
- Around line 27-30: Run Ruff formatting on tests/test_stdlib_inliner.py and
apply the formatter’s changes so _has_plain_import and the rest of the file pass
ruff format --check.
- Around line 48-61: Strengthen test_transitive_dependency_pulled_in and
test_callee_precedes_caller so dependency presence is asserted unconditionally:
require both title_case and capitalize in the emitted definitions, then assert
capitalize appears before title_case. Remove the conditional guard that allows
the ordering test to pass when either definition is missing.

---

Outside diff comments:
In `@tests/test_kotlin.py`:
- Around line 374-380: Update the explicit test runner list in
tests/test_kotlin.py to include all six newly added regression test functions
from Lines 239–309, placing them alongside the existing test_* entries. Ensure
each new test is invoked when the runner executes, without changing the tests
themselves.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: acf0058f-9202-4bec-881b-031c8a33e8aa

📥 Commits

Reviewing files that changed from the base of the PR and between 9783547 and b43e535.

📒 Files selected for processing (14)
  • CHANGELOG.md
  • epl/cli.py
  • epl/kotlin_gen.py
  • epl/kotlin_runtime.py
  • epl/native_portability.py
  • epl/stdlib_inliner.py
  • scripts/_gen_kotlin_runtime.py
  • scripts/kotlin_coverage.py
  • tests/fixtures/android_epl_runtime__com_acme_demo.kt
  • tests/fixtures/android_epl_runtime__com_epl_app.kt
  • tests/test_kotlin.py
  • tests/test_kotlin_gen.py
  • tests/test_kotlin_runtime_golden.py
  • tests/test_stdlib_inliner.py

Comment thread epl/kotlin_gen.py
}

# First pass: collect GUI nodes for layout XML
self._register_symbols(program.statements)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply the symbol pre-pass to Compose generation too.

This fixes generate_android_activity, but generate_compose_activity still starts without _register_symbols(program.statements). Forward calls and receiver types can therefore remain unresolved or be mis-inferred on the Compose path.

As per path instructions, verify correct Jetpack Compose generation and valid Kotlin output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@epl/kotlin_gen.py` at line 213, Update generate_compose_activity to call
_register_symbols(program.statements) before generating Compose code, matching
the pre-pass used by generate_android_activity. Ensure forward calls and
receiver types resolve correctly, then verify the generated Jetpack Compose
output is valid Kotlin.

Source: Path instructions

Comment thread epl/kotlin_gen.py
Comment on lines +999 to 1000
if ret_type != 'Unit' and not self._always_returns(node.body):
self._line('return Unit')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

Do not return Unit from incomplete value-returning functions.

When one branch returns String or Double but another falls through, these paths emit return Unit, which is an incompatible Kotlin return type. Model fallthrough as nullable and emit return null, or reject incomplete returns.

As per path instructions, epl/kotlin_gen.py must produce valid Kotlin syntax and types.

Also applies to: 1387-1388, 1432-1433

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@epl/kotlin_gen.py` around lines 999 - 1000, Update the incomplete-return
handling around _always_returns in the relevant code-generation paths so
value-returning Kotlin functions never emit return Unit. For nullable
value-returning functions, emit return null and ensure the generated return type
permits null; otherwise reject incomplete returns instead. Apply the same
correction to the corresponding logic at all referenced locations while
preserving Unit returns for genuinely Unit-returning functions.

Source: Path instructions

Comment thread epl/kotlin_gen.py
Comment on lines +1154 to +1162
def _declare_hoisted(self, stmts, skip_names=()):
"""Emit scope-top `var` declarations for function-scoped locals first seen
inside a nested block, so later out-of-block uses resolve."""
for nm, kt in self._hoist_locals(stmts, skip_names):
default = self._zero_value(kt)
decl_type = kt if default != 'null' or kt.endswith('?') else f'{kt}?'
self.symbols.define(nm, decl_type)
self.symbols.mark_declared(nm)
self._line(f'var {nm}: {decl_type} = {default}')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Escape hoisted variable names.

Line 1162 emits nm directly, so a nested first assignment to an EPL variable such as val generates invalid var val. Use _safe_ident(nm).

Proposed fix
-            self._line(f'var {nm}: {decl_type} = {default}')
+            self._line(f'var {self._safe_ident(nm)}: {decl_type} = {default}')

As per path instructions, epl/kotlin_gen.py must emit valid Kotlin identifiers.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _declare_hoisted(self, stmts, skip_names=()):
"""Emit scope-top `var` declarations for function-scoped locals first seen
inside a nested block, so later out-of-block uses resolve."""
for nm, kt in self._hoist_locals(stmts, skip_names):
default = self._zero_value(kt)
decl_type = kt if default != 'null' or kt.endswith('?') else f'{kt}?'
self.symbols.define(nm, decl_type)
self.symbols.mark_declared(nm)
self._line(f'var {nm}: {decl_type} = {default}')
def _declare_hoisted(self, stmts, skip_names=()):
"""Emit scope-top `var` declarations for function-scoped locals first seen
inside a nested block, so later out-of-block uses resolve."""
for nm, kt in self._hoist_locals(stmts, skip_names):
default = self._zero_value(kt)
decl_type = kt if default != 'null' or kt.endswith('?') else f'{kt}?'
self.symbols.define(nm, decl_type)
self.symbols.mark_declared(nm)
self._line(f'var {self._safe_ident(nm)}: {decl_type} = {default}')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@epl/kotlin_gen.py` around lines 1154 - 1162, Update `_declare_hoisted` so the
emitted Kotlin declaration uses `_safe_ident(nm)` instead of the raw `nm` in the
`var` statement. Keep symbol-table operations keyed by the original name and
preserve the existing type/default-value logic.

Source: Path instructions

Comment thread epl/kotlin_gen.py
Comment on lines 1561 to +1562
'absolute': 'Int',
'abs': 'Int',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Align abs inference with absNum’s return type.

absNum returns Any, while inference always declares abs/absolute as Int. Code such as x = abs(-1) therefore emits an invalid Int = Any assignment. Infer from the argument or emit a typed expression.

As per path instructions, epl/kotlin_gen.py must produce valid Kotlin types.

Also applies to: 2635-2637

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@epl/kotlin_gen.py` around lines 1561 - 1562, Update the type inference for
abs and absolute in the relevant generator logic to match absNum’s Any return
behavior: infer the result from the argument when possible or emit a typed
expression so assignments such as x = abs(-1) remain valid Kotlin. Apply the
same correction at the additional abs/absolute handling near the other
referenced location, preserving valid Kotlin type generation.

Source: Path instructions

Comment thread epl/kotlin_gen.py
Comment on lines +2484 to +2506
dynamic = lt in self._DYNAMIC or rt in self._DYNAMIC
# Dynamic operands can't use Kotlin's native operators; route to EPLRuntime.
if dynamic:
dyn = {
'*': 'eplMul',
'-': 'eplSub',
'%': 'eplMod',
'**': 'eplPow',
'<': 'eplLt',
'>': 'eplGt',
'<=': 'eplLe',
'>=': 'eplGe',
'==': 'eplEq',
}
if op in dyn:
return f'EPLRuntime.{dyn[op]}({l}, {r})'
if op == '!=':
return f'(!EPLRuntime.eplEq({l}, {r}))'
if op == '//':
return f'kotlin.math.floor(EPLRuntime.toDecimal(EPLRuntime.eplDiv({l}, {r}, {node.line}))).toInt()'
# `+` on a dynamic left is add-or-concat at runtime (String left concats natively).
if op == '+' and lt != 'String':
return f'EPLRuntime.eplAdd({l}, {r})'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Handle dynamic and and or through EPL truthiness.

These operators are absent from the dynamic dispatch block, so Any? and Any? falls through to Kotlin &&/|| and fails compilation.

Proposed fix
         if dynamic:
+            if op == 'and':
+                return f'(EPLRuntime.truthy({l}) && EPLRuntime.truthy({r}))'
+            if op == 'or':
+                return f'(EPLRuntime.truthy({l}) || EPLRuntime.truthy({r}))'
             dyn = {

As per path instructions, epl/kotlin_gen.py must emit valid Kotlin syntax.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dynamic = lt in self._DYNAMIC or rt in self._DYNAMIC
# Dynamic operands can't use Kotlin's native operators; route to EPLRuntime.
if dynamic:
dyn = {
'*': 'eplMul',
'-': 'eplSub',
'%': 'eplMod',
'**': 'eplPow',
'<': 'eplLt',
'>': 'eplGt',
'<=': 'eplLe',
'>=': 'eplGe',
'==': 'eplEq',
}
if op in dyn:
return f'EPLRuntime.{dyn[op]}({l}, {r})'
if op == '!=':
return f'(!EPLRuntime.eplEq({l}, {r}))'
if op == '//':
return f'kotlin.math.floor(EPLRuntime.toDecimal(EPLRuntime.eplDiv({l}, {r}, {node.line}))).toInt()'
# `+` on a dynamic left is add-or-concat at runtime (String left concats natively).
if op == '+' and lt != 'String':
return f'EPLRuntime.eplAdd({l}, {r})'
dynamic = lt in self._DYNAMIC or rt in self._DYNAMIC
# Dynamic operands can't use Kotlin's native operators; route to EPLRuntime.
if dynamic:
if op == 'and':
return f'(EPLRuntime.truthy({l}) && EPLRuntime.truthy({r}))'
if op == 'or':
return f'(EPLRuntime.truthy({l}) || EPLRuntime.truthy({r}))'
dyn = {
'*': 'eplMul',
'-': 'eplSub',
'%': 'eplMod',
'**': 'eplPow',
'<': 'eplLt',
'>': 'eplGt',
'<=': 'eplLe',
'>=': 'eplGe',
'==': 'eplEq',
}
if op in dyn:
return f'EPLRuntime.{dyn[op]}({l}, {r})'
if op == '!=':
return f'(!EPLRuntime.eplEq({l}, {r}))'
if op == '//':
return f'kotlin.math.floor(EPLRuntime.toDecimal(EPLRuntime.eplDiv({l}, {r}, {node.line}))).toInt()'
# `+` on a dynamic left is add-or-concat at runtime (String left concats natively).
if op == '+' and lt != 'String':
return f'EPLRuntime.eplAdd({l}, {r})'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@epl/kotlin_gen.py` around lines 2484 - 2506, Extend the dynamic operator
dispatch in the Kotlin generation logic to handle `and` and `or` via EPLRuntime
truthiness helpers, rather than allowing dynamic operands to fall through to
native Kotlin `&&` or `||`. Update the `dyn` mapping or equivalent branch around
the dynamic handling block, using the existing runtime conventions and emitting
valid Kotlin expressions.

Source: Path instructions

Comment on lines +614 to +620
// ─── Sandboxed file bridge (file_* builtins) ───
// Paths resolve inside the app's private filesDir; a bare name or relative path
// never escapes the sandbox, matching Android's per-app storage model.
private fun resolveFile(path: String): java.io.File {
val base = EPLApplication.instance.applicationContext.filesDir
val f = java.io.File(path)
return if (f.isAbsolute) f else java.io.File(base, path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate the checked-in runtime source that emits this duplicated fixture code.
rg -n -C5 'private fun resolveFile\(path: String\)' epl scripts tests

Repository: abneeshsingh21/EPL

Length of output: 16747


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the generator and the affected fixture/source for the file bridge logic.
sed -n '35,60p' scripts/_gen_kotlin_runtime.py
printf '\n--- fixture 1 ---\n'
sed -n '614,626p' tests/fixtures/android_epl_runtime__com_acme_demo.kt
printf '\n--- fixture 2 ---\n'
sed -n '614,626p' tests/fixtures/android_epl_runtime__com_epl_app.kt

# Read-only probe: show how the current logic treats absolute paths and ../ traversal.
python3 - <<'PY'
import os

base = "/app/filesDir"
samples = [
    "/etc/passwd",
    "notes.txt",
    "../shared_prefs/config.json",
    "subdir/../../secret.txt",
]

for p in samples:
    resolved = p if os.path.isabs(p) else os.path.join(base, p)
    print(f"{p!r} -> {resolved!r} | abs={os.path.isabs(p)} | norm={os.path.normpath(resolved)!r}")
PY

Repository: abneeshsingh21/EPL

Length of output: 3479


Harden the Android file bridge before regenerating the fixtures. Absolute paths bypass filesDir, and .. segments can escape it, so file_* can read/write outside the intended app sandbox. Fix scripts/_gen_kotlin_runtime.py and regenerate both Android fixtures.

📍 Affects 2 files
  • tests/fixtures/android_epl_runtime__com_acme_demo.kt#L614-L620 (this comment)
  • tests/fixtures/android_epl_runtime__com_epl_app.kt#L614-L620
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/fixtures/android_epl_runtime__com_acme_demo.kt` around lines 614 - 620,
The resolveFile implementation generated by scripts/_gen_kotlin_runtime.py must
always confine paths beneath filesDir: reject or safely normalize absolute paths
and prevent .. traversal from escaping the sandbox. Update the generator’s
resolveFile logic, then regenerate both
tests/fixtures/android_epl_runtime__com_acme_demo.kt (lines 614-620) and
tests/fixtures/android_epl_runtime__com_epl_app.kt (lines 614-620) with the
hardened implementation.

Comment thread tests/test_kotlin_gen.py
Comment on lines +162 to +175
def test_class_method_call_return_type_resolved():
"""A call on a user-class instance resolves the class's declared method
return type, not the generic builtin `.add` ⇒ Unit mapping."""
kt = to_kt(
'Class Calc\n'
' Function addup takes a and b\n'
' Return a + b\n'
' End\n'
'End\n'
'c = new Calc\n'
's = c.addup(1, 2)\n'
'Print s'
)
assert 'var s: Unit' not in kt

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Assert the expected return type positively.

'var s: Unit' not in kt also passes for incorrect types or missing declarations. Assert the exact method signature and s declaration—or compile the generated source.

As per path instructions, tests must use meaningful assertions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_kotlin_gen.py` around lines 162 - 175, Strengthen
test_class_method_call_return_type_resolved by positively asserting that the
generated Kotlin includes the expected Calc.addup method signature returning the
inferred numeric type and declares s with that same type, rather than only
checking that Unit is absent. Ensure the assertions still verify the generated
source contains the complete method and variable declarations.

Source: Path instructions

Comment thread tests/test_kotlin.py
Comment on lines +284 to +291
def test_math_builtins_accept_dynamic_args():
# floor/sqrt/abs on a division result (eplDiv returns Any) must coerce via
# EPLRuntime.toDecimal, not `.toDouble()` on Any (unresolved reference).
code = gen('Print floor(7 / 2).')
assert 'EPLRuntime.toDecimal(' in code
assert '.toDouble()).toInt()' not in code or 'toDecimal' in code
# abs preserves int-vs-decimal parity via the runtime helper.
assert 'EPLRuntime.absNum(' in gen('Print absolute(-5).')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the tautological assertion branch.

Line 288 already proves 'toDecimal' in code, so the second assertion always succeeds through its or branch.

-    assert '.toDouble()).toInt()' not in code or 'toDecimal' in code
+    assert '.toDouble()).toInt()' not in code

As per path instructions, test files must use meaningful assertions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_math_builtins_accept_dynamic_args():
# floor/sqrt/abs on a division result (eplDiv returns Any) must coerce via
# EPLRuntime.toDecimal, not `.toDouble()` on Any (unresolved reference).
code = gen('Print floor(7 / 2).')
assert 'EPLRuntime.toDecimal(' in code
assert '.toDouble()).toInt()' not in code or 'toDecimal' in code
# abs preserves int-vs-decimal parity via the runtime helper.
assert 'EPLRuntime.absNum(' in gen('Print absolute(-5).')
def test_math_builtins_accept_dynamic_args():
# floor/sqrt/abs on a division result (eplDiv returns Any) must coerce via
# EPLRuntime.toDecimal, not `.toDouble()` on Any (unresolved reference).
code = gen('Print floor(7 / 2).')
assert 'EPLRuntime.toDecimal(' in code
assert '.toDouble()).toInt()' not in code
# abs preserves int-vs-decimal parity via the runtime helper.
assert 'EPLRuntime.absNum(' in gen('Print absolute(-5).')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_kotlin.py` around lines 284 - 291, Simplify
test_math_builtins_accept_dynamic_args by removing the tautological assertion
branch that checks '.toDouble()).toInt()' with an always-satisfied 'or'
condition. Keep meaningful assertions that verify EPLRuntime.toDecimal is used
for floor and EPLRuntime.absNum is used for absolute.

Source: Path instructions

Comment thread tests/test_stdlib_inliner.py Outdated
Comment on lines +48 to +61
def test_transitive_dependency_pulled_in():
# capitalize is used; if it calls another stdlib helper, that must come too.
prog = _parse('Import "string"\nSay capitalize("hello")\n')
out = inline_stdlib_imports(prog)
assert 'capitalize' in _def_names(out)


def test_callee_precedes_caller():
prog = _parse('Import "string"\nSay title_case("a b")\n')
out = inline_stdlib_imports(prog)
names = _def_names(out)
# title_case depends on capitalize → capitalize must be emitted first.
if 'capitalize' in names and 'title_case' in names:
assert names.index('capitalize') < names.index('title_case')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Make dependency assertions unconditional.

The first test only checks the requested definition; the second passes when either dependency is missing. Use title_case and require both definitions and their order.

Proposed fix
 def test_transitive_dependency_pulled_in():
-    prog = _parse('Import "string"\nSay capitalize("hello")\n')
+    prog = _parse('Import "string"\nSay title_case("hello world")\n')
     out = inline_stdlib_imports(prog)
-    assert 'capitalize' in _def_names(out)
+    names = _def_names(out)
+    assert 'title_case' in names
+    assert 'capitalize' in names

 def test_callee_precedes_caller():
     ...
-    if 'capitalize' in names and 'title_case' in names:
-        assert names.index('capitalize') < names.index('title_case')
+    assert names.index('capitalize') < names.index('title_case')

As per path instructions, test files must provide meaningful assertions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_transitive_dependency_pulled_in():
# capitalize is used; if it calls another stdlib helper, that must come too.
prog = _parse('Import "string"\nSay capitalize("hello")\n')
out = inline_stdlib_imports(prog)
assert 'capitalize' in _def_names(out)
def test_callee_precedes_caller():
prog = _parse('Import "string"\nSay title_case("a b")\n')
out = inline_stdlib_imports(prog)
names = _def_names(out)
# title_case depends on capitalize → capitalize must be emitted first.
if 'capitalize' in names and 'title_case' in names:
assert names.index('capitalize') < names.index('title_case')
def test_transitive_dependency_pulled_in():
# capitalize is used; if it calls another stdlib helper, that must come too.
prog = _parse('Import "string"\nSay title_case("hello world")\n')
out = inline_stdlib_imports(prog)
names = _def_names(out)
assert 'title_case' in names
assert 'capitalize' in names
def test_callee_precedes_caller():
prog = _parse('Import "string"\nSay title_case("a b")\n')
out = inline_stdlib_imports(prog)
names = _def_names(out)
# title_case depends on capitalize → capitalize must be emitted first.
assert names.index('capitalize') < names.index('title_case')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_stdlib_inliner.py` around lines 48 - 61, Strengthen
test_transitive_dependency_pulled_in and test_callee_precedes_caller so
dependency presence is asserted unconditionally: require both title_case and
capitalize in the emitted definitions, then assert capitalize appears before
title_case. Remove the conditional guard that allows the ordering test to pass
when either definition is missing.

Source: Path instructions

@abneeshsingh21
abneeshsingh21 merged commit 7dc9b41 into main Jul 17, 2026
18 checks passed
@abneeshsingh21
abneeshsingh21 deleted the fix/kotlin-swift-native-production branch July 17, 2026 21:27
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant