Skip to content

[Mangler] Handle local archetypes in getDeclTypeForMangling #78855

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
merged 1 commit into from
Feb 27, 2025
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
40 changes: 40 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4016,6 +4016,43 @@ static bool isMethodDecl(const Decl *decl) {
&& decl->getDeclContext()->isTypeContext();
}

/// Map any local archetypes in a decl's interface type out of context, such
/// that the resulting type is suitable for mangling.
///
/// Note this does not guarantee that different archetypes produce different
/// interface types across decls, but it is guaranteed within a single decl
/// type. This is okay though since local decls are assigned discriminators.
static Type mapLocalArchetypesOutOfContextForDecl(const ValueDecl *decl,
Type ty) {
if (!ty->hasLocalArchetype())
return ty;

ASSERT(decl->getDeclContext()->isLocalContext());

CaptureInfo captureInfo;
auto *innerDC = decl->getInnermostDeclContext();
auto genericSig = innerDC->getGenericSignatureOfContext();
if (auto fn = AnyFunctionRef::fromDeclContext(innerDC))
captureInfo = fn->getCaptureInfo();

// Record any captured generic environments we have.
llvm::SmallSetVector<GenericEnvironment *, 4> capturedEnvs;
for (auto *genericEnv : captureInfo.getGenericEnvironments())
capturedEnvs.insert(genericEnv);
Comment on lines +4038 to +4041
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle I think we could purely rely on gathering them from the type, but I don't think there's any harm in doing this and it's more consistent with the closure logic. I don't feel strongly about it though.


// We may still have archetypes local to the current context, e.g for
// decls in local for loops over pack expansions. In this case, collect
// any remaining generic environments from the type.
ty.visit([&](Type t) {
if (auto *archetypeTy = t->getAs<LocalArchetypeType>()) {
capturedEnvs.insert(archetypeTy->getGenericEnvironment());
}
});

return swift::mapLocalArchetypesOutOfContext(ty, genericSig,
capturedEnvs.getArrayRef());
}

CanType ASTMangler::getDeclTypeForMangling(
const ValueDecl *decl,
GenericSignature &genericSig,
Expand Down Expand Up @@ -4048,6 +4085,9 @@ CanType ASTMangler::getDeclTypeForMangling(
ty = ty->stripConcurrency(/*recurse=*/true, /*dropGlobalActor=*/true);
}

// Map any local archetypes out of context.
ty = mapLocalArchetypesOutOfContextForDecl(decl, ty);

auto canTy = ty->getCanonicalType();

if (auto gft = dyn_cast<GenericFunctionType>(canTy)) {
Expand Down
6 changes: 5 additions & 1 deletion lib/AST/LocalArchetypeRequirementCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ Type MapLocalArchetypesOutOfContext::getInterfaceType(
}

Type MapLocalArchetypesOutOfContext::operator()(SubstitutableType *type) const {
auto *archetypeTy = cast<ArchetypeType>(type);
// Local archetypes can appear in interface types alongside generic param
// types, ignore them here.
auto *archetypeTy = dyn_cast<ArchetypeType>(type);
if (!archetypeTy)
return type;

// Primary archetypes just map out of context.
if (isa<PrimaryArchetypeType>(archetypeTy) ||
Expand Down
70 changes: 70 additions & 0 deletions test/SourceKit/CursorInfo/issue-78690.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// https://github.com/swiftlang/swift/issues/78690
// rdar://143077965

protocol P {
associatedtype R
}

func foo<each T>(_ xs: repeat each T) {
for x in repeat each xs {
// RUN: %sourcekitd-test -req=cursor -pos=%(line-1):7 %s -- %s | %FileCheck %s --check-prefix=BASIC
// BASIC: s:4main3fooyyxxQpRvzlF1xL_qd__vp
for x2 in repeat each xs {
// RUN: %sourcekitd-test -req=cursor -pos=%(line-1):9 %s -- %s | %FileCheck %s --check-prefix=NESTED
// NESTED: s:4main3fooyyxxQpRvzlF2x2L_qd__vp
}
}
}

func bar<each T, each U>(xs: repeat each T, ys: repeat each U) {
for x1 in repeat each xs {
for y1 in repeat each ys {
func localFn() {
for x2 in repeat each xs {
for y2 in repeat each ys {
let k = (x1, y1, x2, y2)
// RUN: %sourcekitd-test -req=cursor -pos=%(line-1):17 %s -- %s | %FileCheck %s --check-prefix=DOUBLENESTED
// DOUBLENESTED: s:4main3bar2xs2ysyxxQp_q_q_QptRvzRv_r0_lF7localFnL_yyRvzRv_r0_lF1kL_qd___qd0__qd1__qd2__tvp
// -> (A1, A2, A3, A4)
}
}
}
_ = {
for x2 in repeat each xs {
for y2 in repeat each ys {
let k = (x1, y1, x2, y2)
// RUN: %sourcekitd-test -req=cursor -pos=%(line-1):17 %s -- %s | %FileCheck %s --check-prefix=DOUBLENESTED-CLOSURE
// DOUBLENESTED-CLOSURE: s:4main3bar2xs2ysyxxQp_q_q_QptRvzRv_r0_lFyycfU_1kL_qd___qd0__qd1__qd2__tvp
// -> (A1, A2, A3, A4)
}
}
}
}
}
}

func baz<each T, each U, each V>(
ts: repeat each T, us: repeat each U, urs: repeat (each U).R, vs: repeat each V
) where repeat each U: P, (repeat (each U, each V)): Any {
for t in repeat each ts {
func localFn() {
for y in repeat each us {
func genericLocalFn<A>(_ a: A) {
for (u, ur, v) in repeat (each us, each urs, each vs) {
let k = (a, t, y, u, ur, v)
// RUN: %sourcekitd-test -req=cursor -pos=%(line-1):17 %s -- %s | %FileCheck %s --check-prefix=TUPLE1
// TUPLE1: s:4main3baz2ts2us3urs2vsyxxQp_q_q_Qp1RQy_q_Qpq0_q_QptRvzRv_Rv0_AA1PR_q0_Rh_r1_lF7localFnL_yyRvzRv_Rv0_AaIR_q0_Rh_r1_lF012genericLocalH0L_yyqd__RvzRv_Rv0_AaIR_q0_Rh_r1__lF1kL_qd___qd0__qd1__qd2__AgaIPQyd2__qd2_0_tvp
// -> (A1, A2, A3, A4, A4.main.P.R, B4)

_ = {
let k = (a, t, y, u, ur, v)
// RUN: %sourcekitd-test -req=cursor -pos=%(line-1):19 %s -- %s | %FileCheck %s --check-prefix=TUPLE2
// TUPLE2: s:4main3baz2ts2us3urs2vsyxxQp_q_q_Qp1RQy_q_Qpq0_q_QptRvzRv_Rv0_AA1PR_q0_Rh_r1_lF7localFnL_yyRvzRv_Rv0_AaIR_q0_Rh_r1_lF012genericLocalH0L_yyqd__RvzRv_Rv0_AaIR_q0_Rh_r1__lFyycfU_1kL_qd___qd0__qd1__qd2__AgaIPQyd2__qd2_0_tvp
// -> (A1, A2, A3, A4, A4.main.P.R, B4)
}
}
}
}
}
}
}