Skip to content

Commit e58d02b

Browse files
authored
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 bd7acf1 commit e58d02b

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
@@ -990,8 +990,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
990990
class ErrorType : public TypeBase {
991991
friend class ASTContext;
992992
// The Error type is always canonical.
993-
ErrorType(ASTContext &C, Type originalType)
994-
: TypeBase(TypeKind::Error, &C, RecursiveTypeProperties::HasError) {
993+
ErrorType(ASTContext &C, Type originalType,
994+
RecursiveTypeProperties properties)
995+
: TypeBase(TypeKind::Error, &C, properties) {
996+
assert(properties.hasError());
995997
if (originalType) {
996998
ErrorTypeBits.HasOriginalType = true;
997999
*reinterpret_cast<Type *>(this + 1) = originalType;

lib/AST/ASTContext.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts,
404404
SwiftShimsModuleName(getIdentifier(SWIFT_SHIMS_NAME)),
405405
TypeCheckerDebug(new StderrTypeCheckerDebugConsumer()),
406406
TheErrorType(
407-
new (*this, AllocationArena::Permanent) ErrorType(*this, Type())),
407+
new (*this, AllocationArena::Permanent)
408+
ErrorType(*this, Type(), RecursiveTypeProperties::HasError)),
408409
TheUnresolvedType(new (*this, AllocationArena::Permanent)
409410
UnresolvedType(*this)),
410411
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
@@ -2424,16 +2425,19 @@ Type ErrorType::get(const ASTContext &C) { return C.TheErrorType; }
24242425
Type ErrorType::get(Type originalType) {
24252426
assert(originalType);
24262427

2427-
auto properties = originalType->getRecursiveProperties();
2428-
auto arena = getArena(properties);
2428+
auto originalProperties = originalType->getRecursiveProperties();
2429+
auto arena = getArena(originalProperties);
24292430

24302431
auto &ctx = originalType->getASTContext();
24312432
auto &entry = ctx.Impl.getArena(arena).ErrorTypesWithOriginal[originalType];
24322433
if (entry) return entry;
24332434

24342435
void *mem = ctx.Allocate(sizeof(ErrorType) + sizeof(Type),
24352436
alignof(ErrorType), arena);
2436-
return entry = new (mem) ErrorType(ctx, originalType);
2437+
RecursiveTypeProperties properties = RecursiveTypeProperties::HasError;
2438+
if (originalProperties.hasTypeVariable())
2439+
properties |= RecursiveTypeProperties::HasTypeVariable;
2440+
return entry = new (mem) ErrorType(ctx, originalType, properties);
24372441
}
24382442

24392443
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,

lib/AST/Type.cpp

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

385385
return false;
386386
});
387-
assert(!typeVariables.empty() && "Did not find type variables!");
387+
assert((!typeVariables.empty() || hasError()) &&
388+
"Did not find type variables!");
388389
}
389390
}
390391

0 commit comments

Comments
 (0)