Skip to content

Commit 0b324f8

Browse files
authored
Merge pull request #2789 from MAJKFL/guard-sequential-suggeested-changes
[SwiftLexicalLookup][GSoC] New lookup method signature and `Identifier` initializer changes
2 parents 8a9445f + 2653a6e commit 0b324f8

10 files changed

+105
-125
lines changed

Sources/SwiftLexicalLookup/IntroducingToSequentialParentScopeSyntax.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ protocol IntroducingToSequentialParentScopeSyntax: ScopeSyntax {
1919
/// Returns results matching lookup that should be
2020
/// interleaved with results of the sequential parent.
2121
func lookupFromSequentialParent(
22-
for identifier: Identifier?,
23-
at origin: AbsolutePosition,
22+
_ identifier: Identifier?,
23+
at lookUpPosition: AbsolutePosition,
2424
with config: LookupConfig
2525
) -> [LookupResult]
2626
}

Sources/SwiftLexicalLookup/LookupName.swift

+6-30
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,6 @@ import SwiftSyntax
110110
case declaration(NamedDeclSyntax)
111111
/// Name introduced implicitly by certain syntax nodes.
112112
case implicit(ImplicitDecl)
113-
/// Explicit `self` keyword.
114-
case `self`(IdentifiableSyntax, accessibleAfter: AbsolutePosition?)
115-
/// Explicit `Self` keyword.
116-
case `Self`(IdentifiableSyntax, accessibleAfter: AbsolutePosition?)
117113

118114
/// Syntax associated with this name.
119115
@_spi(Experimental) public var syntax: SyntaxProtocol {
@@ -124,8 +120,6 @@ import SwiftSyntax
124120
return syntax
125121
case .implicit(let implicitName):
126122
return implicitName.syntax
127-
case .self(let syntax, _), .Self(let syntax, _):
128-
return syntax
129123
}
130124
}
131125

@@ -138,36 +132,24 @@ import SwiftSyntax
138132
return Identifier(syntax.name)
139133
case .implicit(let kind):
140134
return kind.identifier
141-
case .self:
142-
return Identifier("self")
143-
case .Self:
144-
return Identifier("Self")
145135
}
146136
}
147137

148138
/// Point, after which the name is available in scope.
149139
/// If set to `nil`, the name is available at any point in scope.
150140
var accessibleAfter: AbsolutePosition? {
151141
switch self {
152-
case .identifier(_, let absolutePosition),
153-
.self(_, let absolutePosition),
154-
.Self(_, let absolutePosition):
142+
case .identifier(_, let absolutePosition):
155143
return absolutePosition
156144
default:
157145
return nil
158146
}
159147
}
160148

161149
/// Checks if this name was introduced before the syntax used for lookup.
162-
func isAccessible(at origin: AbsolutePosition) -> Bool {
150+
func isAccessible(at lookUpPosition: AbsolutePosition) -> Bool {
163151
guard let accessibleAfter else { return true }
164-
return accessibleAfter <= origin
165-
}
166-
167-
/// Checks if this name refers to the looked up phrase.
168-
func refersTo(_ lookedUpIdentifier: Identifier) -> Bool {
169-
guard let identifier else { return false }
170-
return identifier == lookedUpIdentifier
152+
return accessibleAfter <= lookUpPosition
171153
}
172154

173155
/// Extracts names introduced by the given `syntax` structure.
@@ -229,16 +211,10 @@ import SwiftSyntax
229211
accessibleAfter: AbsolutePosition? = nil
230212
) -> [LookupName] {
231213
switch identifiable.identifier.tokenKind {
232-
case .keyword(.self):
233-
return [.self(identifiable, accessibleAfter: accessibleAfter)]
234-
case .keyword(.Self):
235-
return [.Self(identifiable, accessibleAfter: accessibleAfter)]
214+
case .wildcard:
215+
return []
236216
default:
237-
if identifiable.identifier.tokenKind != .wildcard {
238-
return [.identifier(identifiable, accessibleAfter: accessibleAfter)]
239-
} else {
240-
return []
241-
}
217+
return [.identifier(identifiable, accessibleAfter: accessibleAfter)]
242218
}
243219
}
244220

Sources/SwiftLexicalLookup/LookupResult.swift

