Skip to content

Commit 9dcb5a5

Browse files
committed
Properly substitute outer generic parameters in an opaque type environment.
When forming the generic signature of a generic environment for opaque types, substitute for the outer generic parameters based on the provided substitution map. We weren't able to do this before because the substitution cannot be performed when there are interface types or type variables involved. However, the lazy construction of this generic signature and use of other queries on opaque type archetypes ensures that we don't form new generic signatures until we have concrete types to work with. This enables same-type constraints amongst different opaque result types and their associated types.
1 parent 2dd49a8 commit 9dcb5a5

File tree

2 files changed

+16
-50
lines changed

2 files changed

+16
-50
lines changed

lib/AST/GenericEnvironment.cpp

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -81,36 +81,9 @@ GenericSignature GenericEnvironment::getGenericSignature() const {
8181
// map.
8282
SmallVector<Requirement, 2> newRequirements;
8383

84-
// TODO: The proper thing to do to build the environment in which the opaque
85-
// type's archetype exists would be to take the generic signature of the
86-
// decl, feed it into a GenericSignatureBuilder, then add same-type
87-
// constraints into the builder to bind the outer generic parameters
88-
// to their substituted types provided by \c Substitutions. However,
89-
// this is problematic for interface types. In a situation like this:
90-
//
91-
// __opaque_type Foo<t_0_0: P>: Q // internal signature <t_0_0: P, t_1_0: Q>
92-
//
93-
// func bar<t_0_0, t_0_1, t_0_2: P>() -> Foo<t_0_2>
94-
//
95-
// we'd want to feed the GSB constraints to form:
96-
//
97-
// <t_0_0: P, t_1_0: Q where t_0_0 == t_0_2>
98-
//
99-
// even though t_0_2 isn't *in* the generic signature being built; it
100-
// represents a type
101-
// bound elsewhere from some other generic context. If we knew the generic
102-
// environment `t_0_2` came from, then maybe we could map it into that context,
103-
// but currently we have no way to know that with certainty.
104-
//
105-
// Because opaque types are currently limited so that they only have immediate
106-
// protocol constraints, and therefore don't interact with the outer generic
107-
// parameters at all, we can get away without adding these constraints for now.
108-
// Adding where clauses would break this hack.
109-
auto opaqueDecl = getOpaqueTypeDecl();
110-
111-
#if DO_IT_CORRECTLY
11284
// Same-type-constrain the arguments in the outer signature to their
11385
// replacements in the substitution map.
86+
auto opaqueDecl = getOpaqueTypeDecl();
11487
auto subs = getOpaqueSubstitutions();
11588
if (auto outerSig = opaqueDecl->getGenericSignature()) {
11689
for (auto outerParam : outerSig.getGenericParams()) {
@@ -119,27 +92,7 @@ GenericSignature GenericEnvironment::getGenericSignature() const {
11992
Requirement(RequirementKind::SameType, Type(outerParam), boundType));
12093
}
12194
}
122-
#else
123-
// Assert that there are no same type constraints on the opaque type or its
124-
// associated types.
125-
//
126-
// This should not be possible until we add where clause support, with the
127-
// exception of generic base class constraints (handled below).
128-
(void)newRequirements;
129-
# ifndef NDEBUG
130-
for (auto req : opaqueDecl
131-
->getOpaqueInterfaceGenericSignature().getRequirements()) {
132-
auto reqBase = req.getFirstType()->getRootGenericParam();
133-
if (reqBase->getDepth() ==
134-
opaqueDecl->getOpaqueGenericParams().front()->getDepth()) {
135-
assert(req.getKind() != RequirementKind::SameType
136-
&& "supporting where clauses on opaque types requires correctly "
137-
"setting up the generic environment for "
138-
"OpaqueTypeArchetypeTypes; see comment above");
139-
}
140-
}
141-
# endif
142-
#endif
95+
14396
auto signature = buildGenericSignature(
14497
opaqueDecl->getASTContext(),
14598
opaqueDecl->getOpaqueInterfaceGenericSignature(),

test/type/opaque_return_named.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ protocol DefaultInitializable {
107107
extension String: DefaultInitializable { }
108108
extension Int: DefaultInitializable { }
109109

110-
struct Generic<T: P1 & Equatable & DefaultInitializable> {
110+
struct Generic<T: P1 & Equatable & DefaultInitializable>
111+
where T.A: DefaultInitializable {
111112
var value: T
112113

113114
func f() -> <U: Q1, V: P1 where U: Equatable, V: Equatable> (U, V) {
@@ -131,6 +132,18 @@ struct Generic<T: P1 & Equatable & DefaultInitializable> {
131132
print("here")
132133
}
133134
}
135+
136+
// FIXME: expected-warning@+2{{redundant same-type constraint 'C.Element' == 'T.A'}}
137+
// FIXME: expected-note@+1{{previous same-type constraint 'C.Element' == 'T.A' written here}}
138+
func sameTypeParams() -> <C: Collection where C.Element == T.A> C {
139+
[ T.A(), T.A() ]
140+
}
141+
142+
// FIXME: expected-warning@+2{{redundant same-type constraint 'C.Element' == 'T.A'}}
143+
// FIXME: expected-note@+1{{previous same-type constraint 'C.Element' == 'T.A' written here}}
144+
func sameTypeParamsBad() -> <C: Collection where C.Element == T.A> C {
145+
[ T() ] // expected-error{{cannot convert value of type 'T' to expected element type 'T.A'}}
146+
}
134147
}
135148

136149
func testGeneric(i: Int, gs: Generic<String>, gi: Generic<Int>) {

0 commit comments

Comments
 (0)