Skip to content

SR-2484: Improve diagnostic for incorrectly called private init #5237

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

Merged
merged 1 commit into from
Oct 18, 2016

Conversation

xedin
Copy link
Contributor

@xedin xedin commented Oct 11, 2016

Fixes situation where lookup of the constructors is attempted on non MetatypeType base.

Minor refactoring is done around how discovered structural members are treated,
which reduced amount of condition logic.

Resolves SR-2484.

@xedin
Copy link
Contributor Author

xedin commented Oct 11, 2016

/cc @rudkx

@xedin xedin changed the title [Diagnostics] SR-2484: Improve diagnostic for incorrectly called private init SR-2484: Improve diagnostic for incorrectly called private init Oct 11, 2016
@rudkx rudkx self-assigned this Oct 11, 2016
@rudkx
Copy link
Contributor

rudkx commented Oct 11, 2016

@jrose-apple /cc Jordan in case he wants to take a look.

decl->getName(), decl->getFormalAccess());
}

return true;
Copy link
Contributor

@jrose-apple jrose-apple Oct 12, 2016

Choose a reason for hiding this comment

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

This doesn't look right. The return is inside the loop, which means you only diagnose at most one candidate. What if there are two inaccessible candidates?

Copy link
Contributor Author

@xedin xedin Oct 12, 2016

Choose a reason for hiding this comment

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

I just followed the common theme which can be found throughout diagnostics code - once a single problem is diagnosed is returns right away. But i can change this code in a way it where would try to diagnose as many problems with access as possible and return only then. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the problem is "there are no available initializers" and the diagnosis would then include all of the possible candidates. That more closely matches what CalleeCandidateInfo::diagnoseSimpleErrors does, although I'll admit the current code is not set up as well to do that.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like diagnoseSimpleErrors includes candidates which aren't the intended callees (e.g. if you call c.foo(a:) and there is a c.foo() and a c.foo(a:) and they are both private, it lists both of those). If only c.foo() is accessible and you call c.foo(a:) we say you're calling a function that takes no arguments.

I think we could do better for both of these, but this seems like a step in the right direction.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jrose-apple Do you think this still needs additional work before being committed?

Copy link
Contributor

Choose a reason for hiding this comment

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

:-/ I really don't like it. It seems like the kind of thing where a user would say "but I wasn't trying to call that initializer anyway; I was trying to call [some other one that would have been a better match]."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just to clarify, do you think it's a good idea to include all of the possible inaccessible candidates? Or you don't think this is correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, just including all possible inaccessible candidates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All right, I'll do that then :)

!baseObjTy->is<MetatypeType>()) {
if (auto ctorRef = dyn_cast<UnresolvedDotExpr>(expr)) {
if (isa<SuperRefExpr>(ctorRef->getBase())) {
diagnose(anchor->getLoc(), diag::super_initializer_not_in_initializer);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a test for this diagnostic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is pre-existing diagnostic which just got moved, there is a test for it already in
test/Constraints/super_constructor.swift and test/Parse/super.swift

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, got it.


// Suggest inserting a call to 'type(of:)' to construct another object
// of the same dynamic type.
SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced this is a good idea. Most class initializers can't be called on a dynamic type because they're not required, and most protocols don't have initializer requirements at all. Additionally, you've changed the lookup to search on the type rather than the instance all the time, so if we get here there might really be no viable initializers. Or am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above, I've just move it, this was pre-existing.

Copy link
Contributor

@rudkx rudkx left a comment

Choose a reason for hiding this comment

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

LGTM.

decl->getName(), decl->getFormalAccess());
}

return true;
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like diagnoseSimpleErrors includes candidates which aren't the intended callees (e.g. if you call c.foo(a:) and there is a c.foo() and a c.foo(a:) and they are both private, it lists both of those). If only c.foo() is accessible and you call c.foo(a:) we say you're calling a function that takes no arguments.

I think we could do better for both of these, but this seems like a step in the right direction.

@rudkx
Copy link
Contributor

rudkx commented Oct 12, 2016

@swift-ci Smoke test.

@xedin
Copy link
Contributor Author

xedin commented Oct 13, 2016

@jrose-apple I've made a change to diagnose all of the inaccessible candidates found. Please take a look and let me know!

@jrose-apple
Copy link
Contributor

Ah, this isn't quite what I meant; this will produce N diagnostics at the same site with the same message (if there are multiple overloads with the same argument labels). I think something like what diagnoseSimpleErrors is doing is better: one error message, with notes for all the candidates (even if we don't display those notes very well in Xcode right now). That does have a downside of picking only one name for the primary message if there are multiple names, though.

Thoughts?

@xedin
Copy link
Contributor Author

xedin commented Oct 14, 2016

@jrose-apple ah, I've totally misunderstood what you meant, I'll do that momentarily!

@xedin
Copy link
Contributor Author

xedin commented Oct 14, 2016

@jrose-apple Done, it's going to emit 'declared at' messages now for all of the candidates found if there was one with incorrect access. After looking at diagnoseSimpleErrors this makes a lot more sense now! :)


for (auto &candidate : result.ViableCandidates) {
auto decl = candidate.getDecl();
CS->TC.diagnose(decl, diag::decl_declared_here, decl->getName());
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems a little funny here that we were checking for non-decls before and now we're going to skip that check.

Also, nitpick: please use getFullName for these notes, which will help distinguish overloads. (Plain getName is good for the main error because that will drop the argument labels, which is important if they're different.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, it looks like it's a bug in the code in diagnoseSimpleErrors as well, I'll change here and in diagnoseSimpleErrors as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Aha, I was wondering if diagnoseSimpleErrors was in a context where it already knew everything was a decl, but that's probably silly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, it was only checking that for candidates[0], I'm running tests right now locally, will push in a few.

@xedin
Copy link
Contributor Author

xedin commented Oct 15, 2016

@jrose-apple Done, changed both new code and diagnoseSimpleErrors.

@jrose-apple
Copy link
Contributor

Thanks, @xedin!

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - f0b621a8cbd8d336cfb7b9e24dbc210d63a9ded5
Test requested by - @jrose-apple

@jrose-apple
Copy link
Contributor

Once more for the force push.

@swift-ci Please test

@xedin
Copy link
Contributor Author

xedin commented Oct 18, 2016

@jrose-apple Thanks for looking at this!

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.

4 participants