Skip to content

Commit 7c1b150

Browse files
committed
ModuleInterface: Resolve inherited types when computing unsatisfiable conformances.
Previously, unsatisfiable conformances could be omitted from emitted `.swiftinterface` files in lazy typechecking mode since inherited types might be unresolved when gathering the conformances. Adding these test cases also revealed that serialization restrictions needed to be relaxed in order to accomodate unsatisfiable conformances.
1 parent eee122c commit 7c1b150

File tree

7 files changed

+64
-13
lines changed

7 files changed

+64
-13
lines changed

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,9 @@ class InheritedProtocolCollector {
527527
/// For each type directly inherited by \p extension, record any protocols
528528
/// that we would have printed in ConditionalConformanceProtocols.
529529
void recordConditionalConformances(const ExtensionDecl *extension) {
530-
for (TypeLoc inherited : extension->getInherited().getEntries()) {
531-
Type inheritedTy = inherited.getType();
530+
auto inheritedTypes = extension->getInherited();
531+
for (unsigned i : inheritedTypes.getIndices()) {
532+
Type inheritedTy = inheritedTypes.getResolvedType(i);
532533
if (!inheritedTy || !inheritedTy->isExistentialType())
533534
continue;
534535

lib/Serialization/Serialization.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3264,9 +3264,6 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
32643264
size_t addConformances(const IterableDeclContext *declContext,
32653265
ConformanceLookupKind lookupKind,
32663266
SmallVectorImpl<TypeID> &data) {
3267-
// We don't expect to be serializing conformances for skipped decls.
3268-
assert(!S.shouldSkipDecl(declContext->getDecl()));
3269-
32703267
size_t count = 0;
32713268
for (auto conformance : declContext->getLocalConformances(lookupKind)) {
32723269
if (S.shouldSkipDecl(conformance->getProtocol()))
@@ -3353,6 +3350,10 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
33533350
return true;
33543351
}
33553352

3353+
// Paramters don't have meaningful access control.
3354+
if (isa<ParamDecl>(decl) || isa<GenericTypeParamDecl>(decl))
3355+
return true;
3356+
33563357
return false;
33573358
}
33583359

@@ -4897,11 +4898,16 @@ static bool canSkipWhenInvalid(const Decl *D) {
48974898
}
48984899

48994900
bool Serializer::shouldSkipDecl(const Decl *D) const {
4900-
if (Options.SerializeExternalDeclsOnly &&
4901-
!DeclSerializer::isDeserializationSafe(D))
4902-
return true;
4901+
// The presence of -experimental-serialize-external-decls-only is the only
4902+
// reason to omit decls during serialization.
4903+
if (!Options.SerializeExternalDeclsOnly)
4904+
return false;
49034905

4904-
return false;
4906+
// For our purposes, "deserialization safe" is the same thing as "external".
4907+
if (DeclSerializer::isDeserializationSafe(D))
4908+
return false;
4909+
4910+
return true;
49054911
}
49064912

49074913
void Serializer::writeASTBlockEntity(const Decl *D) {

test/Inputs/lazy_typecheck.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public func publicFuncWithOpaqueReturnType() -> some PublicProto { // expected-n
4949

5050
// MARK: - Nominal types
5151

52+
public protocol EmptyPublicProto {}
53+
5254
public protocol PublicProto {
5355
func req() -> Int // expected-note 2 {{protocol requires function 'req()' with type '() -> Int'; add a stub for conformance}}
5456
}
@@ -90,6 +92,12 @@ public struct PublicStruct {
9092
}
9193
}
9294

95+
public struct PublicGenericStruct<T> {
96+
public func publicMethod() -> T {
97+
return true // expected-error {{cannot convert return expression of type 'Bool' to return type 'T'}}
98+
}
99+
}
100+
93101
struct InternalStruct: DoesNotExist { // expected-error {{cannot find type 'DoesNotExist' in scope}}
94102
var x: DoesNotExist // expected-error {{cannot find type 'DoesNotExist' in scope}}
95103

@@ -173,5 +181,11 @@ extension InternalStruct: PublicProto { // expected-error {{type 'InternalStruct
173181
struct InternalStructConformingToInternalProto: InternalProto { // expected-error {{type 'InternalStructConformingToInternalProto' does not conform to protocol 'InternalProto'}}
174182
}
175183

184+
struct InternalStructForConstraint {}
185+
186+
extension PublicGenericStruct where T == InternalStructForConstraint {}
187+
188+
extension PublicGenericStruct: EmptyPublicProto where T == InternalStructForConstraint {}
189+
176190
// FIXME: Test enums
177191
// FIXME: Test global vars

test/Inputs/lazy_typecheck_client.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func testGlobalFunctions() {
2121
}
2222

2323
func testPublicStruct() {
24-
var s = PublicStruct(x: 1)
24+
let s = PublicStruct(x: 1)
2525
_ = s.publicMethod()
2626
PublicStruct.publicStaticMethod()
2727
}
@@ -50,3 +50,18 @@ func testConformances() {
5050
constrainedGenericPublicFunction(x)
5151
}
5252
}
53+
54+
// FIXME: This conformance ought to be included to verify that a redundant
55+
// conformance diagnostic is emitted.
56+
// However, it turns out that the mechanism implemented by
57+
// https://github.com/apple/swift/pull/20433 doesn't actually work when a
58+
// module is built from .swiftinterface because the dummy conformance is marked
59+
// unavailable.
60+
//extension PublicGenericStruct: EmptyPublicProto {}
61+
62+
func takesEmptyProto<T: EmptyPublicProto>(_ t: T) {}
63+
64+
@available(*, unavailable)
65+
func testConditionalConformance<T>(_ s: PublicGenericStruct<T>) {
66+
takesEmptyProto(s) // expected-error {{global function 'takesEmptyProto' requires}}
67+
}

test/ModuleInterface/lazy-typecheck.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: %FileCheck %s < %t/lazy_typecheck.swiftinterface
55

66
// RUN: rm -rf %t/*.swiftmodule
7-
// RUN: %target-swift-frontend -package-name Package -typecheck %S/../Inputs/lazy_typecheck_client.swift -I %t
7+
// RUN: %target-swift-frontend -package-name Package -typecheck -verify %S/../Inputs/lazy_typecheck_client.swift -I %t
88

99
// CHECK: import Swift
1010

@@ -26,6 +26,8 @@
2626
// CHECK-NEXT: }
2727
// CHECK-NEXT: }
2828

29+
// CHECK: public protocol EmptyPublicProto {
30+
// CHECK: }
2931
// CHECK: public protocol PublicProto {
3032
// CHECK: func req() -> Swift.Int
3133
// CHECK: }
@@ -39,6 +41,9 @@
3941
// CHECK: public func publicMethod() -> Swift.Int
4042
// CHECK: public static func publicStaticMethod()
4143
// CHECK: }
44+
// CHECK: public struct PublicGenericStruct<T> {
45+
// CHECK: public func publicMethod() -> T
46+
// CHECK: }
4247
// CHECK: public class PublicClass {
4348
// CHECK: public init(x: Swift.Int)
4449
// CHECK: public func publicMethod() -> Swift.Int
@@ -74,4 +79,9 @@
7479
// CHECK: public func req() throws -> Swift.Int
7580
// CHECK: }
7681
// CHECK: #endif
82+
// CHECK: @available(*, unavailable)
83+
// CHECK-NEXT: extension lazy_typecheck.PublicGenericStruct : lazy_typecheck.EmptyPublicProto where T : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}
7784
// CHECK: extension lazy_typecheck.PublicStructIndirectlyConformingToPublicProto : lazy_typecheck.PublicProto {}
85+
86+
// CHECK: @usableFromInline
87+
// CHECK: internal protocol _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}

test/Serialization/serialize-external-decls-only-lazy-typecheck.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
// RUN: %target-swift-frontend -swift-version 5 %S/../Inputs/lazy_typecheck.swift -enable-library-evolution -parse-as-library -package-name Package -typecheck -verify
33
// RUN: %target-swift-frontend -swift-version 5 %S/../Inputs/lazy_typecheck.swift -module-name lazy_typecheck -emit-module -emit-module-path %t/lazy_typecheck.swiftmodule -enable-library-evolution -parse-as-library -package-name Package -experimental-lazy-typecheck -experimental-skip-all-function-bodies -experimental-serialize-external-decls-only
44

5-
// RUN: %target-swift-frontend -package-name Package -typecheck %S/../Inputs/lazy_typecheck_client.swift -D TEST_PACKAGE -I %t
5+
// RUN: %target-swift-frontend -package-name Package -typecheck -verify %S/../Inputs/lazy_typecheck_client.swift -D TEST_PACKAGE -I %t

test/TBD/lazy-typecheck.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,16 @@ exports:
7171
'_$s14lazy_typecheck12PublicStructV18publicStaticMethodyyFZ',
7272
'_$s14lazy_typecheck12PublicStructV1xACSi_tcfC', '_$s14lazy_typecheck12PublicStructVMa',
7373
'_$s14lazy_typecheck12PublicStructVMn', '_$s14lazy_typecheck12PublicStructVN',
74-
'_$s14lazy_typecheck13inlinableFuncSiyF', '_$s14lazy_typecheck18PublicDerivedClassC1xACSi_tcfC',
74+
'_$s14lazy_typecheck13inlinableFuncSiyF', '_$s14lazy_typecheck16EmptyPublicProtoMp',
75+
'_$s14lazy_typecheck16EmptyPublicProtoTL', '_$s14lazy_typecheck18PublicDerivedClassC1xACSi_tcfC',
7576
'_$s14lazy_typecheck18PublicDerivedClassC1xACSi_tcfc', '_$s14lazy_typecheck18PublicDerivedClassCMa',
7677
'_$s14lazy_typecheck18PublicDerivedClassCMm', '_$s14lazy_typecheck18PublicDerivedClassCMn',
7778
'_$s14lazy_typecheck18PublicDerivedClassCMo', '_$s14lazy_typecheck18PublicDerivedClassCN',
7879
'_$s14lazy_typecheck18PublicDerivedClassCfD', '_$s14lazy_typecheck18PublicDerivedClassCfd',
80+
'_$s14lazy_typecheck19PublicGenericStructV12publicMethodxyF',
81+
'_$s14lazy_typecheck19PublicGenericStructVMa', '_$s14lazy_typecheck19PublicGenericStructVMn',
82+
'_$s14lazy_typecheck19PublicGenericStructVyxGAA05EmptyC5ProtoA2A08InternalE13ForConstraintVRszlMc',
83+
'_$s14lazy_typecheck19PublicGenericStructVyxGAA05EmptyC5ProtoA2A08InternalE13ForConstraintVRszlWP',
7984
'_$s14lazy_typecheck19PublicRethrowsProtoMp', '_$s14lazy_typecheck19PublicRethrowsProtoP3reqSiyKFTj',
8085
'_$s14lazy_typecheck19PublicRethrowsProtoP3reqSiyKFTq', '_$s14lazy_typecheck19PublicRethrowsProtoTL',
8186
'_$s14lazy_typecheck24publicFuncWithDefaultArgyS2iF', '_$s14lazy_typecheck30publicFuncWithOpaqueReturnTypeQryF',

0 commit comments

Comments
 (0)