Skip to content

Commit 7a3e3ae

Browse files
authored
Merge pull request #70353 from DougGregor/error-union-type
[Typed throws] Add an ErrorUnion type to the type system
2 parents bf102d2 + b080b5f commit 7a3e3ae

File tree

15 files changed

+275
-16
lines changed

15 files changed

+275
-16
lines changed

include/swift/AST/Type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ class CanType : public Type {
521521
return isAnyExistentialTypeImpl(*this);
522522
}
523523

524+
/// Is this type the error existential, 'any Error'?
525+
bool isErrorExistentialType() const;
526+
524527
/// Break an existential down into a set of constraints.
525528
ExistentialLayout getExistentialLayout();
526529

include/swift/AST/TypeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ TYPE(Pack, Type)
188188
TYPE(PackExpansion, Type)
189189
TYPE(PackElement, Type)
190190
UNCHECKED_TYPE(TypeVariable, Type)
191+
UNCHECKED_TYPE(ErrorUnion, Type)
191192
ABSTRACT_SUGARED_TYPE(Sugar, Type)
192193
SUGARED_TYPE(Paren, SugarType)
193194
SUGARED_TYPE(TypeAlias, SugarType)

include/swift/AST/Types.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,11 @@ class alignas(1 << TypeAlignInBits) TypeBase
439439
ID : 29
440440
);
441441

442+
SWIFT_INLINE_BITFIELD_FULL(ErrorUnionType, TypeBase, 32,
443+
// Number of terms in the union.
444+
NumTerms : 32
445+
);
446+
442447
SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1,
443448
ExtInfoBits : NumSILExtInfoBits,
444449
HasClangTypeInfo : 1,
@@ -875,6 +880,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
875880
/// an existential metatype.
876881
bool isAnyExistentialType();
877882

883+
/// isErrorExistentialType - Determines whether this type is 'any Error'.
884+
bool isErrorExistentialType();
885+
878886
/// isObjCExistentialType - Determines whether this type is an
879887
/// class-bounded existential type whose required conformances are
880888
/// all @objc. Such types are compatible with ObjC.
@@ -6926,6 +6934,43 @@ TypeVariableType : public TypeBase {
69266934
};
69276935
DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type)
69286936

6937+
/// Represents the union of two or more
6938+
class ErrorUnionType final
6939+
: public TypeBase,
6940+
public llvm::FoldingSetNode,
6941+
private llvm::TrailingObjects<ErrorUnionType, Type> {
6942+
friend TrailingObjects;
6943+
6944+
ErrorUnionType(const ASTContext *ctx, ArrayRef<Type> terms,
6945+
RecursiveTypeProperties properties)
6946+
: TypeBase(TypeKind::ErrorUnion, /*Context=*/ctx, properties) {
6947+
Bits.ErrorUnionType.NumTerms = terms.size();
6948+
std::uninitialized_copy(terms.begin(), terms.end(),
6949+
getTrailingObjects<Type>());
6950+
}
6951+
6952+
public:
6953+
/// Form a new error union type from a set of terms.
6954+
static Type get(const ASTContext &ctx, ArrayRef<Type> terms);
6955+
6956+
ArrayRef<Type> getTerms() const {
6957+
return { getTrailingObjects<Type>(), Bits.ErrorUnionType.NumTerms };
6958+
};
6959+
6960+
// Support for FoldingSet.
6961+
void Profile(llvm::FoldingSetNodeID &id) const {
6962+
Profile(id, getTerms());
6963+
}
6964+
6965+
static void Profile(llvm::FoldingSetNodeID &id, ArrayRef<Type> terms);
6966+
6967+
// Implement isa/cast/dyncast/etc.
6968+
static bool classof(const TypeBase *T) {
6969+
return T->getKind() == TypeKind::ErrorUnion;
6970+
}
6971+
};
6972+
DEFINE_EMPTY_CAN_TYPE_WRAPPER(ErrorUnionType, Type)
6973+
69296974
/// PlaceholderType - This represents a placeholder type for a type variable
69306975
/// or dependent member type that cannot be resolved to a concrete type
69316976
/// because the expression is ambiguous. This type is only used by the
@@ -7283,6 +7328,10 @@ inline bool CanType::isAnyExistentialTypeImpl(CanType type) {
72837328
return isExistentialTypeImpl(type) || isa<ExistentialMetatypeType>(type);
72847329
}
72857330

