Skip to content

Commit 43324e8

Browse files
authored
Merge pull request #40710 from DougGregor/structural-opaque-result-types
2 parents 243141e + a2f7745 commit 43324e8

38 files changed

+678
-343
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ CHANGELOG
33

44
_**Note:** This is in reverse chronological order, so newer entries are added to the top._
55

6+
## Swift Next
7+
8+
* [SE-0328][]:
9+
10+
Opaque types (expressed with 'some') can now be used in structural positions
11+
within a result type, including having multiple opaque types in the same
12+
result. For example:
13+
14+
```
15+
func getSomeDictionary() -> [some Hashable: some Codable] {
16+
return [ 1: "One", 2: "Two" ]
17+
}
18+
```
619
Swift 5.6
720
---------
821

@@ -8761,6 +8774,7 @@ Swift 1.0
87618774
[SE-0316]: <https://github.com/apple/swift-evolution/blob/main/proposals/0316-global-actors.md>
87628775
[SE-0324]: <https://github.com/apple/swift-evolution/blob/main/proposals/0324-c-lang-pointer-arg-conversion.md>
87638776
[SE-0323]: <https://github.com/apple/swift-evolution/blob/main/proposals/0323-async-main-semantics.md>
8777+
[SE-0328]: <https://github.com/apple/swift-evolution/blob/main/proposals/0328-structural-opaque-result-types.md>
87648778

87658779
[SR-75]: <https://bugs.swift.org/browse/SR-75>
87668780
[SR-106]: <https://bugs.swift.org/browse/SR-106>

include/swift/AST/ASTMangler.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ class ASTMangler : public Mangler {
339339
}
340340

341341
void appendBoundGenericArgs(Type type, GenericSignature sig,
342-
bool &isFirstArgList);
342+
bool &isFirstArgList,
343+
const ValueDecl *forDecl = nullptr);
343344

344345
/// Append the bound generics arguments for the given declaration context
345346
/// based on a complete substitution map.
@@ -349,18 +350,21 @@ class ASTMangler : public Mangler {
349350
unsigned appendBoundGenericArgs(DeclContext *dc,
350351
GenericSignature sig,
351352
SubstitutionMap subs,
352-
bool &isFirstArgList);
353+
bool &isFirstArgList,
354+
const ValueDecl *forDecl = nullptr);
353355

354356
/// Append the bound generic arguments as a flat list, disregarding depth.
355357
void appendFlatGenericArgs(SubstitutionMap subs,
356-
GenericSignature sig);
358+
GenericSignature sig,
359+
const ValueDecl *forDecl = nullptr);
357360

358361
/// Append any retroactive conformances.
359362
void appendRetroactiveConformances(Type type, GenericSignature sig);
360363
void appendRetroactiveConformances(SubstitutionMap subMap,
361364
GenericSignature sig,
362365
ModuleDecl *fromModule);
363-
void appendImplFunctionType(SILFunctionType *fn, GenericSignature sig);
366+
void appendImplFunctionType(SILFunctionType *fn, GenericSignature sig,
367+
const ValueDecl *forDecl = nullptr);
364368

365369
void appendContextOf(const ValueDecl *decl);
366370

include/swift/AST/Decl.h

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,45 +2699,63 @@ class GenericTypeDecl : public GenericContext, public TypeDecl {
26992699
/// The declared type uses a special kind of archetype type to represent
27002700
/// abstracted types, e.g. `(some P, some Q)` becomes `((opaque archetype 0),
27012701
/// (opaque archetype 1))`.
2702-
class OpaqueTypeDecl : public GenericTypeDecl {
2702+
class OpaqueTypeDecl final :
2703+
public GenericTypeDecl,
2704+
private llvm::TrailingObjects<OpaqueTypeDecl, OpaqueReturnTypeRepr *> {
2705+
friend TrailingObjects;
2706+
27032707
/// The original declaration that "names" the opaque type. Although a specific
27042708
/// opaque type cannot be explicitly named, oapque types can propagate
27052709
/// arbitrarily through expressions, so we need to know *which* opaque type is
27062710
/// propagated.
2707-
ValueDecl *NamingDecl;
2711+
///
2712+
/// The bit indicates whether there are any trailing
2713+
/// OpaqueReturnTypeReprs.
2714+
llvm::PointerIntPair<ValueDecl *, 1>
2715+
NamingDeclAndHasOpaqueReturnTypeRepr;
27082716

27092717
/// The generic signature of the opaque interface to the type. This is the
27102718
/// outer generic signature with added generic parameters representing the
27112719
/// abstracted underlying types.
27122720
GenericSignature OpaqueInterfaceGenericSignature;
27132721

2714-
/// The type repr of the underlying type. Might be null if no source location
2715-
/// is availble, e.g. if this decl was loaded from a serialized module.
2716-
OpaqueReturnTypeRepr *UnderlyingInterfaceRepr;
2717-
2718-
/// The generic parameter that represents the underlying type.
2719-
GenericTypeParamType *UnderlyingInterfaceType;
2720-
27212722
/// If known, the underlying type and conformances of the opaque type,
27222723
/// expressed as a SubstitutionMap for the opaque interface generic signature.
27232724
/// This maps types in the interface generic signature to the outer generic
27242725
/// signature of the original declaration.
27252726
Optional<SubstitutionMap> UnderlyingTypeSubstitutions;
27262727

27272728
mutable Identifier OpaqueReturnTypeIdentifier;
2728-
2729-
public:
2729+
27302730
OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams,
27312731
DeclContext *DC,
27322732
GenericSignature OpaqueInterfaceGenericSignature,
2733-
OpaqueReturnTypeRepr *UnderlyingInterfaceRepr,
2734-
GenericTypeParamType *UnderlyingInterfaceType);
2733+
ArrayRef<OpaqueReturnTypeRepr *> OpaqueReturnTypeReprs);
2734+
2735+
unsigned getNumOpaqueReturnTypeReprs() const {
2736+
return NamingDeclAndHasOpaqueReturnTypeRepr.getInt()
2737+
? getOpaqueGenericParams().size()
2738+
: 0;
2739+
}
2740+
2741+
size_t numTrailingObjects(OverloadToken<OpaqueReturnTypeRepr *>) const {
2742+
return getNumOpaqueReturnTypeReprs();
2743+
}
2744+
2745+
public:
2746+
static OpaqueTypeDecl *get(
2747+
ValueDecl *NamingDecl, GenericParamList *GenericParams,
2748+
DeclContext *DC,
2749+
GenericSignature OpaqueInterfaceGenericSignature,
2750+
ArrayRef<OpaqueReturnTypeRepr *> OpaqueReturnTypeReprs);
27352751

2736-
ValueDecl *getNamingDecl() const { return NamingDecl; }
2752+
ValueDecl *getNamingDecl() const {
2753+
return NamingDeclAndHasOpaqueReturnTypeRepr.getPointer();
2754+
}
27372755

27382756
void setNamingDecl(ValueDecl *D) {
2739-
assert(!NamingDecl && "already have naming decl");
2740-
NamingDecl = D;
2757+
assert(!getNamingDecl() && "already have naming decl");
2758+
NamingDeclAndHasOpaqueReturnTypeRepr.setPointer(D);
27412759
}
27422760

27432761
/// Is this opaque type the opaque return type of the given function?
@@ -2754,11 +2772,24 @@ class OpaqueTypeDecl : public GenericTypeDecl {
27542772
GenericSignature getOpaqueInterfaceGenericSignature() const {
27552773
return OpaqueInterfaceGenericSignature;
27562774
}
2757-
2758-
GenericTypeParamType *getUnderlyingInterfaceType() const {
2759-
return UnderlyingInterfaceType;
2775+
2776+
/// Retrieve the generic parameters that represent the opaque types described by this opaque
2777+
/// type declaration.
2778+
TypeArrayView<GenericTypeParamType> getOpaqueGenericParams() const {
2779+
return OpaqueInterfaceGenericSignature.getInnermostGenericParams();
27602780
}
2761-
2781+
2782+
/// Retrieve the buffer containing the opaque return type
2783+
/// representations that correspond to the opaque generic parameters.
2784+
ArrayRef<OpaqueReturnTypeRepr *> getOpaqueReturnTypeReprs() const {
2785+
return {
2786+
getTrailingObjects<OpaqueReturnTypeRepr *>(),
2787+
getNumOpaqueReturnTypeReprs()
2788+
};
2789+
}
2790+
2791+
/// The substitutions that map the generic parameters of the opaque type to
2792+
/// their underlying types, when that information is known.
27622793
Optional<SubstitutionMap> getUnderlyingTypeSubstitutions() const {
27632794
return UnderlyingTypeSubstitutions;
27642795
}

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,9 +1876,6 @@ ERROR(opaque_type_invalid_constraint,none,
18761876
"and/or a base class", ())
18771877
NOTE(opaque_of_optional_rewrite,none,
18781878
"did you mean to write an optional of an 'opaque' type?", ())
1879-
ERROR(more_than_one_opaque_type,none,
1880-
"%0 contains multiple 'opaque' types, but only one 'opaque' type is "
1881-
"supported", (TypeRepr*))
18821879
ERROR(inferred_opaque_type,none,
18831880
"property definition has inferred type %0, involving the 'some' "
18841881
"return type of another declaration", (Type))
@@ -4135,8 +4132,8 @@ ERROR(opaque_type_no_underlying_type_candidates,none,
41354132
"function declares an opaque return type, but has no return statements "
41364133
"in its body from which to infer an underlying type", ())
41374134
ERROR(opaque_type_mismatched_underlying_type_candidates,none,
4138-
"function declares an opaque return type, but the return statements "
4139-
"in its body do not have matching underlying types", ())
4135+
"function declares an opaque return type %0, but the return statements "
4136+
"in its body do not have matching underlying types", (TypeRepr *))
41404137
NOTE(opaque_type_underlying_type_candidate_here,none,
41414138
"return statement has underlying type %0", (Type))
41424139
ERROR(opaque_type_self_referential_underlying_type,none,

include/swift/AST/Expr.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,8 +3018,13 @@ class LinearToDifferentiableFunctionExpr : public ImplicitConversionExpr {
30183018
/// (opaque type)" and "S<T> ---> S<(opaque type)>".
30193019
class UnderlyingToOpaqueExpr : public ImplicitConversionExpr {
30203020
public:
3021-
UnderlyingToOpaqueExpr(Expr *subExpr, Type ty)
3022-
: ImplicitConversionExpr(ExprKind::UnderlyingToOpaque, subExpr, ty) {}
3021+
/// The substitutions to be applied to the opaque type declaration to
3022+
/// produce the resulting type.
3023+
const SubstitutionMap substitutions;
3024+
3025+
UnderlyingToOpaqueExpr(Expr *subExpr, Type ty, SubstitutionMap substitutions)
3026+
: ImplicitConversionExpr(ExprKind::UnderlyingToOpaque, subExpr, ty),
3027+
substitutions(substitutions) {}
30233028

30243029
static bool classof(const Expr *E) {
30253030
return E->getKind() == ExprKind::UnderlyingToOpaque;

include/swift/AST/Types.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5601,17 +5601,15 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
56015601
/// func foo() -> (some P, some Q)
56025602
///
56035603
/// then the underlying type of `some P` would be ordinal 0, and `some Q` would be ordinal 1.
5604-
unsigned getOrdinal() const {
5605-
// TODO [OPAQUE SUPPORT]: multiple opaque types
5606-
return 0;
5607-
}
5604+
unsigned getOrdinal() const;
56085605

56095606
static void Profile(llvm::FoldingSetNodeID &ID,
56105607
OpaqueTypeDecl *OpaqueDecl,
5608+
unsigned ordinal,
56115609
SubstitutionMap Substitutions);
56125610

56135611
void Profile(llvm::FoldingSetNodeID &ID) {
5614-
Profile(ID, getDecl(), getSubstitutions());
5612+
Profile(ID, getDecl(), getOrdinal(), getSubstitutions());
56155613
};
56165614

56175615
private:

include/swift/Option/FrontendOptions.td

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,10 +494,6 @@ def enable_experimental_named_opaque_types :
494494
Flag<["-"], "enable-experimental-named-opaque-types">,
495495
HelpText<"Enable experimental support for named opaque result types">;
496496

497-
def enable_experimental_structural_opaque_types :
498-
Flag<["-"], "enable-experimental-structural-opaque-types">,
499-
HelpText<"Enable experimental support for structural opaque result types">;
500-
501497
def enable_explicit_existential_types :
502498
Flag<["-"], "enable-explicit-existential-types">,
503499
HelpText<"Enable experimental support for explicit existential types">;

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3316,6 +3316,11 @@ class ConstraintSystem {
33163316
ArrayRef<ConstraintLocator::PathElement> path,
33173317
unsigned summaryFlags);
33183318

3319+
/// Retrieve a locator for opening the opaque archetype for the given
3320+
/// opaque type.
3321+
ConstraintLocator *getOpenOpaqueLocator(
3322+
ConstraintLocatorBuilder locator, OpaqueTypeDecl *opaqueDecl);
3323+
33193324
/// Retrive the constraint locator for the given anchor and
33203325
/// path, uniqued and automatically infer the summary flags
33213326
ConstraintLocator *

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,18 +1510,18 @@ SDKNode *swift::ide::api::
15101510
SwiftDeclCollector::constructTypeNode(Type T, TypeInitInfo Info) {
15111511
if (Ctx.checkingABI()) {
15121512
T = T->getCanonicalType();
1513-
// If the type is a opaque result type (some Type) and we're in the ABI mode,
1514-
// we should substitute the opaque result type to its underlying type.
1515-
// Notice this only works if the opaque result type is from an inlinable
1516-
// function where the function body is present in the swift module file, thus
1517-
// allowing us to know the concrete type.
1518-
if (auto OTA = T->getAs<OpaqueTypeArchetypeType>()) {
1519-
if (auto *D = OTA->getDecl()) {
1520-
if (auto SubMap = D->getUnderlyingTypeSubstitutions()) {
1521-
T = Type(D->getUnderlyingInterfaceType()).
1522-
subst(*SubMap)->getCanonicalType();
1523-
}
1524-
}
1513+
1514+
if (T->hasOpaqueArchetype()) {
1515+
// When the type contains an opaque result type and we're in the ABI mode,
1516+
// we should substitute the opaque result type to its underlying type.
1517+
// Notice this only works if the opaque result type is from an inlinable
1518+
// function where the function body is present in the swift module file,
1519+
// thus allowing us to know the concrete type.
1520+
ReplaceOpaqueTypesWithUnderlyingTypes replacer(
1521+
/*inContext=*/nullptr, ResilienceExpansion::Maximal,
1522+
/*isWholeModuleContext=*/false);
1523+
T = T.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes)
1524+
->getCanonicalType();
15251525
}
15261526
}
15271527

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4283,17 +4283,15 @@ DependentMemberType *DependentMemberType::get(Type base,
42834283
OpaqueTypeArchetypeType *
42844284
OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl, unsigned ordinal,
42854285
SubstitutionMap Substitutions) {
4286-
// TODO [OPAQUE SUPPORT]: multiple opaque types
4287-
assert(ordinal == 0 && "we only support one 'some' type per composite type");
4288-
auto opaqueParamType = Decl->getUnderlyingInterfaceType();
4286+
auto opaqueParamType = Decl->getOpaqueGenericParams()[ordinal];
42894287

42904288
// TODO: We could attempt to preserve type sugar in the substitution map.
42914289
// Currently archetypes are assumed to be always canonical in many places,
42924290
// though, so doing so would require fixing those places.
42934291
Substitutions = Substitutions.getCanonical();
42944292

42954293
llvm::FoldingSetNodeID id;
4296-
Profile(id, Decl, Substitutions);
4294+
Profile(id, Decl, ordinal, Substitutions);
42974295

42984296
auto &ctx = Decl->getASTContext();
42994297

lib/AST/ASTDemangler.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,6 @@ Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor,
265265
auto opaqueDecl = parentModule->lookupOpaqueResultType(mangledName);
266266
if (!opaqueDecl)
267267
return Type();
268-
// TODO [OPAQUE SUPPORT]: multiple opaque types
269-
assert(ordinal == 0 && "not implemented");
270-
if (ordinal != 0)
271-
return Type();
272-
273268
SmallVector<Type, 8> allArgs;
274269
for (auto argSet : args) {
275270
allArgs.append(argSet.begin(), argSet.end());

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ namespace {
567567
OS << " naming_decl=";
568568
printDeclName(OTD->getNamingDecl());
569569
PrintWithColorRAII(OS, TypeColor) << " opaque_interface="
570-
<< Type(OTD->getUnderlyingInterfaceType()).getString();
570+
<< OTD->getDeclaredInterfaceType().getString();
571571
OS << " in "
572572
<< OTD->getOpaqueInterfaceGenericSignature()->getAsString();
573573
if (auto underlyingSubs = OTD->getUnderlyingTypeSubstitutions()) {
@@ -3776,6 +3776,7 @@ namespace {
37763776
StringRef label) {
37773777
printArchetypeCommon(T, "opaque_type", label);
37783778
printField("decl", T->getDecl()->getNamingDecl()->printRef());
3779+
printField("ordinal", T->getOrdinal());
37793780
if (!T->getSubstitutions().empty()) {
37803781
OS << '\n';
37813782
SmallPtrSet<const ProtocolConformance *, 4> Dumped;

0 commit comments

Comments
 (0)