-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[AST] More JSON AST dump improvements. #80498
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
Conversation
- For type USRs, use `mapTypeOutOfContext()` to replace primary archetypes with type parameters. If the type contains local archetypes, replace them with their existential upper bounds. - For inheritance of types, print the derived semantic information instead of the inheritance list as it is written. - Dump conformance requirements as protocol decl USRs instead of type USRs, since the latter involves an existential conversion that loses suppressed protocols. - Fix a small bug in conformance dumping where the `MemberLoading` field wasn't propagated to the nested printer, which caused protocols to be dumped as simple names instead of USRs.
The earlier changes to ASTDumper only printed information like retroactiveness and safety when printing the `InheritedEntries` of a decl. Now that we print the actual resolved semantic information instead of the inheritance list as-written, we need to surface these values via the `ProtocolConformance`s.
@slavapestov Thanks for all the pointers for these improvements. Would you mind reviewing this change please? |
lib/AST/ASTDumper.cpp
Outdated
// decl instead of the type. The type USR for a protocol is based on | ||
// the equivalent expanded existential, which drops suppressed | ||
// protocols. | ||
if (requirement.getKind() == RequirementKind::Conformance) { |
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.
Maybe switch over the 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.
Done, and used a fallthrough instead of a separate else-branch to handle the non-parsable case, reducing some duplication.
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.
Realized I had missed an opportunity to turn the entire larger conditional into part of the same switch
—printing the protocol name instead of the type yields the same result as printing the type in non-parsable mode, so we don't need to treat isParsable()
as a special case at all here.
lib/AST/ASTDumper.cpp
Outdated
Label::always("conformances")); | ||
|
||
if (auto CD = dyn_cast<ClassDecl>(DC); CD && CD->hasSuperclass()) { | ||
printReferencedDeclField(CD->getSuperclassDecl(), |
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.
More generally there is a superclass type getSuperclass()
which is not just a decl. Eg,
class G<T> {}
class B: G<Int> {}
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.
Switched to getSuperclass()
for classes.
For a class-constrained ProtocolDecl
, it looks like I don't have a Type
-returning getSuperclass()
there. But the full type is accessible in the requirement_signature
that's being dumped; in your example there's a subclass_of
requirement that contains the mangled G<Int>
. So that'll just have to be a different access path for clients.
[&](Label label) { | ||
printHead("opaque_to_existential_mapping", FieldLabelColor, label); | ||
for (const auto OTD : opaqueDecls) { | ||
Type interfaceType = OTD->getDeclaredInterfaceType(); |
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.
calling getDeclaredInterfaceType() on OpaqueTypeDecl should produce an assertion failure; are you sure you have test coverage for 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.
Hmm, it seems to be working? When I dump an OpaqueTypeDecl
in the context of the declaring function, declared_interface_type
is one of the fields we dump (line ~2158). For this snippet:
func f() -> some Sequence { [] }
I get
"opaque_result_decl": {
"_kind": "opaque_type",
...
"declared_interface_type": "$s3lib1fQryFQOyQo_D",
and the top-level mapping is
"opaque_to_existential_mapping": {
"_kind": "opaque_to_existential_mapping",
"$s3lib1fQryFQOyQo_D": "$sST_pD"
}
There are tests exercising opaque types in the omnibus Frontend/ast-dump-json-no-crash.swift
test.
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 used getDeclaredInterfaceType()
because it seemed to be the most likely match for what would appear in expressions that use the type, but I'm also happy to switch it to something else more appropriate.
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 see, I missed that we set it in OpaqueResultTypeRequest::evaluate(). My apologies.
However, my original concern is that opaque return type can appear in a nested position, and we might have more than one opaque return type, eg:
func f() -> (some Any, some Any)? {}
Indeed, it appears that the declared interface type of the opaque result declaration is the entire return type of the function in this case, (some Any, some Any)?
, so your castTo<OpaqueTypeArchetypeType>()
will fail. You probably want to walk the declared interface type to collect all opaque archetypes that it contains.
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.
Ah, right. Updated this to use transformRec
to replace any OpaqueTypeArchetypeType
s with their getExistentialType()
, and added a handful of tests that cover different structural situations.
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.
Thanks!
lib/AST/ASTDumper.cpp
Outdated
// decl instead of the type. The type USR for a protocol is based on | ||
// the equivalent expanded existential, which drops suppressed | ||
// protocols. | ||
if (requirement.getKind() == RequirementKind::Conformance) { |
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, and used a fallthrough instead of a separate else-branch to handle the non-parsable case, reducing some duplication.
[&](Label label) { | ||
printHead("opaque_to_existential_mapping", FieldLabelColor, label); | ||
for (const auto OTD : opaqueDecls) { | ||
Type interfaceType = OTD->getDeclaredInterfaceType(); |
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.
Hmm, it seems to be working? When I dump an OpaqueTypeDecl
in the context of the declaring function, declared_interface_type
is one of the fields we dump (line ~2158). For this snippet:
func f() -> some Sequence { [] }
I get
"opaque_result_decl": {
"_kind": "opaque_type",
...
"declared_interface_type": "$s3lib1fQryFQOyQo_D",
and the top-level mapping is
"opaque_to_existential_mapping": {
"_kind": "opaque_to_existential_mapping",
"$s3lib1fQryFQOyQo_D": "$sST_pD"
}
There are tests exercising opaque types in the omnibus Frontend/ast-dump-json-no-crash.swift
test.
lib/AST/ASTDumper.cpp
Outdated
Label::always("conformances")); | ||
|
||
if (auto CD = dyn_cast<ClassDecl>(DC); CD && CD->hasSuperclass()) { | ||
printReferencedDeclField(CD->getSuperclassDecl(), |
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.
Switched to getSuperclass()
for classes.
For a class-constrained ProtocolDecl
, it looks like I don't have a Type
-returning getSuperclass()
there. But the full type is accessible in the requirement_signature
that's being dumped; in your example there's a subclass_of
requirement that contains the mangled G<Int>
. So that'll just have to be a different access path for clients.
c2a4ec0
to
1ad6596
Compare
@slavapestov Any other changes you'd like to see here? |
@swift-ci please test |
@swift-ci please smoke test |
@swift-ci please smoke test |
@swift-ci please smoke test Linux platform |
[AST] More JSON AST dump improvements.
These improvements came about through great back-and-forth in this forum thread. They are summarized as follows:
mapTypeOutOfContext()
to replace any primary archetypes with type parameters when computing a type USR.