Skip to content

[Demangle-to-AST] Match invertible-generics extensions with no signature #72644

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
26 changes: 26 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1864,6 +1864,32 @@ class ExtensionDecl final : public GenericContext, public Decl,
/// the original nominal type context.
bool isInSameDefiningModule() const;

/// Determine whether this extension is equivalent to one that requires at
/// at least some constraints to be written in the source.
///
/// This result will differ from `isConstrainedExtension()` when any of
/// the generic parameters of the type are invertible, e.g.,
/// \code
/// struct X<T: ~Copyable>: ~Copyable { }
///
/// // Implies `T: Copyable`. This extension `!isWrittenWithConstraints()`
/// // and `isConstrainedExtension()`.
/// extension X { }
///
/// // This extension `isWrittenWithConstraints()`
/// // and `!isConstrainedExtension()`.
/// extension X where T: ~Copyable { }
///
/// // Implies `T: Copyable`. This extension `isWrittenWithConstraints()`
/// // and `isConstrainedExtension()`.
/// extension X where T: P { }
///
/// // This extension `isWrittenWithConstraints()`
/// // and `isConstrainedExtension()`.
/// extension X where T: Q, T: ~Copyable { }
/// \endcode
bool isWrittenWithConstraints() const;

/// Returns the name of the category specified by the \c \@_objcImplementation
/// attribute, or \c None if the name is invalid or
/// \c isObjCImplementation() is false.
Expand Down
3 changes: 3 additions & 0 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,9 @@ ASTBuilder::findDeclContext(NodePointer node) {
continue;
}

if (!ext->isWrittenWithConstraints() && !genericSig)
return ext;

auto extSig = ext->getGenericSignature().getCanonicalSignature();
if (extSig == genericSig) {
return ext;
Expand Down
48 changes: 48 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1763,6 +1763,54 @@ bool ExtensionDecl::isConstrainedExtension() const {
return !typeSig->isEqual(extSig);
}

bool ExtensionDecl::isWrittenWithConstraints() const {
auto nominal = getExtendedNominal();
if (!nominal)
return false;

// If there's no generic signature, then it's written without constraints.
CanGenericSignature extSig = getGenericSignature().getCanonicalSignature();
if (!extSig)
return false;

CanGenericSignature typeSig =
nominal->getGenericSignature().getCanonicalSignature();

// Get the requirements and inverses for both the extension and type.
SmallVector<Requirement, 2> extReqs;
SmallVector<InverseRequirement, 2> extInverseReqs;
extSig->getRequirementsWithInverses(extReqs, extInverseReqs);

SmallVector<Requirement, 2> typeReqs;
SmallVector<InverseRequirement, 2> typeInverseReqs;
typeSig->getRequirementsWithInverses(typeReqs, typeInverseReqs);

// If the (non-inverse) requirements are different between the extension and
// the original type, it's written with constraints. Note that
// the extension can only add requirements, so we need only check the size
// (not the specific requirements).
if (extReqs.size() > typeReqs.size()) {
return true;
}

assert(extReqs.size() == typeReqs.size());

// If the type has no inverse requirements, there are no extra constraints
// to write.
if (typeInverseReqs.empty()) {
return false;
}

// If the extension has no inverse requirements, then there are no constraints
// that need to be written down.
if (extInverseReqs.empty()) {
return false;
}

// We have inverses that need to be written out.
return true;
}

bool ExtensionDecl::isInSameDefiningModule() const {
auto decl = getExtendedNominal();
auto extensionAlterName = getAlternateModuleName();
Expand Down
14 changes: 14 additions & 0 deletions test/IRGen/mangling_inverse_generics_evolution.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ extension XQ: Q where T: ~Copyable {
struct A { }
}

protocol HasResult {
associatedtype Success
}

extension Result: HasResult {
func testMe() -> Success? {
var x: Result.Success? = nil
if case let .success(s) = self {
x = s
}
return x
}
}

// Class metadata

@_fixed_layout
Expand Down