B3: the shape checks Part A could not remove - #17
Merged
Conversation
This was referenced Aug 6, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds the remaining B3 validation checks that Part A couldn’t make unrepresentable, by validating declaration shapes that depend on cross-field relationships or declaration context (container).
Changes:
- Add shape validation for: bare properties (
val x), enum entries missing constructor arguments, and bodiless functions in disallowed containers. - Track declaration container context (
file/interface/abstract class/concrete) to validate bodiless-function legality. - Extend and adjust tests to cover the new checks and update incidental bodiless functions to include bodies.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/validate.rs | Introduces B3 shape checks (property, enum entry, function body) with container-aware traversal. |
| src/tests.rs | Adds targeted tests for the new checks and updates existing tests to satisfy the new function-body rule. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+556
to
+571
| if let KtClassKind::Enum { ctor, entries } = &c.kind { | ||
| if !ctor.is_empty() { | ||
| for e in entries.iter().filter(|e| e.args.is_none()) { | ||
| d.push( | ||
| Check::EnumEntryMissingArguments, | ||
| &inner, | ||
| format!( | ||
| "entry `{}` passes no arguments, but the enum declares {} \ | ||
| constructor parameter(s)", | ||
| e.name, | ||
| ctor.len() | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
| } |
Comment on lines
+529
to
+533
| Container::Abstract => f | ||
| .modifiers | ||
| .iter() | ||
| .any(|m| m.split(' ').any(|w| w == "abstract")), | ||
| Container::File | Container::Concrete => false, |
Three shapes are still buildable after the structural work, because each depends on a relation between fields or on where a declaration sits rather than on one field's type: * `val x` with no type, no value and no accessors * an enum entry passing no arguments to a constructor the enum declares * a function with no body somewhere that does not mean "abstract" The last one needs context, so the walker tracks its container: an interface member is abstract by position and needs no keyword; a member of an abstract or sealed class may be abstract but has to say so; at top level, inside a concrete class, or inside a companion — which is concrete — a body is always required. `external` is a body kind since A5, so it is never flagged. The property check is deliberately narrow. Only the all-three-absent case is unambiguously wrong: a type alone is an abstract property and a value alone infers its type, so flagging either would be a false positive. Tested. Two existing tests built bodiless functions incidentally while asserting something else; they now supply bodies.
milyin
force-pushed
the
step/b3-shape-checks
branch
from
August 6, 2026 11:40
133b37d to
42419dc
Compare
milyin
force-pushed
the
step/b2-scopes-and-namespaces
branch
from
August 6, 2026 11:40
4405e14 to
093b90d
Compare
milyin
changed the base branch from
step/b2-scopes-and-namespaces
to
docs/validation-umbrella
August 6, 2026 11:41
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step B3 of #6. Stacked on #16. Last of the checks.
Part A (#7–#11) made most bad shapes unbuildable. Three survive, because each
depends on a relation between fields or on where a declaration sits rather
than on one field's type — neither of which a type in the model can capture.
property-without-type-or-valueval x— no type, no value, no accessorsenum-entry-missing-argumentsenum class K(val code: Int) { A(1), B }function-without-bodyfun run()at top levelThe bodiless-function rule needs context
The walker tracks what encloses each declaration:
interface/sealed interfaceabstract/sealedclassabstractA companion is concrete, which is easy to overlook: an interface's companion
object holds real code, so its members need bodies even though the interface's
own members do not. Tested.
externalhas been a body kind since A5 (#11) rather than a modifier, so anexternal funis never flagged here — it has a body kind, just not a body.The property check is deliberately narrow
Only the all three absent case is flagged. A type alone is an abstract
property; a value alone infers its type; accessors alone is the third legal
shape. Flagging any of those would be a false positive, so the check stays on
the one case that is unambiguously wrong. There is a test asserting all four
legal shapes pass.
Verification
All 80 pre-existing tests pass. Six added, including the negative cases: an enum
with no constructor needing no entry arguments, and the four legal property
shapes.
Two existing tests built bodiless functions incidentally while asserting
something else (import collection, identifier checks); they now supply bodies.