+10
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,14 @@ import SwiftSyntax
3636
return names
3737
}
3838
}
39+
40+
/// Returns result specific for the particular `scope` kind with provided `names`.
41+
static func getResult(for scope: ScopeSyntax, withNames names: [LookupName]) -> LookupResult {
42+
switch Syntax(scope).as(SyntaxEnum.self) {
43+
case .sourceFile(let sourceFileSyntax):
44+
return .fromFileScope(sourceFileSyntax, withNames: names)
45+
default:
46+
return .fromScope(scope, withNames: names)
47+
}
48+
}
3949
}

Sources/SwiftLexicalLookup/ScopeImplementations.swift

+27-31
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,15 @@ import SwiftSyntax
9797
/// - for `memberBlock` - a, b, c, d, e, f
9898
/// - for `codeBlock` - a
9999
@_spi(Experimental) public func lookup(
100-
for identifier: Identifier?,
101-
at origin: AbsolutePosition,
100+
_ identifier: Identifier?,
101+
at lookUpPosition: AbsolutePosition,
102102
with config: LookupConfig
103103
) -> [LookupResult] {
104104
switch config.fileScopeHandling {
105105
case .memberBlock:
106106
let names = introducedNames(using: .memberBlock)
107107
.filter { lookupName in
108-
checkName(identifier, refersTo: lookupName, at: origin)
108+
checkIdentifier(identifier, refersTo: lookupName, at: lookUpPosition)
109109
}
110110

111111
return names.isEmpty ? [] : [.fromFileScope(self, withNames: names)]
@@ -119,24 +119,22 @@ import SwiftSyntax
119119

120120
if encounteredNonDeclaration {
121121
sequentialItems.append(codeBlockItem)
122+
} else if item.is(DeclSyntax.self) {
123+
let foundNames = LookupName.getNames(from: item)
124+
members.append(
125+
contentsOf: foundNames.filter { checkIdentifier(identifier, refersTo: $0, at: lookUpPosition) }
126+
)
122127
} else {
123-
if item.is(DeclSyntax.self) {
124-
let foundNames = LookupName.getNames(from: item)
125-
126-
members.append(contentsOf: foundNames.filter { checkName(identifier, refersTo: $0, at: origin) })
127-
} else {
128-
encounteredNonDeclaration = true
129-
sequentialItems.append(codeBlockItem)
130-
}
128+
encounteredNonDeclaration = true
129+
sequentialItems.append(codeBlockItem)
131130
}
132131
}
133132

134133
let sequentialNames = sequentialLookup(
135134
in: sequentialItems,
136-
for: identifier,
137-
at: origin,
138-
with: config,
139-
createResultsForThisScopeWith: { .fromFileScope(self, withNames: $0) }
135+
identifier,
136+
at: lookUpPosition,
137+
with: config
140138
)
141139

142140
return (members.isEmpty ? [] : [.fromFileScope(self, withNames: members)]) + sequentialNames
@@ -154,16 +152,15 @@ import SwiftSyntax
154152
}
155153

