Skip to content

Rough sketch of AST/Sema support for tuple conformances #60639

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 12 commits into from
Sep 10, 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
10 changes: 9 additions & 1 deletion include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ namespace swift {
enum class Associativity : unsigned char;
class AvailabilityContext;
class BoundGenericType;
class BuiltinTupleDecl;
class ClangModuleLoader;
class ClangNode;
class ClangTypeConverter;
Expand Down Expand Up @@ -953,7 +954,7 @@ class ASTContext final {
const CanType TheIEEE80Type; /// 80-bit IEEE floating point
const CanType TheIEEE128Type; /// 128-bit IEEE floating point
const CanType ThePPC128Type; /// 128-bit PowerPC 2xDouble

/// Adds a search path to SearchPathOpts, unless it is already present.
///
/// Does any proper bookkeeping to keep all module loaders up to date as well.
Expand Down Expand Up @@ -1421,6 +1422,13 @@ class ASTContext final {
/// invocation decoder of the given distributed actor.
FuncDecl *getDistributedActorArgumentDecodingMethod(NominalTypeDecl *);

/// The special Builtin.TheTupleType, which parents tuple extensions and
/// conformances.
BuiltinTupleDecl *getBuiltinTupleDecl();

/// The declared interface type of Builtin.TheTupleType.
BuiltinTupleType *getBuiltinTupleType();

private:
friend Decl;

Expand Down
1 change: 0 additions & 1 deletion include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ TYPE_ATTR(Sendable)
TYPE_ATTR(unchecked)
TYPE_ATTR(_typeSequence)
TYPE_ATTR(_local)
TYPE_ATTR(tuple)

// SIL-specific attributes
TYPE_ATTR(block_storage)
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2542,9 +2542,6 @@ class TypeAttributes {
};
Optional<OpaqueReturnTypeRef> OpaqueReturnTypeOf;

// Force construction of a one-element tuple type.
bool IsTuple = false;

TypeAttributes() {}

bool isValid() const { return AtLoc.isValid(); }
Expand Down
42 changes: 42 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4755,6 +4755,48 @@ class ProtocolDecl final : public NominalTypeDecl {
}
};

/// This is the special singleton Builtin.TheTupleType. It is not directly
/// visible in the source language, but we use it to attach extensions
/// and conformances for tuple types.
///
/// - The declared interface type is the special TheTupleType singleton.
/// - The generic parameter list has one pack generic parameter, <Elements...>
/// - The generic signature has no requirements, <Elements...>
/// - The self interface type is the tuple type containing a single pack
/// expansion, (Elements...).
class BuiltinTupleDecl final : public NominalTypeDecl {
TupleType *TupleSelfType = nullptr;

public:
BuiltinTupleDecl(Identifier Name, DeclContext *Parent);

SourceRange getSourceRange() const {
return SourceRange();
}

TupleType *getTupleSelfType() const;

// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() == DeclKind::BuiltinTuple;
}
static bool classof(const GenericTypeDecl *D) {
return D->getKind() == DeclKind::BuiltinTuple;
}
static bool classof(const NominalTypeDecl *D) {
return D->getKind() == DeclKind::BuiltinTuple;
}
static bool classof(const DeclContext *C) {
if (auto D = C->getAsDecl())
return classof(D);
return false;
}
static bool classof(const IterableDeclContext *C) {
auto NTD = dyn_cast<NominalTypeDecl>(C);
return NTD && classof(NTD);
}
};

/// AbstractStorageDecl - This is the common superclass for VarDecl and
/// SubscriptDecl, representing potentially settable memory locations.
class AbstractStorageDecl : public ValueDecl {
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/DeclNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ ABSTRACT_DECL(Value, Decl)
NOMINAL_TYPE_DECL(Struct, NominalTypeDecl)
NOMINAL_TYPE_DECL(Class, NominalTypeDecl)
NOMINAL_TYPE_DECL(Protocol, NominalTypeDecl)
DECL_RANGE(NominalType, Enum, Protocol)
NOMINAL_TYPE_DECL(BuiltinTuple, NominalTypeDecl)
DECL_RANGE(NominalType, Enum, BuiltinTuple)
GENERIC_VALUE_DECL(OpaqueType, GenericTypeDecl)
GENERIC_VALUE_DECL(TypeAlias, GenericTypeDecl)
DECL_RANGE(GenericType, Enum, TypeAlias)
Expand Down
2 changes: 0 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -5179,8 +5179,6 @@ ERROR(opened_bad_interface_type,none,
"@opened interface type %0 is not a type parameter", (Type))
ERROR(sil_function_input_label,PointsToFirstBadToken,
"SIL function types cannot have labeled inputs", ())
ERROR(sil_function_output_label,PointsToFirstBadToken,
"SIL function types cannot have labeled results", ())
ERROR(sil_non_coro_yields,PointsToFirstBadToken,
"non-coroutine SIL function types cannot have @yield results", ())
ERROR(sil_function_repeat_convention,PointsToFirstBadToken,
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ IDENTIFIER_WITH_NAME(PatternMatchVar, "$match")
IDENTIFIER(dynamicallyCall)
IDENTIFIER(dynamicMember)
IDENTIFIER(Element)
IDENTIFIER(Elements)
IDENTIFIER_(enclosingInstance)
IDENTIFIER(Encodable)
IDENTIFIER(encode)
Expand Down Expand Up @@ -313,6 +314,9 @@ IDENTIFIER_WITH_NAME(TypeWrapperProperty, "$_storage")
IDENTIFIER(storageKeyPath)
IDENTIFIER(memberwise)

// The singleton instance of TupleTypeDecl in the Builtin module
IDENTIFIER(TheTupleType)

#undef IDENTIFIER
#undef IDENTIFIER_
#undef IDENTIFIER_WITH_NAME
3 changes: 2 additions & 1 deletion include/swift/AST/TypeNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ ABSTRACT_TYPE(AnyGeneric, Type)
TYPE(Struct, NominalType)
TYPE(Class, NominalType)
TYPE(Protocol, NominalType)
TYPE_RANGE(Nominal, Enum, Protocol)
TYPE(BuiltinTuple, NominalType)
TYPE_RANGE(Nominal, Enum, BuiltinTuple)
ABSTRACT_TYPE(BoundGeneric, Type)
TYPE(BoundGenericClass, BoundGenericType)
TYPE(BoundGenericEnum, BoundGenericType)
Expand Down
32 changes: 27 additions & 5 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class ArgumentList;
class AssociatedTypeDecl;
class ASTContext;
enum BufferPointerTypeKind : unsigned;
class BuiltinTupleDecl;
class ClassDecl;
class ClangModuleLoader;
class DependentMemberType;
Expand Down Expand Up @@ -899,20 +900,24 @@ class alignas(1 << TypeAlignInBits) TypeBase
bool satisfiesClassConstraint();

/// Determine whether this type can be used as a base type for AST
/// name lookup, which is the case for nominal types, protocol compositions
/// and archetypes.
/// name lookup, which is the case for nominal types, existential types,
/// archetypes, and tuples.
///
/// Generally, the static vs instance and mutating vs nonmutating distinction
/// is handled elsewhere, so metatypes, lvalue types and inout types are not
/// allowed here.
///
/// Similarly, tuples formally have members, but this does not go through
/// name lookup.
/// Tuples have formal members to project elements by index or by label; these
/// are handled directly by Sema and do not go through name lookup.
///
/// Bona fide members on tuples are defined on extensions of
/// Builtin.TheTupleType.
bool mayHaveMembers() {
return (is<ArchetypeType>() ||
is<ModuleType>() ||
isExistentialType() ||
getAnyNominal());
getAnyNominal() ||
is<TupleType>());
}

/// Checks whether this type may potentially be callable. This returns true
Expand Down Expand Up @@ -5489,6 +5494,23 @@ BEGIN_CAN_TYPE_WRAPPER(ExistentialType, Type)
PROXY_CAN_TYPE_SIMPLE_GETTER(getConstraintType)
END_CAN_TYPE_WRAPPER(ExistentialType, Type)


/// BuiltinTupleType - A singleton nominal type which serves as the declared
/// interface type of Builtin.TheTupleType.
class BuiltinTupleType : public NominalType {
public:
// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::BuiltinTuple;
}

private:
friend class ASTContext;
BuiltinTupleType(BuiltinTupleDecl *TheDecl, const ASTContext &Ctx);
};
BEGIN_CAN_TYPE_WRAPPER(BuiltinTupleType, NominalType)
END_CAN_TYPE_WRAPPER(BuiltinTupleType, NominalType)

/// LValueType - An l-value is a handle to a physical object. The
/// type of that object uniquely determines the type of an l-value
/// for it.
Expand Down
46 changes: 46 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,12 @@ struct ASTContext::Implementation {

/// Memory allocation arena for the term rewriting system.
std::unique_ptr<rewriting::RewriteContext> TheRewriteContext;

/// The singleton Builtin.TheTupleType.
BuiltinTupleDecl *TheTupleTypeDecl = nullptr;

/// The declared interface type of Builtin.TheTupleType.
BuiltinTupleType *TheTupleType = nullptr;
};

ASTContext::Implementation::Implementation()
Expand Down Expand Up @@ -3173,6 +3179,14 @@ PackType *PackType::get(const ASTContext &C, ArrayRef<Type> elements) {
RecursiveTypeProperties properties;
bool isCanonical = true;
for (Type eltTy : elements) {
assert(!eltTy->isTypeParameter() ||
!eltTy->getRootGenericParam()->isTypeSequence() &&
"Pack type parameter outside of a pack expansion");
assert(!eltTy->is<SequenceArchetypeType>() &&
"Pack type archetype outside of a pack expansion");
assert(!eltTy->is<PackType>() &&
"Cannot have pack directly inside another pack");

properties |= eltTy->getRecursiveProperties();
if (!eltTy->isCanonical())
isCanonical = false;
Expand Down Expand Up @@ -4511,6 +4525,11 @@ Type ExistentialType::get(Type constraint) {
properties);
}

BuiltinTupleType::BuiltinTupleType(BuiltinTupleDecl *TheDecl,
const ASTContext &Ctx)
: NominalType(TypeKind::BuiltinTuple, &Ctx, TheDecl, Type(),
RecursiveTypeProperties()) { }

LValueType *LValueType::get(Type objectTy) {
assert(!objectTy->is<LValueType>() && !objectTy->is<InOutType>() &&
"cannot have 'inout' or @lvalue wrapped inside an @lvalue");
Expand Down Expand Up @@ -5914,3 +5933,30 @@ bool ASTContext::isASCIIString(StringRef s) const {
}
return true;
}

/// The special Builtin.TheTupleType, which parents tuple extensions and
/// conformances.
BuiltinTupleDecl *ASTContext::getBuiltinTupleDecl() {
auto &result = getImpl().TheTupleTypeDecl;

if (result)
return result;

result = new (*this) BuiltinTupleDecl(Id_TheTupleType,
TheBuiltinModule->getFiles()[0]);
result->setAccess(AccessLevel::Public);

return result;
}

/// The declared interface type of Builtin.TheTupleType.
BuiltinTupleType *ASTContext::getBuiltinTupleType() {
auto &result = getImpl().TheTupleType;

if (result)
return result;

result = new (*this) BuiltinTupleType(getBuiltinTupleDecl(), *this);

return result;
}
11 changes: 11 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,11 @@ namespace {
printCommonPost(CD);
}

void visitBuiltinTupleDecl(BuiltinTupleDecl *BTD) {
printCommon(BTD, "builtin_tuple_decl");
printCommonPost(BTD);
}

void visitPatternBindingDecl(PatternBindingDecl *PBD) {
printCommon(PBD, "pattern_binding_decl");

Expand Down Expand Up @@ -3800,6 +3805,12 @@ namespace {
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitBuiltinTupleType(BuiltinTupleType *T, StringRef label) {
printCommon(label, "builtin_tuple_type");
printField("decl", T->getDecl()->printRef());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitMetatypeType(MetatypeType *T, StringRef label) {
printCommon(label, "metatype_type");
if (T->hasRepresentation())
Expand Down
8 changes: 7 additions & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,7 +1330,8 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
case TypeKind::Struct:
case TypeKind::BoundGenericClass:
case TypeKind::BoundGenericEnum:
case TypeKind::BoundGenericStruct: {
case TypeKind::BoundGenericStruct:
case TypeKind::BuiltinTuple: {
GenericTypeDecl *Decl;
if (auto typeAlias = dyn_cast<TypeAliasType>(type.getPointer()))
Decl = typeAlias->getDecl();
Expand Down Expand Up @@ -2473,6 +2474,9 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
return;
}

if (nominal && isa<BuiltinTupleDecl>(nominal))
return appendOperator("BT");

appendContextOf(decl);

// Always use Clang names for imported Clang declarations, unless they don't
Expand Down Expand Up @@ -2554,6 +2558,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
case DeclKind::Struct:
appendOperator("V");
break;
case DeclKind::BuiltinTuple:
llvm_unreachable("Not implemented");
}
}

Expand Down
20 changes: 13 additions & 7 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3673,6 +3673,11 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
Options.BracketOptions.shouldCloseNominal(decl));
}
}

void PrintAST::visitBuiltinTupleDecl(BuiltinTupleDecl *decl) {
llvm_unreachable("Not implemented");
}

static bool isStructOrClassContext(DeclContext *dc) {
auto *nominal = dc->getSelfNominalTypeDecl();
if (nominal == nullptr)
Expand Down Expand Up @@ -5563,13 +5568,6 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
Printer.callPrintStructurePre(PrintStructureKind::TupleType);
SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::TupleType); };

// Single-element tuples can only appear in SIL mode.
if (T->getNumElements() == 1 &&
!T->getElement(0).hasName() &&
!T->getElementType(0)->is<PackExpansionType>()) {
Printer << "@tuple ";
}

Printer << "(";

auto Fields = T->getElements();
Expand All @@ -5587,6 +5585,10 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
if (TD.hasName()) {
Printer.printName(TD.getName(), PrintNameContext::TupleElement);
Printer << ": ";
} else if (e == 1 && !EltType->is<PackExpansionType>()) {
// Unlabeled one-element tuples always print the empty label to
// distinguish them from the older syntax for ParenType.
Printer << "_: ";
}
visit(EltType);
}
Expand Down Expand Up @@ -6334,6 +6336,10 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}
}

void visitBuiltinTupleType(BuiltinTupleType *T) {
printQualifiedType(T);
}

void visitLValueType(LValueType *T) {
Printer << "@lvalue ";
visit(T->getObjectType());
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ASTScopeCreation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ class NodeAdder
VISIT_AND_CREATE_WHOLE_PORTION(OpaqueTypeDecl, OpaqueTypeScope)
#undef VISIT_AND_CREATE_WHOLE_PORTION

ASTScopeImpl *visitBuiltinTupleDecl(BuiltinTupleDecl *btd, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
llvm_unreachable("BuiltinTupleDecl should never appear in a source file");
}

// This declaration is handled from
// addChildrenForParsedAccessors
ASTScopeImpl *visitAccessorDecl(AccessorDecl *ad, ASTScopeImpl *p,
Expand Down
Loading