From 273549239baed22c300782b17337ca01a4ee0c6d Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Wed, 12 Jun 2024 17:19:58 -0700 Subject: [PATCH] AST: fix `isWrittenWithConstraints` Surprisingly, there are some situations where an extension can end up with _fewer_ constraints than the extended type. That was baked-in as an assertion in this new-ish method. I haven't figured out why that can happen in the reproducer only when using `-interpret` mode. It didn't trigger the assertion for me when compiling normally. The fix is simple: check all the requirements, rather than using a short-cut. resolves rdar://125659789 / https://github.com/apple/swift/issues/72719 --- lib/AST/Decl.cpp | 16 +++++++++++----- validation-test/execution/issue-72719.swift | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 validation-test/execution/issue-72719.swift diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index daf2b8c759f..a847e54d14b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1809,14 +1809,20 @@ bool ExtensionDecl::isWrittenWithConstraints() const { 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()) { + // the original type, it's written with constraints. + if (extReqs.size() != typeReqs.size()) { return true; } - assert(extReqs.size() == typeReqs.size()); + // In case of equal number of constraints, we have to check the specific + // requirements. Extensions can end up with fewer requirements than the type + // extended, due to a same-type requirement in the extension. + // + // This mirrors the 'same' check in `ASTMangler::gatherGenericSignatureParts` + for (size_t i = 0; i < extReqs.size(); i++) { + if (extReqs[i] != typeReqs[i]) + return true; + } // If the type has no inverse requirements, there are no extra constraints // to write. diff --git a/validation-test/execution/issue-72719.swift b/validation-test/execution/issue-72719.swift new file mode 100644 index 00000000000..2f45c87be74 --- /dev/null +++ b/validation-test/execution/issue-72719.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -interpret %s +// REQUIRES: executable_test + +// This only reproduced if you provide the -interpret flag! +// https://github.com/apple/swift/issues/72719 + +protocol D {} +struct U: D, Equatable {} +class Q {} +class R {} +extension R where E == U { + struct S {} + static func a(_: T) -> R { + let x = Q>() + fatalError() + } +}