@@ -30,9 +30,6 @@ using namespace swift;
30
30
// / Get the method dispatch mechanism for a method.
31
31
MethodDispatch
32
32
swift::getMethodDispatch (AbstractFunctionDecl *method) {
33
- // Final methods can be statically referenced.
34
- if (method->isFinal ())
35
- return MethodDispatch::Static;
36
33
// Some methods are forced to be statically dispatched.
37
34
if (method->hasForcedStaticDispatch ())
38
35
return MethodDispatch::Static;
@@ -41,23 +38,23 @@ swift::getMethodDispatch(AbstractFunctionDecl *method) {
41
38
if (method->isImportAsMember ())
42
39
return MethodDispatch::Static;
43
40
44
- // If this declaration is in a class but not marked final, then it is
45
- // always dynamically dispatched.
46
41
auto dc = method->getDeclContext ();
47
- if (isa<ClassDecl>(dc))
48
- return MethodDispatch::Class;
49
42
50
- // Class extension methods are only dynamically dispatched if they're
51
- // dispatched by objc_msgSend, which happens if they're foreign or dynamic.
52
43
if (dc->getAsClassOrClassExtensionContext ()) {
53
- if (method->hasClangNode ())
54
- return MethodDispatch::Class;
55
- if (auto fd = dyn_cast<FuncDecl>(method)) {
56
- if (fd->isAccessor () && fd->getAccessorStorageDecl ()->hasClangNode ())
57
- return MethodDispatch::Class;
58
- }
59
44
if (method->isDynamic ())
60
45
return MethodDispatch::Class;
46
+
47
+ // Final methods can be statically referenced.
48
+ if (method->isFinal ())
49
+ return MethodDispatch::Static;
50
+
51
+ // Members defined directly inside a class are dynamically dispatched.
52
+ if (isa<ClassDecl>(dc))
53
+ return MethodDispatch::Class;
54
+
55
+ // Imported class methods are dynamically dispatched.
56
+ if (method->isObjC () && method->hasClangNode ())
57
+ return MethodDispatch::Class;
61
58
}
62
59
63
60
// Otherwise, it can be referenced statically.
@@ -79,151 +76,30 @@ bool swift::requiresForeignToNativeThunk(ValueDecl *vd) {
79
76
return false ;
80
77
}
81
78
82
- // / FIXME: merge requiresForeignEntryPoint() into getMethodDispatch() and add
83
- // / an ObjectiveC case to the MethodDispatch enum.
84
79
bool swift::requiresForeignEntryPoint (ValueDecl *vd) {
85
- if (vd->isImportAsMember ())
80
+ assert (!isa<AbstractStorageDecl>(vd));
81
+
82
+ if (vd->isDynamic ())
86
83
return true ;
87
84
88
- // Final functions never require ObjC dispatch.
89
- if (vd->isFinal ())
90
- return false ;
85
+ if (vd->isObjC () && isa<ProtocolDecl>(vd->getDeclContext ()))
86
+ return true ;
87
+
88
+ if (vd->isImportAsMember ())
89
+ return true ;
91
90
92
- if (requiresForeignToNativeThunk (vd ))
91
+ if (vd-> hasClangNode ( ))
93
92
return true ;
94
93
95
94
if (auto *fd = dyn_cast<FuncDecl>(vd)) {
96
-
97
95
// Property accessors should be generated alongside the property.
98
- if (fd->isGetterOrSetter ())
99
- return requiresForeignEntryPoint (fd->getAccessorStorageDecl ());
100
-
101
- return fd->isDynamic ();
102
- }
103
-
104
- if (auto *cd = dyn_cast<ConstructorDecl>(vd)) {
105
- if (cd->hasClangNode ())
106
- return true ;
107
-
108
- return cd->isDynamic ();
109
- }
110
-
111
- if (auto *asd = dyn_cast<AbstractStorageDecl>(vd))
112
- return asd->requiresForeignGetterAndSetter ();
113
-
114
- return vd->isDynamic ();
115
- }
116
-
117
- // / TODO: We should consult the cached LoweredLocalCaptures the SIL
118
- // / TypeConverter calculates, but that would require plumbing SILModule&
119
- // / through every SILDeclRef constructor. Since this is only used to determine
120
- // / "natural uncurry level", and "uncurry level" is a concept we'd like to
121
- // / phase out, it's not worth it.
122
- static bool hasLoweredLocalCaptures (AnyFunctionRef AFR,
123
- llvm::DenseSet<AnyFunctionRef> &visited) {
124
- if (!AFR.getCaptureInfo ().hasLocalCaptures ())
125
- return false ;
126
-
127
- // Scan for local, non-function captures.
128
- bool functionCapturesToRecursivelyCheck = false ;
129
- auto addFunctionCapture = [&](AnyFunctionRef capture) {
130
- if (visited.find (capture) == visited.end ())
131
- functionCapturesToRecursivelyCheck = true ;
132
- };
133
- for (auto &capture : AFR.getCaptureInfo ().getCaptures ()) {
134
- if (!capture.getDecl ()->getDeclContext ()->isLocalContext ())
135
- continue ;
136
- // We transitively capture a local function's captures.
137
- if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl ())) {
138
- addFunctionCapture (func);
139
- continue ;
140
- }
141
- // We may either directly capture properties, or capture through their
142
- // accessors.
143
- if (auto var = dyn_cast<VarDecl>(capture.getDecl ())) {
144
- switch (var->getStorageKind ()) {
145
- case VarDecl::StoredWithTrivialAccessors:
146
- llvm_unreachable (" stored local variable with trivial accessors?" );
147
-
148
- case VarDecl::InheritedWithObservers:
149
- llvm_unreachable (" inherited local variable?" );
150
-
151
- case VarDecl::StoredWithObservers:
152
- case VarDecl::Addressed:
153
- case VarDecl::AddressedWithTrivialAccessors:
154
- case VarDecl::AddressedWithObservers:
155
- case VarDecl::ComputedWithMutableAddress:
156
- // Directly capture storage if we're supposed to.
157
- if (capture.isDirect ())
158
- return true ;
159
-
160
- // Otherwise, transitively capture the accessors.
161
- LLVM_FALLTHROUGH;
162
-
163
- case VarDecl::Computed:
164
- addFunctionCapture (var->getGetter ());
165
- if (auto setter = var->getSetter ())
166
- addFunctionCapture (setter);
167
- continue ;
168
-
169
- case VarDecl::Stored:
96
+ if (fd->isGetterOrSetter ()) {
97
+ auto *asd = fd->getAccessorStorageDecl ();
98
+ if (asd->isObjC () && asd->hasClangNode ())
170
99
return true ;
171
- }
172
100
}
173
- // Anything else is directly captured.
174
- return true ;
175
101
}
176
-
177
- // Recursively consider function captures, since we didn't have any direct
178
- // captures.
179
- auto captureHasLocalCaptures = [&](AnyFunctionRef capture) -> bool {
180
- if (visited.insert (capture).second )
181
- return hasLoweredLocalCaptures (capture, visited);
182
- return false ;
183
- };
184
-
185
- if (functionCapturesToRecursivelyCheck) {
186
- for (auto &capture : AFR.getCaptureInfo ().getCaptures ()) {
187
- if (!capture.getDecl ()->getDeclContext ()->isLocalContext ())
188
- continue ;
189
- if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl ())) {
190
- if (captureHasLocalCaptures (func))
191
- return true ;
192
- continue ;
193
- }
194
- if (auto var = dyn_cast<VarDecl>(capture.getDecl ())) {
195
- switch (var->getStorageKind ()) {
196
- case VarDecl::StoredWithTrivialAccessors:
197
- llvm_unreachable (" stored local variable with trivial accessors?" );
198
-
199
- case VarDecl::InheritedWithObservers:
200
- llvm_unreachable (" inherited local variable?" );
201
-
202
- case VarDecl::StoredWithObservers:
203
- case VarDecl::Addressed:
204
- case VarDecl::AddressedWithTrivialAccessors:
205
- case VarDecl::AddressedWithObservers:
206
- case VarDecl::ComputedWithMutableAddress:
207
- assert (!capture.isDirect () && " should have short circuited out" );
208
- // Otherwise, transitively capture the accessors.
209
- LLVM_FALLTHROUGH;
210
-
211
- case VarDecl::Computed:
212
- if (captureHasLocalCaptures (var->getGetter ()))
213
- return true ;
214
- if (auto setter = var->getSetter ())
215
- if (captureHasLocalCaptures (setter))
216
- return true ;
217
- continue ;
218
-
219
- case VarDecl::Stored:
220
- llvm_unreachable (" should have short circuited out" );
221
- }
222
- }
223
- llvm_unreachable (" should have short circuited out" );
224
- }
225
- }
226
-
102
+
227
103
return false ;
228
104
}
229
105
0 commit comments