-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Add CustomDebugDescription conformance to AnyKeyPath #60133
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
Add CustomDebugDescription conformance to AnyKeyPath #60133
Conversation
SE pull request: swiftlang/swift-evolution#1724 @jckarter tagging you here per the "how to contribute" doc in the swift compiler repo, as I assume you'll want to review this at some point |
@swift-ci Please 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.
Welcome! This looks pretty good! I just have a few nitpicks to hopefully make things a little easier to read. In general, the Swift project uses 2 space indentation instead of 4 both in the runtime and stdlib.
stdlib/public/core/KeyPath.swift
Outdated
} | ||
return _openExistential(base, do: project) | ||
} | ||
func addChain() { |
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 think you can replace this with a single description.append(".")
at the beginning of the loop.
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.
My first version of this function was implemented like that, but unfortunately I don't think it works. Optionals require some special handling, otherwise we end up with stuff like \Theme.background.?alpha
.
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.
then I think you can it at the end of the loop and do a description.removeLast()
once you're outside it.
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.
It wasn't quite that simple, but the suggestion gave me an idea for a different impl which I think addresses this.
stdlib/public/core/KeyPath.swift
Outdated
@_silgen_name("swift_keypath_dladdr") | ||
internal func keypath_dladdr(_: UnsafeRawPointer) -> UnsafePointer<CChar>? | ||
|
||
@_silgen_name("swift_keypathSourceString") | ||
internal func demangle( | ||
name: UnsafePointer<CChar> | ||
) -> UnsafePointer<CChar>? | ||
|
||
|
||
fileprivate func dynamicLibraryAddress<Base, Leaf>( | ||
of pointer: ComputedAccessorsPtr, | ||
_: Base.Type, | ||
_ leaf: Leaf.Type | ||
) -> String { | ||
let getter: ComputedAccessorsPtr.Getter<Base, Leaf> = pointer.getter() | ||
let pointer = unsafeBitCast(getter, to: UnsafeRawPointer.self) | ||
if let cString = keypath_dladdr(UnsafeRawPointer(pointer)), | ||
let demangled = demangle(name: cString) { | ||
defer { | ||
demangled.deallocate() | ||
} | ||
return String(cString: demangled) | ||
} else { | ||
return "<computed \(pointer) (\(leaf))>" | ||
} | ||
} |
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 think all of this and the actual implementation in debugDescription
should be inside a #if SWIFT_ENABLE_REFLECTION
.
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 just want to confirm, if SWIFT_ENABLE_REFLECTION
is off, we should print "(value cannot be printed without reflection)"
, right?
Oh, could it be possible to add the types in the subscript case? |
Thanks! I believe the issues with indentation should be addressed at this point.
Yes! I didn't notice this earlier, but the type is there based on the output of |
@Azoy I believe that all of the issues you raised have been addressed. I've been having issues building the full toolchain so I'm not sure if my changes to the api digester worked, but I do believe that the test failures on Windows and Linux should also be resolved. |
@swift-ci 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.
One of the Linux CI failures appears unrelated, but the other one is real.
The Windows one also seemed like an infra issue to me when I saw it last night. For my context, is it common for the CI to be flaky? |
77b36b6
to
cc9ca5e
Compare
@xwu I believe I've addressed all of your comments. One thing I wanted to flag: currently, the availability of the new conformance is set to 5.7. Is there any chance that this makes it into 5.7, or should I change that to some other version? |
Thanks! |
Ah, thanks for flagging this: we are past making it into 5.7, but in any case the availability version for newly added things on the main branch should be |
I will change to 5.8. Looks like CI failed the API digester test on MacOS. Not sure where to go from here in terms of debugging that. Linux looks like it might be the same (presumably spurious) error from before, but I'm not sure. Windows passed though! |
Wooo about the passing Windows CI. Yes I'm stumped by the API digester warning; it seems to me to be a false positive but I don't want to be hasty in suggesting that we just add it to the list and call it aday; perhaps @Azoy can help here to verify. |
@swift-ci test Linux platform |
|
||
@available(SwiftStdLib 5.7, *) | ||
public var debugDescription: String { | ||
#if SWIFT_ENABLE_REFLECTION |
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.
This works, but I think the rest of the stdlib has used the style of:
#if SWIFT_ENABLE_REFLECTION
extension AnyKeyPath: CustomDebugStringConvertible {
...
}
#else
extension AnyKeyPath: CustomDebugStringConvertible {
give default message here
}
#endif
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've changed this to not be nested in the function, matching SourceCompatibilityShims.swift.
@@ -638,3 +638,5 @@ internal struct _TeeStream<L: TextOutputStream, R: TextOutputStream> | |||
internal mutating func _lock() { left._lock(); right._lock() } | |||
internal mutating func _unlock() { right._unlock(); left._unlock() } | |||
} | |||
|
|||
internal let noReflectionMetadataErrorMessage = "(value cannot be printed without reflection)" |
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 think we generally want to avoid globals in the stdlib, I would prefer to keep this string literal everywhere that it's used.
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 will revert this. Can you explain/link to why the stdlib avoids globals? I would like to understand if the reason is exclusive to the stdlib or something that is applicable outside.
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.
Globals have a place in the language, but I think we would reserve them for things like global caches if we had any of those (like the ones in the runtime). This is simple enough that I don't think it's worth having one.
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, interesting. My guess was that it would be a perf issue related to initializing the let in a thread safe way.
My goal with making this change was to prevent code duplication, but it's definitely not a particularly serious issue if this string gets copy pasted around a few times.
@swift-ci please test |
I haven't investigated deeply, but if it's the same Linux test falling again, and other CI builds on main are successful, then it's not a spurious error and probably needs some PR tweaking... |
Yeah, it looks like it's this Pr. TL:DR I think the right approach is to add these symbols to the allowlist of the test (symbol-visibility-linux.test-sh). But I would like to confirm with the author of the test (@compnerd). Long version: My understanding is that the test lists all symbols in a binary, then diffs that output with a list of all strong symbols in the same binary. The goal is to ensure there are no weakly linked symbols at all. But there are two weakly linked symbols in the output:
Demangling these, it looks like we caused a new version of Anyway, I think what is happening is that I used these in the impls of some of the functions I wrote, without realizing that they're brand new templates that have never been used before. C++ is instantiating (is that the right word?) these templates, and using weak linking, for whatever reason. The test is filled with inverted matches which appear to be an allowlist, and based on the names it seems like they might also be templates. So the obvious, quick solution is to add the two functions there and move on. But I'd like to understand why this Pr causes this; nothing has changed in the allowlist since April. So it feels like there's something different (and potentially unidiomatic/wrong) about how I'm using C++ in this Pr. |
:sigh: libstdc++. Yes, these two instantiations should be okay to add to the allowlist. The problem here is that the GNU C++ runtime decorates the template bodies such that an instantiation will be weak as it is in global namespace and attributed so as to coalesce the copies requiring weak ODR semantics giving them weak global linkage. This is an artifact of the implementation and we cannot control that even with |
Thanks! I've added them to the allowlist. |
Are there suitably equivalent LLVM types that can be used here instead? |
I don't believe so. I see two options in the llvm programmer's manual:
I think we could optimize the |
@swift-ci test |
I'll defer to you and other reviewers :) |
@swift-ci please test Linux platform |
@swift-ci please test macOS platform |
@swift-ci please test Windows platform |
Looks like CI is green. Any other changes needed to the Pr? |
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.
Woooo, nice to see. Can you clang-format the .cpp files?
demangling mostly works fix dots printing works add tests add conformance to AnyKeyPath implement SPI subscripts fully work comments use cross platform image inspection remove unnecessary comment fix fix issues add conditional conformance add types try to fix the api-digester test cr feedback: move impls behind flag, remove addChain(), switch statement, fallthrough instead of if-elses, move import cr feedback: refactor switch statement fix #ifdef reindent, cr feedback: removes manual memory management fix missing whitespace fix typo fix indentation issues switch to regexes checks should test in on all platforms print types in subscripts add test for empty subscript Update test/api-digester/stability-stdlib-abi-without-asserts.test Co-authored-by: Xiaodi Wu <[email protected]> add commas fix failing test fix stdlib annotation cr feedback: remove global, refactor ifdef cr feedback: switch back to manual memory management switch to 5.8 macro add new weakly linked functions to the allowlist fix one more failing test more cr feedback more cr feedback
2fa6f99
to
fe42b28
Compare
Done. |
@swift-ci test |
@Azoy How's it look to you? |
Thanks so much! Super excited this is in finally. |
…rios anymore The file check expectations (the way we print stuff) is different after swiftlang#60133. rdar://100564676
Implementation of this pitch, adds a conformance to
CustomDebugDescription
toAnyKeyPath
. This will need an SE before it's merged.I haven't modified api-digester yet, which I think I need to do...? I intended to see what the CI says first.