Skip to content

Commit 601c968

Browse files
committed
Make sure ErrorTypes containing type variables are marked as such. (#7963)
In some cases, the type checker will produce error types with the "original type" intact for recovery purposes. Like other types, when the original type contains a type variable, the ErrorType instance will be allocated in the "temporary" memory arena associated with the active constraint solver, because there's no way that particular error will come up again once the constraint system containing that type variable has been destroyed. However, we weren't propagating that "contains a type variable" information to the newly-created ErrorType, which meant that any type /containing/ that ErrorType would be allocated in the "permanent" arena. In practice, this would always be a DependentMemberType; not too many types are created without looking at their base types at all. The arena containing the ErrorType would then be deallocated, and its memory reused later on for a /different/ type. If we ever tried to make a DependentMemberType whose base was this new type, we'd find the old DependentMemberType instance in our cache and return that. The result was that we'd have a DependentMemberType whose "HasError" bit was set even though the base type was not an error type, and which was considered canonical whether or not the base type was. This would then either hit an assertion later on or result in nonsensical errors like "'C.Iterator' is not the same type as 'C.Iterator'". Because the reused address always referred to a valid type, none of the usual dynamic analysis tools could catch the problem. It really comes down to using a pointer address as a key in a map---but even without that, we were allocating types in the permanent arena that really should be temporary, which is a waste of memory. Likely fixes rdar://problem/30382791, a nondeterministic failure we've been seeing for weeks on the bots and on developer machines.
1 parent ce937d9 commit 601c968

File tree

3 files changed

+14
-7
lines changed

3 files changed

+14
-7
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -992,8 +992,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
992992
class ErrorType : public TypeBase {
993993
friend class ASTContext;
994994
// The Error type is always canonical.
995-
ErrorType(ASTContext &C, Type originalType)
996-
: TypeBase(TypeKind::Error, &C, RecursiveTypeProperties::HasError) {
995+
ErrorType(ASTContext &C, Type originalType,
996+
RecursiveTypeProperties properties)
997+
: TypeBase(TypeKind::Error, &C, properties) {
998+
assert(properties.hasError());
997999
if (originalType) {
9981000
ErrorTypeBits.HasOriginalType = true;
9991001
*reinterpret_cast<Type *>(this + 1) = originalType;

lib/AST/ASTContext.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts,
402402
SwiftShimsModuleName(getIdentifier(SWIFT_SHIMS_NAME)),
403403
TypeCheckerDebug(new StderrTypeCheckerDebugConsumer()),
404404
TheErrorType(
405-
new (*this, AllocationArena::Permanent) ErrorType(*this, Type())),
405+
new (*this, AllocationArena::Permanent)
406+
ErrorType(*this, Type(), RecursiveTypeProperties::HasError)),
406407
TheUnresolvedType(new (*this, AllocationArena::Permanent)
407408
UnresolvedType(*this)),
408409
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
@@ -2435,16 +2436,19 @@ Type ErrorType::get(const ASTContext &C) { return C.TheErrorType; }
24352436
Type ErrorType::get(Type originalType) {
24362437
assert(originalType);
24372438

2438-
auto properties = originalType->getRecursiveProperties();
2439-
auto arena = getArena(properties);
2439+
auto originalProperties = originalType->getRecursiveProperties();
2440+
auto arena = getArena(originalProperties);
24402441

24412442
auto &ctx = originalType->getASTContext();
24422443
auto &entry = ctx.Impl.getArena(arena).ErrorTypesWithOriginal[originalType];
24432444
if (entry) return entry;
24442445

24452446
void *mem = ctx.Allocate(sizeof(ErrorType) + sizeof(Type),
24462447
alignof(ErrorType), arena);
2447-
return entry = new (mem) ErrorType(ctx, originalType);
2448+
RecursiveTypeProperties properties = RecursiveTypeProperties::HasError;
2449+
if (originalProperties.hasTypeVariable())
2450+
properties |= RecursiveTypeProperties::HasTypeVariable;
2451+
return entry = new (mem) ErrorType(ctx, originalType, properties);
24482452
}
24492453

24502454
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,8 @@ TypeBase::getTypeVariables(SmallVectorImpl<TypeVariableType *> &typeVariables) {
470470

471471
return false;
472472
});
473-
assert(!typeVariables.empty() && "Did not find type variables!");
473+
assert((!typeVariables.empty() || hasError()) &&
474+
"Did not find type variables!");
474475
}
475476
}
476477

0 commit comments

Comments
 (0)