Skip to content
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

Relocate recursion detection logic. #27

Merged
merged 5 commits into from
Jan 3, 2020

Conversation

danilvpetrov
Copy link
Member

@danilvpetrov danilvpetrov commented Dec 29, 2019

This PR removes the recursion detection logic from visitor.visitMap(), visitor.visitPtr(), and visitor.visitSlice() methods and places it on the top of visitor.visit() method to have a single point of recursion detection and recursion marker printing.

This PR is a precursor to #26 as sync.Map filter requires recursion detection when rendering sync.Map elements.

This commit removes the  recursion detection logic from
`visitor.visitMap()`, `visitor.visitPtr()`, and `visitor.visitSlice()`
methods and places it on the top of `visitor.visit()` method to have a
single point of recursion detection and recursion marker printing.

Adding `Value.CanNil()` method is required to detect whether it is safe
to call `Value.IsNil()` on all possible kinds of values without causing
the code to panic.

Also an if branch was placed inside the `visitor.enter()` method to exit
the method if the value is an empty interface. That was required to keep
the interface rendering tests from failing and to keep the behaviour
backward-compatible.
@danilvpetrov danilvpetrov force-pushed the relocate-recursive-detection branch from ba37971 to 24e7647 Compare December 29, 2019 22:22
@danilvpetrov danilvpetrov marked this pull request as ready for review December 29, 2019 22:27
@danilvpetrov danilvpetrov requested a review from jmalloc December 29, 2019 22:28
value.go Outdated Show resolved Hide resolved
visitor.go Outdated

// If the value is an empty interface, return false as there is a specific
// case for rendering empty interfaces.
if v.DynamicType.Kind() == reflect.Interface && v.Value.IsNil() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this if is removed, is the output still correct? Could we remove this, and let the enter() function handle rendering the nil interfaces, and remove visitInterface()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can definitely do that. However we still need this condition from visitor.visitInterface() to keep the tests as they are.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrm, I guess since there is still interface-specific logic it belongs in a visitInterface() method, but something about having to do this check twice feels wrong, but I haven't come up with a "better" way yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think now that this has been made more generic, it probably shouldn't be responsible for nil rendering at all, only for the recursion. Which means we should let the nil rendering fall through to the filters and main switch statement regardless of the type (ie, not just interfaces). Does that make sense?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely it makes sense. I'll commit more changes towards that direction soon.

Copy link
Member Author

@danilvpetrov danilvpetrov Jan 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, my last commit is an attempt to let only a single purpose for visitor.enter() method - recursion detection and recursive marker rendering.

I had to replace Value.canNil() with Value.canPointer() method since visitor.enter() no longer needs to check the value for nil, but it still needs to check if we can safely acquire a pointer from the value.

value.go Outdated Show resolved Hide resolved
danilvpetrov and others added 3 commits December 31, 2019 09:36
The purpose of this commit is to refactor `visitor.enter()` method to
narrow down its purpose to concurrency detection only. Previous nil
value rendering was relocated to the types that specifically require nil
rendering (ptr, slice, and map). Nil interface rendering was left intact
as it requires some specifics when rendering ambiguous static types.

As the remaining logic in `visitor.enter` now requires to receive a
pointer from the given type, `Value.canNil()` method was replaced with
`Value.canPointer()` method to check if it is safe to acquire a pointer
from a value.
visitor.go Outdated Show resolved Hide resolved
@danilvpetrov danilvpetrov merged commit 4ab8945 into master Jan 3, 2020
@danilvpetrov danilvpetrov deleted the relocate-recursive-detection branch January 3, 2020 01:11
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.

2 participants