|
32 | 32 | #include "swift/AST/ForeignAsyncConvention.h" |
33 | 33 | #include "swift/AST/ForeignErrorConvention.h" |
34 | 34 | #include "swift/AST/GenericEnvironment.h" |
| 35 | +#include "swift/AST/TypeDifferenceVisitor.h" |
35 | 36 | #include "swift/Basic/STLExtras.h" |
36 | 37 | #include "swift/SIL/FormalLinkage.h" |
37 | 38 | #include "swift/SIL/PrettyStackTrace.h" |
@@ -139,6 +140,51 @@ void SILGenModule::emitBackDeploymentThunk(SILDeclRef thunk) { |
139 | 140 | emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); |
140 | 141 | } |
141 | 142 |
|
| 143 | +namespace { |
| 144 | + |
| 145 | +/// Checker that validates that a distributed thunk is completely the same |
| 146 | +/// except that self can vary by isolation. |
| 147 | +struct DistributedThunkDiffChecker |
| 148 | + : CanTypeDifferenceVisitor<DistributedThunkDiffChecker> { |
| 149 | + using SuperTy = CanTypeDifferenceVisitor<DistributedThunkDiffChecker>; |
| 150 | + |
| 151 | + bool visitSILFunctionTypeComponents(CanSILFunctionType type1, |
| 152 | + CanSILFunctionType type2) { |
| 153 | + // If they do not both have a self param. Just delegate to our parent. |
| 154 | + if (!type1->hasSelfParam() || !type2->hasSelfParam()) { |
| 155 | + return SuperTy::visitSILFunctionTypeComponents(type1, type2); |
| 156 | + } |
| 157 | + |
| 158 | + // Otherwise, we both have self. First check if we have the same number of |
| 159 | + // parameters. |
| 160 | + auto type1Params = type1->getParameters(); |
| 161 | + auto type2Params = type2->getParameters(); |
| 162 | + if (type1Params.size() != type2Params.size()) |
| 163 | + return visitDifferentTypeStructure(type1, type2); |
| 164 | + |
| 165 | + // Then check if self is the same ignoring isolation. |
| 166 | + auto self1 = type1Params.back(); |
| 167 | + auto self2 = type2Params.back(); |
| 168 | + auto self1Options = self1.getOptions() - SILParameterInfo::Isolated; |
| 169 | + auto self2Options = self2.getOptions() - SILParameterInfo::Isolated; |
| 170 | + |
| 171 | + if (self1.getConvention() != self2.getConvention() || |
| 172 | + !self1Options.containsOnly(self2Options)) |
| 173 | + return visitDifferentTypeStructure(type1, type2); |
| 174 | + |
| 175 | + // Finally, check our self type, non-self components, results, and yields. |
| 176 | + return visit(self1.getInterfaceType(), self2.getInterfaceType()) || |
| 177 | + visitComponentArray(type1, type2, type1Params.drop_back(), |
| 178 | + type2Params.drop_back()) || |
| 179 | + visitComponentArray(type1, type2, type1->getResults(), |
| 180 | + type2->getResults()) || |
| 181 | + visitComponentArray(type1, type2, type1->getYields(), |
| 182 | + type2->getYields()); |
| 183 | + } |
| 184 | +}; |
| 185 | + |
| 186 | +} // namespace |
| 187 | + |
142 | 188 | SILValue |
143 | 189 | SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, |
144 | 190 | SILConstantInfo constantInfo, |
@@ -171,18 +217,35 @@ SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, |
171 | 217 | auto existingType = |
172 | 218 | f->getLoweredFunctionTypeInContext(B.getTypeExpansionContext()); |
173 | 219 | if (existingType != constantFnTypeInContext) { |
174 | | - // This can happen for example when using @_silgen_name or @_extern(c) |
175 | | - // attributes |
176 | | - SGM.diagnose(loc.getSourceLoc(), diag::function_type_mismatch, existingType, |
177 | | - constantFnTypeInContext); |
178 | | - SGM.diagnose(f->getLocation().getSourceLoc(), diag::function_declared_here); |
179 | | - return SILUndef::get(constantInfo.getSILType(), F); |
| 220 | + auto emitError = [&] { |
| 221 | + // This can happen for example when using @_silgen_name or @_extern(c) |
| 222 | + // attributes |
| 223 | + SGM.diagnose(loc.getSourceLoc(), diag::function_type_mismatch, |
| 224 | + existingType, constantFnTypeInContext); |
| 225 | + SGM.diagnose(f->getLocation().getSourceLoc(), |
| 226 | + diag::function_declared_here); |
| 227 | + return SILUndef::get(constantInfo.getSILType(), F); |
| 228 | + }; |
| 229 | + |
| 230 | + // If we have a distributed thunk, see if we only differ by isolation. |
| 231 | + if (f->isDistributed() && f->isThunk()) { |
| 232 | + DistributedThunkDiffChecker diffChecker; |
| 233 | + if (diffChecker.visit(existingType, constantFnTypeInContext)) { |
| 234 | + return emitError(); |
| 235 | + } |
| 236 | + |
| 237 | + // We differ only by isolation... so do not error. |
| 238 | + } else { |
| 239 | + // This can happen for example when using @_silgen_name or @_extern(c) |
| 240 | + // attributes |
| 241 | + return emitError(); |
| 242 | + } |
180 | 243 | } |
181 | 244 |
|
182 | 245 | if (callPreviousDynamicReplaceableImpl) |
183 | 246 | return B.createPreviousDynamicFunctionRef(loc, f); |
184 | | - else |
185 | | - return B.createFunctionRefFor(loc, f); |
| 247 | + |
| 248 | + return B.createFunctionRefFor(loc, f); |
186 | 249 | } |
187 | 250 |
|
188 | 251 | static const clang::Type *prependParameterType( |
|
0 commit comments