Skip to content

[Diagnostics][Sema] warn inconstructible enum #16987

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 4 commits into from
Jun 14, 2018

Conversation

AnthonyLatsis
Copy link
Collaborator

Resolves SR-6273.

Simple cases, I do not recurse into tuples or other possibly inconstructible types. Should I, or is it an overkill?

!(elt->isIndirect() || E->isIndirect()))
return false;

auto argTy = elt->getArgumentInterfaceType();
Copy link
Contributor

@CodaFi CodaFi Jun 4, 2018

Choose a reason for hiding this comment

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

You can simplify this and handle nested uninhabited tuples by using TypeBase::isStructurallyUninhabited

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a bit unexpected for me, can you explain why a tuple containing an uninhabited type is uninhabited? I also don't understand how this can help to simplify.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a bit unexpected for me, can you explain why a tuple containing an uninhabited type is uninhabited?

enum Foo {
  case bar(Never)
}

Copy link
Collaborator Author

@AnthonyLatsis AnthonyLatsis Jun 5, 2018

Choose a reason for hiding this comment

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

If I understand correctly now, uninhabited means 'not constructible'. So you can't construct a tuple that has an empty enum, because you can't instantiate an empty enum. The first thing that comes to mind when I see uninhabited is a type with no explicit members. Maybe implicit as well. Well, actually, if a type has neither explicit nor implicit members, it is inconstructible. But it's still a somewhat confusing way to put it for me.

Do I correctly understand that you want me to firstly check if the argument is uninhabited so that such cases are also counted in favor of inconstructability? The diagnostic would then be misleading the way it is now.

It can be changed then to enum is not constructible because its cases are either recursive or contain a non-constructible type.

Copy link
Collaborator Author

@AnthonyLatsis AnthonyLatsis Jun 5, 2018

Choose a reason for hiding this comment

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

@CodaFi But, I'm don't think it's a good idea to warn about 'uninhabited' cases. Similar to how we don't warn about empty enums. WDYT?

Copy link
Collaborator Author

@AnthonyLatsis AnthonyLatsis Jun 5, 2018

Choose a reason for hiding this comment

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

@CodaFi Using the terminology Slava gave, I don't think we should warn about uninhabited types (The issue faces non-well-founded types, or unconstructibly infinite types – the way @jckarter describes them in the report).

enum Foo1 { case A(Never), case B(Foo1) } // uninhabited

enum Foo2 { case A(Int, Foo2), case B(Foo2) // non-well-founded

@@ -3209,6 +3209,8 @@ ERROR(unsupported_recursive_struct,none,
"contains it",
(Type))

WARNING(type_not_constructible,none,
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we're only diagnosing direct self-recursion in the payload type, could you make this diagnostic more specific?

return false;

for (auto elt: elts) {
if (!elt->hasInterfaceType() ||
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you assert that RequireDelayedChecking got tripped if the element has no interface type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It might not get tripped because I have a call to the method in the fast path before the loop in expandEnum where it is set.

}
return false;
};
auto isInconstructible = [containsType, E]() -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

These are only used once so they can be pulled out as static functions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

For the same reason, isn't it preferable to leave them in the function scope unless they are relatively long or complex? It's more readable and uniform this way.

@AnthonyLatsis
Copy link
Collaborator Author

@jckarter Do you want to actually disallow them or just warn?

@xwu
Copy link
Collaborator

xwu commented Jun 4, 2018

Can we standardize on terminology?

  • The branch name uses unconstructible
  • Most of the rest of this commit uses inconstructible
  • The warning is named type_not_constructible

I find very few results on Google for either "unconstructible type" or "inconstructible type." Could we maybe just stick to not constructible (or, if necessary, non-constructible) throughout?

@AnthonyLatsis
Copy link
Collaborator Author

AnthonyLatsis commented Jun 4, 2018

@xwu I think 'not constructible' is a good idea and it sounds good, besides, IIRC diagnostic guidelines discourage these negations on long words. Thanks!

@slavapestov
Copy link
Contributor

slavapestov commented Jun 5, 2018

The standard term for a type that does not have values is "uninhabited". A recursive type that does not have a base case is "non-well-founded".

@AnthonyLatsis
Copy link
Collaborator Author

AnthonyLatsis commented Jun 5, 2018

@slavapestov Thank you. Is it preferable to keep the compiler formal while using the non-formal diagnostic message?

@jckarter
Copy link
Contributor

jckarter commented Jun 5, 2018

"Is not constructible" sounds a bit opaque to me too. "'T' is impossible to instantiate because it's infinitely recursive" might be more understandable?

@AnthonyLatsis
Copy link
Collaborator Author

AnthonyLatsis commented Jun 5, 2018

I think the part preceding is not constructible is pretty expressive and straight-forward. How about we change the ending to is impossible to instantiate?

infinitely recursive enum is impossible to instantiate is an option as well, but it doesn't sound as good to me.

Copy link
Contributor

@xedin xedin left a comment

Choose a reason for hiding this comment

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

FYI, @jrose-apple wrote an excellent document about diagnostics phrasing and other nuances https://github.com/apple/swift/blob/master/docs/Diagnostics.md

@AnthonyLatsis
Copy link
Collaborator Author

AnthonyLatsis commented Jun 6, 2018

Yeah, one of the first docs I've read. It's great!

@AnthonyLatsis
Copy link
Collaborator Author

Any comments? Does the message sound alright?

@jckarter
Copy link
Contributor

Sounds good to me.

@jckarter
Copy link
Contributor

@swift-ci Please smoke test

@AnthonyLatsis
Copy link
Collaborator Author

AnthonyLatsis commented Jun 13, 2018

⛵️?

@jckarter jckarter merged commit 823ed14 into swiftlang:master Jun 14, 2018
@AnthonyLatsis AnthonyLatsis deleted the warn-unconstructible-enum branch February 17, 2022 21:04
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.

6 participants