7331+
inline bool TypeBase::isErrorExistentialType() {
7332+
return getCanonicalType().isErrorExistentialType();
7333+
}
7334+
72867335
inline bool TypeBase::isClassExistentialType() {
72877336
CanType T = getCanonicalType();
72887337
if (auto pt = dyn_cast<ProtocolType>(T))

lib/AST/ASTContext.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ struct ASTContext::Implementation {
458458
llvm::DenseMap<Type, InOutType*> InOutTypes;
459459
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
460460
DependentMemberTypes;
461+
llvm::FoldingSet<ErrorUnionType> ErrorUnionTypes;
461462
llvm::DenseMap<void *, PlaceholderType *> PlaceholderTypes;
462463
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
463464
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
@@ -3014,6 +3015,50 @@ Type ErrorType::get(Type originalType) {
30143015
return entry = new (mem) ErrorType(ctx, originalType, properties);
30153016
}
30163017

3018+
void ErrorUnionType::Profile(llvm::FoldingSetNodeID &id, ArrayRef<Type> terms) {
3019+
id.AddInteger(terms.size());
3020+
for (auto term : terms) {
3021+
id.AddPointer(term.getPointer());
3022+
}
3023+
}
3024+
3025+
Type ErrorUnionType::get(const ASTContext &ctx, ArrayRef<Type> terms) {
3026+
// Peep-hole the simple cases. Error union types are always synthesized by
3027+
// the type checker and never written explicitly, so we have no use for
3028+
// extra type sugar around them.
3029+
switch (terms.size()) {
3030+
case 0: return ctx.getNeverType();
3031+
case 1: return terms[0];
3032+
default: break;
3033+
}
3034+
3035+
// Determine canonicality and recursive type properties.
3036+
bool isCanonical = true;
3037+
RecursiveTypeProperties properties;
3038+
for (Type term : terms) {
3039+
if (!term->isCanonical())
3040+
isCanonical = false;
3041+
properties |= term->getRecursiveProperties();
3042+
}
3043+
3044+
// Check whether we've seen this type before.
3045+
auto arena = getArena(properties);
3046+
void *insertPos = nullptr;
3047+
llvm::FoldingSetNodeID id;
3048+
ErrorUnionType::Profile(id, terms);
3049+
if (auto knownTy = ctx.getImpl().getArena(arena).ErrorUnionTypes
3050+
.FindNodeOrInsertPos(id, insertPos))
3051+
return knownTy;
3052+
3053+
// Use trailing objects for term storage.
3054+
auto size = totalSizeToAlloc<Type>(terms.size());
3055+
auto mem = ctx.Allocate(size, alignof(ErrorUnionType), arena);
3056+
auto unionTy = new (mem) ErrorUnionType(isCanonical ? &ctx : nullptr,
3057+
terms, properties);
3058+
ctx.getImpl().getArena(arena).ErrorUnionTypes.InsertNode(unionTy, insertPos);
3059+
return unionTy;
3060+
}
3061+
30173062
Type PlaceholderType::get(ASTContext &ctx, Originator originator) {
30183063
assert(originator);
30193064

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4435,6 +4435,13 @@ namespace {
44354435
printFoot();
44364436
}
44374437

4438+
void visitErrorUnionType(ErrorUnionType *T, StringRef label) {
4439+
printCommon("error_union_type", label);
4440+
for (auto term : T->getTerms())
4441+
printRec(term);
4442+
printFoot();
4443+
}
4444+
44384445
#undef TRIVIAL_TYPE_PRINTER
44394446
};
44404447

lib/AST/ASTMangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,9 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
11791179
case TypeKind::TypeVariable:
11801180
llvm_unreachable("mangling type variable");
11811181

1182+
case TypeKind::ErrorUnion:
1183+
llvm_unreachable("Error unions should not persist to mangling");
1184+
11821185
case TypeKind::Module:
11831186
llvm_unreachable("Cannot mangle module type yet");
11841187

lib/AST/ASTPrinter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6327,6 +6327,17 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
63276327
Printer << "_";
63286328
}
63296329

6330+
void visitErrorUnionType(ErrorUnionType *T) {
6331+
Printer << "error_union(";
6332+
interleave(T->getTerms(),
6333+
[&](Type type) {
6334+
visit(type);
6335+
}, [&]{
6336+
Printer << ", ";
6337+
});
6338+
Printer << ")";
6339+
}
6340+
63306341
void visitPlaceholderType(PlaceholderType *T) {
63316342
if (Options.PrintTypesForDebugging) {
63326343
Printer << "<<placeholder for ";

lib/AST/Type.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig,
314314
case TypeKind::PackElement:
315315
case TypeKind::SILPack:
316316
case TypeKind::BuiltinTuple:
317+
case TypeKind::ErrorUnion:
317318
#define REF_STORAGE(Name, ...) \
318319
case TypeKind::Name##Storage:
319320
#include "swift/AST/ReferenceStorage.def"
@@ -1875,6 +1876,15 @@ CanType TypeBase::computeCanonicalType() {
18751876
Result = BoundGenericType::get(BGT->getDecl(), parentTy, CanGenericArgs);
18761877
break;
18771878
}
1879+
case TypeKind::ErrorUnion: {
1880+
SmallVector<Type, 2> newTerms;
1881+
for (auto term : cast<ErrorUnionType>(this)->getTerms()) {
1882+
newTerms.push_back(term->getCanonicalType());
1883+
}
1884+
ASTContext &ctx = newTerms[0]->getASTContext();
1885+
Result = ErrorUnionType::get(ctx, newTerms).getPointer();
1886+
break;
1887+
}
18781888
}
18791889

18801890
// Cache the canonical type for future queries.
@@ -4709,6 +4719,48 @@ case TypeKind::Id:
47094719
return ParenType::get(Ptr->getASTContext(), underlying);
47104720
}
47114721

4722+
case TypeKind::ErrorUnion: {
4723+
auto errorUnion = cast<ErrorUnionType>(base);
4724+
bool anyChanged = false;
4725+
SmallVector<Type, 4> terms;
4726+
unsigned Index = 0;
4727+
for (Type term : errorUnion->getTerms()) {
4728+
Type transformedTerm =
4729+
term.transformWithPosition(TypePosition::Invariant, fn);
4730+
if (!transformedTerm)
4731+
return Type();
4732+
4733+
// If nothing has changed, just keep going.
4734+
if (!anyChanged &&
4735+
transformedTerm.getPointer() == term.getPointer()) {
4736+
++Index;
4737+
continue;
4738+
}
4739+
4740+
// If this is the first change we've seen, copy all of the previous
4741+
// elements.
4742+
if (!anyChanged) {
4743+
// Copy all of the previous elements.
4744+
terms.append(errorUnion->getTerms().begin(),
4745+
errorUnion->getTerms().begin() + Index);
4746+
anyChanged = true;
4747+
}
4748+
4749+
// If the transformed type is a pack, immediately expand it.
4750+
if (auto termPack = getTransformedPack(transformedTerm)) {
4751+
auto termElements = termPack->getElementTypes();
4752+
terms.append(termElements.begin(), termElements.end());
4753+
} else {
4754+
terms.push_back(transformedTerm);
4755+
}
4756+
}
4757+
4758+
if (!anyChanged)
4759+
return *this;
4760+
4761+
return ErrorUnionType::get(Ptr->getASTContext(), terms);
4762+
}
4763+
47124764
case TypeKind::Pack: {
47134765
auto pack = cast<PackType>(base);
47144766
bool anyChanged = false;
@@ -5407,6 +5459,7 @@ ReferenceCounting TypeBase::getReferenceCounting() {
54075459
case TypeKind::PackElement:
54085460
case TypeKind::SILPack:
54095461
case TypeKind::BuiltinTuple:
5462+
case TypeKind::ErrorUnion:
54105463
#define REF_STORAGE(Name, ...) \
54115464
case TypeKind::Name##Storage:
54125465
#include "swift/AST/ReferenceStorage.def"
@@ -5640,6 +5693,13 @@ bool TypeBase::hasSimpleTypeRepr() const {
56405693
}
56415694
}
56425695

5696+
bool CanType::isErrorExistentialType() const {
5697+
if (!isExistentialTypeImpl(*this))
5698+
return false;
5699+
5700+
return const_cast<CanType *>(this)->getExistentialLayout().isErrorExistential();
5701+
}
5702+
56435703
bool CanType::isForeignReferenceType() {
56445704
if (auto *classDecl = getPointer()->lookThroughAllOptionalTypes()->getClassOrBoundGenericClass())
56455705
return classDecl->isForeignReferenceType();

lib/AST/TypeWalker.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ class Traversal : public TypeVisitor<Traversal, bool>
250250

251251
bool visitTypeVariableType(TypeVariableType *ty) { return false; }
252252

253+
bool visitErrorUnionType(ErrorUnionType *ty) {
254+
for (auto term : ty->getTerms())
255+
if (doIt(term))
256+
return true;
257+
return false;
258+
}
259+
253260
bool visitSILBlockStorageType(SILBlockStorageType *ty) {
254261
return doIt(ty->getCaptureType());
255262
}

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,6 +1974,7 @@ class GetSendableType :
19741974
NEVER_VISIT(PackExpansionType)
19751975
NEVER_VISIT(PackElementType)
19761976
NEVER_VISIT(TypeVariableType)
1977+
NEVER_VISIT(ErrorUnionType)
19771978

19781979
VISIT(SugarType, recurse)
19791980

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
18611861
case TypeKind::Unresolved:
18621862
case TypeKind::LValue:
18631863
case TypeKind::TypeVariable:
1864+
case TypeKind::ErrorUnion:
18641865
case TypeKind::Placeholder:
18651866
case TypeKind::Module:
18661867
case TypeKind::SILBlockStorage:

lib/Sema/CSSimplify.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7458,6 +7458,9 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
74587458

74597459
return matchTypes(pack1, pack2, kind, subflags, locator);
74607460
}
7461+
7462+
case TypeKind::ErrorUnion:
7463+
break;
74617464
}
74627465
}
74637466

@@ -8118,6 +8121,7 @@ ConstraintSystem::simplifyConstructionConstraint(
81188121
case TypeKind::ParameterizedProtocol:
81198122
case TypeKind::Protocol:
81208123
case TypeKind::Existential:
8124+
case TypeKind::ErrorUnion:
81218125
// Break out to handle the actual construction below.
81228126
break;
81238127

0 commit comments

Comments
 (0)