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 ) 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 new file mode 100644 index 00000000000..1807895ca56 --- /dev/null +++ b/Sources/SwiftLexicalLookup/QualifiedLookup/NominalTypeDeclSyntax.swift @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +/// 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: NominalTypeDeclSyntaxProtocol, SyntaxHashable { + 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 NominalTypeDeclSyntaxProtocol = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .enumDecl(let declGroup): + var box: any NominalTypeDeclSyntaxProtocol = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .classDecl(let declGroup): + var box: any NominalTypeDeclSyntaxProtocol = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .actorDecl(let declGroup): + var box: any NominalTypeDeclSyntaxProtocol = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + case .protocolDecl(let declGroup): + var box: any NominalTypeDeclSyntaxProtocol = declGroup + box[keyPath: keyPath] = newValue + _syntaxNode = box._syntaxNode + default: + fatalError("[Internal Error] Invalid syntax kind for DeclGroupSyntaxType: \(_syntaxNode.kind)") + } + } + + public init(_ syntax: __shared some NominalTypeDeclSyntaxProtocol) { + self = Syntax(syntax).cast(Self.self) + } + + 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), + ]) +} diff --git a/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift b/Sources/SwiftLexicalLookup/QualifiedLookup/ValueDeclSyntax.swift index 7effa2a7090..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 NominalTypeDeclSyntax) { - // 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/NominalTypeDeclScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclScopeSyntax.swift new file mode 100644 index 00000000000..34ac89b04fe --- /dev/null +++ b/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclScopeSyntax.swift @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 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 + +/// Helper scope for nominal types (structs, enums, classes, actors, protocols). +@_spi(Experimental) +public protocol NominalTypeDeclScopeSyntax: NominalTypeDeclSyntaxProtocol, ScopeSyntax, LookInMembersScopeSyntax {} + +extension NominalTypeDeclScopeSyntax /*: LookInMembersScopeSyntax */ { + @_spi(Experimental) public var lookupMembersPosition: AbsolutePosition { + name.positionAfterSkippingLeadingTrivia + } +} + +// 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( + _ identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + // 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 { + lookInMembers = [LookupResult.lookForMembers(in: Syntax(self))] + } + + return lookInMembers + lookupInParent(identifier, at: lookUpPosition, with: config) + } +} diff --git a/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift deleted file mode 100644 index 314b9ebf870..00000000000 --- a/Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift +++ /dev/null @@ -1,49 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2024 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 - -@_spi(Experimental) -public protocol NominalTypeDeclSyntax: LookInMembersScopeSyntax, DeclGroupSyntax, NamedDeclSyntax, - WithGenericParametersScopeSyntax -{ - var genericParameterClause: GenericParameterClauseSyntax? { get } -} - -extension NominalTypeDeclSyntax { - @_spi(Experimental) public var lookupMembersPosition: AbsolutePosition { - name.positionAfterSkippingLeadingTrivia - } - - /// Nominal type doesn't introduce any names by itself. - @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { - [] - } - - /// Function used by generic parameter clause - /// scope on return from it's lookup. - @_spi(Experimental) public func returningLookupFromGenericParameterScope( - _ identifier: Identifier?, - 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) - } else { - return [.lookForMembers(in: Syntax(self))] + lookupInParent(identifier, at: lookUpPosition, with: config) - } - } -} diff --git a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift index bbed72263ae..fc63d11300d 100644 --- a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift @@ -363,26 +363,103 @@ import SwiftSyntax } } -@_spi(Experimental) extension ActorDeclSyntax: NominalTypeDeclSyntax { +/// 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: NominalTypeDeclSyntax { +@_spi(Experimental) extension ClassDeclSyntax: NominalTypeDeclScopeSyntax, WithGenericParametersScopeSyntax { + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [] + } @_spi(Experimental) public var scopeDebugName: String { "ClassDeclScope" } } -@_spi(Experimental) extension StructDeclSyntax: NominalTypeDeclSyntax { +@_spi(Experimental) extension ActorDeclSyntax: NominalTypeDeclScopeSyntax, WithGenericParametersScopeSyntax { + @_spi(Experimental) public var defaultIntroducedNames: [LookupName] { + [] + } @_spi(Experimental) public var scopeDebugName: String { - "StructDeclScope" + "ActorDeclScope" } } -@_spi(Experimental) extension EnumDeclSyntax: NominalTypeDeclSyntax { +@_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" } + }