super: walk up inheritance chain past empty intermediates#2594
Merged
super: walk up inheritance chain past empty intermediates#2594
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes several inheritance “skip-level” edge cases in daScript’s super lowering by making super()/super.method()/delete super.self resolve past empty intermediate classes/structs, and adds tests + documentation updates to lock in the intended behavior.
Changes:
- Move
super(args)constructor rewriting to post-visit type inference and add ancestor walk-up + improved diagnostics. - Update
delete super.selflowering to search up the inheritance chain for the nearest ancestor finalizer (skipping empty intermediates). - Add language tests for skip-level inheritance cases and update the reference docs accordingly.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/ast/ast_infer_type.cpp |
Adjusts inference-time rewrites for super() constructors, super calls, and delete super.self to walk up inheritance chains and improve diagnostics. |
tests/language/super.das |
Adds tests covering skip-level constructor and method resolution through an empty intermediate class. |
tests/language/super_finalize.das |
Adds tests ensuring delete super.self chains correctly past empty intermediates for both classes and structs. |
doc/source/reference/language/classes.rst |
Documents super walk-up behavior and updates delete super.self rewrite description. |
doc/source/reference/language/structs.rst |
Updates delete super.self rewrite description for structs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
3cda894 to
7a012af
Compare
Fixes three related gaps when an intermediate class/struct in the chain defines neither the constructor, the method being overridden, nor a finalizer. * `super()` constructor: rewritten in InferTypes::visit (post-visit), not preVisit, so argument types are populated. Walks up classParent->parent->... and matches by argument types. Previously crashed with SIGSEGV on `super(arg)` because preVisit fed null arg->type into findMatchingFunctions. * `super.method()` already had walk-up logic (visit ExprCall) but was missing this fix. * `delete super.self`: walks up selfStruct->parent looking for the nearest ancestor whose type resolves a user-defined `finalize`. Filters out auto-generated finalizers (generateStructureFinalizer / makeClassFinalize) via Function::generated, since they don't chain to ancestors. Previously cast unconditionally to the immediate parent, silently dropping ancestor finalizers when the parent was empty. Tests/language: 4 new skip-level cases for super/super.method in super.das and 4 new cases (1-empty, 2-empty, mid-chain, struct-skip) in super_finalize.das. classes.rst and structs.rst updated to describe the walk-up. 925/925 tests/language pass under both interpreter and AOT. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7a012af to
ae69669
Compare
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.
Summary
Fixes three related gaps in the
supermachinery when an intermediate class/struct defines no constructor, no method, or no finalizer.super()constructor. Was crashing with SIGSEGV onsuper(arg)because the rewrite ran inInferTypes::preVisit(ExprCall*), wherearg->typeis stillnullptrandfindMatchingFunctionssegfaults on null type lookups. Moved the rewrite tovisit(post-visit), where children are typed. Also added the walk-up loop and "no matching super constructor" / "too many candidates" diagnostics for parity withsuper.method().super.method(). Already had walk-up logic invisit(ExprCall*); left untouched, now exercised by new tests.delete super.self. Was always casting to the immediate parent, so a chain likeclass C : B {}/class B : A { def operator delete }silently dropped A's finalizer when invoked from C. Now walksselfStruct->parent->parent…and stops at the nearest ancestor whose type resolves a user-definedfinalize, filtering out auto-generatedgenerateStructureFinalizer/makeClassFinalizeviaFunction::generated(those don't chain).The walk-up matches by argument types, so overloaded
super(args)calls andsuper.method(args)overrides still pick the correct ancestor.What changed
src/ast/ast_infer_type.cpp— moved super constructor rewrite from preVisit to post-visit; added walk-up + diagnostics fordelete super.self.tests/language/super.das— 4 new skip-level tests (default ctor, ctor with args, method, method with args).tests/language/super_finalize.das— 4 new tests: 1-empty intermediate class, 2-empty deep class, mid-chain (only some ancestors define finalizers), struct skip-level.doc/source/reference/language/classes.rst— added a "walks up the inheritance chain to the nearest ancestor that does" subsection with a workedBase/Mid/Leafexample; updated thedelete super.selfrewrite description fromcast<Base>tocast<Ancestor>.doc/source/reference/language/structs.rst— same one-line correction fordelete super.self.Test plan
tests/language/super.das— 12/12 pass under interpreter and AOT (was 8 before; 4 new skip-level cases)tests/language/super_finalize.das— 8/8 pass under interpreter and AOT (was 4 before; 4 new skip-level cases)tests/language/— 925/925 pass under interpreter (was 917 before adding the 8 new cases)tests/language/under AOT (test_aot -use-aot) — 925/925 passtests/language/cant_delete_super_self.das(negative test) — still produces the same expected compile errorsexamples/wip.das(the original repro) compiles and runs🤖 Generated with Claude Code