Skip to content

Commit 2f72f06

Browse files
authored
Merge pull request #10033 from augusto2112/fix-objc-protocol
[lldb] Fix dynamic type resolution for ObjC protocol existentials
2 parents 3a15703 + 419a0bb commit 2f72f06

File tree

8 files changed

+124
-12
lines changed

8 files changed

+124
-12
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2867,10 +2867,15 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
28672867
else if (type_info.AllSet(eTypeIsMetatype | eTypeIsProtocol))
28682868
success = GetDynamicTypeAndAddress_ExistentialMetatype(
28692869
in_value, val_type, use_dynamic, class_type_or_name, address);
2870-
else if (type_info.AnySet(eTypeIsProtocol))
2871-
success = GetDynamicTypeAndAddress_Existential(in_value, val_type, use_dynamic,
2872-
class_type_or_name, address);
2873-
else {
2870+
else if (type_info.AnySet(eTypeIsProtocol)) {
2871+
if (type_info.AnySet(eTypeIsObjC))
2872+
success = GetDynamicTypeAndAddress_Class(in_value, val_type, use_dynamic,
2873+
class_type_or_name, address,
2874+
static_value_type, local_buffer);
2875+
else
2876+
success = GetDynamicTypeAndAddress_Existential(
2877+
in_value, val_type, use_dynamic, class_type_or_name, address);
2878+
} else {
28742879
CompilerType bound_type;
28752880
if (type_info.AnySet(eTypeHasUnboundGeneric | eTypeHasDynamicSelf)) {
28762881
// Perform generic type resolution.

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6188,11 +6188,18 @@ SwiftASTContext::GetTypeInfo(opaque_compiler_type_t type,
61886188
eTypeInstanceIsPointer;
61896189
break;
61906190

6191-
case swift::TypeKind::Protocol:
6191+
case swift::TypeKind::Protocol: {
6192+
auto *protocol =
6193+
llvm::cast<swift::ProtocolType>(swift_can_type.getPointer());
6194+
swift::ProtocolDecl *decl = protocol->getDecl();
6195+
if (decl->isObjC())
6196+
swift_flags |= eTypeIsObjC | eTypeHasValue;
6197+
LLVM_FALLTHROUGH;
6198+
}
61926199
case swift::TypeKind::ProtocolComposition:
6193-
case swift::TypeKind::Existential:
6200+
case swift::TypeKind::Existential: {
61946201
swift_flags |= eTypeHasChildren | eTypeIsStructUnion | eTypeIsProtocol;
6195-
break;
6202+
} break;
61966203
case swift::TypeKind::ExistentialMetatype:
61976204
swift_flags |= eTypeIsProtocol;
61986205
LLVM_FALLTHROUGH;

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,22 +1653,47 @@ swift::Demangle::NodePointer TypeSystemSwiftTypeRef::GetDemangleTreeForPrinting(
16531653
return GetNodeForPrintingImpl(dem, node, flavor, resolve_objc_module);
16541654
}
16551655

1656-
/// Determine wether this demangle tree contains a node of kind \c kind.
1656+
/// Determine wether this demangle tree contains a node of kind \c kind and with
1657+
/// text \c text (if provided).
16571658
static bool Contains(swift::Demangle::NodePointer node,
1658-
swift::Demangle::Node::Kind kind) {
1659+
swift::Demangle::Node::Kind kind,
1660+
llvm::StringRef text = "") {
16591661
if (!node)
16601662
return false;
16611663

1662-
if (node->getKind() == kind)
1663-
return true;
1664+
if (node->getKind() == kind) {
1665+
if (text.empty())
1666+
return true;
1667+
if (!node->hasText())
1668+
return false;
1669+
return node->getText() == text;
1670+
}
16641671

16651672
for (swift::Demangle::NodePointer child : *node)
1666-
if (Contains(child, kind))
1673+
if (Contains(child, kind, text))
16671674
return true;
16681675

16691676
return false;
16701677
}
16711678

1679+
static bool ProtocolCompositionContainsSingleObjcProtocol(
1680+
swift::Demangle::NodePointer node) {
1681+
// Kind=ProtocolList
1682+
// Kind=TypeList
1683+
// Kind=Type
1684+
// Kind=Protocol
1685+
// Kind=Module, text="__C"
1686+
// Kind=Identifier, text="SomeIdentifier"
1687+
if (node->getKind() != Node::Kind::ProtocolList)
1688+
return false;
1689+
NodePointer type_list = node->getFirstChild();
1690+
if (type_list->getKind() != Node::Kind::TypeList ||
1691+
type_list->getNumChildren() != 1)
1692+
return false;
1693+
NodePointer type = type_list->getFirstChild();
1694+
return Contains(type, Node::Kind::Module, swift::MANGLING_MODULE_OBJC);
1695+
}
1696+
16721697
/// Determine wether this demangle tree contains a generic type parameter.
16731698
static bool ContainsGenericTypeParameter(swift::Demangle::NodePointer node) {
16741699
return Contains(node, swift::Demangle::Node::Kind::DependentGenericParamType);
@@ -1855,6 +1880,8 @@ uint32_t TypeSystemSwiftTypeRef::CollectTypeInfo(
18551880
swift_flags |= eTypeIsProtocol;
18561881
// Bug-for-bug-compatibility.
18571882
swift_flags |= eTypeHasChildren | eTypeIsStructUnion;
1883+
if (ProtocolCompositionContainsSingleObjcProtocol(node))
1884+
swift_flags |= eTypeIsObjC | eTypeHasValue;
18581885
break;
18591886

18601887
case Node::Kind::ExistentialMetatype:
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFT_BRIDGING_HEADER := bridging-header.h
3+
OBJC_SOURCES := objc.m
4+
SWIFT_OBJC_INTEROP := 1
5+
6+
include Makefile.rules
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
7+
class TestSwiftObjcProtocol(TestBase):
8+
@skipUnlessDarwin
9+
@swiftTest
10+
def test(self):
11+
"""Tests that dynamic type resolution works for an Objective-C protocol existential"""
12+
self.build()
13+
(target, process, thread, breakpoint) = lldbutil.run_to_source_breakpoint(
14+
self, "break here", lldb.SBFileSpec("main.swift")
15+
)
16+
17+
self.runCmd("settings set symbols.swift-enable-ast-context false")
18+
self.expect("frame variable v", substrs=["SwiftClass", "a = 42", "b = 938"])
19+
lldbutil.continue_to_breakpoint(process, breakpoint)
20+
self.expect(
21+
"frame variable v",
22+
substrs=["ObjcClass", "_someString", '"The objc string"'],
23+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
#include <Foundation/Foundation.h>
3+
4+
@protocol ObjcProtocol <NSObject>
5+
@end
6+
7+
@interface ObjcClass : NSObject <ObjcProtocol>
8+
@property NSString *someString;
9+
- (instancetype)init;
10+
+ (id<ObjcProtocol>)getP;
11+
@end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class SwiftClass: NSObject, ObjcProtocol {
2+
let a = 42
3+
let b = 938
4+
}
5+
6+
func foo(v: (any ObjcProtocol)) {
7+
print(v) // break here
8+
}
9+
10+
func f() {
11+
let swiftClass = SwiftClass()
12+
foo(v: swiftClass)
13+
let objcClass = ObjcClass()!
14+
foo(v: objcClass)
15+
}
16+
f()
17+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include "bridging-header.h"
2+
3+
@implementation ObjcClass
4+
5+
- (instancetype)init {
6+
self = [super init];
7+
if (self) {
8+
self.someString = @"The objc string";
9+
}
10+
return self;
11+
}
12+
13+
+ (id<ObjcProtocol>)getP {
14+
return [ObjcClass new];
15+
}
16+
@end

0 commit comments

Comments
 (0)