Repository navigation
fix(kotlin): a trailing-lambda scope function never binds a Java method (#155) - #438
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
| Layer / File(s) | Summary |
|---|---|
Capture and persist trailing-lambda syntax src/langfacts.h, src/model.h, src/ingest_metrics.h, src/ingest_sidecap.h, src/ingest_model.h, src/ingest_cache.h, src/quality.h, test/cachefuzzcheck.sh, test/pyimportprecisecheck.sh, test/qschemetripcheck.sh |
Kotlin language facts enable detection of a direct trailing lambda. The flag is transferred to references and added to cache records. Cache and parser versions and cache-layout checks are updated. |
Filter scope-function candidates src/externalnames.h, src/graph.h, docs/ARCHITECTURE.md, changelog.d/155-kotlin-scope-functions.md |
A sorted name table identifies the five scope functions. Graph resolution filters non-Kotlin candidates for matching trailing-lambda calls before receiver checks and skips later receiver narrowing for those calls. The documentation describes the behavior and stated limits. |
Validate resolution and cache behavior test/kotlincheck.sh, test/falseedgecheck.sh |
Kotlin fixtures check candidate bindings, external census rows, Java caller and map stability, mutation behavior, deterministic cache output, and XML validity. |
Priority:
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested reviewers: joyful-ii-v-i
Merge Risk: 
Minimal · up to 70999
-
No actionable issue is established for this change. Merge after the normal required checks.
Pre-merge checks: 
4
-
Full details: Title check
-
Explanation
The title "fix(kotlin): a trailing-lambda scope function never binds a Java method (
#155)" matches the main change. The changeset adds a per-call trailing-lambda flag and a Kotlin false-edge rule. That rule drops Java method candidates for trailing-lambda calls to let, run, with, apply, and also, and it keeps Kotlin candidates. The title names the Kotlin scope-function scope and the Java-binding fix. It also carries the conventional fix(kotlin) prefix and the issue reference#155. The title is accurate and specific, and it fits a teammate scanning history.
Full details: Linked Issues check
-
Explanation
Issue
#155coding requirements, from the issue body and the current PR description:- Remove false Java edges for Kotlin trailing-lambda calls to run, let, apply, also, with. Met. The Kotlin arm in FalseEdgeRules (FE-A) drops non-Kotlin candidates for these calls. The rule runs before the receiver gate. Typed receivers skip receiver narrowing for these calls.
- Keep Kotlin candidates. Met. Kotlin candidates survive the filter. A Kotlin-defined run stays a candidate, and kotlincheck section 15 is described as checking this.
- Report unbound sites as external. Met. When filtering leaves no candidate, the call resolves to external=. Refused sites appear in the external census.
- Preserve the real block.run() edge on a Runnable. Met by construction. The per-call fact is set only when kotlinTrailingLambda finds an annotated_lambda under call_suffix. Calls without a trailing lambda keep their edges. Section 15 includes a mutation that removes the trailing lambda and checks that the Java edge returns. The fixtures that hold the Runnable case are in excluded paths (test/falseedgefix/**), so their run results are not independently verified. The rule gate alone establishes the behavior.
- Cached per-call-site fact in the reference record. Met. Reference::trailingLambda is carried through RawRef, writeRef and readRef (one byte, kMinRefRecordBytes 60 to 61). The quality mirrors and walkers in cachefuzzcheck and pyimportprecisecheck follow the new layout.
- Sorted name table in src/externalnames.h. Met. kKotlinScopeFunctionNames holds also, apply, let, run, with. A compile-time sortedness and uniqueness check and an isKotlinScopeFunction binary search are added.
- Version bumps, mirrors and pins. Met. kParserVer 224 to 228 and kCacheVersion 39 to 41, with mirrors in quality.h. A re-pin log entry is added in qschemetripcheck.sh. The PR states that 228 and 41 are placeholders.
- Kotlin test section in test/kotlincheck.sh. Met. Section 15 is added.
Not assessed as a coding requirement: the measurements on retrofit, nowinandroid and ktor. They are verification runs, not code. The PR does not report them. The issue prompt (prompts/help-wanted/kotlin-scope-functions.md) is not in the supplied evidence. No requirement from it is assessed.
Known limits stated in the PR (parenthesized lambdas, Java scope-name methods called with a trailing lambda, qualified kotlin.run) are not in the issue's stated requirements, so they do not fail this check.
Full details: Out of Scope Changes check
-
Explanation
Every included change ties to the
#155trailing-lambda fix:- Core behavior: Reference::trailingLambda (model.h), RawRef and cache record (ingest_cache.h), emitReferences copy (ingest_model.h), kotlinTrailingLambda helper (ingest_metrics.h), C++ capture gated by langFacts trailingLambdaScopeFns (ingest_sidecap.h, langfacts.h), name table (externalnames.h), FE-A rule (graph.h).
- Required version and mirror updates: quality.h mirrors, parser and cache version constants, cache walkers in cachefuzzcheck.sh and pyimportprecisecheck.sh, re-pin log in qschemetripcheck.sh.
- Tests and docs for the feature: kotlincheck.sh section 15, falseedgecheck.sh arm J, changelog fragment, ARCHITECTURE.md section.
- Showcase capture regeneration (docs/captures, ignored path): a generated artifact of the behavior change. Its contents were not inspected because the path is excluded. Its absence or presence does not change this verdict.
The Java-edge loss for same-named Java methods called from Kotlin with a trailing lambda is the intended effect of the rule. The PR discloses it as a known floor. It is not an unrelated change.
The qschemetrip.hash re-pin is described as a separate commit. The hash path is excluded and was not inspected.
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
Comment @coderabbitai help to get the list of available commands.
f807568 to
ad69a52
Compare
…od (redhat-et#155) A Kotlin call to run, let, apply, also or with that has a trailing lambda is the stdlib scope function. FE-A now drops the non-Kotlin candidates for it. An emptied set lands as external= with proof. One new u8 on the call record carries the trailing-lambda fact. kParserVer 228 and kCacheVersion 41 are placeholders above every live value. The qschemetrip re-pin is the next commit. Co-Authored-By: Claude <noreply@anthropic.com>
ad69a52 to
64aab91
Compare
Co-Authored-By: Claude <noreply@anthropic.com>
|
CI note: the only failure on the last run was cppqualcheck on macos-26 (shard 3/4), a 30 s alarm on two --uses queries while the runner was heavily loaded (3100 s wall). It is not related to this change. I cannot rerun jobs, so I pushed again to start a fresh run. |
64aab91 to
4438f15
Compare
… calls (redhat-et#155 review B1) The scope-function arm skipped every receiver rule for let/run/with/apply/also with a trailing lambda, so t.run { } on a t: Task split over every Kotlin run via="name". Rule 2 and FE-B receiver evidence run again; a pick holding a non-Kotlin method is undone and FE-A decides the call. kotlincheck 15l (typed and constructed receivers) and 15m (no via="name" on tree C's go row) are red at 4438f15 and green here. Floors reworded: a Java-typed receiver is not checked; qualified kotlin.run { } can bind an in-tree run. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…edhat-et#155 review B2) kKotlinScopeFunctionNames is asserted sorted by the shared isStrictlySortedTable, and kotlinTrailingLambda reads call_suffix then annotated_lambda with firstChildOfKind instead of a nested forEachChild. Behaviour is unchanged. The one remaining one-line idiom clone (inSortedTable ~ isMarkdownGrammarExtension) is acked: no shared helper fits two different tables across docparse.h and externalnames.h. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…edhat-et#155 review B3) Both were generated from a checkout rooted at /w, and the generator's path scrub replaced every /w with '.', corrupting about 36 spans in the capture and 25 in COMMANDS.md. They are restored to the base state here and regenerated on the merged tree at landing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Thank you @llvm-x86. This is a careful piece of work, and it follows the #155 plan closely: one per-call fact, an FE-A arm instead of a new standalone rule, a name table with a regenerating
Three things came out of review, and we made all of them as commits on top of your head so you don't have to. We pushed them to your
After these commits, at the new head, on macOS (AppleClang dev build, plus an llvm@22 ASan build for the first two): Still open, for you or a follow-up:
Versions: we renumber |
|
Thank you for the review and the three commits. I will not push to this branch again. About the capture: that was my fault. I generated it in a /w checkout and did not check the path scrub. Dropping both files was the right fix. About the arity-0 question: I did not consider it, and I think it is the better design. A Java candidate with no parameters cannot be the target of a trailing-lambda call. A candidate with a parameter can be (Exec.run(Runnable)). So dropping only the arity-0 candidates and hedging the rest turns the floor into a hedge, and it brings back the e.run { } edge that main had. I agree it is a follow-up, not a blocker. I can open it as a separate issue or PR on top of this one after it lands, if you want. |
Train 36: Kotlin scope functions (#438) + framework hooks not dead (#437), @llvm-x86; G1 coverage (#431), @liziye627-design
…est hooks + closure self-dispatch (maintainer head 80dbb88) Conflicts vs redhat-et#438: src/langfacts.h field block (both facts kept), test/qschemetripcheck.sh RE-PIN LOG (both entries kept), test/qschemetrip.hash and changelog.d/versions.md (re-derived in the train's versions commit). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s; refuse a scratch dir inside the repo A checkout at /w made the capture's plain str.replace turn src/wrap into src.rap and .github/workflows into .github.orkflows (redhat-et#438 review: ~61 spans). exportscrub.scrub_root replaces a root only where no path character precedes or follows it; the scratch dir is scrubbed first, and showcase_capture refuses a scratch dir inside the checkout (it would publish as ./build/... instead of <scratch>). showcasecapturecheck arm (S): byte-exact over a ROOT=/w text, a plain-replace mutant must differ, and the inside-repo refusal (red before this commit: 2 FAIL). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eme 24; qschemetrip re-derived once Renumbers redhat-et#438's placeholders (228 / 41) and redhat-et#437's (scheme 23) strictly above every live value: main / train 35 226 / 40 / 22, every origin ref and open PR head, lane rust-degraded's placeholder 229 (rich 230) / 42. quality.h mirrors follow (their 40 = train 34 / 226 = 2026-10-24 history lines restored), the pyimportprecisecheck cache walker reads 43, changelog.d/versions.md states it once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ain-36 composed binary One regen for redhat-et#431 + redhat-et#438 + redhat-et#437 with the whole-path scrub (redhat-et#438's /w-corrupted capture was dropped in 24d8554). 265 commands, clean tree; dictv unchanged (8c941c6c17d27549 / 932). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fragments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The vendored tree-sitter-rust predates precise capturing (Rust 1.82). It reads use<..> as a generic type named use, and an EMPTY `+ use<>` needs a MISSING type; around a long enough body the recovery collapses the whole file into one root ERROR node (err_ratio=1.000), and every associated fn loses its impl owner. On zed that is 25 files, among them workspace/src/pane.rs, workspace/src/workspace.rs and language/src/buffer.rs, so Pane::save_item, Workspace::new_local and Buffer::edit could not bind. src/rustusebounds.h is the Rust layer of the blank-and-re-parse family in src/macroreparse.h: for a Rust file whose first parse holds error bytes it names each bound (`+ use<..>`, or `use<..> +` right after impl), blanks exactly those bytes (offsets and lines unchanged), re-parses, and adopts the second tree only with strictly fewer error bytes. A use<..> list names only in-scope generics and lifetimes, so nothing the index records is lost. Disclosed on --skipped: why=use-bounds-blanked, use_bounds_blanked=, use_bounds_blanked_files=; the count rides the cache record. Gate: test/macroreparsecheck.sh section RS (RS1 owners bind at the original line, RS2 disclosure, RS3 controls byte-identical, RS4 base reproduces, RS5 warm cache) and 19 Rust cases in test/macroreparse_unit.cpp. kParserVer 226 -> 229 and kCacheVersion 40 -> 42 are PLACEHOLDERS above the live values (redhat-et#438's 228, redhat-et#155's 41), renumbered at landing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #155, built to the plan the maintainer approved on the issue.
Problem. A Kotlin call with a trailing lambda to
let/run/with/apply/alsois the stdlib scope function. Ripwire bound it to a Java method of the same name (s.run { }toJob.run).Change.
Reference::trailingLambda, carried throughRawRef, the cache record (+1 byte,kMinRefRecordBytes60 to 61) and the quality mirrors.FalseEdgeRules(FE-A) drops non-Kotlin candidates for these calls and reportsexternal=when none is left. Kotlin candidates stay. Calls without a trailing lambda keep their edges.b: lib.Builderthenb.apply { }) skip receiver narrowing for these calls. Review found this case binding the Java method.externalnames.hwith a javap provenance command and a sortednessstatic_assert. The Kotlin predicates sit in aLangFactscolumn (trailingLambdaScopeFns), so the langidentity ratchet does not rise.kotlinchecksection 15,falseedgecheckarm J with fixtures. Walkers incachefuzzcheckandpyimportprecisecheckfollow the new record layout. Showcase capture regenerated.Versions.
kParserVer228 andkCacheVersion41 are placeholders; please renumber at landing. Theqschemetripre-pin is its own commit.Known floors (changelog fragment): parenthesised lambdas are not covered; a Java method of a scope-function name called from Kotlin with a trailing lambda is dropped; a qualified
kotlin.run { }can still bind an in-tree Kotlinrun.Checks. Three reviewers; the one real bug is fixed. Full suite on Linux (g++-14): the failures left were load timeouts and missing tools, and the suspect gates pass alone.
Summary by CodeRabbit
Bug Fixes
let,run,with,apply, andalsowith a trailing lambda no longer incorrectly match same-named Java methods. Kotlin candidates are retained, and calls without a matching Kotlin target are reported as external.runretain their existing behavior.Documentation