Skip to content

Make sure ErrorTypes containing type variables are marked as such. #7963

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 1 commit into from
Mar 7, 2017

Conversation

jrose-apple
Copy link
Contributor

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.

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.
@jrose-apple
Copy link
Contributor Author

@swift-ci Please test

@slavapestov
Copy link
Contributor

Should this go into 3.1?

@jrose-apple
Copy link
Contributor Author

Maybe. We haven't being seeing failures on 3.1 because of it, so it's unclear whether the potential risk is worth the change. There's an Apple-internal thread discussing it.

@jrose-apple jrose-apple merged commit e58d02b into swiftlang:master Mar 7, 2017
@jrose-apple jrose-apple deleted the to-err-is-human branch March 7, 2017 23:18
jrose-apple added a commit to jrose-apple/swift that referenced this pull request Mar 7, 2017
…wiftlang#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants