From fc90afa7c6488ac91c198248a998826314528543 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 1 Oct 2026 08:17:10 +0200 Subject: [PATCH 1/3] Unified: Expand Swift dictionary literal corpus --- .../collections/dictionary-literal.output | 110 ++++++++++++++++-- .../collections/dictionary-literal.swift | 5 +- 2 files changed, 103 insertions(+), 12 deletions(-) diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output index 7993dd1a841a..0e7ec33aa15c 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output @@ -1,10 +1,51 @@ -let d = ["a": 1, "b": 2] +let key = "a" +let value = 1 +let d = [key: value, "b": 2] +let empty: [String: Int] = [:] --- sourceFile endOfFileToken: endOfFile statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "a" + pattern: + identifierPattern + identifier: identifier "key" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "value" codeBlockItem item: variableDecl @@ -25,15 +66,11 @@ sourceFile colon: : trailingComma: , value: - integerLiteralExpr - literal: integerLiteral "1" + declReferenceExpr + baseName: identifier "value" key: - stringLiteralExpr - closingQuote: " - openingQuote: " - segments: - stringSegment - content: stringSegment "a" + declReferenceExpr + baseName: identifier "key" dictionaryElement colon: : value: @@ -49,14 +86,65 @@ sourceFile pattern: identifierPattern identifier: identifier "d" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + dictionaryExpr + leftSquare: [ + rightSquare: ] + content: : + pattern: + identifierPattern + identifier: identifier "empty" + typeAnnotation: + typeAnnotation + colon: : + type: + dictionaryType + colon: : + leftSquare: [ + rightSquare: ] + value: + identifierType + name: identifier "Int" + key: + identifierType + name: identifier "String" --- top_level source="⟨body⟩" body: - block source="⟨stmt⟩" + block source="⟨stmt⟩\n⟨stmt⟩\n⟨stmt⟩\n⟨stmt⟩" stmt: + variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" + modifier: modifier "let" source="let" + pattern: identifier "key" source="key" + value: string_literal "\"a\"" source="\"a\"" + variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" + modifier: modifier "let" source="let" + pattern: identifier "value" source="value" + value: int_literal "1" source="1" variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: identifier "d" source="d" - value: map_literal "[\"a\": 1, \"b\": 2]" source="[\"a\": 1, \"b\": 2]" + value: map_literal "[key: value, \"b\": 2]" source="[key: value, \"b\": 2]" + variable_declaration source="⟨modifier⟩ ⟨pattern⟩: ⟨type⟩ = ⟨value⟩" + modifier: modifier "let" source="let" + pattern: identifier "empty" source="empty" + type: + generic_type_expr source="[⟨type_argument⟩: ⟨type_argument⟩]" + base: identifier "Dictionary" source="" + type_argument: + identifier "String" source="String" + identifier "Int" source="Int" + value: map_literal "[:]" source="[:]" diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.swift b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.swift index 1b9eb5ebe2c4..7f3d9ad7daec 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.swift +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.swift @@ -1 +1,4 @@ -let d = ["a": 1, "b": 2] +let key = "a" +let value = 1 +let d = [key: value, "b": 2] +let empty: [String: Int] = [:] From 60347a3479b15ed8cc3a9ff86c8f169ae88d8ada Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 30 Sep 2026 15:16:08 +0200 Subject: [PATCH 2/3] Unified: Extract Swift dictionary literals --- unified/extractor/src/languages/swift/swift.rs | 17 ++++++++++++++--- .../swift/collections/dictionary-literal.output | 10 +++++++++- .../switch-expression-pattern.output | 6 +++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 9bdb142eb28b..2af698a4bc98 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -958,9 +958,20 @@ fn translation_rules() -> Vec> { (array_literal element: {els}) ), rule!((arrayElement expression: @e) => expr { e }), - // A dictionary literal (`["a": 1]`) is kept as an opaque `map_literal` - // leaf (its source span). - rule!((dictionaryExpr) => (map_literal)), + // An empty dictionary literal, `[:]`. + rule!((dictionaryExpr content: ":") => (map_literal)), + // A non-empty dictionary literal, `[key: value]`. + rule!( + (dictionaryExpr content: (dictionaryElement)* @els) + => + (map_literal element: {els}) + ), + // A key-value pair, `key: value`. + rule!( + (dictionaryElement key: @key value: @value) + => + (key_value_pair key: {key} value: {value}) + ), // A subscript access (`xs[0]`) is modelled as a call. swift-syntax does // report a distinct `subscriptCallExpr`, so giving // subscripts their own shape needs only a `subscript_expr` node in diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output index 0e7ec33aa15c..b94bae665654 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output @@ -137,7 +137,15 @@ top_level source="⟨body⟩" variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: identifier "d" source="d" - value: map_literal "[key: value, \"b\": 2]" source="[key: value, \"b\": 2]" + value: + map_literal source="[⟨element⟩, ⟨element⟩]" + element: + key_value_pair source="⟨key⟩: ⟨value⟩" + key: identifier "key" source="key" + value: identifier "value" source="value" + key_value_pair source="⟨key⟩: ⟨value⟩" + key: string_literal "\"b\"" source="\"b\"" + value: int_literal "2" source="2" variable_declaration source="⟨modifier⟩ ⟨pattern⟩: ⟨type⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: identifier "empty" source="empty" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output index 0ecefc622b94..bd170eeb80a4 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output @@ -341,7 +341,11 @@ top_level source="⟨body⟩" value: identifier "offset" source="offset" array_literal source="[⟨element⟩]" element: identifier "value" source="value" - map_literal "[key: value]" source="[key: value]" + map_literal source="[⟨element⟩]" + element: + key_value_pair source="⟨key⟩: ⟨value⟩" + key: identifier "key" source="key" + value: identifier "value" source="value" call_expr source="⟨argument⟩?" callee: member_access_expr source="" From 023065dd85831c970b3a6f4bb2eae2f185ad6741 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 1 Oct 2026 09:03:36 +0200 Subject: [PATCH 3/3] Unified: Accept changes to expected files --- .../library-tests/controlflow/basicblock-slices.expected | 2 +- .../library-tests/type-inference/type-inference.expected | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected index ef1418bdcbd0..b6a0308729fc 100644 --- a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected +++ b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected @@ -342,7 +342,7 @@ | 413 | cfg.swift:413:5:413:9 | field | 'field -> 0 -^ ... = ...' | | 417 | cfg.swift:417:1:419:1 | func dictionaryLiteral | 'func dictionaryLiteral' | | 417 | cfg.swift:417:24:417:24 | x | 'x -> y -> Block' | -| 418 | cfg.swift:418:10:418:25 | MapLiteral | 'MapLiteral -^ ReturnExpr' | +| 418 | cfg.swift:418:11:418:13 | "x" | '"x" -> x -^ KeyValuePair -> "y" -> y -^ KeyValuePair -^ MapLiteral -^ ReturnExpr' | | 421 | cfg.swift:421:1:444:1 | func localDeclarations | 'func localDeclarations' | | 421 | cfg.swift:421:33:444:1 | Block | 'Block' | | 422 | cfg.swift:422:3:427:3 | class MyLocalClass | 'class MyLocalClass -V MyLocalClass' | diff --git a/unified/ql/test/library-tests/type-inference/type-inference.expected b/unified/ql/test/library-tests/type-inference/type-inference.expected index 8e6754ef9a90..7e6b7f2586e4 100644 --- a/unified/ql/test/library-tests/type-inference/type-inference.expected +++ b/unified/ql/test/library-tests/type-inference/type-inference.expected @@ -1602,6 +1602,10 @@ inferType | key_paths.swift:204:22:204:23 | 30 | | {EXTERNAL LOCATION} | Int | | key_paths.swift:205:15:205:17 | arr | | {EXTERNAL LOCATION} | Array | | key_paths.swift:205:15:205:17 | arr | Element | {EXTERNAL LOCATION} | Int | +| key_paths.swift:208:15:208:17 | "x" | | {EXTERNAL LOCATION} | String | +| key_paths.swift:208:20:208:20 | 1 | | {EXTERNAL LOCATION} | Int | +| key_paths.swift:208:23:208:25 | "y" | | {EXTERNAL LOCATION} | String | +| key_paths.swift:208:28:208:28 | 2 | | {EXTERNAL LOCATION} | Int | | lub.swift:12:7:12:7 | b | | lub.swift:5:1:7:1 | B | | lub.swift:12:11:12:13 | B(...) | | lub.swift:5:1:7:1 | B | | lub.swift:14:7:14:7 | x | | lub.swift:5:1:7:1 | B | @@ -2094,6 +2098,8 @@ inferType | overload_resolution.swift:428:7:428:10 | dict | | {EXTERNAL LOCATION} | Dictionary | | overload_resolution.swift:428:7:428:10 | dict | Key | {EXTERNAL LOCATION} | String | | overload_resolution.swift:428:7:428:10 | dict | Value | {EXTERNAL LOCATION} | Int | +| overload_resolution.swift:428:30:428:32 | "a" | | {EXTERNAL LOCATION} | String | +| overload_resolution.swift:428:35:428:35 | 1 | | {EXTERNAL LOCATION} | Int | | overload_resolution.swift:432:14:432:18 | index | | {EXTERNAL LOCATION} | Int | | overload_resolution.swift:433:12:433:15 | data | | {EXTERNAL LOCATION} | Array | | overload_resolution.swift:433:12:433:15 | data | Element | {EXTERNAL LOCATION} | Int |