Skip to content

[SE-0335] Enable explicit existential types. #40666

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 24 commits into from
Jan 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cf44889
[ClangImporter] When importing ObjC pointer types, wrap protocol
hborla Dec 14, 2021
f368b77
[Sema] Account for ExistentialType in lookupExistentialConformance.
hborla Dec 14, 2021
02f5e47
[Sema] Resolve @_implements protocols using the generic requirement
hborla Dec 14, 2021
efeb709
[Deserialization] Fix deserialization of explicit existential types.
hborla Dec 21, 2021
6cee193
[Type System] When explicit existential types are enabled, wrap Error
hborla Dec 21, 2021
a7fa469
[GenericSignature] Don't allow conformance requirements with explicit
hborla Dec 21, 2021
f6f53f6
[Codable] When explicit existential types are enabled, synthesize Cod…
hborla Dec 21, 2021
86730ca
[Interop] Handle existential types in ClangTypeConverter and
hborla Dec 21, 2021
1d56338
[SILOptimizer] Use the constraint type in ExistentialSpecializer when
hborla Dec 21, 2021
f7a82ac
[Type Reconstruction] For now, reconstruct existential types without
hborla Dec 21, 2021
5e4fbc4
[Diagnostics] Stage in the new error message for existential types that
hborla Dec 21, 2021
733648b
[Sema] When explicit existential types are enabled, type witnesses that
hborla Dec 22, 2021
d971d48
[Type System] With explicit existential types, make sure existential
hborla Jan 7, 2022
b7c6348
[Sema] Implement type join for existential types.
hborla Jan 7, 2022
5dced8e
[ConstraintSystem] Fix a few constraint system corner cases with expl…
hborla Jan 7, 2022
f018328
[TypeResolver] Fix a few corner cases in type resolution for explicit
hborla Jan 7, 2022
6e6ca13
[Type System] Use the constraint type of an existential type in
hborla Jan 7, 2022
3021071
[ASTPrinter] Add an option that controls whether existential types
hborla Jan 7, 2022
ee331a8
[Type System] Enable explicit existential types.
hborla Jan 8, 2022
6060de6
[AST] Teach ExistentialType::get to only produce ExistentialType when
hborla Jan 8, 2022
c48b593
[Diagnostics] Remove the warning for 'any Any' and 'any AnyObject'.
hborla Jan 8, 2022
992a871
[Type Reconstruction] Re-construct existential types with Existential…
hborla Jan 11, 2022
6608bf8
[Sema] Fix the source compatibility check for member operators with
hborla Jan 14, 2022
626bea2
[ConstraintSystem] Return an existential type in getTypeOfMemberRefer…
hborla Jan 14, 2022
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
2 changes: 1 addition & 1 deletion include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ class ASTContext final {

/// Retrieve the declaration of Swift.Error.
ProtocolDecl *getErrorDecl() const;
CanType getExceptionType() const;
CanType getErrorExistentialType() const;

#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
/** Retrieve the declaration of Swift.NAME. */ \
Expand Down
5 changes: 3 additions & 2 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ASTBuilder {

Demangle::NodeFactory &getNodeFactory() { return Factory; }

Type decodeMangledType(NodePointer node);
Type decodeMangledType(NodePointer node, bool forRequirement = true);
Type createBuiltinType(StringRef builtinName, StringRef mangledName);

TypeDecl *createTypeDecl(NodePointer node);
Expand Down Expand Up @@ -109,7 +109,8 @@ class ASTBuilder {

Type createProtocolCompositionType(ArrayRef<ProtocolDecl *> protocols,
Type superclass,
bool isClassBound);
bool isClassBound,
bool forRequirement = true);

Type createExistentialMetatypeType(Type instance,
Optional<Demangle::ImplMetatypeRepresentation> repr=None);
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/ASTSynthesis.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ inline Type synthesizeType(SynthesisContext &SC,
switch (kind) {
case _any: return SC.Context.TheAnyType;
case _bridgeObject: return SC.Context.TheBridgeObjectType;
case _error: return SC.Context.getExceptionType();
case _error: return SC.Context.getErrorExistentialType();
case _executor: return SC.Context.TheExecutorType;
case _job: return SC.Context.TheJobType;
case _nativeObject: return SC.Context.TheNativeObjectType;
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4363,6 +4363,11 @@ class ProtocolDecl final : public NominalTypeDecl {
/// not exist.
AssociatedTypeDecl *getAssociatedType(Identifier name) const;

/// Returns the existential type for this protocol.
Type getExistentialType() const {
return ExistentialType::get(getDeclaredInterfaceType());
}

/// Walk this protocol and all of the protocols inherited by this protocol,
/// transitively, invoking the callback function for each protocol.
///
Expand Down
6 changes: 2 additions & 4 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2441,8 +2441,8 @@ ERROR(protocol_composition_one_class,none,
"contains class %1", (Type, Type))

ERROR(requires_conformance_nonprotocol,none,
"type %0 constrained to non-protocol, non-class type %1",
(Type, Type))
"type %0 constrained to non-protocol, non-class type '%1'",
(Type, StringRef))
NOTE(requires_conformance_nonprotocol_fixit,none,
"use '%0 == %1' to require '%0' to be '%1'",
(StringRef, StringRef))
Expand Down Expand Up @@ -4648,8 +4648,6 @@ ERROR(unchecked_not_inheritance_clause,none,
ERROR(unchecked_not_existential,none,
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))

WARNING(unnecessary_any,none,
"'any' is redundant on type %0", (Type))
ERROR(any_not_existential,none,
"'any' has no effect on %select{concrete type|type parameter}0 %1",
(bool, Type))
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ struct PrintOptions {

bool PrintImplicitAttrs = true;

/// Whether to print the \c any keyword for existential
/// types.
bool PrintExplicitAny = false;

/// Whether to skip keywords with a prefix of underscore such as __consuming.
bool SkipUnderscoredKeywords = false;

Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ class SelfProtocolConformance : public RootProtocolConformance {
public:
/// Get the protocol being conformed to.
ProtocolDecl *getProtocol() const {
return getType()->castTo<ProtocolType>()->getDecl();
return dyn_cast<ProtocolDecl>(getType()->getAnyNominal());
}

/// Get the declaration context in which this conformance was declared.
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ class CanType : public Type {

static bool isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig,
bool functionsCount);
static bool isConstraintTypeImpl(CanType type);
static bool isExistentialTypeImpl(CanType type);
static bool isAnyExistentialTypeImpl(CanType type);
static bool isObjCExistentialTypeImpl(CanType type);
Expand Down Expand Up @@ -457,6 +458,10 @@ class CanType : public Type {
/*functions count*/ false);
}

bool isConstraintType() const {
return isConstraintTypeImpl(*this);
}

/// Is this type existential?
bool isExistentialType() const {
return isExistentialTypeImpl(*this);
Expand Down
21 changes: 20 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
return getRecursiveProperties().hasDependentMember();
}

/// Whether this type represents a generic constraint.
bool isConstraintType() const;

/// isExistentialType - Determines whether this type is an existential type,
/// whose real (runtime) type is unknown but which is known to conform to
/// some set of protocols. Protocol and protocol-conformance types are
Expand Down Expand Up @@ -2731,6 +2734,8 @@ class ExistentialMetatypeType : public AnyMetatypeType {
static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::ExistentialMetatype;
}

Type getExistentialInstanceType();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the existence of this method, but it messes up TypeWalker if I make AnyMetatypeType::getInstanceType() return ExistentialType for existential metatypes. Alternatively, I could add getRawInstanceType() or something like that for the few places that actually need the stored InstanceType. Really, I'd like to just replace ExistentialMetatypeType with ExistentialType(MetatypeType(...))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your longer-term goal of removing ExistentialMetatypeType is good and in the meantime, this workaround is reasonable.


private:
ExistentialMetatypeType(Type T, const ASTContext *C,
Expand Down Expand Up @@ -5243,7 +5248,7 @@ class ExistentialType final : public TypeBase {
ConstraintType(constraintType) {}

public:
static ExistentialType *get(Type constraint);
static Type get(Type constraint);

Type getConstraintType() const { return ConstraintType; }

Expand Down Expand Up @@ -6335,6 +6340,15 @@ inline GenericTypeParamType *TypeBase::getRootGenericParam() {
return t->castTo<GenericTypeParamType>();
}

inline bool TypeBase::isConstraintType() const {
return getCanonicalType().isConstraintType();
}

inline bool CanType::isConstraintTypeImpl(CanType type) {
return (isa<ProtocolType>(type) ||
isa<ProtocolCompositionType>(type));
}

inline bool TypeBase::isExistentialType() {
return getCanonicalType().isExistentialType();
}
Expand Down Expand Up @@ -6441,6 +6455,8 @@ inline NominalTypeDecl *TypeBase::getNominalOrBoundGenericNominal() {
inline NominalTypeDecl *CanType::getNominalOrBoundGenericNominal() const {
if (auto Ty = dyn_cast<NominalOrBoundGenericNominalType>(*this))
return Ty->getDecl();
if (auto Ty = dyn_cast<ExistentialType>(*this))
return Ty->getConstraintType()->getNominalOrBoundGenericNominal();
return nullptr;
}

Expand All @@ -6449,6 +6465,9 @@ inline NominalTypeDecl *TypeBase::getAnyNominal() {
}

inline Type TypeBase::getNominalParent() {
if (auto existential = getAs<ExistentialType>())
return existential->getConstraintType()->getNominalParent();

return castTo<AnyGenericType>()->getParent();
}

Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ namespace swift {

/// Enable support for explicit existential types via the \c any
/// keyword.
bool EnableExplicitExistentialTypes = false;
bool EnableExplicitExistentialTypes = true;

/// Enable experimental flow-sensitive concurrent captures.
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
Expand Down
60 changes: 40 additions & 20 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,16 @@ void decodeRequirement(NodePointer node,

BuiltType constraintType;
if (child->getKind() ==
Demangle::Node::Kind::DependentGenericConformanceRequirement ||
child->getKind() ==
Demangle::Node::Kind::DependentGenericSameTypeRequirement) {
Demangle::Node::Kind::DependentGenericConformanceRequirement) {
constraintType = Builder.decodeMangledType(child->getChild(1));
if (!constraintType)
return;
} else if (child->getKind() ==
Demangle::Node::Kind::DependentGenericSameTypeRequirement) {
constraintType = Builder.decodeMangledType(
child->getChild(1), /*forRequirement=*/false);
if (!constraintType)
return;
}

switch (child->getKind()) {
Expand Down Expand Up @@ -468,15 +472,17 @@ class TypeDecoder {
explicit TypeDecoder(BuilderType &Builder) : Builder(Builder) {}

/// Given a demangle tree, attempt to turn it into a type.
TypeLookupErrorOr<BuiltType> decodeMangledType(NodePointer Node) {
return decodeMangledType(Node, 0);
TypeLookupErrorOr<BuiltType> decodeMangledType(NodePointer Node,
bool forRequirement = true) {
return decodeMangledType(Node, 0, forRequirement);
}

protected:
static const unsigned MaxDepth = 1024;

TypeLookupErrorOr<BuiltType> decodeMangledType(NodePointer Node,
unsigned depth) {
unsigned depth,
bool forRequirement = true) {
if (depth > TypeDecoder::MaxDepth)
return TypeLookupError("Mangled type is too complex");

Expand All @@ -499,7 +505,8 @@ class TypeDecoder {
if (Node->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR0(Node, "no children.");

return decodeMangledType(Node->getChild(0), depth + 1);
return decodeMangledType(Node->getChild(0), depth + 1,
forRequirement);
case NodeKind::Class:
{
#if SWIFT_OBJC_INTEROP
Expand Down Expand Up @@ -543,7 +550,8 @@ class TypeDecoder {
return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList");

for (auto genericArg : *genericArgs) {
auto paramType = decodeMangledType(genericArg, depth + 1);
auto paramType = decodeMangledType(genericArg, depth + 1,
/*forRequirement=*/false);
if (paramType.isError())
return paramType;
args.push_back(paramType.getType());
Expand Down Expand Up @@ -698,14 +706,16 @@ class TypeDecoder {
}

return Builder.createProtocolCompositionType(Protocols, Superclass,
IsClassBound);
IsClassBound,
forRequirement);
}

case NodeKind::Protocol:
case NodeKind::ProtocolSymbolicReference: {
if (auto Proto = decodeMangledProtocolType(Node, depth + 1)) {
return Builder.createProtocolCompositionType(Proto, BuiltType(),
/*IsClassBound=*/false);
/*IsClassBound=*/false,
forRequirement);
}

return MAKE_NODE_TYPE_ERROR0(Node, "failed to decode protocol type");
Expand Down Expand Up @@ -845,7 +855,8 @@ class TypeDecoder {
Node->getKind() == NodeKind::EscapingObjCBlock);

auto result =
decodeMangledType(Node->getChild(firstChildIdx + 1), depth + 1);
decodeMangledType(Node->getChild(firstChildIdx + 1), depth + 1,
/*forRequirement=*/false);
if (result.isError())
return result;
return Builder.createFunctionType(
Expand Down Expand Up @@ -962,7 +973,8 @@ class TypeDecoder {
if (Node->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR0(Node, "no children");

return decodeMangledType(Node->getChild(0), depth + 1);
return decodeMangledType(Node->getChild(0), depth + 1,
/*forRequirement=*/false);

case NodeKind::Tuple: {
llvm::SmallVector<BuiltType, 8> elements;
Expand Down Expand Up @@ -994,7 +1006,8 @@ class TypeDecoder {

// Decode the element type.
auto elementType =
decodeMangledType(element->getChild(typeChildIndex), depth + 1);
decodeMangledType(element->getChild(typeChildIndex), depth + 1,
/*forRequirement=*/false);
if (elementType.isError())
return elementType;

Expand All @@ -1012,9 +1025,11 @@ class TypeDecoder {
"fewer children (%zu) than required (2)",
Node->getNumChildren());

return decodeMangledType(Node->getChild(1), depth + 1);
return decodeMangledType(Node->getChild(1), depth + 1,
/*forRequirement=*/false);
}
return decodeMangledType(Node->getChild(0), depth + 1);
return decodeMangledType(Node->getChild(0), depth + 1,
/*forRequirement=*/false);

case NodeKind::DependentGenericType: {
if (Node->getNumChildren() < 2)
Expand Down Expand Up @@ -1161,7 +1176,8 @@ return {}; // Not Implemented!
"more substitutions than generic params");
while (index >= genericParamsAtDepth[paramDepth])
++paramDepth, index = 0;
auto substTy = decodeMangledType(subst, depth + 1);
auto substTy = decodeMangledType(subst, depth + 1,
/*forRequirement=*/false);
if (substTy.isError())
return substTy;
substitutions.emplace_back(
Expand Down Expand Up @@ -1243,7 +1259,8 @@ return {}; // Not Implemented!
if (genericsNode->getKind() != NodeKind::TypeList)
break;
for (auto argNode : *genericsNode) {
auto arg = decodeMangledType(argNode, depth + 1);
auto arg = decodeMangledType(argNode, depth + 1,
/*forRequirement=*/false);
if (arg.isError())
return arg;
genericArgsBuf.push_back(arg.getType());
Expand Down Expand Up @@ -1480,7 +1497,8 @@ return {}; // Not Implemented!
}
}

auto paramType = decodeMangledType(node, depth + 1);
auto paramType = decodeMangledType(node, depth + 1,
/*forRequirement=*/false);
if (paramType.isError())
return false;

Expand Down Expand Up @@ -1544,8 +1562,10 @@ return {}; // Not Implemented!

template <typename BuilderType>
inline TypeLookupErrorOr<typename BuilderType::BuiltType>
decodeMangledType(BuilderType &Builder, NodePointer Node) {
return TypeDecoder<BuilderType>(Builder).decodeMangledType(Node);
decodeMangledType(BuilderType &Builder, NodePointer Node,
bool forRequirement = false) {
return TypeDecoder<BuilderType>(Builder)
.decodeMangledType(Node, forRequirement);
}

SWIFT_END_INLINE_NAMESPACE
Expand Down
5 changes: 3 additions & 2 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ class TypeRefBuilder {

void clearNodeFactory() { Dem.clear(); }

BuiltType decodeMangledType(Node *node);
BuiltType decodeMangledType(Node *node, bool forRequirement = true);

///
/// Factory methods for all TypeRef kinds
Expand Down Expand Up @@ -492,7 +492,8 @@ class TypeRefBuilder {

const ProtocolCompositionTypeRef *
createProtocolCompositionType(llvm::ArrayRef<BuiltProtocolDecl> protocols,
BuiltType superclass, bool isClassBound) {
BuiltType superclass, bool isClassBound,
bool forRequirement = true) {
std::vector<const TypeRef *> protocolRefs;
for (const auto &protocol : protocols) {
if (!protocol)
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -2220,7 +2220,7 @@ visitOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *Inst) {
auto openedType = Inst->getType().getASTType();
auto exType = Inst->getOperand()->getType().getASTType();
while (auto exMetatype = dyn_cast<ExistentialMetatypeType>(exType)) {
exType = exMetatype.getInstanceType();
exType = exMetatype->getExistentialInstanceType()->getCanonicalType();
openedType = cast<MetatypeType>(openedType).getInstanceType();
}
remapOpenedType(cast<OpenedArchetypeType>(openedType));
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -7072,7 +7072,7 @@ class InitExistentialMetatypeInst final
auto exType = getType().getASTType();
auto concreteType = getOperand()->getType().getASTType();
while (auto exMetatype = dyn_cast<ExistentialMetatypeType>(exType)) {
exType = exMetatype.getInstanceType();
exType = exMetatype->getExistentialInstanceType()->getCanonicalType();
concreteType = cast<MetatypeType>(concreteType).getInstanceType();
}
assert(exType.isExistentialType());
Expand Down
6 changes: 6 additions & 0 deletions lib/APIDigester/ModuleAnalyzerNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,12 @@ static StringRef getTypeName(SDKContext &Ctx, Type Ty,
if (auto *NAT = dyn_cast<TypeAliasType>(Ty.getPointer())) {
return NAT->getDecl()->getNameStr();
}

if (auto existential = Ty->getAs<ExistentialType>()) {
return getTypeName(Ctx, existential->getConstraintType(),
IsImplicitlyUnwrappedOptional);
}

if (Ty->getAnyNominal()) {
if (IsImplicitlyUnwrappedOptional) {
assert(Ty->getOptionalObjectType());
Expand Down
Loading