Skip to content

Commit 319b3e6

Browse files
author
willtunnels
authored
Add support for opaque result types in structural positions (#38392)
* [TypeResolver][TypeChecker] Add support for structural opaque result types * [TypeResolver][TypeChecker] Clean up changes that add structural opaque result types
1 parent f85d496 commit 319b3e6

34 files changed

+569
-349
lines changed

include/swift/AST/Decl.h

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2537,7 +2537,10 @@ class ValueDecl : public Decl {
25372537
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;
25382538

25392539
/// Get the representative for this value's opaque result type, if it has one.
2540-
OpaqueReturnTypeRepr *getOpaqueResultTypeRepr() const;
2540+
/// Returns a `TypeRepr` instead of an `OpaqueReturnTypeRepr` because 'some'
2541+
/// types might appear in one or more structural positions, e.g. (some P,
2542+
/// some Q), or we might have a `NamedOpaqueReturnTypeRepr`.
2543+
TypeRepr *getOpaqueResultTypeRepr() const;
25412544

25422545
/// Retrieve the attribute associating this declaration with a
25432546
/// result builder, if there is one.
@@ -2629,26 +2632,30 @@ class GenericTypeDecl : public GenericContext, public TypeDecl {
26292632
/// clients of the opaque type, only exposing the type as something conforming
26302633
/// to a given set of constraints.
26312634
///
2632-
/// Currently, opaque types do not normally have an explicit spelling in source
2633-
/// code. One is formed implicitly when a declaration is written with an opaque
2634-
/// result type, as in:
2635+
/// An `OpaqueTypeDecl` is formed implicitly when a declaration is written with
2636+
/// an opaque result type, as in the following example:
26352637
///
26362638
/// func foo() -> some SignedInteger { return 1 }
26372639
///
2638-
/// The declared type is a special kind of ArchetypeType representing the
2639-
/// abstracted underlying type.
2640+
/// The declared type uses a special kind of archetype type to represent
2641+
/// abstracted types, e.g. `(some P, some Q)` becomes `((opaque archetype 0),
2642+
/// (opaque archetype 1))`.
26402643
class OpaqueTypeDecl : public GenericTypeDecl {
26412644
/// The original declaration that "names" the opaque type. Although a specific
26422645
/// opaque type cannot be explicitly named, oapque types can propagate
26432646
/// arbitrarily through expressions, so we need to know *which* opaque type is
26442647
/// propagated.
26452648
ValueDecl *NamingDecl;
2646-
2649+
26472650
/// The generic signature of the opaque interface to the type. This is the
2648-
/// outer generic signature with an added generic parameter representing the
2649-
/// underlying type.
2651+
/// outer generic signature with added generic parameters representing the
2652+
/// abstracted underlying types.
26502653
GenericSignature OpaqueInterfaceGenericSignature;
2651-
2654+
2655+
/// The type repr of the underlying type. Might be null if no source location
2656+
/// is availble, e.g. if this decl was loaded from a serialized module.
2657+
OpaqueReturnTypeRepr *UnderlyingInterfaceRepr;
2658+
26522659
/// The generic parameter that represents the underlying type.
26532660
GenericTypeParamType *UnderlyingInterfaceType;
26542661

@@ -2661,12 +2668,12 @@ class OpaqueTypeDecl : public GenericTypeDecl {
26612668
mutable Identifier OpaqueReturnTypeIdentifier;
26622669

26632670
public:
2664-
OpaqueTypeDecl(ValueDecl *NamingDecl,
2665-
GenericParamList *GenericParams,
2671+
OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams,
26662672
DeclContext *DC,
26672673
GenericSignature OpaqueInterfaceGenericSignature,
2674+
OpaqueReturnTypeRepr *UnderlyingInterfaceRepr,
26682675
GenericTypeParamType *UnderlyingInterfaceType);
2669-
2676+
26702677
ValueDecl *getNamingDecl() const { return NamingDecl; }
26712678

26722679
void setNamingDecl(ValueDecl *D) {
@@ -2680,6 +2687,11 @@ class OpaqueTypeDecl : public GenericTypeDecl {
26802687
/// function could also be the getter of a storage declaration.
26812688
bool isOpaqueReturnTypeOfFunction(const AbstractFunctionDecl *func) const;
26822689

2690+
/// Get the ordinal of the anonymous opaque parameter of this decl with type
2691+
/// repr `repr`, as introduce implicitly by an occurrence of "some" in return
2692+
/// position e.g. `func f() -> some P`. Returns -1 if `repr` is not found.
2693+
unsigned getAnonymousOpaqueParamOrdinal(OpaqueReturnTypeRepr *repr) const;
2694+
26832695
GenericSignature getOpaqueInterfaceGenericSignature() const {
26842696
return OpaqueInterfaceGenericSignature;
26852697
}

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,6 +1864,11 @@ WARNING(spi_attribute_on_import_of_public_module,none,
18641864
ERROR(opaque_type_invalid_constraint,none,
18651865
"an 'opaque' type must specify only 'Any', 'AnyObject', protocols, "
18661866
"and/or a base class", ())
1867+
NOTE(opaque_of_optional_rewrite,none,
1868+
"did you mean to write an optional of an 'opaque' type?", ())
1869+
ERROR(more_than_one_opaque_type,none,
1870+
"%0 contains multiple 'opaque' types, but only one 'opaque' type is "
1871+
"supported", (TypeRepr*))
18671872
ERROR(inferred_opaque_type,none,
18681873
"property definition has inferred type %0, involving the 'some' "
18691874
"return type of another declaration", (Type))
@@ -4062,9 +4067,6 @@ WARNING(trailing_closure_requires_parens,none,
40624067
" statement; pass as a parenthesized argument to silence this warning",
40634068
())
40644069

4065-
ERROR(opaque_type_var_no_init,none,
4066-
"property declares an opaque return type, but has no initializer "
4067-
"expression from which to infer an underlying type", ())
40684070
ERROR(opaque_type_no_underlying_type_candidates,none,
40694071
"function declares an opaque return type, but has no return statements "
40704072
"in its body from which to infer an underlying type", ())
@@ -4076,6 +4078,9 @@ NOTE(opaque_type_underlying_type_candidate_here,none,
40764078
ERROR(opaque_type_self_referential_underlying_type,none,
40774079
"function opaque return type was inferred as %0, which defines the "
40784080
"opaque type in terms of itself", (Type))
4081+
ERROR(opaque_type_var_no_init,none,
4082+
"property declares an opaque return type, but has no initializer "
4083+
"expression from which to infer an underlying type", ())
40794084
ERROR(opaque_type_var_no_underlying_type,none,
40804085
"property declares an opaque return type, but cannot infer the "
40814086
"underlying type from its initializer expression", ())

include/swift/AST/Expr.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,8 +3193,9 @@ class LinearToDifferentiableFunctionExpr : public ImplicitConversionExpr {
31933193
}
31943194
};
31953195

3196-
3197-
/// Use an opaque type to abstract a value of the underlying concrete type.
3196+
/// Use an opaque type to abstract a value of the underlying concrete type,
3197+
/// possibly nested inside other types. E.g. can perform coversions "T --->
3198+
/// (opaque type)" and "S<T> ---> S<(opaque type)>".
31983199
class UnderlyingToOpaqueExpr : public ImplicitConversionExpr {
31993200
public:
32003201
UnderlyingToOpaqueExpr(Expr *subExpr, Type ty)

include/swift/AST/TypeRepr.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,20 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr {
150150
return walk(walker);
151151
}
152152

153+
/// Look through the given type and its children to find a type for
154+
/// which the given predicate returns true.
155+
///
156+
/// \param pred A predicate function object. It should return true if the
157+
/// given type node satisfies the criteria.
158+
///
159+
/// \returns true if the predicate returns true for the given type or any of
160+
/// its children.
161+
bool findIf(llvm::function_ref<bool(TypeRepr *)> pred);
162+
163+
/// Check recursively whether this type repr or any of its decendants are
164+
/// opaque return type reprs.
165+
bool hasOpaque();
166+
153167
//*** Allocation Routines ************************************************/
154168

155169
void *operator new(size_t bytes, const ASTContext &C,
@@ -1108,9 +1122,9 @@ class OpaqueReturnTypeRepr : public TypeRepr {
11081122
/// A TypeRepr for a type with a generic parameter list of named opaque return
11091123
/// types.
11101124
///
1111-
/// This can occur only as the return type of a function declaration, to specify
1112-
/// subtypes which should be abstracted from callers, given a set of generic
1113-
/// constraints that the concrete types satisfy:
1125+
/// This can occur only as the return type of a function declaration, or the
1126+
/// type of a property, to specify types which should be abstracted from
1127+
/// callers, given a set of generic constraints that the concrete types satisfy:
11141128
///
11151129
/// func foo() -> <T: Collection> T { return [1] }
11161130
class NamedOpaqueReturnTypeRepr : public TypeRepr {

include/swift/AST/Types.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5472,13 +5472,13 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
54725472
GenericEnvironment *Environment;
54735473

54745474
public:
5475-
/// Get
5476-
54775475
/// Get an opaque archetype representing the underlying type of the given
5478-
/// opaque type decl.
5479-
static OpaqueTypeArchetypeType *get(OpaqueTypeDecl *Decl,
5476+
/// opaque type decl's opaque param with ordinal `ordinal`. For example, in
5477+
/// `(some P, some Q)`, `some P`'s type param would have ordinal 0 and `some
5478+
/// Q`'s type param would have ordinal 1.
5479+
static OpaqueTypeArchetypeType *get(OpaqueTypeDecl *Decl, unsigned ordinal,
54805480
SubstitutionMap Substitutions);
5481-
5481+
54825482
OpaqueTypeDecl *getDecl() const {
54835483
return OpaqueDecl;
54845484
}
@@ -5509,7 +5509,7 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
55095509
///
55105510
/// then the underlying type of `some P` would be ordinal 0, and `some Q` would be ordinal 1.
55115511
unsigned getOrdinal() const {
5512-
// TODO: multiple opaque types
5512+
// TODO [OPAQUE SUPPORT]: multiple opaque types
55135513
return 0;
55145514
}
55155515

include/swift/Sema/Constraint.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ enum class ConstraintKind : char {
154154
/// The first type is a function type, the second is the function's
155155
/// result type.
156156
FunctionResult,
157-
/// The first type is a type that's a candidate to be the underlying type of
158-
/// the second opaque archetype.
159-
OpaqueUnderlyingType,
160157
/// The first type will be equal to the second type, but only when the
161158
/// second type has been fully determined (and mapped down to a concrete
162159
/// type). At that point, this constraint will be treated like an `Equal`
@@ -604,7 +601,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
604601
case ConstraintKind::DynamicCallableApplicableFunction:
605602
case ConstraintKind::BindOverload:
606603
case ConstraintKind::OptionalObject:
607-
case ConstraintKind::OpaqueUnderlyingType:
608604
case ConstraintKind::OneWayEqual:
609605
case ConstraintKind::OneWayBindParam:
610606
case ConstraintKind::DefaultClosureType:

include/swift/Sema/ConstraintLocator.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,19 @@ class LocatorPathElt::OpenedGeneric final : public StoredPointerElement<GenericS
785785
}
786786
};
787787

788+
class LocatorPathElt::OpenedOpaqueArchetype final
789+
: public StoredPointerElement<OpaqueTypeDecl> {
790+
public:
791+
OpenedOpaqueArchetype(OpaqueTypeDecl *decl)
792+
: StoredPointerElement(PathElementKind::OpenedOpaqueArchetype, decl) {}
793+
794+
OpaqueTypeDecl *getDecl() const { return getStoredPointer(); }
795+
796+
static bool classof(const LocatorPathElt *elt) {
797+
return elt->getKind() == ConstraintLocator::OpenedOpaqueArchetype;
798+
}
799+
};
800+
788801
class LocatorPathElt::KeyPathDynamicMember final : public StoredPointerElement<NominalTypeDecl> {
789802
public:
790803
KeyPathDynamicMember(NominalTypeDecl *keyPathDecl)

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ SIMPLE_LOCATOR_PATH_ELT(MemberRefBase)
134134
/// base of the locator.
135135
CUSTOM_LOCATOR_PATH_ELT(OpenedGeneric)
136136

137+
/// This is referring to a type produced by opening an opaque type archetype
138+
/// type at the base of the locator.
139+
CUSTOM_LOCATOR_PATH_ELT(OpenedOpaqueArchetype)
140+
137141
/// An optional payload.
138142
SIMPLE_LOCATOR_PATH_ELT(OptionalPayload)
139143

include/swift/Sema/ConstraintSystem.h

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ struct AppliedBuilderTransform {
792792
Type builderType;
793793

794794
/// The result type of the body, to which the returned expression will be
795-
/// converted.
795+
/// converted. Opaque types should be unopened.
796796
Type bodyResultType;
797797

798798
/// An expression whose value has been recorded for later use.
@@ -3318,9 +3318,8 @@ class ConstraintSystem {
33183318
bool isFavored = false);
33193319

33203320
/// Add the appropriate constraint for a contextual conversion.
3321-
void addContextualConversionConstraint(
3322-
Expr *expr, Type conversionType, ContextualTypePurpose purpose,
3323-
bool isOpaqueReturnType);
3321+
void addContextualConversionConstraint(Expr *expr, Type conversionType,
3322+
ContextualTypePurpose purpose);
33243323

33253324
/// Convenience function to pass an \c ArrayRef to \c addJoinConstraint
33263325
Type addJoinConstraint(ConstraintLocator *locator,
@@ -3856,6 +3855,12 @@ class ConstraintSystem {
38563855
/// \returns The opened type, or \c type if there are no archetypes in it.
38573856
Type openType(Type type, OpenedTypeMap &replacements);
38583857

3858+
/// "Open" an opaque archetype type.
3859+
Type openOpaqueType(Type type, ConstraintLocatorBuilder locator);
3860+
3861+
/// Recurse over the given type and open any opaque archetype types.
3862+
Type openOpaqueTypeRec(Type type, ConstraintLocatorBuilder locator);
3863+
38593864
/// "Open" the given function type.
38603865
///
38613866
/// If the function type is non-generic, this is equivalent to calling
@@ -4593,12 +4598,6 @@ class ConstraintSystem {
45934598
TypeMatchOptions flags,
45944599
ConstraintLocatorBuilder locator);
45954600

4596-
/// Attempt to simplify an OpaqueUnderlyingType constraint.
4597-
SolutionKind simplifyOpaqueUnderlyingTypeConstraint(Type type1,
4598-
Type type2,
4599-
TypeMatchOptions flags,
4600-
ConstraintLocatorBuilder locator);
4601-
46024601
/// Attempt to simplify the BridgingConversion constraint.
46034602
SolutionKind simplifyBridgingConstraint(Type type1,
46044603
Type type2,
@@ -4729,10 +4728,10 @@ class ConstraintSystem {
47294728
///
47304729
/// \returns \c None when the result builder cannot be applied at all,
47314730
/// otherwise the result of applying the result builder.
4732-
Optional<TypeMatchResult> matchResultBuilder(
4733-
AnyFunctionRef fn, Type builderType, Type bodyResultType,
4734-
ConstraintKind bodyResultConstraintKind,
4735-
ConstraintLocatorBuilder locator);
4731+
Optional<TypeMatchResult>
4732+
matchResultBuilder(AnyFunctionRef fn, Type builderType, Type bodyResultType,
4733+
ConstraintKind bodyResultConstraintKind,
4734+
ConstraintLocatorBuilder locator);
47364735

47374736
/// Matches a wrapped or projected value parameter type to its backing
47384737
/// property wrapper type by applying the property wrapper.

lib/AST/ASTContext.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4160,9 +4160,12 @@ DependentMemberType *DependentMemberType::get(Type base,
41604160
}
41614161

41624162
OpaqueTypeArchetypeType *
4163-
OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
4164-
SubstitutionMap Substitutions)
4165-
{
4163+
OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl, unsigned ordinal,
4164+
SubstitutionMap Substitutions) {
4165+
// TODO [OPAQUE SUPPORT]: multiple opaque types
4166+
assert(ordinal == 0 && "we only support one 'some' type per composite type");
4167+
auto opaqueParamType = Decl->getUnderlyingInterfaceType();
4168+
41664169
// TODO: We could attempt to preserve type sugar in the substitution map.
41674170
// Currently archetypes are assumed to be always canonical in many places,
41684171
// though, so doing so would require fixing those places.
@@ -4238,18 +4241,18 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
42384241
}
42394242
}
42404243
#else
4241-
// Assert that there are no same type constraints on the underlying type
4242-
// or its associated types.
4244+
// Assert that there are no same type constraints on the opaque type or its
4245+
// associated types.
42434246
//
42444247
// This should not be possible until we add where clause support, with the
42454248
// exception of generic base class constraints (handled below).
42464249
(void)newRequirements;
42474250
# ifndef NDEBUG
4248-
for (auto reqt :
4251+
for (auto req :
42494252
Decl->getOpaqueInterfaceGenericSignature().getRequirements()) {
4250-
auto reqtBase = reqt.getFirstType()->getRootGenericParam();
4251-
if (reqtBase->isEqual(Decl->getUnderlyingInterfaceType())) {
4252-
assert(reqt.getKind() != RequirementKind::SameType
4253+
auto reqBase = req.getFirstType()->getRootGenericParam();
4254+
if (reqBase->isEqual(opaqueParamType)) {
4255+
assert(req.getKind() != RequirementKind::SameType
42534256
&& "supporting where clauses on opaque types requires correctly "
42544257
"setting up the generic environment for "
42554258
"OpaqueTypeArchetypeTypes; see comment above");
@@ -4265,9 +4268,8 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
42654268
std::move(newRequirements)},
42664269
nullptr);
42674270

4268-
auto opaqueInterfaceTy = Decl->getUnderlyingInterfaceType();
4269-
auto layout = signature->getLayoutConstraint(opaqueInterfaceTy);
4270-
auto superclass = signature->getSuperclassBound(opaqueInterfaceTy);
4271+
auto reqs = signature->getLocalRequirements(opaqueParamType);
4272+
auto superclass = reqs.superclass;
42714273
#if !DO_IT_CORRECTLY
42724274
// Ad-hoc substitute the generic parameters of the superclass.
42734275
// If we correctly applied the substitutions to the generic signature
@@ -4276,25 +4278,23 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
42764278
superclass = superclass.subst(Substitutions);
42774279
}
42784280
#endif
4279-
const auto protos = signature->getRequiredProtocols(opaqueInterfaceTy);
42804281

42814282
auto mem = ctx.Allocate(
42824283
OpaqueTypeArchetypeType::totalSizeToAlloc<ProtocolDecl *, Type, LayoutConstraint>(
4283-
protos.size(), superclass ? 1 : 0, layout ? 1 : 0),
4284+
reqs.protos.size(), superclass ? 1 : 0, reqs.layout ? 1 : 0),
42844285
alignof(OpaqueTypeArchetypeType),
42854286
arena);
4286-
4287-
auto newOpaque = ::new (mem) OpaqueTypeArchetypeType(Decl, Substitutions,
4288-
properties,
4289-
opaqueInterfaceTy,
4290-
protos, superclass, layout);
4291-
4287+
4288+
auto newOpaque = ::new (mem)
4289+
OpaqueTypeArchetypeType(Decl, Substitutions, properties, opaqueParamType,
4290+
reqs.protos, superclass, reqs.layout);
4291+
42924292
// Create a generic environment and bind the opaque archetype to the
42934293
// opaque interface type from the decl's signature.
42944294
auto *env = GenericEnvironment::getIncomplete(signature);
4295-
env->addMapping(GenericParamKey(opaqueInterfaceTy), newOpaque);
4295+
env->addMapping(GenericParamKey(opaqueParamType), newOpaque);
42964296
newOpaque->Environment = env;
4297-
4297+
42984298
// Look up the insertion point in the folding set again in case something
42994299
// invalidated it above.
43004300
{
@@ -4304,7 +4304,7 @@ OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl,
43044304
assert(!existing && "race to create opaque archetype?!");
43054305
set.InsertNode(newOpaque, insertPos);
43064306
}
4307-
4307+
43084308
return newOpaque;
43094309
}
43104310

0 commit comments

Comments
 (0)