Skip to content

Commit 1f59f10

Browse files
committed
Unwind the Bogus Delayed Categories Hack
Delayed categories only existed to keep ClangImporter/objc_redeclared_properties passing. But this test appears to exhibit incorrect behavior as written. The clang importer implements limited behavior for overwriting variable declarations. If that overwrite occurs somewhere else in the class hierarchy, the declaration is rewritten as a Swift override. The remaining case is categories, which enable all sorts of awful redeclaration behaviors. When a bridging header declares a category that tries to stomp the API surface of another category, we need to import that category first, and we would import that category first - by accident. Re-entrancy does have its upsides. In order to keep the tests passing post re-entrant lookup, we stubbed in a hack that delayed categories in the bridging header so they were installed last, which meant the variable merging logic would mostly decline to import those properties. But the rest of the world expects the opposite: Bridging header contents are more sacred than the rest of the SDK and must be installed *first* in order for a number of nightmarish header hacks to go through. Unwind the old, incorrect emergent behavior and re-establish the correct behavior as the way the world ought to work. Resolves rdar://58493356, rdar://58493357, rdar://58493362, rdar://58493370
1 parent 7f4e5a5 commit 1f59f10

File tree

2 files changed

+14
-32
lines changed

2 files changed

+14
-32
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,32 +2974,8 @@ void ClangImporter::loadExtensions(NominalTypeDecl *nominal,
29742974
SmallVector<clang::NamedDecl *, 4> DelayedCategories;
29752975

29762976
// Simply importing the categories adds them to the list of extensions.
2977-
for (auto I = objcClass->visible_categories_begin(),
2978-
E = objcClass->visible_categories_end();
2979-
I != E; ++I) {
2980-
// Delay installing categories that don't have an owning module.
2981-
if (!I->hasOwningModule()) {
2982-
DelayedCategories.push_back(*I);
2983-
continue;
2984-
}
2985-
2986-
Impl.importDeclReal(*I, Impl.CurrentVersion);
2987-
}
2988-
2989-
// Install all the delayed categories.
2990-
//
2991-
// The very notion of a delayed category is a result of an emergent behavior
2992-
// of the visible categories list and the order we import modules. The list
2993-
// appears in deserialization order rather than some "source order", so it's
2994-
// possible for, say, a bridging header to import a module that defines an
2995-
// interface and some categories, but for the categories in the bridging
2996-
// header to appear *before* the categories in the module - the imported
2997-
// module will be deserialized on demand. We take it on faith that if there
2998-
// is no owning module for a given category, that it was created in such a
2999-
// way, and thus we install it last to try to emulate what we want
3000-
// "source order" to mean.
3001-
for (const auto *DelayedCat : DelayedCategories) {
3002-
Impl.importDeclReal(DelayedCat, Impl.CurrentVersion);
2977+
for (const auto *Cat : objcClass->visible_categories()) {
2978+
Impl.importDeclReal(Cat, Impl.CurrentVersion);
30032979
}
30042980
}
30052981

test/ClangImporter/objc_redeclared_properties_incompatible.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,27 +75,33 @@ func testCategoryWithInitializer() {
7575
let obj = PropertiesInitCategory()
7676

7777
let _: Int = obj.nullabilityChange
78-
// CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
78+
// CHECK-PUBLIC: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
79+
// CHECK-PRIVATE: [[@LINE-2]]:20: error: cannot convert value of type 'Base?' to specified type 'Int'
7980

8081
let _: Int = obj.missingGenerics
81-
// CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
82+
// CHECK-PUBLIC: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
83+
// CHECK-PRIVATE: [[@LINE-2]]:20: error: cannot convert value of type 'GenericClass<AnyObject>' to specified type 'Int'
8284

8385
let _: Int = obj.typeChange
84-
// CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
86+
// CHECK-PUBLIC: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
87+
// CHECK-PRIVATE: [[@LINE-2]]:20: error: cannot convert value of type 'PrivateSubclass' to specified type 'Int'
8588

8689
obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
8790
// CHECK-PUBLIC: [[@LINE-1]]:7: error: cannot assign to property: 'readwriteChange' is a get-only property
8891
}
8992

9093
func testCategoryWithoutInitializer(obj: PropertiesNoInitCategory) {
9194
let _: Int = obj.nullabilityChange
92-
// CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
95+
// CHECK-PUBLIC: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
96+
// CHECK-PRIVATE: [[@LINE-2]]:20: error: cannot convert value of type 'Base?' to specified type 'Int'
9397

9498
let _: Int = obj.missingGenerics
95-
// CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
99+
// CHECK-PUBLIC: [[@LINE-1]]:20: error: cannot convert value of type 'GenericClass<Base>' to specified type 'Int'
100+
// CHECK-PRIVATE: [[@LINE-2]]:20: error: cannot convert value of type 'GenericClass<AnyObject>' to specified type 'Int'
96101

97102
let _: Int = obj.typeChange
98-
// CHECK: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
103+
// CHECK-PUBLIC: [[@LINE-1]]:20: error: cannot convert value of type 'Base' to specified type 'Int'
104+
// CHECK-PRIVATE: [[@LINE-2]]:20: error: cannot convert value of type 'PrivateSubclass' to specified type 'Int'
99105

100106
obj.readwriteChange = Base() // CHECK-PRIVATE-NOT: [[@LINE]]:{{.+}}: error
101107
// CHECK-PUBLIC: [[@LINE-1]]:7: error: cannot assign to property: 'readwriteChange' is a get-only property

0 commit comments

Comments
 (0)