Skip to content

Comments

Refactor FunDecl semantic#8609

Merged
dlang-bot merged 1 commit intodlang:masterfrom
thewilsonator:refactor-funcsem
Sep 5, 2018
Merged

Refactor FunDecl semantic#8609
dlang-bot merged 1 commit intodlang:masterfrom
thewilsonator:refactor-funcsem

Conversation

@thewilsonator
Copy link
Contributor

I sincerely apologise for the diff size, and would recommend using something other than the regular diff algorithm as it logically consists of a small addition combined with a massive deletion, and a massive addition, not lots of additions and deletions. Does anyone know how to use --patience or --histogram with GitHub?

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @thewilsonator! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + dmd#8609"

@JinShil
Copy link
Contributor

JinShil commented Aug 24, 2018

Would be better if each new function were its own commit, or even better its own PR. But a few global comments before I even attempt to review this: 1) All new functions should have full DDoc headers with Params and Returns where applicable. Follow the style guide at https://dlang.org/dstyle.html#phobos_documentation 2) make any new functions private if they don't need to be exposed to other modules. 3) consider if any of the functions should be methods of the class instead of free functions in semantic. 4) void invariant(): I would prefer if function names always began with verbs. What is that function doing? Same with nestedFuncLit().

@thewilsonator
Copy link
Contributor Author

Will do func per commit.

  1. Almost all the function are void function()s. I'm trying improve the docs with those, but will do.
  2. The whole struct is private do the functions need to be as well?
  3. ? they are all part of a private struct.
  4. Ya I'm having a hard time describing what they actually do. I've been staring at them for too long. Will take a break and have a look with fresh eyes and a rested mind.

@JinShil
Copy link
Contributor

JinShil commented Aug 24, 2018

? they are all part of a private struct.

Sorry, I didn't look at it in detail. It's hard to see the surround scope in these diffs. It's not a concern if the scope is private.

@thewilsonator
Copy link
Contributor Author

Yeah, hopefully will be more obvious when I do it 1 commit per function.

@WalterBright
Copy link
Member

Sorry, this is pretty much impossible to review, and no description of what is being done here. Try multiple PRs, each with a smallish chunk (not multiple commits to one PR). Is there a reason to combine all these into one PR?
BTW, this is failing all tests. Doing smaller PRs means the mistake is FAR FAR easier to find.


assert(funcdecl.type == f || (funcdecl.type.ty == Tfunction && f.purity == PURE.impure && (cast(TypeFunction)funcdecl.type).purity >= PURE.fwdref));
f = cast(TypeFunction)funcdecl.type;
void semantic()
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming this function semantic is really confusing. In dmd there are 3 semantic stages named bluntly dsymbolSemantic, semantic2 and semantic3. Although the function is defined in the file semantic3, on caller site it is not obvious to the reader which of the semantic passes it is calling. I would recommend renaming it doSemantic3 or semantic3Impl or whatever that makes it obvious that it's the invocation of semantic3

sym.loc = funcdecl.loc;
sym.endlinnum = funcdecl.endloc.linnum;
sc2 = sc2.push(sym);
private struct FuncDeclSem
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this struct really needed? Why not just free functions?

Copy link
Contributor

@RazvanN7 RazvanN7 left a comment

Choose a reason for hiding this comment

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

Making smaller PRs is the way to go here and I suggest first breaking the visit(FuncDeclaration) method into smaller functions. After all those PR's are merged you should try submitting the PR with the creation of the struct FuncDeclSem because it will be more obvious if the struct is needed or not. Smaller refactoring PRs are easy to review and merge.

@thewilsonator
Copy link
Contributor Author

The struct is absolutely required, otherwise each function call will take a ridiculous number of arguments. The struct will hold each used local variable of visit(FuncDeclaration), and there are by my count 13 of them.

}
}

private struct FuncDeclSem3
Copy link
Member

@ibuclaw ibuclaw Aug 26, 2018

Choose a reason for hiding this comment

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

Maybe you should instead move this to a new module which encapulates running semantic on FuncDeclaration, you could also move functionSemantic and functionSemantic3 there too.

module dmd.funcsemantic;

extern(C++) bool functionSemantic(FuncDeclaration fd);
extern(C++) bool functionSemantic3(FuncDeclaration fd);

private struct Semantic3Function // Or whatever you insist on naming it.
{
  FuncDeclaration funcdecl;
}

The visitor entry in semantic3.d could then just call functionSemantic3.