156154
@_spi(Experimental) public func lookup(
157-
for identifier: Identifier?,
158-
at origin: AbsolutePosition,
155+
_ identifier: Identifier?,
156+
at lookUpPosition: AbsolutePosition,
159157
with config: LookupConfig
160158
) -> [LookupResult] {
161159
sequentialLookup(
162160
in: statements,
163-
for: identifier,
164-
at: origin,
165-
with: config,
166-
createResultsForThisScopeWith: { .fromScope(self, withNames: $0) }
161+
identifier,
162+
at: lookUpPosition,
163+
with: config
167164
)
168165
}
169166
}
@@ -274,14 +271,14 @@ import SwiftSyntax
274271
/// }
275272
/// ```
276273
@_spi(Experimental) public func lookup(
277-
for identifier: Identifier?,
278-
at origin: AbsolutePosition,
274+
_ identifier: Identifier?,
275+
at lookUpPosition: AbsolutePosition,
279276
with config: LookupConfig
280277
) -> [LookupResult] {
281-
if let elseBody, elseBody.position <= origin, elseBody.endPosition >= origin {
282-
return lookupInParent(for: identifier, at: origin, with: config)
278+
if let elseBody, elseBody.range.contains(lookUpPosition) {
279+
return lookupInParent(identifier, at: lookUpPosition, with: config)
283280
} else {
284-
return defaultLookupImplementation(for: identifier, at: origin, with: config)
281+
return defaultLookupImplementation(identifier, at: lookUpPosition, with: config)
285282
}
286283
}
287284
}
@@ -319,15 +316,14 @@ import SwiftSyntax
319316
/// // a is visible here
320317
/// ```
321318
func lookupFromSequentialParent(
322-
for identifier: Identifier?,
323-
at origin: AbsolutePosition,
319+
_ identifier: Identifier?,
320+
at lookUpPosition: AbsolutePosition,
324321
with config: LookupConfig
325322
) -> [LookupResult] {
326-
guard body.position > origin || body.endPosition < origin
327-
else { return [] }
323+
guard !body.range.contains(lookUpPosition) else { return [] }
328324

329325
let names = namesIntroducedToSequentialParent.filter { introducedName in
330-
checkName(identifier, refersTo: introducedName, at: origin)
326+
checkIdentifier(identifier, refersTo: introducedName, at: lookUpPosition)
331327
}
332328

333329
return names.isEmpty ? [] : [.fromScope(self, withNames: names)]

Sources/SwiftLexicalLookup/ScopeSyntax.swift

+21-19
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ extension SyntaxProtocol {
4444
/// in this exact order. The constant declaration within the function body is omitted
4545
/// due to the ordering rules that prioritize visibility within the function body.
4646
@_spi(Experimental) public func lookup(
47-
for identifier: Identifier?,
47+
_ identifier: Identifier?,
4848
with config: LookupConfig = LookupConfig()
4949
) -> [LookupResult] {
50-
scope?.lookup(for: identifier, at: self.position, with: config) ?? []
50+
scope?.lookup(identifier, at: self.position, with: config) ?? []
5151
}
5252
}
5353

@@ -58,10 +58,9 @@ extension SyntaxProtocol {
5858
var introducedNames: [LookupName] { get }
5959
/// Finds all declarations `identifier` refers to. `syntax` specifies the node lookup was triggered with.
6060
/// If `identifier` set to `nil`, returns all available names at the given node.
61-
/// `state` represents lookup state passed between lookup methods.
6261
func lookup(
63-
for identifier: Identifier?,
64-
at origin: AbsolutePosition,
62+
_ identifier: Identifier?,
63+
at lookUpPosition: AbsolutePosition,
6564
with config: LookupConfig
6665
) -> [LookupResult]
6766
}
@@ -74,47 +73,50 @@ extension SyntaxProtocol {
7473
/// Returns `LookupResult` of all names introduced in this scope that `identifier`
7574
/// refers to and is accessible at given syntax node then passes lookup to the parent.
7675
/// If `identifier` set to `nil`, returns all available names at the given node.
77-
/// `state` represents lookup state passed between lookup methods.
7876
@_spi(Experimental) public func lookup(
79-
for identifier: Identifier?,
80-
at origin: AbsolutePosition,
77+
_ identifier: Identifier?,
78+
at lookUpPosition: AbsolutePosition,
8179
with config: LookupConfig
8280
) -> [LookupResult] {
83-
defaultLookupImplementation(for: identifier, at: origin, with: config)
81+
defaultLookupImplementation(identifier, at: lookUpPosition, with: config)
8482
}
8583

8684
/// Returns `LookupResult` of all names introduced in this scope that `identifier`
8785
/// refers to and is accessible at given syntax node then passes lookup to the parent.
8886
/// If `identifier` set to `nil`, returns all available names at the given node.
8987
func defaultLookupImplementation(
90-
for identifier: Identifier?,
91-
at origin: AbsolutePosition,
88+
_ identifier: Identifier?,
89+
at lookUpPosition: AbsolutePosition,
9290
with config: LookupConfig
9391
) -> [LookupResult] {
9492
let filteredNames =
9593
introducedNames
9694
.filter { introducedName in
97-
checkName(identifier, refersTo: introducedName, at: origin)
95+
checkIdentifier(identifier, refersTo: introducedName, at: lookUpPosition)
9896
}
9997

10098
if filteredNames.isEmpty {
101-
return lookupInParent(for: identifier, at: origin, with: config)
99+
return lookupInParent(identifier, at: lookUpPosition, with: config)
102100
} else {
103101
return [.fromScope(self, withNames: filteredNames)]
104-
+ lookupInParent(for: identifier, at: origin, with: config)
102+
+ lookupInParent(identifier, at: lookUpPosition, with: config)
105103
}
106104
}
107105

108106
/// Looks up in parent scope.
109107
func lookupInParent(
110-
for identifier: Identifier?,
111-
at origin: AbsolutePosition,
108+
_ identifier: Identifier?,
109+
at lookUpPosition: AbsolutePosition,
112110
with config: LookupConfig
113111
) -> [LookupResult] {
114-
parentScope?.lookup(for: identifier, at: origin, with: config) ?? []
112+
parentScope?.lookup(identifier, at: lookUpPosition, with: config) ?? []
115113
}
116114

117-
func checkName(_ name: Identifier?, refersTo introducedName: LookupName, at origin: AbsolutePosition) -> Bool {
118-
introducedName.isAccessible(at: origin) && (name == nil || introducedName.refersTo(name!))
115+
func checkIdentifier(
116+
_ identifier: Identifier?,
117+
refersTo introducedName: LookupName,
118+
at lookUpPosition: AbsolutePosition
119+
) -> Bool {
120+
introducedName.isAccessible(at: lookUpPosition) && (identifier == nil || introducedName.identifier == identifier!)
119121
}
120122
}

Sources/SwiftLexicalLookup/SequentialScopeSyntax.swift

+19-12
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,19 @@ extension SequentialScopeSyntax {
4040
/// code block scope in this exact order.
4141
func sequentialLookup(
4242
in codeBlockItems: some Collection<CodeBlockItemSyntax>,
43-
for identifier: Identifier?,
44-
at origin: AbsolutePosition,
45-
with config: LookupConfig,
46-
createResultsForThisScopeWith getResults: ([LookupName]) -> (LookupResult)
43+
_ identifier: Identifier?,
44+
at lookUpPosition: AbsolutePosition,
45+
with config: LookupConfig
4746
) -> [LookupResult] {
47+
// Sequential scope needs to ensure all type declarations are
48+
// available in the whole scope (first loop) and
49+
// then that results from IntroducingToSequentialParentScopeSyntax
50+
// are properly interleaved with the results produced by this scope.
4851
var results: [LookupResult] = []
52+
// We need to use currentChunk because we
53+
// can't add the names directly to results
54+
// as we need to partition them based on results
55+
// obtained from IntroducingToSequentialParentScopeSyntax
4956
var currentChunk: [LookupName] = []
5057
var itemsWithoutNamedDecl: [CodeBlockItemSyntax] = []
5158

@@ -55,23 +62,23 @@ extension SequentialScopeSyntax {
5562
from: codeBlockItem.item,
5663
accessibleAfter: codeBlockItem.endPosition
5764
).filter { introducedName in
58-
checkName(identifier, refersTo: introducedName, at: origin)
65+
checkIdentifier(identifier, refersTo: introducedName, at: lookUpPosition)
5966
}
6067
} else {
6168
itemsWithoutNamedDecl.append(codeBlockItem)
6269
}
6370
}
6471

6572
for codeBlockItem in itemsWithoutNamedDecl {
66-
guard codeBlockItem.position < origin else { break }
73+
guard codeBlockItem.position <= lookUpPosition else { break }
6774

6875
if let introducingToParentScope = Syntax(codeBlockItem.item).asProtocol(SyntaxProtocol.self)
6976
as? IntroducingToSequentialParentScopeSyntax
7077
{
7178
// Get results from encountered scope.
7279
let introducedResults = introducingToParentScope.lookupFromSequentialParent(
73-
for: identifier,
74-
at: origin,
80+
identifier,
81+
at: lookUpPosition,
7582
with: config
7683
)
7784

@@ -80,7 +87,7 @@ extension SequentialScopeSyntax {
8087

8188
// If there are some names collected, create a new result for this scope.
8289
if !currentChunk.isEmpty {
83-
results.append(getResults(currentChunk))
90+
results.append(LookupResult.getResult(for: self, withNames: currentChunk))
8491
currentChunk = []
8592
}
8693

@@ -91,16 +98,16 @@ extension SequentialScopeSyntax {
9198
from: codeBlockItem.item,
9299
accessibleAfter: codeBlockItem.endPosition
93100
).filter { introducedName in
94-
checkName(identifier, refersTo: introducedName, at: origin)
101+
checkIdentifier(identifier, refersTo: introducedName, at: lookUpPosition)
95102
}
96103
}
97104
}
98105

99106
// If there are some names collected, create a new result for this scope.
100107
if !currentChunk.isEmpty {
101-
results.append(getResults(currentChunk))
108+
results.append(LookupResult.getResult(for: self, withNames: currentChunk))
102109
}
103110

104-
return results.reversed() + lookupInParent(for: identifier, at: origin, with: config)
111+
return results.reversed() + lookupInParent(identifier, at: lookUpPosition, with: config)
105112
}
106113
}

0 commit comments

Comments
 (0)