Skip to content

Commit 05f2c49

Browse files
authored
Merge pull request #40993 from DougGregor/opaque-parameters
Opaque parameters
2 parents e5433cd + 49bc1ed commit 05f2c49

21 files changed

+436
-73
lines changed

include/swift/AST/Decl.h

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,15 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
492492
SWIFT_INLINE_BITFIELD_EMPTY(TypeDecl, ValueDecl);
493493
SWIFT_INLINE_BITFIELD_EMPTY(AbstractTypeParamDecl, TypeDecl);
494494

495-
SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, AbstractTypeParamDecl, 16+16+1,
495+
SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, AbstractTypeParamDecl, 16+16+1+1,
496496
: NumPadBits,
497497

498498
Depth : 16,
499499
Index : 16,
500-
TypeSequence : 1
500+
TypeSequence : 1,
501+
502+
/// Whether this generic parameter represents an opaque type.
503+
IsOpaqueType : 1
501504
);
502505

503506
SWIFT_INLINE_BITFIELD_EMPTY(GenericTypeDecl, TypeDecl);
@@ -2786,7 +2789,8 @@ class OpaqueTypeDecl final :
27862789
/// Get the ordinal of the anonymous opaque parameter of this decl with type
27872790
/// repr `repr`, as introduce implicitly by an occurrence of "some" in return
27882791
/// position e.g. `func f() -> some P`. Returns -1 if `repr` is not found.
2789-
unsigned getAnonymousOpaqueParamOrdinal(OpaqueReturnTypeRepr *repr) const;
2792+
Optional<unsigned> getAnonymousOpaqueParamOrdinal(
2793+
OpaqueReturnTypeRepr *repr) const;
27902794