Copy link
Member

@ibuclaw ibuclaw Aug 26, 2018

Choose a reason for hiding this comment

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

Actually, the tangle is even worse than I thought.

We have the following methods that do "semantic" on a function.

  • DsymbolSemanticVisitor::visit(FuncDeclaration)
  • DsymbolSemanticVisitor::funcDeclarationSemantic(FuncDeclaration)
  • FuncDeclaration::functionSemantic
  • FuncDeclaration::functionSemantic3
  • Semantic3Visitor::visit(FuncDeclaration)

I revise my suggestion, they should probably go into two separate leaf modules - funcsemantic and funcsemantic3 - each with one public entry point named accordingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're saying fold Semantic3Visitor::visit(FuncDeclaration) out of https://github.com/dlang/dmd/blob/master/src/dmd/func.d#L391 so that it calls the function directly? Sure, but I think it would be better suited to a later PR. I want to get this refactored to a comprehendible state so I can fix 14246 with hopefully a bit more finesse than last time it was tried.

I've half a mind to (eventually) move all the semantic analysis modules to a separate directory, src/dmd is mighty cluttered.

I think this is ready to be merged, not sure why buildkite is failing.

}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

I see the point of factoring out checkInContractOverrides() into a separate function, but I don't see the point of creating FuncDeclSem3?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It will hold local variables of visit(FuncDeclaration) so that there won't be heaps of arguments to the function.

Copy link
Member

Choose a reason for hiding this comment

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

We already have Scope for that.

@thewilsonator
Copy link
Contributor Author

Can we move forward with this? I'm not sure why build kite is failing though.

}

uint oldErrors = global.errors;
auto fds = FuncDeclSem3(funcdecl,sc);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be made const or are we expecting it to change?

Copy link
Contributor Author

@thewilsonator thewilsonator Sep 3, 2018

Choose a reason for hiding this comment

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

It will eventually. e: change that is. It will hold the locals vars of the function which all do.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok.

@dlang-bot dlang-bot merged commit d6ad81d into dlang:master Sep 5, 2018
@ibuclaw
Copy link
Member

ibuclaw commented Sep 5, 2018

Why was this merged without waiting for all reviewers to acknowledge the responses to their questions?

@jacob-carlborg
Copy link
Contributor

Someone thought two approvals were good enough?

@WalterBright
Copy link
Member

This is apparently the start of a major refactoring. I don't know why it is being done. What is it intended to accomplish? How will the code get better? Until this is all clear and agreed upon, we should not be proceeding with it.

For example, I've provided lists before of goals of refactoring. As far as I can see, this addresses none of them.

@RazvanN7
Copy link
Contributor

RazvanN7 commented Sep 6, 2018

@ibuclaw This is just the start of the refactorization and it is not divergent with your suggestion. The purpose of this refactorization is to break the semantic3 for FuncDeclarations into smaller-documented functions. Your suggestion can be implemented in a future PR

@WalterBright The goal of this refactoring is to make semantic3::visit(FuncDeclaration) more readable as it has >1000 lines of code. I have been working with that code myself and it is really hard to try and isolate the code of interest in that giant chunk. This PR (and subsequent ones) will refactor the logic into separate function that are documented. This will make it easier to read and understand what the code does.

@ibuclaw
Copy link
Member

ibuclaw commented Sep 11, 2018

As per https://github.com/dlang/dmd/pull/8609/files#discussion_r213101229 and #8609 (comment), moving from a member function of one type to a member function of another is not improving encapsulation. At least my suggestion of putting all moved code into a free function in a new module should have been followed (unless me and @WalterBright disagree there, of course).

@thewilsonator
Copy link
Contributor Author

You are right, but the point of this and the next 24ish PRs is not to improve encapsulation but to improve comprehensibility, 1100 lines is too much for me to make functional changes in and I suspect too much for reviewers as well. PRs that follow after that can deal with encapsulation.

@ibuclaw
Copy link
Member

ibuclaw commented Sep 12, 2018

However moving the code to another place in the same module does not improve comprehensibility. You're better off hitting two birds with one stone here and just moving them to a new module from the start.

@thewilsonator
Copy link
Contributor Author

However moving the code to another place in the same module does not improve comprehensibility.

Oh, but it does. Going from 1100 lines of almost completely undocumented code, to ~300 of documented code at a high level leads to a massive increase in the ability to comprehend what the code is doing. Or you have a different definition of comprehensibility than I do.

Splitting out code to a new module can come later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants