Constructors#19
Merged
Merged
Conversation
arguments are available during type body evaluation, and NOT during field evaluation; must be explicitly assigned as slots Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
Revert the ClassBlock/ClassExpr/ClassDecl grammar duplication from cca0cdf. Parsing new() anywhere simplifies the grammar and allows better error messages to be raised at a later phase.
NewConstructorDecl.Infer now returns a descriptive InferError with source annotation instead of silently succeeding. Inside a class body, Infer is never called directly (ClassDecl.inferNewConstructor handles it), so the error only triggers for misplaced constructors.
The formatter was missing cases for NewConstructorDecl in formatNode, nodeLocation, and isFunctionDef, causing format-then-reparse to fail for files with explicit constructors.
Documents how to run tests, update error golden files, add new error tests, and use the error reporting infrastructure.
Constructor arguments now follow the same formatting rules as field definition arguments, including multiline splitting based on line length, docstrings, and directives.
Move test-mismatch and test-private-arg from mod/ into dagger-sdk/testdata/ and add corresponding test methods in the DaggerSDKSuite. The old standalone modules are removed.
If a user writes `pub new(...): Foo! { ... }` inside a type body,
the parser treats it as a regular method named "new" and produces a
confusing type error. Now we check for slots named "new" during
class inference and emit a clear error pointing them to the correct
`new(...) { ... }` syntax.
These tests predated real constructors and used 'new' as a regular field name, which now conflicts with constructor syntax. Migrated to proper new() constructors or removed the field where unnecessary.
Verifies that fields can be assigned without 'self.' prefix when constructor arg names don't shadow the field names.
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.
This PR adds support for explicit constructor definitions in Dang using the
new(...) { ... }syntax. This enables constructor arguments that are not automatically exposed as fields, which is essential for Dagger module serialization where some constructor inputs shouldn't be persisted.Motivation
Previously, Dang derived constructors from public fields - constructor parameter names matched field names exactly. This caused issues with Dagger's serialization model:
New Syntax
Key features:
new()bodynew()implicitly returnsselfnew()is only valid inside class bodies (parse error elsewhere)Changes
Grammar (
pkg/dang/dang.peg)NewConstructorrule:new(args) { block }ClassExprandClassBlockto restrictnew()to class bodiesClassrule now usesClassBlockinstead of genericBlockAST (
pkg/dang/slots.go)NewConstructorDeclstruct withArgs,BodyBlock,DocString,LocClassDeclmethods updated to find and handleNewConstructorDeclfindNewConstructor()andbodyFormsWithoutNew()helpersType Inference (
pkg/dang/slots.go)ClassDecl.Hoist: Usesnew()args if present, otherwise derives from fieldsClassDecl.Infer: Separately infersnew()body with args in scopeinferNewConstructor(): Adds constructor args to env before inferring bodyEvaluation (
pkg/dang/eval.go)ConstructorFunctionnow hasNewBody *BlockfieldConstructorFunction.Call:new()body with access toselfand argscheckRequiredFields(): Runtime validation of field assignmentDagger SDK (
dagger-sdk/entrypoint/main.go)SlotDecl.Eval'sGetLocalcheck prevents defaults from clobbering loaded stateBackwards Compatibility
new()continue to derive constructors from fields (existing behavior)Tests
tests/test_explicit_constructor.dang: Comprehensive test casestests/errors/constructor_arg_in_method_body.dang: Verifies args scoped tonew()tests/errors/new_outside_class.dang: Verifiesnew()only valid in class bodiesmod/test-mismatch/: Tests constructor arg names differing from field namesmod/test-private-arg/: Updated to use new syntaxExample: Dagger Module
Here
source2is the constructor arg (with Dagger directives), butsourceis the serialized field. The arg name doesn't need to match the field name.