27912795
GenericSignature getOpaqueInterfaceGenericSignature() const {
27922796
return OpaqueInterfaceGenericSignature;
@@ -2993,9 +2997,14 @@ class AbstractTypeParamDecl : public TypeDecl {
29932997
/// \code
29942998
/// func min<T : Comparable>(x : T, y : T) -> T { ... }
29952999
/// \endcode
2996-
class GenericTypeParamDecl : public AbstractTypeParamDecl {
2997-
public:
2998-
static const unsigned InvalidDepth = 0xFFFF;
3000+
class GenericTypeParamDecl final :
3001+
public AbstractTypeParamDecl,
3002+
private llvm::TrailingObjects<GenericTypeParamDecl, OpaqueReturnTypeRepr *>{
3003+
friend TrailingObjects;
3004+
3005+
size_t numTrailingObjects(OverloadToken<OpaqueReturnTypeRepr *>) const {
3006+
return isOpaqueType() ? 1 : 0;
3007+
}
29993008

30003009
/// Construct a new generic type parameter.
30013010
///
@@ -3006,7 +3015,29 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl {
30063015
/// \param name The name of the generic parameter.
30073016
/// \param nameLoc The location of the name.
30083017
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
3009-
bool isTypeSequence, unsigned depth, unsigned index);
3018+
bool isTypeSequence, unsigned depth, unsigned index,
3019+
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr);
3020+
3021+
public:
3022+
/// Construct a new generic type parameter.
3023+
///
3024+
/// \param dc The DeclContext in which the generic type parameter's owner
3025+
/// occurs. This should later be overwritten with the actual declaration
3026+
/// context that owns the type parameter.
3027+
///
3028+
/// \param name The name of the generic parameter.
3029+
/// \param nameLoc The location of the name.
3030+
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
3031+
bool isTypeSequence, unsigned depth, unsigned index)
3032+
: GenericTypeParamDecl(dc, name, nameLoc, isTypeSequence, depth, index,
3033+
false, nullptr) { }
3034+
3035+
static const unsigned InvalidDepth = 0xFFFF;
3036+
3037+
static GenericTypeParamDecl *
3038+
create(DeclContext *dc, Identifier name, SourceLoc nameLoc,
3039+
bool isTypeSequence, unsigned depth, unsigned index,
3040+
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr);
30103041

30113042
/// The depth of this generic type parameter, i.e., the number of outer
30123043
/// levels of generic parameter lists that enclose this type parameter.
@@ -3034,9 +3065,33 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl {
30343065
/// \code
30353066
/// func foo<@_typeSequence T>(_ : T...) { }
30363067
/// struct Foo<@_typeSequence T> { }
3037-
/// \encode
3068+
/// \endcode
30383069
bool isTypeSequence() const { return Bits.GenericTypeParamDecl.TypeSequence; }
30393070

3071+
/// Determine whether this generic parameter represents an opaque type.
3072+
///
3073+
/// \code
3074+
/// // "some P" is representated by a generic type parameter.
3075+
/// func f() -> [some P] { ... }
3076+
/// \endcode
3077+
bool isOpaqueType() const {
3078+
return Bits.GenericTypeParamDecl.IsOpaqueType;
3079+
}
3080+
3081+
/// Retrieve the opaque return type representation described by this
3082+
/// generic parameter, or NULL if any of the following are true:
3083+
/// - the generic parameter does not describe an opaque type
3084+
/// - the opaque type was introduced via the "named opaque parameters"
3085+
/// extension, meaning that it was specified explicitly
3086+
/// - the enclosing declaration was deserialized, in which case it lost
3087+
/// the source location information and has no type representation.
3088+
OpaqueReturnTypeRepr *getOpaqueTypeRepr() const {
3089+
if (!isOpaqueType())
3090+
return nullptr;
3091+
3092+
return *getTrailingObjects<OpaqueReturnTypeRepr *>();
3093+
}
3094+
30403095
/// The index of this generic type parameter within its generic parameter
30413096
/// list.
30423097
///

include/swift/AST/TypeRepr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ enum class TypeReprKind : uint8_t {
4747
enum : unsigned { NumTypeReprKindBits =
4848
countBitsUsed(static_cast<unsigned>(TypeReprKind::Last_TypeRepr)) };
4949

50+
class OpaqueReturnTypeRepr;
51+
using CollectedOpaqueReprs = SmallVector<OpaqueReturnTypeRepr *, 2>;
52+
5053
/// Representation of a type as written in source.
5154
class alignas(1 << TypeReprAlignInBits) TypeRepr
5255
: public ASTAllocated<TypeRepr> {
@@ -165,6 +168,10 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
165168
/// opaque return type reprs.
166169
bool hasOpaque();
167170

171+
/// Walk the type representation recursively, collecting any
172+
/// `OpaqueReturnTypeRepr`s.
173+
CollectedOpaqueReprs collectOpaqueReturnTypeReprs();
174+
168175
//*** Allocation Routines ************************************************/
169176

170177
void print(raw_ostream &OS, const PrintOptions &Opts = PrintOptions()) const;

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ namespace swift {
313313
/// `func f() -> <T> T`.
314314
bool EnableExperimentalNamedOpaqueTypes = false;
315315

316+
/// Enable experimental support for opaque parameter types, e.g.
317+
/// `func f(collection: some Collection)`.
318+
bool EnableExperimentalOpaqueParameters = false;
319+
316320
/// Enable support for explicit existential types via the \c any
317321
/// keyword.
318322
bool EnableExplicitExistentialTypes = true;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ def enable_experimental_eager_clang_module_diagnostics :
295295
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
296296
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;
297297

298+
def enable_experimental_opaque_parameters :
299+
Flag<["-"], "enable-experimental-opaque-parameters">,
300+
HelpText<"Enable experimental support for opaque parameters">;
301+
298302
def enable_experimental_pairwise_build_block :
299303
Flag<["-"], "enable-experimental-pairwise-build-block">,
300304
HelpText<"Enable experimental pairwise 'buildBlock' for result builders">;

lib/AST/ASTPrinter.cpp

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,7 +1660,42 @@ void PrintAST::printSingleDepthOfGenericSignature(
16601660
});
16611661
};
16621662

1663-
if (printParams) {
1663+
/// Separate the explicit generic parameters from the implicit, opaque
1664+
/// generic parameters. We only print the former.
1665+
TypeArrayView<GenericTypeParamType> opaqueGenericParams;
1666+
for (unsigned index : indices(genericParams)) {
1667+
auto gpDecl = genericParams[index]->getDecl();
1668+
if (!gpDecl)
1669+
continue;
1670+
1671+
if (gpDecl->isOpaqueType() && gpDecl->isImplicit()) {
1672+
// We found the first implicit opaque type parameter. Split the
1673+
// generic parameters array at this position.
1674+
opaqueGenericParams = genericParams.slice(index);
1675+
genericParams = genericParams.slice(0, index);
1676+
break;
1677+
}
1678+
}
1679+
1680+
// Determines whether a given type is based on one of the opaque generic
1681+
// parameters.
1682+
auto dependsOnOpaque = [&](Type type) {
1683+
if (opaqueGenericParams.empty())
1684+
return false;
1685+
1686+
if (!type->isTypeParameter())
1687+
return false;
1688+
1689+
auto rootGP = type->getRootGenericParam();
1690+
for (auto opaqueGP : opaqueGenericParams) {
1691+
if (rootGP->isEqual(opaqueGP))
1692+
return true;
1693+
}
1694+
1695+
return false;
1696+
};
1697+
1698+
if (printParams && !genericParams.empty()) {
16641699
// Print the generic parameters.
16651700
Printer << "<";
16661701
llvm::interleave(
@@ -1688,10 +1723,17 @@ void PrintAST::printSingleDepthOfGenericSignature(
16881723
continue;
16891724

16901725
auto first = req.getFirstType();
1726+
1727+
if (dependsOnOpaque(first))
1728+
continue;
1729+
16911730
Type second;
16921731

1693-
if (req.getKind() != RequirementKind::Layout)
1732+
if (req.getKind() != RequirementKind::Layout) {
16941733
second = req.getSecondType();
1734+
if (dependsOnOpaque(second))
1735+
continue;
1736+
}
16951737

16961738
if (!subMap.empty()) {
16971739
Type subFirst = substParam(first);
@@ -1750,7 +1792,7 @@ void PrintAST::printSingleDepthOfGenericSignature(
17501792
}
17511793
}
17521794

1753-
if (printParams)
1795+
if (printParams && !genericParams.empty())
17541796
Printer << ">";
17551797
}
17561798

@@ -6033,7 +6075,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
60336075
}
60346076

60356077
void visitGenericTypeParamType(GenericTypeParamType *T) {
6036-
if (T->getDecl() == nullptr) {
6078+
auto decl = T->getDecl();
6079+
if (!decl) {
60376080
// If we have an alternate name for this type, use it.
60386081
if (Options.AlternativeTypeNames) {
60396082
auto found = Options.AlternativeTypeNames->find(T->getCanonicalType());
@@ -6049,6 +6092,25 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
60496092
T = Options.GenericSig->getSugaredType(T);
60506093
}
60516094

6095+
// Print opaque types as "some ..."
6096+
if (decl && decl->isOpaqueType()) {
6097+
// If we have and should print based on the type representation, do so.
6098+
if (auto opaqueRepr = decl->getOpaqueTypeRepr()) {
6099+
if (willUseTypeReprPrinting(opaqueRepr, Type(), Options)) {
6100+
opaqueRepr->print(Printer, Options);
6101+
return;
6102+
}
6103+
}
6104+
6105+
// Print based on the type.
6106+
Printer << "some ";
6107+
if (auto inheritedType = decl->getInherited().front().getType())
6108+
inheritedType->print(Printer, Options);
6109+
else
6110+
Printer << "Any";
6111+
return;
6112+
}
6113+
60526114
const auto Name = T->getName();
60536115
if (Name.empty()) {
60546116
Printer << "<anonymous>";

lib/AST/Builtins.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ static GenericTypeParamDecl*
234234
createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
235235
ModuleDecl *M = ctx.TheBuiltinModule;
236236
Identifier ident = ctx.getIdentifier(name);
237-
auto genericParam = new (ctx) GenericTypeParamDecl(
237+
auto genericParam = GenericTypeParamDecl::create(
238238
&M->getMainFile(FileUnitKind::Builtin), ident, SourceLoc(),
239-
/*type sequence*/ false, 0, index);
239+
/*type sequence*/ false, 0, index, /*opaque type=*/false, nullptr);
240240
return genericParam;
241241
}
242242

lib/AST/Decl.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4102,16 +4102,21 @@ AbstractTypeParamDecl::getConformingProtocols() const {
41024102
return { };
41034103
}
41044104

4105-
GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
4106-
SourceLoc nameLoc,
4107-
bool isTypeSequence, unsigned depth,
4108-
unsigned index)
4109-
: AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name, nameLoc) {
4105+
GenericTypeParamDecl::GenericTypeParamDecl(
4106+
DeclContext *dc, Identifier name, SourceLoc nameLoc,
4107+
bool isTypeSequence, unsigned depth, unsigned index,
4108+
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr
4109+
) : AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name, nameLoc) {
41104110
Bits.GenericTypeParamDecl.Depth = depth;
41114111
assert(Bits.GenericTypeParamDecl.Depth == depth && "Truncation");
41124112
Bits.GenericTypeParamDecl.Index = index;
41134113
assert(Bits.GenericTypeParamDecl.Index == index && "Truncation");
41144114
Bits.GenericTypeParamDecl.TypeSequence = isTypeSequence;
4115+
Bits.GenericTypeParamDecl.IsOpaqueType = isOpaqueType;
4116+
assert(isOpaqueType || !opaqueTypeRepr);
4117+
if (isOpaqueType)
4118+
*getTrailingObjects<OpaqueReturnTypeRepr *>() = opaqueTypeRepr;
4119+
41154120
auto &ctx = dc->getASTContext();
41164121
RecursiveTypeProperties props = RecursiveTypeProperties::HasTypeParameter;
41174122
if (this->isTypeSequence())
@@ -4120,6 +4125,21 @@ GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
41204125
setInterfaceType(MetatypeType::get(type, ctx));
41214126
}
41224127

4128+
GenericTypeParamDecl *
4129+
GenericTypeParamDecl::create(
4130+
DeclContext *dc, Identifier name, SourceLoc nameLoc,
4131+
bool isTypeSequence, unsigned depth, unsigned index,
4132+
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr) {
4133+
ASTContext &ctx = dc->getASTContext();
4134+
auto mem = ctx.Allocate(
4135+
totalSizeToAlloc<OpaqueReturnTypeRepr *>(isOpaqueType ? 1 : 0),
4136+
alignof(GenericTypeParamDecl));
4137+
return new (mem) GenericTypeParamDecl(
4138+
dc, name, nameLoc, isTypeSequence, depth, index, isOpaqueType,
4139+
opaqueTypeRepr);
4140+
}
4141+
4142+
41234143
SourceRange GenericTypeParamDecl::getSourceRange() const {
41244144
SourceLoc endLoc = getNameLoc();
41254145

@@ -7857,15 +7877,15 @@ GenericTypeParamDecl *OpaqueTypeDecl::getExplicitGenericParam(
78577877
return genericParamType->getDecl();
78587878
}
78597879

7860-
unsigned OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(
7880+
Optional<unsigned> OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(
78617881
OpaqueReturnTypeRepr *repr) const {
78627882
assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() &&
78637883
"can't do opaque param lookup without underlying interface repr");
78647884
auto opaqueReprs = getOpaqueReturnTypeReprs();
78657885
auto found = std::find(opaqueReprs.begin(), opaqueReprs.end(), repr);
78667886
if (found != opaqueReprs.end())
78677887
return found - opaqueReprs.begin();
7868-
return -1;
7888+
return None;
78697889
}
78707890

78717891
Identifier OpaqueTypeDecl::getOpaqueReturnTypeIdentifier() const {

lib/AST/GenericParamList.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ GenericParamList::clone(DeclContext *dc) const {
7373
auto &ctx = dc->getASTContext();
7474
SmallVector<GenericTypeParamDecl *, 2> params;
7575
for (auto param : getParams()) {
76-
auto *newParam = new (ctx) GenericTypeParamDecl(
76+
auto *newParam = GenericTypeParamDecl::create(
7777
dc, param->getName(), SourceLoc(), param->isTypeSequence(),
78-
GenericTypeParamDecl::InvalidDepth, param->getIndex());
78+
GenericTypeParamDecl::InvalidDepth, param->getIndex(),
79+
param->isOpaqueType(), param->getOpaqueTypeRepr());
7980
newParam->setImplicit(true);
8081
params.push_back(newParam);
8182
}

0 commit comments

Comments
 (0)