From f62f3b897d192c4764ac95152fde26a7093abba1 Mon Sep 17 00:00:00 2001 From: Filip Sakellariou Date: Wed, 8 Jul 2026 12:20:21 -0400 Subject: [PATCH 1/5] SwiftLexicalLookup: Rename NominalTypeDeclSyntax -> NonProtocolNominalTypeDeclSyntax. --- .../QualifiedLookup/ValueDeclSyntax.swift | 2 +- ...yntax.swift => NonProtocolNominalTypeDeclSyntax.swift} | 4 ++-- .../SwiftLexicalLookup/Scopes/ScopeImplementations.swift | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) rename Sources/SwiftLexicalLookup/Scopes/{NominalTypeDeclSyntax.swift => NonProtocolNominalTypeDeclSyntax.swift} (92%) diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift index 7effa2a7090..227014a22f3 100644 --- a/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift @@ -541,7 +541,7 @@ extension ValueDeclSyntax { // Protocols extension ValueDeclSyntax { - init(fromProtocol syntax: borrowing some NominalTypeDeclSyntax) { + init(fromProtocol syntax: borrowing some NonProtocolNominalTypeDeclSyntax) { // We know this cast is going to succeed. Go through `init(_: SyntaxData)` just to double-check and // verify the kind matches in debug builds and get maximum performance in release builds. self = Syntax(syntax).cast(ValueDeclSyntax.self) diff --git a/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift similarity index 92% rename from Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift index 314b9ebf870..d5270d4e8d9 100644 --- a/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift @@ -13,13 +13,13 @@ import SwiftSyntax @_spi(Experimental) -public protocol NominalTypeDeclSyntax: LookInMembersScopeSyntax, DeclGroupSyntax, NamedDeclSyntax, +public protocol NonProtocolNominalTypeDeclSyntax: LookInMembersScopeSyntax, DeclGroupSyntax, NamedDeclSyntax, WithGenericParametersScopeSyntax { var genericParameterClause: GenericParameterClauseSyntax? { get } } -extension NominalTypeDeclSyntax { +extension NonProtocolNominalTypeDeclSyntax { @_spi(Experimental) public var lookupMembersPosition: AbsolutePosition { name.positionAfterSkippingLeadingTrivia } diff --git a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift index bbed72263ae..c91ce0f4f6c 100644 --- a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift @@ -363,22 +363,22 @@ import SwiftSyntax } } -@_spi(Experimental) extension ActorDeclSyntax: NominalTypeDeclSyntax { +@_spi(Experimental) extension ActorDeclSyntax: NonProtocolNominalTypeDeclSyntax { @_spi(Experimental) public var scopeDebugName: String { "ActorDeclScope" } } -@_spi(Experimental) extension ClassDeclSyntax: NominalTypeDeclSyntax { +@_spi(Experimental) extension ClassDeclSyntax: NonProtocolNominalTypeDeclSyntax { @_spi(Experimental) public var scopeDebugName: String { "ClassDeclScope" } } -@_spi(Experimental) extension StructDeclSyntax: NominalTypeDeclSyntax { +@_spi(Experimental) extension StructDeclSyntax: NonProtocolNominalTypeDeclSyntax { @_spi(Experimental) public var scopeDebugName: String { "StructDeclScope" } } -@_spi(Experimental) extension EnumDeclSyntax: NominalTypeDeclSyntax { +@_spi(Experimental) extension EnumDeclSyntax: NonProtocolNominalTypeDeclSyntax { @_spi(Experimental) public var scopeDebugName: String { "EnumDeclScope" } From 3db300d5accc64c58747ca6d2991935dced06fc4 Mon Sep 17 00:00:00 2001 From: Filip Sakellariou Date: Wed, 8 Jul 2026 12:34:28 -0400 Subject: [PATCH 2/5] SwiftLexicalLookup: Add TypeLikeSyntax, NominalTypeDeclSyntax and TypeDeclSyntax. --- .../NominalTypeDeclSyntax.swift | 120 ++++++++++++++++++ .../QualifiedLookup/TypeDeclSyntax.swift | 89 +++++++++++++ .../QualifiedLookup/TypeLikeSyntax.swift | 40 ++++++ 3 files changed, 249 insertions(+) create mode 100644 Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift create mode 100644 Sources/SwiftLexicalLookup/QualifiedLookup/TypeDeclSyntax.swift create mode 100644 Sources/SwiftLexicalLookup/QualifiedLookup/TypeLikeSyntax.swift diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift new file mode 100644 index 00000000000..1f20f435f7e --- /dev/null +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax + +/// A nominal type declaration (struct, enum, class, actor, protocol). +@_spi(_QualifiedLookup) public struct NominalTypeDeclSyntax: SyntaxProtocol, Hashable { + public private(set) var _syntaxNode: Syntax + + public init?(_ node: __shared some SyntaxProtocol) { + switch node.kind { + case .structDecl, .enumDecl, .classDecl, .actorDecl, .protocolDecl: + _syntaxNode = node._syntaxNode + default: + return nil + } + } + + public static var structure: SyntaxNodeStructure { + SyntaxNodeStructure.choices([ + .node(StructDeclSyntax.self), + .node(EnumDeclSyntax.self), + .node(ClassDeclSyntax.self), + .node(ActorDeclSyntax.self), + .node(ProtocolDeclSyntax.self), + ]) + } +} + +extension NominalTypeDeclSyntax: DeclGroupSyntax { + private func _getGroupProp(_ prop: KeyPath) -> T { + switch _syntaxNode.as(SyntaxEnum.self) { + case .structDecl(let declGroup): + return declGroup[keyPath: prop] + case .enumDecl(let declGroup): + return declGroup[keyPath: prop] + case .classDecl(let declGroup): + return declGroup[keyPath: prop] + case .actorDecl(let declGroup): + return declGroup[keyPath: prop] + case .protocolDecl(let declGroup): + return declGroup[keyPath: prop] + default: + fatalError("[Internal Error] Invalid syntax kind for NominalTypeDeclSyntax \(_syntaxNode.kind)") + } + } + + private mutating func _setGroupProp( + _ keyPath: WritableKeyPath, + newValue: T + ) { + switch _syntaxNode.as(SyntaxEnum.self) { + case .structDecl(let declGroup): + var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .enumDecl(let declGroup): + var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .classDecl(let declGroup): + var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .actorDecl(let declGroup): + var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .protocolDecl(let declGroup): + var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + default: + fatalError("[Internal Error] Invalid syntax kind for DeclGroupSyntaxType: \(_syntaxNode.kind)") + } + } + + public var name: TokenSyntax { + get { _getGroupProp(\.name) } + set { _setGroupProp(\.name, newValue: newValue) } + } + + public var attributes: AttributeListSyntax { + get { _getGroupProp(\.attributes) } + set { _setGroupProp(\.attributes, newValue: newValue) } + } + + public var modifiers: DeclModifierListSyntax { + get { _getGroupProp(\.modifiers) } + set { _setGroupProp(\.modifiers, newValue: newValue) } + } + public var introducer: TokenSyntax { + get { _getGroupProp(\.introducer) } + set { _setGroupProp(\.introducer, newValue: newValue) } + } + + public var inheritanceClause: InheritanceClauseSyntax? { + get { _getGroupProp(\.inheritanceClause) } + set { _setGroupProp(\.inheritanceClause, newValue: newValue) } + } + + public var genericWhereClause: GenericWhereClauseSyntax? { + get { _getGroupProp(\.genericWhereClause) } + set { _setGroupProp(\.genericWhereClause, newValue: newValue) } + } + + public var memberBlock: MemberBlockSyntax { + get { _getGroupProp(\.memberBlock) } + set { _setGroupProp(\.memberBlock, newValue: newValue) } + } +} diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/TypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/TypeDeclSyntax.swift new file mode 100644 index 00000000000..8cf9c8d7e25 --- /dev/null +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/TypeDeclSyntax.swift @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax + +/// A nominal type declaration (struct, enum, class, actor, protocol), type +/// alias, associated type or generic parameter. +@_spi(_QualifiedLookup) public struct TypeDeclSyntax: Hashable, SyntaxProtocol { + public private(set) var _syntaxNode: Syntax + + public init?(_ node: __shared some SyntaxProtocol) { + switch node.kind { + case .structDecl, .enumDecl, .classDecl, .actorDecl, .protocolDecl, .typeAliasDecl, .associatedTypeDecl, + .genericParameter: + _syntaxNode = node._syntaxNode + default: + return nil + } + } + + public static var structure: SyntaxNodeStructure { + SyntaxNodeStructure.choices([ + .node(StructDeclSyntax.self), + .node(EnumDeclSyntax.self), + .node(ClassDeclSyntax.self), + .node(ActorDeclSyntax.self), + .node(ProtocolDeclSyntax.self), + .node(TypeAliasDeclSyntax.self), + .node(AssociatedTypeDeclSyntax.self), + .node(GenericParameterSyntax.self), + ]) + } +} + +// MARK: Name + +extension TypeDeclSyntax { + public var name: TokenSyntax { + switch _syntaxNode.as(SyntaxEnum.self) { + case .structDecl(let structDecl): + return structDecl.name + case .enumDecl(let enumDecl): + return enumDecl.name + case .classDecl(let classDecl): + return classDecl.name + case .actorDecl(let actorDecl): + return actorDecl.name + case .protocolDecl(let protocolDecl): + return protocolDecl.name + case .typeAliasDecl(let typeAliasDecl): + return typeAliasDecl.name + case .associatedTypeDecl(let associatedTypeDecl): + return associatedTypeDecl.name + case .genericParameter(let genericParameter): + return genericParameter.name + default: + fatalError("[Internal Error] Invalid syntax kind for TypeDeclSyntax: \(_syntaxNode.kind)") + } + } +} + +// MARK: Upcasts + +extension TypeDeclSyntax { + public init(_ nominalType: NominalTypeDeclSyntax) { + self = Syntax(nominalType).cast(TypeDeclSyntax.self) + } + + public init(_ typeAlias: TypeAliasDeclSyntax) { + self = Syntax(typeAlias).cast(TypeDeclSyntax.self) + } + + public init(_ associatedType: AssociatedTypeDeclSyntax) { + self = Syntax(associatedType).cast(TypeDeclSyntax.self) + } + + public init(_ genericParameter: GenericParameterSyntax) { + self = Syntax(genericParameter).cast(TypeDeclSyntax.self) + } +} diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/TypeLikeSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/TypeLikeSyntax.swift new file mode 100644 index 00000000000..6f693384527 --- /dev/null +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/TypeLikeSyntax.swift @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax + +/// A protocol for ``TypeLikeSyntax`` nodes. +@_spi(_QualifiedLookup) public protocol TypeLikeSyntaxProtocol: SyntaxProtocol {} + +@_spi(_QualifiedLookup) extension TypeSyntax: TypeLikeSyntaxProtocol {} +@_spi(_QualifiedLookup) extension NominalTypeDeclSyntax: TypeLikeSyntaxProtocol {} + +/// Either ``TypeSyntax`` or a nominal type. Helps us track which syntax is +/// responsible for a given type-resolution request. +@_spi(_QualifiedLookup) public struct TypeLikeSyntax: Sendable, Hashable, TypeLikeSyntaxProtocol { + public private(set) var _syntaxNode: Syntax + + public init?(_ node: __shared some SyntaxProtocol) { + guard node.is(TypeSyntax.self) || node.is(NominalTypeDeclSyntax.self) else { return nil } + _syntaxNode = Syntax(node) + } + + public init(_ typeLikeSyntax: TypeLikeSyntaxProtocol) { + self._syntaxNode = typeLikeSyntax._syntaxNode + } + + // TODO: Are we allowed to have non-primitive node types?? + public static let structure = SyntaxNodeStructure.choices([ + SyntaxNodeStructure.SyntaxChoice.node(TypeSyntax.self), + SyntaxNodeStructure.SyntaxChoice.node(NominalTypeDeclSyntax.self), + ]) +} From e19617eccba2aa7ed011727d0931e0c9705f8983 Mon Sep 17 00:00:00 2001 From: Filip Sakellariou Date: Tue, 14 Jul 2026 14:48:17 -0400 Subject: [PATCH 3/5] SwiftLexicalLookup: Refactor NonProtocolNominalTypeDeclSyntax->NominalTypeDeclScopeSyntax and clean up helper types. --- .../QualifiedLookup/DeclGroupLookup.swift | 4 +- .../NominalTypeDeclSyntax.swift | 24 ++- .../QualifiedLookup/ValueDeclSyntax.swift | 127 +------------- .../NonProtocolNominalTypeDeclSyntax.swift | 37 ++-- .../Scopes/ScopeImplementations.swift | 159 ++++++++++-------- 5 files changed, 123 insertions(+), 228 deletions(-) diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/DeclGroupLookup.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/DeclGroupLookup.swift index d0f336beaf5..a6f5374b7fb 100644 --- a/Sources/SwiftLexicalLookup/QualifiedLookup/DeclGroupLookup.swift +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/DeclGroupLookup.swift @@ -85,8 +85,8 @@ import SwiftSyntax } } - public init(exactly node: some DeclGroupSyntax) { - self.init(node)! + public init(_ syntax: __shared some DeclGroupSyntax) { + self = Syntax(syntax).cast(Self.self) } public var attributes: AttributeListSyntax { diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift index 1f20f435f7e..1807895ca56 100644 --- a/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift @@ -12,8 +12,12 @@ import SwiftSyntax +/// Protocol for `NominalTypeDeclSyntax`. Only `[Struct/Enum/Class/Actor/Protocol]DeclSyntax` +/// should conform. +@_spi(_QualifiedLookup) public protocol NominalTypeDeclSyntaxProtocol: DeclGroupSyntax, NamedDeclSyntax {} + /// A nominal type declaration (struct, enum, class, actor, protocol). -@_spi(_QualifiedLookup) public struct NominalTypeDeclSyntax: SyntaxProtocol, Hashable { +@_spi(_QualifiedLookup) public struct NominalTypeDeclSyntax: NominalTypeDeclSyntaxProtocol, SyntaxHashable { public private(set) var _syntaxNode: Syntax public init?(_ node: __shared some SyntaxProtocol) { @@ -37,7 +41,7 @@ import SwiftSyntax } extension NominalTypeDeclSyntax: DeclGroupSyntax { - private func _getGroupProp(_ prop: KeyPath) -> T { + private func _getGroupProp(_ prop: KeyPath) -> T { switch _syntaxNode.as(SyntaxEnum.self) { case .structDecl(let declGroup): return declGroup[keyPath: prop] @@ -55,28 +59,28 @@ extension NominalTypeDeclSyntax: DeclGroupSyntax { } private mutating func _setGroupProp( - _ keyPath: WritableKeyPath, + _ keyPath: WritableKeyPath, newValue: T ) { switch _syntaxNode.as(SyntaxEnum.self) { case .structDecl(let declGroup): - var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + var box: any NominalTypeDeclSyntaxProtocol = declGroup box[keyPath: keyPath] = newValue _syntaxNode = box._syntaxNode case .enumDecl(let declGroup): - var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + var box: any NominalTypeDeclSyntaxProtocol = declGroup box[keyPath: keyPath] = newValue _syntaxNode = box._syntaxNode case .classDecl(let declGroup): - var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + var box: any NominalTypeDeclSyntaxProtocol = declGroup box[keyPath: keyPath] = newValue _syntaxNode = box._syntaxNode case .actorDecl(let declGroup): - var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + var box: any NominalTypeDeclSyntaxProtocol = declGroup box[keyPath: keyPath] = newValue _syntaxNode = box._syntaxNode case .protocolDecl(let declGroup): - var box: any DeclGroupSyntax & NamedDeclSyntax = declGroup + var box: any NominalTypeDeclSyntaxProtocol = declGroup box[keyPath: keyPath] = newValue _syntaxNode = box._syntaxNode default: @@ -84,6 +88,10 @@ extension NominalTypeDeclSyntax: DeclGroupSyntax { } } + public init(_ syntax: __shared some NominalTypeDeclSyntaxProtocol) { + self = Syntax(syntax).cast(Self.self) + } + public var name: TokenSyntax { get { _getGroupProp(\.name) } set { _setGroupProp(\.name, newValue: newValue) } diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift index 227014a22f3..cd19a7bcc9c 100644 --- a/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift @@ -487,19 +487,7 @@ extension ValueDeclSyntax { // Conrete types extension ValueDeclSyntax { // Types - public init(_ syntax: StructDeclSyntax) { - self.init(syntax)! - } - public init(_ syntax: EnumDeclSyntax) { - self.init(syntax)! - } - public init(_ syntax: ClassDeclSyntax) { - self.init(syntax)! - } - public init(_ syntax: ActorDeclSyntax) { - self.init(syntax)! - } - public init(_ syntax: ProtocolDeclSyntax) { + public init(_ syntax: __shared some NominalTypeDeclSyntaxProtocol) { self.init(syntax)! } public init(_ syntax: TypeAliasDeclSyntax) { @@ -539,67 +527,6 @@ extension ValueDeclSyntax { } } -// Protocols -extension ValueDeclSyntax { - init(fromProtocol syntax: borrowing some NonProtocolNominalTypeDeclSyntax) { - // We know this cast is going to succeed. Go through `init(_: SyntaxData)` just to double-check and - // verify the kind matches in debug builds and get maximum performance in release builds. - self = Syntax(syntax).cast(ValueDeclSyntax.self) - } -} - -// MARK: `as` Casts - -extension ValueDeclSyntax { - public func `as`(_ syntaxType: StructDeclSyntax.Type) -> StructDeclSyntax? { - return StructDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: EnumDeclSyntax.Type) -> EnumDeclSyntax? { - return EnumDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: ClassDeclSyntax.Type) -> ClassDeclSyntax? { - return ClassDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: ActorDeclSyntax.Type) -> ActorDeclSyntax? { - return ActorDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: ProtocolDeclSyntax.Type) -> ProtocolDeclSyntax? { - return ProtocolDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: TypeAliasDeclSyntax.Type) -> TypeAliasDeclSyntax? { - return TypeAliasDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: AssociatedTypeDeclSyntax.Type) -> AssociatedTypeDeclSyntax? { - return AssociatedTypeDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: FunctionDeclSyntax.Type) -> FunctionDeclSyntax? { - return FunctionDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: InitializerDeclSyntax.Type) -> InitializerDeclSyntax? { - return InitializerDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: DeinitializerDeclSyntax.Type) -> DeinitializerDeclSyntax? { - return DeinitializerDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: IdentifierPatternSyntax.Type) -> IdentifierPatternSyntax? { - return IdentifierPatternSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: SubscriptDeclSyntax.Type) -> SubscriptDeclSyntax? { - return SubscriptDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: MacroDeclSyntax.Type) -> MacroDeclSyntax? { - return MacroDeclSyntax(_syntaxNode) - } - public func `as`(_ syntaxType: EnumCaseElementSyntax.Type) -> EnumCaseElementSyntax? { - return EnumCaseElementSyntax(_syntaxNode) - } - - @available(*, deprecated, message: "This cast will always fail") - public func `as`(_ syntaxType: S.Type) -> S? { - return nil - } -} - // MARK: DeclSyntaxProtocol Conversions extension DeclSyntaxProtocol { @@ -611,55 +538,3 @@ extension DeclSyntaxProtocol { self.as(syntaxType) != nil } } - -// MARK: `is` Checks - -extension ValueDeclSyntax { - public func `is`(_ syntaxType: StructDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: EnumDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: ClassDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: ActorDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: ProtocolDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: TypeAliasDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: AssociatedTypeDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: FunctionDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: InitializerDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: DeinitializerDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: IdentifierPatternSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: SubscriptDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: MacroDeclSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - public func `is`(_ syntaxType: EnumCaseElementSyntax.Type) -> Bool { - return self.as(syntaxType) != nil - } - - @available(*, deprecated, message: "This check will always fail") - public func `is`(_ syntaxType: S.Type) -> Bool { - return false - } -} diff --git a/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift index d5270d4e8d9..34ac89b04fe 100644 --- a/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift @@ -12,23 +12,19 @@ import SwiftSyntax +/// Helper scope for nominal types (structs, enums, classes, actors, protocols). @_spi(Experimental) -public protocol NonProtocolNominalTypeDeclSyntax: LookInMembersScopeSyntax, DeclGroupSyntax, NamedDeclSyntax, - WithGenericParametersScopeSyntax -{ - var genericParameterClause: GenericParameterClauseSyntax? { get } -} +public protocol NominalTypeDeclScopeSyntax: NominalTypeDeclSyntaxProtocol, ScopeSyntax, LookInMembersScopeSyntax {} -extension NonProtocolNominalTypeDeclSyntax { +extension NominalTypeDeclScopeSyntax /*: LookInMembersScopeSyntax */ { @_spi(Experimental) public var lookupMembersPosition: AbsolutePosition { name.positionAfterSkippingLeadingTrivia } +} - /// Nominal type doesn't introduce any names by itself. - @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { - [] - } - +// Default implementations for structs/enums/classes/actors, which have +// generic parameters instead of primary-associated types. +extension NominalTypeDeclScopeSyntax where Self: WithGenericParametersScopeSyntax, Self: WithGenericParametersSyntax { /// Function used by generic parameter clause /// scope on return from it's lookup. @_spi(Experimental) public func returningLookupFromGenericParameterScope( @@ -36,14 +32,19 @@ extension NonProtocolNominalTypeDeclSyntax { at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { - if let inheritanceClause, inheritanceClause.range.contains(lookUpPosition) { - return lookupInParent(identifier, at: lookUpPosition, with: config) - } else if let genericParameterClause, genericParameterClause.range.contains(lookUpPosition) { - return lookupInParent(identifier, at: lookUpPosition, with: config) - } else if name.range.contains(lookUpPosition) || genericWhereClause?.range.contains(lookUpPosition) ?? false { - return lookupInParent(identifier, at: lookUpPosition, with: config) + // Don't look for members if we're in the name, generic-parameter clause, + // inheritance clause, or generic-where clause. + let lookInMembers: [LookupResult] + if name.range.contains(lookUpPosition) + || genericParameterClause?.range.contains(lookUpPosition) == true + || inheritanceClause?.range.contains(lookUpPosition) == true + || genericWhereClause?.range.contains(lookUpPosition) == true + { + lookInMembers = [] } else { - return [.lookForMembers(in: Syntax(self))] + lookupInParent(identifier, at: lookUpPosition, with: config) + lookInMembers = [LookupResult.lookForMembers(in: Syntax(self))] } + + return lookInMembers + lookupInParent(identifier, at: lookUpPosition, with: config) } } diff --git a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift index c91ce0f4f6c..fc63d11300d 100644 --- a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift @@ -363,26 +363,103 @@ import SwiftSyntax } } -@_spi(Experimental) extension ActorDeclSyntax: NonProtocolNominalTypeDeclSyntax { +/// The only nominal types that introduce implicit `Self` are protocols. +/// See: https://github.com/swiftlang/swift-syntax/pull/2852#discussion_r1775049671 +@_spi(Experimental) extension StructDeclSyntax: NominalTypeDeclScopeSyntax, WithGenericParametersScopeSyntax { + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [] + } @_spi(Experimental) public var scopeDebugName: String { - "ActorDeclScope" + "StructDeclScope" + } +} +@_spi(Experimental) extension EnumDeclSyntax: NominalTypeDeclScopeSyntax, WithGenericParametersScopeSyntax { + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [] + } + @_spi(Experimental) public var scopeDebugName: String { + "EnumDeclScope" } } -@_spi(Experimental) extension ClassDeclSyntax: NonProtocolNominalTypeDeclSyntax { +@_spi(Experimental) extension ClassDeclSyntax: NominalTypeDeclScopeSyntax, WithGenericParametersScopeSyntax { + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [] + } @_spi(Experimental) public var scopeDebugName: String { "ClassDeclScope" } } -@_spi(Experimental) extension StructDeclSyntax: NonProtocolNominalTypeDeclSyntax { +@_spi(Experimental) extension ActorDeclSyntax: NominalTypeDeclScopeSyntax, WithGenericParametersScopeSyntax { + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [] + } @_spi(Experimental) public var scopeDebugName: String { - "StructDeclScope" + "ActorDeclScope" } } -@_spi(Experimental) extension EnumDeclSyntax: NonProtocolNominalTypeDeclSyntax { +@_spi(Experimental) extension ProtocolDeclSyntax: NominalTypeDeclScopeSyntax { + // Like extensions, protocols introduce implicit `Self`; see comment above. + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [.implicit(.Self(DeclSyntax(self)))] + } + @_spi(Experimental) public var scopeDebugName: String { - "EnumDeclScope" + "ProtocolDeclScope" + } + + /// For the lookup initiated from inside primary + /// associated type clause, this function also finds + /// all associated type declarations made inside the + /// protocol member block. + /// + /// ### Example + /// ```swift + /// class A {} + /// + /// protocol Foo*/> { + /// associatedtype A + /// class A {} + /// } + /// ``` + /// For the lookup started at the primary associated type `A`, + /// the function returns exactly two results. First associated with the member + /// block that consists of the `associatedtype A` declaration and + /// the latter one from the file scope and `class A` exactly in this order. + public func lookup( + _ identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + var results: [LookupResult] = [] + + if let primaryAssociatedTypeClause, + primaryAssociatedTypeClause.range.contains(lookUpPosition) + { + results = memberBlock.lookupAssociatedTypeDeclarations( + identifier, + at: lookUpPosition, + with: config + ) + } + + let lookInMembers: [LookupResult] + + if inheritanceClause?.range.contains(lookUpPosition) != false { + lookInMembers = [.lookForMembers(in: Syntax(self))] + } else { + lookInMembers = [] + } + + return results + + defaultLookupImplementation( + identifier, + at: lookUpPosition, + with: config, + propagateToParent: false + ) + lookInMembers + lookupInParent(identifier, at: lookUpPosition, with: config) } } + @_spi(Experimental) extension ExtensionDeclSyntax: ScopeSyntax, LookInMembersScopeSyntax { @_spi(Experimental) public var lookupMembersPosition: AbsolutePosition { if let memberType = extendedType.as(MemberTypeSyntax.self) { @@ -663,73 +740,6 @@ import SwiftSyntax } } -@_spi(Experimental) extension ProtocolDeclSyntax: ScopeSyntax, LookInMembersScopeSyntax { - /// Protocol declarations don't introduce names by themselves. - @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { - [.implicit(.Self(DeclSyntax(self)))] - } - - @_spi(Experimental) public var lookupMembersPosition: AbsolutePosition { - name.positionAfterSkippingLeadingTrivia - } - - @_spi(Experimental) public var scopeDebugName: String { - "ProtocolDeclScope" - } - - /// For the lookup initiated from inside primary - /// associated type clause, this function also finds - /// all associated type declarations made inside the - /// protocol member block. - /// - /// ### Example - /// ```swift - /// class A {} - /// - /// protocol Foo*/> { - /// associatedtype A - /// class A {} - /// } - /// ``` - /// For the lookup started at the primary associated type `A`, - /// the function returns exactly two results. First associated with the member - /// block that consists of the `associatedtype A` declaration and - /// the latter one from the file scope and `class A` exactly in this order. - public func lookup( - _ identifier: Identifier?, - at lookUpPosition: AbsolutePosition, - with config: LookupConfig - ) -> [LookupResult] { - var results: [LookupResult] = [] - - if let primaryAssociatedTypeClause, - primaryAssociatedTypeClause.range.contains(lookUpPosition) - { - results = memberBlock.lookupAssociatedTypeDeclarations( - identifier, - at: lookUpPosition, - with: config - ) - } - - let lookInMembers: [LookupResult] - - if !(inheritanceClause?.range.contains(lookUpPosition) ?? false) { - lookInMembers = [.lookForMembers(in: Syntax(self))] - } else { - lookInMembers = [] - } - - return results - + defaultLookupImplementation( - identifier, - at: lookUpPosition, - with: config, - propagateToParent: false - ) + lookInMembers + lookupInParent(identifier, at: lookUpPosition, with: config) - } -} - @_spi(Experimental) extension GenericParameterClauseSyntax: GenericParameterScopeSyntax { /// Generic parameter names introduced by this clause. @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { @@ -1062,4 +1072,5 @@ extension SubscriptDeclSyntax: WithGenericParametersScopeSyntax, CanInterleaveRe @_spi(Experimental) public var scopeDebugName: String { "IfConfigScope" } + } From 759df6849e8f84f1f4ff209ae8ed08111a5dae81 Mon Sep 17 00:00:00 2001 From: Filip Sakellariou Date: Tue, 14 Jul 2026 14:52:21 -0400 Subject: [PATCH 4/5] SwiftLexicalLookup: Rename NonProtocolNominalTypeDeclSyntax.swift->NominalTypeDeclScopeSyntax.swift --- ...minalTypeDeclSyntax.swift => NominalTypeDeclScopeSyntax.swift} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Sources/SwiftLexicalLookup/Scopes/{NonProtocolNominalTypeDeclSyntax.swift => NominalTypeDeclScopeSyntax.swift} (100%) diff --git a/Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclScopeSyntax.swift similarity index 100% rename from Sources/SwiftLexicalLookup/Scopes/NonProtocolNominalTypeDeclSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclScopeSyntax.swift From 58b966582ddd632593afb6101a147740c244ec89 Mon Sep 17 00:00:00 2001 From: Filip Sakellariou Date: Tue, 14 Jul 2026 16:31:22 -0400 Subject: [PATCH 5/5] SwiftLexicalLookup: Add new qualified-lookup types to CMakeLists.txt --- Sources/SwiftLexicalLookup/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftLexicalLookup/CMakeLists.txt b/Sources/SwiftLexicalLookup/CMakeLists.txt index 531af5e8c5b..7213d300f51 100644 --- a/Sources/SwiftLexicalLookup/CMakeLists.txt +++ b/Sources/SwiftLexicalLookup/CMakeLists.txt @@ -18,7 +18,7 @@ add_swift_syntax_library(SwiftLexicalLookup Scopes/GenericParameterScopeSyntax.swift Scopes/IntroducingToSequentialParentScopeSyntax.swift Scopes/LookInMembersScopeSyntax.swift - Scopes/NominalTypeDeclSyntax.swift + Scopes/NominalTypeDeclScopeSyntax.swift Scopes/ScopeImplementations.swift Scopes/ScopeSyntax.swift Scopes/SequentialScopeSyntax.swift @@ -28,6 +28,9 @@ add_swift_syntax_library(SwiftLexicalLookup QualifiedLookup/DeclName.swift QualifiedLookup/DeclScope.swift QualifiedLookup/MemberKind.swift + QualifiedLookup/NominalTypeDeclSyntax.swift + QualifiedLookup/TypeDeclSyntax.swift + QualifiedLookup/TypeLikeSyntax.swift QualifiedLookup/ValueDeclSyntax.swift )