Skip to content

Commit a83349b

Browse files
authored
Merge pull request swiftlang#24875 from jckarter/opaque-type-subst-assertion
AST: Cut a different corner when building GenericEnvironments for OpaqueTypeArchetypeTypes.
2 parents 8e5c027 + eeeb469 commit a83349b

File tree

2 files changed

+66
-43
lines changed

2 files changed

+66
-43
lines changed

lib/AST/ASTContext.cpp

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3440,50 +3440,13 @@ DependentMemberType *DependentMemberType::get(Type base,
34403440

34413441
OpaqueTypeArchetypeType *
34423442
OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
3443-
SubstitutionMap Substitutions) {
3443+
SubstitutionMap Substitutions)
3444+
{
34443445
// TODO: We could attempt to preserve type sugar in the substitution map.
3446+
// Currently archetypes are assumed to be always canonical in many places,
3447+
// though, so doing so would require fixing those places.
34453448
Substitutions = Substitutions.getCanonical();
3446-
3447-
// TODO: Eventually an opaque archetype ought to be arbitrarily substitutable
3448-
// into any generic environment. However, there isn't currently a good way to
3449-
// do this with GenericSignatureBuilder; in a situation like this:
3450-
//
3451-
// __opaque_type Foo<t_0_0: P>: Q // internal signature <t_0_0: P, t_1_0: Q>
3452-
//
3453-
// func bar<t_0_0, t_0_1, t_0_2: P>() -> Foo<t_0_2>
3454-
//
3455-
// we'd want to feed the GSB constraints to form:
3456-
//
3457-
// <t_0_0: P, t_1_0: Q where t_0_0 == t_0_2>
3458-
//
3459-
// even though t_0_2 isn't *in* this generic signature; it represents a type
3460-
// bound elsewhere from some other generic context. If we knew the generic
3461-
// environment `t_0_2` came from, then maybe we could map it into that context,
3462-
// but currently we have no way to know that with certainty.
3463-
//
3464-
// For now, opaque types cannot propagate across decls; every declaration
3465-
// with an opaque type has a unique opaque decl. Therefore, the only
3466-
// expressions involving opaque types ought to be contextualized inside
3467-
// function bodies, and the only time we need an opaque interface type should
3468-
// be for the opaque decl itself and the originating decl with the opaque
3469-
// result type, in which case the interface type mapping is identity and
3470-
// this problem can be temporarily avoided.
3471-
#ifndef NDEBUG
3472-
for (unsigned i : indices(Substitutions.getReplacementTypes())) {
3473-
auto replacement = Substitutions.getReplacementTypes()[i];
3474-
3475-
if (!replacement->hasTypeParameter())
3476-
continue;
3477-
3478-
auto replacementParam = replacement->getAs<GenericTypeParamType>();
3479-
if (!replacementParam)
3480-
llvm_unreachable("opaque types cannot currently be parameterized by non-identity type parameter mappings");
3481-
3482-
assert(i == Decl->getGenericSignature()->getGenericParamOrdinal(replacementParam)
3483-
&& "opaque types cannot currently be parameterized by non-identity type parameter mappings");
3484-
}
3485-
#endif
3486-
3449+
34873450
llvm::FoldingSetNodeID id;
34883451
Profile(id, Decl, Substitutions);
34893452

@@ -3517,7 +3480,34 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
35173480
// decl have all been same-type-bound to the arguments from our substitution
35183481
// map.
35193482
GenericSignatureBuilder builder(ctx);
3483+
35203484
builder.addGenericSignature(Decl->getOpaqueInterfaceGenericSignature());
3485+
// TODO: The proper thing to do to build the environment in which the opaque
3486+
// type's archetype exists would be to take the generic signature of the
3487+
// decl, feed it into a GenericSignatureBuilder, then add same-type
3488+
// constraints into the builder to bind the outer generic parameters
3489+
// to their substituted types provided by \c Substitutions. However,
3490+
// this is problematic for interface types. In a situation like this:
3491+
//
3492+
// __opaque_type Foo<t_0_0: P>: Q // internal signature <t_0_0: P, t_1_0: Q>
3493+
//
3494+
// func bar<t_0_0, t_0_1, t_0_2: P>() -> Foo<t_0_2>
3495+
//
3496+
// we'd want to feed the GSB constraints to form:
3497+
//
3498+
// <t_0_0: P, t_1_0: Q where t_0_0 == t_0_2>
3499+
//
3500+
// even though t_0_2 isn't *in* the generic signature being built; it
3501+
// represents a type
3502+
// bound elsewhere from some other generic context. If we knew the generic
3503+
// environment `t_0_2` came from, then maybe we could map it into that context,
3504+
// but currently we have no way to know that with certainty.
3505+
//
3506+
// Because opaque types are currently limited so that they only have immediate
3507+
// protocol constraints, and therefore don't interact with the outer generic
3508+
// parameters at all, we can get away without adding these constraints for now.
3509+
// Adding where clauses would break this hack.
3510+
#if DO_IT_CORRECTLY
35213511
// Same-type-constrain the arguments in the outer signature to their
35223512
// replacements in the substitution map.
35233513
if (auto outerSig = Decl->getGenericSignature()) {
@@ -3529,7 +3519,24 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
35293519
[](Type, Type) { llvm_unreachable("error?"); });
35303520
}
35313521
}
3532-
3522+
#else
3523+
// Assert that there are no same type constraints on the underlying type.
3524+
// or its associated types.
3525+
//
3526+
// This should not be possible until we add where clause support.
3527+
# ifndef NDEBUG
3528+
for (auto reqt :
3529+
Decl->getOpaqueInterfaceGenericSignature()->getRequirements()) {
3530+
auto reqtBase = reqt.getFirstType()->getRootGenericParam();
3531+
if (reqtBase->isEqual(Decl->getUnderlyingInterfaceType())) {
3532+
assert(reqt.getKind() != RequirementKind::SameType
3533+
&& "supporting where clauses on opaque types requires correctly "
3534+
"setting up the generic environment for "
3535+
"OpaqueTypeArchetypeTypes; see comment above");
3536+
}
3537+
}
3538+
# endif
3539+
#endif
35333540
auto signature = std::move(builder)
35343541
.computeGenericSignature(SourceLoc());
35353542

test/type/opaque.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,19 @@ func closure() -> some P {
349349
}
350350
return 42
351351
}
352+
353+
protocol HasAssocType {
354+
associatedtype Assoc
355+
356+
func assoc() -> Assoc
357+
}
358+
359+
struct GenericWithOpaqueAssoc<T>: HasAssocType {
360+
func assoc() -> some Any { return 0 }
361+
}
362+
363+
struct OtherGeneric<X, Y, Z> {
364+
var x: GenericWithOpaqueAssoc<X>.Assoc
365+
var y: GenericWithOpaqueAssoc<Y>.Assoc
366+
var z: GenericWithOpaqueAssoc<Z>.Assoc
367+
}

0 commit comments

Comments
 (0)