Skip to content

Commit 2e61205

Browse files
committed
Move SIL's checkASTTypeForABIDifferences into TypeBase::matches
It's doing essentially the same walk, just with different rules at each step. This is also something we want accessible at the AST level (see subsequent commits).
1 parent f170b94 commit 2e61205

File tree

3 files changed

+42
-81
lines changed

3 files changed

+42
-81
lines changed

include/swift/AST/Types.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,9 @@ enum class TypeMatchFlags {
232232
///
233233
/// This includes function parameters and result types as well as tuple
234234
/// elements, but excludes generic parameters.
235-
AllowTopLevelOptionalMismatch = 1 << 2
235+
AllowTopLevelOptionalMismatch = 1 << 2,
236+
/// Allow any ABI-compatible types to be considered matching.
237+
AllowABICompatible = 1 << 3,
236238
};
237239
using TypeMatchOptions = OptionSet<TypeMatchFlags>;
238240

lib/AST/Type.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,6 +2316,31 @@ bool TypeBase::isTriviallyRepresentableIn(ForeignLanguage language,
23162316
llvm_unreachable("Unhandled ForeignRepresentableKind in switch.");
23172317
}
23182318

2319+
static bool isABICompatibleEvenAddingOptional(CanType t1, CanType t2) {
2320+
// Classes, class-constrained archetypes, and pure-ObjC existential
2321+
// types all have single retainable pointer representation; optionality
2322+
// change is allowed.
2323+
// NOTE: This doesn't use isAnyClassReferenceType because we want it to
2324+
// return a conservative answer for dependent types. There's probably
2325+
// a better answer here, though.
2326+
if ((t1->mayHaveSuperclass() || t1->isObjCExistentialType()) &&
2327+
(t2->mayHaveSuperclass() || t2->isObjCExistentialType())) {
2328+
return true;
2329+
}
2330+
2331+
// Class metatypes are ABI-compatible even under optionality change.
2332+
if (auto metaTy1 = dyn_cast<MetatypeType>(t1)) {
2333+
if (auto metaTy2 = dyn_cast<MetatypeType>(t2)) {
2334+
if (metaTy1.getInstanceType().getClassOrBoundGenericClass() &&
2335+
metaTy2.getInstanceType().getClassOrBoundGenericClass()) {
2336+
return true;
2337+
}
2338+
}
2339+
}
2340+
2341+
return false;
2342+
}
2343+
23192344
namespace {
23202345
enum class ParameterPosition {
23212346
NotParameter,
@@ -2342,6 +2367,10 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
23422367
}
23432368

23442369
// Value-to-optional.
2370+
if (matchMode.contains(TypeMatchFlags::AllowABICompatible)) {
2371+
if (isABICompatibleEvenAddingOptional(t1, obj2))
2372+
return true;
2373+
}
23452374
if (matchMode.contains(TypeMatchFlags::AllowOverride) ||
23462375
matchMode.contains(TypeMatchFlags::AllowTopLevelOptionalMismatch)) {
23472376
return matches(t1, obj2, matchMode, ParameterPosition::NotParameter,
@@ -2393,12 +2422,17 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
23932422
}
23942423

23952424
// Function-to-function.
2396-
// FIXME: This completely leaves out generic functions.
2397-
if (auto fn2 = dyn_cast<FunctionType>(t2)) {
2398-
auto fn1 = dyn_cast<FunctionType>(t1);
2425+
if (auto fn2 = dyn_cast<AnyFunctionType>(t2)) {
2426+
auto fn1 = dyn_cast<AnyFunctionType>(t1);
23992427
if (!fn1)
24002428
return false;
24012429

2430+
// FIXME: Handle generic functions in non-ABI matches.
2431+
if (!matchMode.contains(TypeMatchFlags::AllowABICompatible)) {
2432+
if (!isa<FunctionType>(t1) || !isa<FunctionType>(t2))
2433+
return false;
2434+
}
2435+
24022436
// When checking overrides, allow the base type to be throwing even if the
24032437
// overriding type isn't.
24042438
auto ext1 = fn1->getExtInfo();

lib/SIL/SILFunctionType.cpp

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,83 +1795,8 @@ bool TypeConverter::requiresNewVTableEntry(SILDeclRef method) {
17951795
// @guaranteed or whatever.
17961796
static bool checkASTTypeForABIDifferences(CanType type1,
17971797
CanType type2) {
1798-
// Unwrap optionals, but remember that we did.
1799-
bool type1WasOptional = false;
1800-
bool type2WasOptional = false;
1801-
if (auto object = type1.getAnyOptionalObjectType()) {
1802-
type1WasOptional = true;
1803-
type1 = object;
1804-
}
1805-
if (auto object = type2.getAnyOptionalObjectType()) {
1806-
type2WasOptional = true;
1807-
type2 = object;
1808-
}
1809-
1810-
// Forcing IUOs always requires a new vtable entry.
1811-
if (type1WasOptional && !type2WasOptional)
1812-
return true;
1813-
1814-
// Except for the above case, we should not be making a value less optional.
1815-
1816-
// If we're introducing a level of optionality, only certain types are
1817-
// ABI-compatible -- check below.
1818-
bool optionalityChange = (!type1WasOptional && type2WasOptional);
1819-
1820-
// If the types are identical and there was no optionality change,
1821-
// we're done.
1822-
if (type1 == type2 && !optionalityChange)
1823-
return false;
1824-
1825-
// Classes, class-constrained archetypes, and pure-ObjC existential types
1826-
// all have single retainable pointer representation; optionality change
1827-
// is allowed.
1828-
if ((type1->mayHaveSuperclass() ||
1829-
type1->isObjCExistentialType()) &&
1830-
(type2->mayHaveSuperclass() ||
1831-
type2->isObjCExistentialType()))
1832-
return false;
1833-
1834-
// Class metatypes are ABI-compatible even under optionality change.
1835-
if (auto metaTy1 = dyn_cast<MetatypeType>(type1)) {
1836-
if (auto metaTy2 = dyn_cast<MetatypeType>(type2)) {
1837-
if (metaTy1.getInstanceType().getClassOrBoundGenericClass() &&
1838-
metaTy2.getInstanceType().getClassOrBoundGenericClass())
1839-
return false;
1840-
}
1841-
}
1842-
1843-
if (!optionalityChange) {
1844-
// Function parameters are ABI compatible if their differences are
1845-
// trivial.
1846-
if (auto fnTy1 = dyn_cast<AnyFunctionType>(type1)) {
1847-
if (auto fnTy2 = dyn_cast<AnyFunctionType>(type2)) {
1848-
return (
1849-
checkASTTypeForABIDifferences(fnTy2.getInput(), fnTy1.getInput()) ||
1850-
checkASTTypeForABIDifferences(fnTy1.getResult(), fnTy2.getResult()));
1851-
}
1852-
}
1853-
1854-
// Tuple types are ABI-compatible if their elements are.
1855-
if (auto tuple1 = dyn_cast<TupleType>(type1)) {
1856-
if (auto tuple2 = dyn_cast<TupleType>(type2)) {
1857-
if (tuple1->getNumElements() != tuple2->getNumElements())
1858-
return true;
1859-
1860-
for (unsigned i = 0, e = tuple1->getNumElements(); i < e; i++) {
1861-
if (checkASTTypeForABIDifferences(tuple1.getElementType(i),
1862-
tuple2.getElementType(i)))
1863-
return true;
1864-
}
1865-
1866-
// Tuple lengths and elements match
1867-
return false;
1868-
}
1869-
}
1870-
}
1871-
1872-
// The types are different, or there was an optionality change resulting
1873-
// in a change in representation.
1874-
return true;
1798+
return !type1->matches(type2, TypeMatchFlags::AllowABICompatible,
1799+
/*resolver*/nullptr);
18751800
}
18761801

18771802
bool TypeConverter::requiresNewVTableEntryUncached(SILDeclRef derived) {

0 commit comments

Comments
 (0)