Skip to content

Fix https://bugs.swift.org/projects/SR/issues/SR-15807 [5.7] #42501

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,11 @@ SmallVector<InheritedNominalEntry, 4> getDirectlyInheritedNominalTypeDecls(
SelfBounds getSelfBoundsFromWhereClause(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl);

/// Retrieve the set of nominal type declarations that appear as the
/// constraint type of any "Self" constraints in the generic signature of the
/// given protocol or protocol extension.
SelfBounds getSelfBoundsFromGenericSignature(const ExtensionDecl *extDecl);

/// Retrieve the TypeLoc at the given \c index from among the set of
/// type declarations that are directly "inherited" by the given declaration.
inline const TypeLoc &getInheritedTypeLocAtIndex(
Expand Down
16 changes: 16 additions & 0 deletions include/swift/AST/NameLookupRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,22 @@ class SelfBoundsFromWhereClauseRequest
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *>) const;
};

/// Request the nominal types that occur as the right-hand side of "Self: Foo"
/// constraints in the generic signature of a protocol extension.
class SelfBoundsFromGenericSignatureRequest
: public SimpleRequest<SelfBoundsFromGenericSignatureRequest,
SelfBounds(const ExtensionDecl *),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
SelfBounds evaluate(Evaluator &evaluator, const ExtensionDecl *extDecl) const;
};

/// Request all type aliases and nominal types that appear in the "where"
/// clause of an extension.
class TypeDeclsFromWhereClauseRequest :
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/NameLookupTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ SWIFT_REQUEST(NameLookup, SelfBoundsFromWhereClauseRequest,
SelfBounds(llvm::PointerUnion<const TypeDecl *,
const ExtensionDecl *>),
Uncached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, SelfBoundsFromGenericSignatureRequest,
SelfBounds(const ExtensionDecl * extDecl),
Uncached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, SuperclassDeclRequest, ClassDecl *(NominalTypeDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, HasMissingDesignatedInitializersRequest,
Expand Down
33 changes: 33 additions & 0 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,39 @@ SelfBounds swift::getSelfBoundsFromWhereClause(
SelfBoundsFromWhereClauseRequest{decl}, {});
}

SelfBounds SelfBoundsFromGenericSignatureRequest::evaluate(
Evaluator &evaluator, const ExtensionDecl *extDecl) const {
SelfBounds result;
ASTContext &ctx = extDecl->getASTContext();
auto selfType = extDecl->getSelfInterfaceType();
for (const auto &req : extDecl->getGenericRequirements()) {
auto kind = req.getKind();
if (kind != RequirementKind::Conformance &&
kind != RequirementKind::Superclass)
continue;
// The left-hand side of the type constraint must be 'Self'.
bool isSelfLHS = selfType->isEqual(req.getFirstType());
if (!isSelfLHS)
continue;

auto rhsDecls = directReferencesForType(req.getSecondType());
SmallVector<ModuleDecl *, 2> modulesFound;
auto rhsNominals = resolveTypeDeclsToNominal(
evaluator, ctx, rhsDecls, modulesFound, result.anyObject);
result.decls.insert(result.decls.end(), rhsNominals.begin(),
rhsNominals.end());
}

return result;
}

SelfBounds
swift::getSelfBoundsFromGenericSignature(const ExtensionDecl *extDecl) {
auto &ctx = extDecl->getASTContext();
return evaluateOrDefault(ctx.evaluator,
SelfBoundsFromGenericSignatureRequest{extDecl}, {});
}

TinyPtrVector<TypeDecl *>
TypeDeclsFromWhereClauseRequest::evaluate(Evaluator &evaluator,
ExtensionDecl *ext) const {
Expand Down
12 changes: 10 additions & 2 deletions lib/Sema/TypeCheckProtocolInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,16 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
if (!checkConformance(proto))
return false;

// Now check any additional bounds on 'Self' from the where clause.
auto bounds = getSelfBoundsFromWhereClause(extension);
// Source file and module file have different ways to get self bounds.
// Source file extension will have trailing where clause which can avoid
// computing a generic signature. Module file will not have
// trailing where clause, so it will compute generic signature to get
// self bounds which might result in slow performance.
SelfBounds bounds;
if (extension->getParentSourceFile() != nullptr)
bounds = getSelfBoundsFromWhereClause(extension);
else
bounds = getSelfBoundsFromGenericSignature(extension);
for (auto *decl : bounds.decls) {
if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
if (!checkConformance(proto))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
public protocol DefaultsBridge {
associatedtype T
}

public struct BridgeStructSerializable<T: Codable>: DefaultsBridge {
}

public struct BridgeStructRawRepresentable<T: RawRepresentable>: DefaultsBridge {
}

public protocol DefaultsSerializable {
associatedtype Bridge: DefaultsBridge
static var _defaults: Bridge { get }
}

public extension DefaultsSerializable where Self: Codable {
static var _defaults: BridgeStructSerializable<Self> { return BridgeStructSerializable() }
}

public extension DefaultsSerializable where Self: RawRepresentable {
static var _defaults: BridgeStructRawRepresentable<Self> { return BridgeStructRawRepresentable() }
}

public struct ModuleAFoo: Codable, DefaultsSerializable {
}
16 changes: 16 additions & 0 deletions test/Sema/where_clause_across_module_boundaries.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/ModuleA.swiftmodule %S/Inputs/where_clause_across_module_boundaries_module.swift
// RUN: %target-typecheck-verify-swift -I %t

// SR-15807:
// Associated Type Inference fails across module boundaries
// Self bounds from where clause cannot be accessed across modules.
// This test is intended to test whether it can use generic signature to get self bounds.
import ModuleA

struct ModuleBFoo: Codable, DefaultsSerializable {
}

enum ModuleBBar: Int, Codable, DefaultsSerializable { // expected-error {{type 'ModuleBBar' does not conform to protocol 'DefaultsSerializable'}}
case foo, bar
}