Skip to content

Opaque parameters #40993

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 63 additions & 8 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -492,12 +492,15 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
SWIFT_INLINE_BITFIELD_EMPTY(TypeDecl, ValueDecl);
SWIFT_INLINE_BITFIELD_EMPTY(AbstractTypeParamDecl, TypeDecl);

SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, AbstractTypeParamDecl, 16+16+1,
SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, AbstractTypeParamDecl, 16+16+1+1,
: NumPadBits,

Depth : 16,
Index : 16,
TypeSequence : 1
TypeSequence : 1,

/// Whether this generic parameter represents an opaque type.
IsOpaqueType : 1
);

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

GenericSignature getOpaqueInterfaceGenericSignature() const {
return OpaqueInterfaceGenericSignature;
Expand Down Expand Up @@ -2993,9 +2997,14 @@ class AbstractTypeParamDecl : public TypeDecl {
/// \code
/// func min<T : Comparable>(x : T, y : T) -> T { ... }
/// \endcode
class GenericTypeParamDecl : public AbstractTypeParamDecl {
public:
static const unsigned InvalidDepth = 0xFFFF;
class GenericTypeParamDecl final :
public AbstractTypeParamDecl,
private llvm::TrailingObjects<GenericTypeParamDecl, OpaqueReturnTypeRepr *>{
friend TrailingObjects;

size_t numTrailingObjects(OverloadToken<OpaqueReturnTypeRepr *>) const {
return isOpaqueType() ? 1 : 0;
}

/// Construct a new generic type parameter.
///
Expand All @@ -3006,7 +3015,29 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl {
/// \param name The name of the generic parameter.
/// \param nameLoc The location of the name.
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
bool isTypeSequence, unsigned depth, unsigned index);
bool isTypeSequence, unsigned depth, unsigned index,
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr);

public:
/// Construct a new generic type parameter.
///
/// \param dc The DeclContext in which the generic type parameter's owner
/// occurs. This should later be overwritten with the actual declaration
/// context that owns the type parameter.
///
/// \param name The name of the generic parameter.
/// \param nameLoc The location of the name.
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
bool isTypeSequence, unsigned depth, unsigned index)
: GenericTypeParamDecl(dc, name, nameLoc, isTypeSequence, depth, index,
false, nullptr) { }

static const unsigned InvalidDepth = 0xFFFF;

static GenericTypeParamDecl *
create(DeclContext *dc, Identifier name, SourceLoc nameLoc,
bool isTypeSequence, unsigned depth, unsigned index,
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr);

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

/// Determine whether this generic parameter represents an opaque type.
///
/// \code
/// // "some P" is representated by a generic type parameter.
/// func f() -> [some P] { ... }
/// \endcode
bool isOpaqueType() const {
return Bits.GenericTypeParamDecl.IsOpaqueType;
}

/// Retrieve the opaque return type representation described by this
/// generic parameter, or NULL if any of the following are true:
/// - the generic parameter does not describe an opaque type
/// - the opaque type was introduced via the "named opaque parameters"
/// extension, meaning that it was specified explicitly
/// - the enclosing declaration was deserialized, in which case it lost
/// the source location information and has no type representation.
OpaqueReturnTypeRepr *getOpaqueTypeRepr() const {
if (!isOpaqueType())
return nullptr;

return *getTrailingObjects<OpaqueReturnTypeRepr *>();
}

/// The index of this generic type parameter within its generic parameter
/// list.
///
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ enum class TypeReprKind : uint8_t {
enum : unsigned { NumTypeReprKindBits =
countBitsUsed(static_cast<unsigned>(TypeReprKind::Last_TypeRepr)) };

class OpaqueReturnTypeRepr;
using CollectedOpaqueReprs = SmallVector<OpaqueReturnTypeRepr *, 2>;

/// Representation of a type as written in source.
class alignas(1 << TypeReprAlignInBits) TypeRepr
: public ASTAllocated<TypeRepr> {
Expand Down Expand Up @@ -165,6 +168,10 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
/// opaque return type reprs.
bool hasOpaque();

/// Walk the type representation recursively, collecting any
/// `OpaqueReturnTypeRepr`s.
CollectedOpaqueReprs collectOpaqueReturnTypeReprs();

//*** Allocation Routines ************************************************/

void print(raw_ostream &OS, const PrintOptions &Opts = PrintOptions()) const;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ namespace swift {
/// `func f() -> <T> T`.
bool EnableExperimentalNamedOpaqueTypes = false;

/// Enable experimental support for opaque parameter types, e.g.
/// `func f(collection: some Collection)`.
bool EnableExperimentalOpaqueParameters = false;

/// Enable support for explicit existential types via the \c any
/// keyword.
bool EnableExplicitExistentialTypes = true;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ def enable_experimental_eager_clang_module_diagnostics :
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;

def enable_experimental_opaque_parameters :
Flag<["-"], "enable-experimental-opaque-parameters">,
HelpText<"Enable experimental support for opaque parameters">;

def enable_experimental_pairwise_build_block :
Flag<["-"], "enable-experimental-pairwise-build-block">,
HelpText<"Enable experimental pairwise 'buildBlock' for result builders">;
Expand Down
70 changes: 66 additions & 4 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1658,7 +1658,42 @@ void PrintAST::printSingleDepthOfGenericSignature(
});
};

if (printParams) {
/// Separate the explicit generic parameters from the implicit, opaque
/// generic parameters. We only print the former.
TypeArrayView<GenericTypeParamType> opaqueGenericParams;
for (unsigned index : indices(genericParams)) {
auto gpDecl = genericParams[index]->getDecl();
if (!gpDecl)
continue;

if (gpDecl->isOpaqueType() && gpDecl->isImplicit()) {
// We found the first implicit opaque type parameter. Split the
// generic parameters array at this position.
opaqueGenericParams = genericParams.slice(index);
genericParams = genericParams.slice(0, index);
break;
}
}

// Determines whether a given type is based on one of the opaque generic
// parameters.
auto dependsOnOpaque = [&](Type type) {
if (opaqueGenericParams.empty())
return false;

if (!type->isTypeParameter())
return false;

auto rootGP = type->getRootGenericParam();
for (auto opaqueGP : opaqueGenericParams) {
if (rootGP->isEqual(opaqueGP))
return true;
}

return false;
};

if (printParams && !genericParams.empty()) {
// Print the generic parameters.
Printer << "<";
llvm::interleave(
Expand Down Expand Up @@ -1686,10 +1721,17 @@ void PrintAST::printSingleDepthOfGenericSignature(
continue;

auto first = req.getFirstType();

if (dependsOnOpaque(first))
continue;

Type second;

if (req.getKind() != RequirementKind::Layout)
if (req.getKind() != RequirementKind::Layout) {
second = req.getSecondType();
if (dependsOnOpaque(second))
continue;
}

if (!subMap.empty()) {
Type subFirst = substParam(first);
Expand Down Expand Up @@ -1748,7 +1790,7 @@ void PrintAST::printSingleDepthOfGenericSignature(
}
}

if (printParams)
if (printParams && !genericParams.empty())
Printer << ">";
}

Expand Down Expand Up @@ -6031,7 +6073,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}

void visitGenericTypeParamType(GenericTypeParamType *T) {
if (T->getDecl() == nullptr) {
auto decl = T->getDecl();
if (!decl) {
// If we have an alternate name for this type, use it.
if (Options.AlternativeTypeNames) {
auto found = Options.AlternativeTypeNames->find(T->getCanonicalType());
Expand All @@ -6047,6 +6090,25 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
T = Options.GenericSig->getSugaredType(T);
}

// Print opaque types as "some ..."
if (decl && decl->isOpaqueType()) {
// If we have and should print based on the type representation, do so.
if (auto opaqueRepr = decl->getOpaqueTypeRepr()) {
if (willUseTypeReprPrinting(opaqueRepr, Type(), Options)) {
opaqueRepr->print(Printer, Options);
return;
}
}

// Print based on the type.
Printer << "some ";
if (auto inheritedType = decl->getInherited().front().getType())
inheritedType->print(Printer, Options);
else
Printer << "Any";
return;
}

const auto Name = T->getName();
if (Name.empty()) {
Printer << "<anonymous>";
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ static GenericTypeParamDecl*
createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
ModuleDecl *M = ctx.TheBuiltinModule;
Identifier ident = ctx.getIdentifier(name);
auto genericParam = new (ctx) GenericTypeParamDecl(
auto genericParam = GenericTypeParamDecl::create(
&M->getMainFile(FileUnitKind::Builtin), ident, SourceLoc(),
/*type sequence*/ false, 0, index);
/*type sequence*/ false, 0, index, /*opaque type=*/false, nullptr);
return genericParam;
}

Expand Down
34 changes: 27 additions & 7 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4102,16 +4102,21 @@ AbstractTypeParamDecl::getConformingProtocols() const {
return { };
}

GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
SourceLoc nameLoc,
bool isTypeSequence, unsigned depth,
unsigned index)
: AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name, nameLoc) {
GenericTypeParamDecl::GenericTypeParamDecl(
DeclContext *dc, Identifier name, SourceLoc nameLoc,
bool isTypeSequence, unsigned depth, unsigned index,
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr
) : AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name, nameLoc) {
Bits.GenericTypeParamDecl.Depth = depth;
assert(Bits.GenericTypeParamDecl.Depth == depth && "Truncation");
Bits.GenericTypeParamDecl.Index = index;
assert(Bits.GenericTypeParamDecl.Index == index && "Truncation");
Bits.GenericTypeParamDecl.TypeSequence = isTypeSequence;
Bits.GenericTypeParamDecl.IsOpaqueType = isOpaqueType;
assert(isOpaqueType || !opaqueTypeRepr);
if (isOpaqueType)
*getTrailingObjects<OpaqueReturnTypeRepr *>() = opaqueTypeRepr;

auto &ctx = dc->getASTContext();
RecursiveTypeProperties props = RecursiveTypeProperties::HasTypeParameter;
if (this->isTypeSequence())
Expand All @@ -4120,6 +4125,21 @@ GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
setInterfaceType(MetatypeType::get(type, ctx));
}

GenericTypeParamDecl *
GenericTypeParamDecl::create(
DeclContext *dc, Identifier name, SourceLoc nameLoc,
bool isTypeSequence, unsigned depth, unsigned index,
bool isOpaqueType, OpaqueReturnTypeRepr *opaqueTypeRepr) {
ASTContext &ctx = dc->getASTContext();
auto mem = ctx.Allocate(
totalSizeToAlloc<OpaqueReturnTypeRepr *>(isOpaqueType ? 1 : 0),
alignof(GenericTypeParamDecl));
return new (mem) GenericTypeParamDecl(
dc, name, nameLoc, isTypeSequence, depth, index, isOpaqueType,
opaqueTypeRepr);
}


SourceRange GenericTypeParamDecl::getSourceRange() const {
SourceLoc endLoc = getNameLoc();

Expand Down Expand Up @@ -7857,15 +7877,15 @@ GenericTypeParamDecl *OpaqueTypeDecl::getExplicitGenericParam(
return genericParamType->getDecl();
}

unsigned OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(
Optional<unsigned> OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(
OpaqueReturnTypeRepr *repr) const {
assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() &&
"can't do opaque param lookup without underlying interface repr");
auto opaqueReprs = getOpaqueReturnTypeReprs();
auto found = std::find(opaqueReprs.begin(), opaqueReprs.end(), repr);
if (found != opaqueReprs.end())
return found - opaqueReprs.begin();
return -1;
return None;
}

Identifier OpaqueTypeDecl::getOpaqueReturnTypeIdentifier() const {
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/GenericParamList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ GenericParamList::clone(DeclContext *dc) const {
auto &ctx = dc->getASTContext();
SmallVector<GenericTypeParamDecl *, 2> params;
for (auto param : getParams()) {
auto *newParam = new (ctx) GenericTypeParamDecl(
auto *newParam = GenericTypeParamDecl::create(
dc, param->getName(), SourceLoc(), param->isTypeSequence(),
GenericTypeParamDecl::InvalidDepth, param->getIndex());
GenericTypeParamDecl::InvalidDepth, param->getIndex(),
param->isOpaqueType(), param->getOpaqueTypeRepr());
newParam->setImplicit(true);
params.push_back(newParam);
}
Expand Down
Loading