compiler: allow unnamed -> named tuples conversions on name match#2642
Conversation
bf57c04 to
1d835df
Compare
borisbat
left a comment
There was a problem hiding this comment.
- documentation. update tuple.rst (or whatever its called) - when it would match, and what it would and would-not match
- language tutorial on tuples should expand on this
- update serializer version
There was a problem hiding this comment.
Pull request overview
This PR adds compiler support for treating bare-variable tuple literals as named tuples when their variable names match the target tuple field names, addressing #2641.
Changes:
- Tracks shorthand tuple field names during parsing.
- Seeds tuple record types during inference for typed variable initialization and function-call matching.
- Adds language tests for successful shorthand tuple use and mismatch failure.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
utils/dasFormatter/ds_parser.ypp |
Mirrors tuple shorthand metadata collection in formatter parser. |
tests/language/tuple.das |
Adds successful shorthand tuple language tests. |
tests/language/failed_tuple_shorthand_mismatch.das |
Adds expected-failure test for mismatched shorthand names. |
src/parser/parser_impl.h |
Declares shorthand tuple name collection helper. |
src/parser/parser_impl.cpp |
Implements shorthand tuple name collection from bare variables. |
src/parser/ds2_parser.ypp |
Adds shorthand metadata collection to gen2 parser grammar. |
src/parser/ds2_parser.cpp |
Regenerated gen2 parser output. |
src/parser/ds_parser.ypp |
Adds shorthand metadata collection to parser grammar. |
src/parser/ds_parser.cpp |
Regenerated parser output. |
src/builtin/module_builtin_ast_serialize.cpp |
Serializes new tuple shorthand metadata. |
src/ast/ast.cpp |
Preserves shorthand metadata when cloning tuple expressions. |
src/ast/ast_infer_type.cpp |
Seeds shorthand tuple record types from typed let/global initializers. |
src/ast/ast_infer_type_make.cpp |
Promotes matching shorthand names into tuple record names. |
src/ast/ast_infer_type_function.cpp |
Attempts shorthand-based function-call rematching. |
include/daScript/ast/ast_infer_type.h |
Declares new inference hooks/helpers. |
include/daScript/ast/ast_expressions.h |
Adds tuple shorthand metadata storage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| vector<TypeDeclPtr> hypTypes; | ||
| hypTypes.reserve(expr->arguments.size()); | ||
| for (auto arg : expr->arguments) hypTypes.push_back(arg ? arg->type : nullptr); | ||
| for (size_t idx : shorthandIndices) { | ||
| auto mkt = static_cast<ExprMakeTuple*>(expr->arguments[idx]); | ||
| auto hyp = new TypeDecl(*mkt->type); | ||
| hyp->argNames = mkt->shorthandRecordNames; | ||
| hypTypes[idx] = hyp; | ||
| } | ||
| MatchingFunctions hypFns, hypGens; | ||
| findMatchingFunctionsAndGenerics(hypFns, hypGens, expr->name, hypTypes); | ||
| if (hypFns.size() + hypGens.size() != 1) return false; | ||
| for (size_t idx : shorthandIndices) { | ||
| auto mkt = static_cast<ExprMakeTuple*>(expr->arguments[idx]); | ||
| mkt->recordType = new TypeDecl(*mkt->type); | ||
| mkt->recordType->argNames = mkt->shorthandRecordNames; | ||
| mkt->recordType->ref = false; | ||
| mkt->recordType->constant = false; | ||
| } | ||
| return true; |
There was a problem hiding this comment.
I don't see how to resolve it cleanly.
What we do now: promote everything to named.
What you suggest: promote to named one by one, attempting to match function.
Your scenario misses the case:
foo((x,y), (a,b)) -> foo(tuple<x:int;y:float>, tuple<a:int;b:float>)
My scenario misses case:
foo((x,y), (a,b)) -> foo(tuple<x:int;y:float>, tuple<int;float>)
| var arr : array<tuple<eid : int; distSq : float>> | ||
| let eid = 7 | ||
| let distSq = 2.5 | ||
| arr |> push((eid, distSq)) |
There was a problem hiding this comment.
how do i tell it to explicitly be nameless. say there are TWO push functions
push ( a : tuple<int,float> )
push ( a : tuple<edi:int, distSq:float> )
and i write push((eid,distSq)) - which one would it pick?
There was a problem hiding this comment.
We give priority to unnamed tuples:
if (functions.empty() && generics.empty() && trySeedTupleShorthand(expr)) {
So we will try this feature only if nothing matched earlier.
This code works fine and prints 1. I will add it to tests anyway.
def foo(x : tuple<int; float>) {
print("1")
}
def foo(x : tuple<x: int; y: float>) {
print("2");
}
[export]
def main{
var x = 123
var y = 321.
foo((x, y))
}
0b57c1f to
f2981e6
Compare
It's useful to be able to not repeat yourself. If tuple names exactly match variable names we want to assign we should allow to write unnamed tuple. See tests for more details.
f2981e6 to
6d29e57
Compare
Support unnamed -> named promotion for return tuples as well.
It's useful to be able to not repeat yourself. If tuple names exactly match variable names we want to assign we should allow to write unnamed tuple. See tests for more details.
Closes #2641