-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[GSB] Improve handling of layout constraints #8253
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
[GSB] Improve handling of layout constraints #8253
Conversation
@swift-ci please smoke test |
@DougGregor Please have a look. |
lib/AST/ASTContext.cpp
Outdated
case LayoutConstraintKind::UnknownLayout: | ||
return LayoutConstraint( | ||
&LayoutConstraintInfo::UnknownLayoutConstraintInfo); | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the default, right? It'll end up suppressing warnings that we'd rather see when the switch isn't covering all of the cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
lib/AST/LayoutConstraint.cpp
Outdated
@@ -106,6 +110,24 @@ bool LayoutConstraintInfo::isNativeRefCountedObject(LayoutConstraintKind Kind) { | |||
return Kind == LayoutConstraintKind::NativeRefCountedObject; | |||
} | |||
|
|||
bool LayoutConstraintInfo::isClass(LayoutConstraintKind Kind) { | |||
return Kind == LayoutConstraintKind::Class; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this return true when kind == LayoutConstraintKind::NativeClass
? It "is" a class constraint, after all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this I introduced isAnyClass
. This predicate is intended to be used to check the exact kind.
lib/AST/LayoutConstraint.cpp
Outdated
} | ||
|
||
if ((*this)->isClass() && Other->isNativeClass()) { | ||
// Prefer a more concrete _NativeClass conttraint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a return Other;
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. I forgot it while copy&pasting the code.
lib/AST/LayoutConstraint.cpp
Outdated
|
||
if (Other->isClass() && (*this)->isNativeClass()) { | ||
// Prefer a more concrete _NativeClass conttraint. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a return *this
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
lib/AST/LayoutConstraint.cpp
Outdated
// Prefer a more concrete _NativeClass conttraint. | ||
} | ||
|
||
return LayoutConstraint::getUnknownLayout(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might it be better to have a 2-D table to describe the results? It's pretty hard to make sure that this long sequence of if
statements does the right thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DougGregor Please have a look at the update that I pushed. It uses a 2-D table, but I'm not quite happy with it. The initialization of the table looked pretty ugly. I had to use macros to shorten it. And I'm still not quite convinced it is really easier. WDYT?
lib/AST/LayoutConstraint.cpp
Outdated
|
||
bool LayoutConstraintInfo::isRefCounted(LayoutConstraintKind Kind) { | ||
return Kind == LayoutConstraintKind::RefCountedObject || | ||
Kind == LayoutConstraintKind::Class; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this also check for Kind == LayoutConstraintKind::NativeRefCountedObject
and Kind == LayoutConstraintKind::NativeClass
?
@@ -100,6 +102,7 @@ class C2 : C, P4 { } | |||
// CHECK: superclassConformance3 | |||
// CHECK: Requirements: | |||
// CHECK-NEXT: τ_0_0 : C2 [τ_0_0: Explicit @ {{.*}}:46] | |||
// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:46 -> Superclass] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay.
lib/AST/LayoutConstraint.cpp
Outdated
if (!initializedMergeTable) { | ||
// initialize the merge table once. | ||
initializedMergeTable = true; | ||
MERGE_TO(TrivialOfAtMostSize, Trivial, TrivialOfAtMostSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to use initializer list nesting { { ... }, { ... }, ... }
to avoid the imperative initialization and initializedMergeTable
bit. It'll also make sure that cases never get skipped, e.g., the missing merge(TrivialOfExactSize, TrivialOfExactSize)
case.
lib/AST/LayoutConstraint.cpp
Outdated
return LayoutConstraint::getUnknownLayout(); | ||
|
||
if ((*this)->getKind() == mergeKind) | ||
return *this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the result is one of the sized cases (TrivialOfExactSize
or TrivialOfAtMostSize
), you'll need to do some checking of the size to determine the proper result. The lookup table doesn't always suffice in these cases... for example, the merge(TrivialOfExactSize, TrivialOfExactSize)
case might produce TrivialOfExactSize
(if the sizes are the same) and might produce TrivialOfAtMostSize
or UnknownLayout
(if the sizes are different; we can choose which semantics we prefer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -170,6 +196,18 @@ class LayoutConstraintInfo : public llvm::FoldingSetNode { | |||
|
|||
static bool isNativeRefCountedObject(LayoutConstraintKind Kind); | |||
|
|||
static bool isAnyRefCountedObject(LayoutConstraintKind Kind); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the reason for these static
versions. They just seem to bloat the API.
include/swift/AST/LayoutConstraint.h
Outdated
return isNativeClass(Kind); | ||
} | ||
|
||
bool isAnyClass() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still find it confusing that we have isClass()
and isAnyClass()
. If someone wants the isClass()
behavior, they can just check the kind exactly. Are you opposed to giving isClass
() the behavior that isAnyClass()
has (i.e., so isClass()
answers the question "is it some kind of class?") and removing isAnyClass()
entirely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
include/swift/AST/LayoutConstraint.h
Outdated
return isAnyClass(Kind); | ||
} | ||
|
||
bool isRefCounted() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These behavior the way I'd expect: isRefCounted()
is true
for any layout kind that ensures reference-counting.
@DougGregor I pushed the updated version. This one initializes all entries in the merge table. Does it look more reliable? |
lib/AST/LayoutConstraint.cpp
Outdated
// If we got here, it means that the Self == Other check above has failed. | ||
// And that could only happen if either the kinds are different or | ||
// size/alignment parameters are different. | ||
return LayoutConstraint::getUnknownLayout(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, it probably doesn't matter, but one could merge exact-size(N) and at-most-size(N) into exact-size(N).
- Add support for _Class and _NativeClass layout constraints, which are supposed to represent T: Superclass and P: class constraints in the future. - Use the re-factoring to also reduce the number of dynamic allocations when creating layout constraints. Simple non-parametrized layout constraints are now represented as statically allocated singletons (static members of LayoutConstraintInfo).
This PR addresses TODOs from swiftlang#8241. - It supports merging for layout constraints, e.g., if both a _Trivial constraint and a _Trivial(64) constraint appear on a type parameter, we keep only _Trivial(64) as a more specific layout constraint. We do a similar thing for ref-counted/native-ref-counted. The overall idea is to keep the more specific of two compatible layout constraints. - The presence of a superclass constraint implies a layout constraint, e.g., a superclass constraint implies _Class or _NativeClass
80d2ac7
to
e1403c6
Compare
@swift-ci please smoke test |
Thank you! |
This PR addresses TODOs from #8241.