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

[Sema] Disallow stored properties to have uninhabited types #19992

Merged
merged 5 commits into from
Oct 26, 2018

Conversation

Azoy
Copy link
Contributor

@Azoy Azoy commented Oct 23, 2018

Resolves: SR-8811

cc: @jrose-apple @CodaFi

Reword comment

Add tuple test case
@harlanhaskins
Copy link
Contributor

@swift-ci please test

Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

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

Thanks for picking this up!

@@ -2461,6 +2461,15 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
}
}

// Reject variable if it is a stored property with a structurally
// uninhabited type
if (VD->isInstanceMember() && VD->hasStorage() &&
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is limited to members; any stored type properties or globals or even locals would have the same problem.

@@ -1367,6 +1367,10 @@ ERROR(pattern_binds_no_variables,none,
"variables",
(unsigned))

ERROR(stored_property_no_uninhabited_type,none,
"stored property %0 cannot have uninhabited type %1",
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't love this diagnostic because I don't think "uninhabited" is a great user-facing term, but I can't think of anything really better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea, I was looking for ways to reword this, but I couldn't come up with anything.

Copy link
Contributor

Choose a reason for hiding this comment

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

The compiler seems to define uninhabited types as either enums with no cases, or tuples containing uninhabited types. Could we just call it a "caseless enum" or "enum with no cases"? I suppose that might require a separate phrasing for tuples:

ERROR(stored_property_no_uninhabited_enum,none,
      "stored property %0 cannot have caseless enum %1", ...)
 ERROR(stored_property_no_uninhabited_tuple,none,
      "stored property %0 cannot have tuple type %1 containing caseless enum", ...)

Copy link
Contributor Author

@Azoy Azoy Oct 23, 2018

Choose a reason for hiding this comment

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

How does this sound?

// Non-structurally
"%select{%select{variable|constant}0|property}1 %2 cannot have "
"enum type %3 with no cases"

// structurally
"%select{%select{variable|constant}0|property}1 %2 cannot have "
"tuple type %3 containing enum with no cases"

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 7991aec

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 7991aec

@Azoy
Copy link
Contributor Author

Azoy commented Oct 23, 2018

@jrose-apple how should we handle IRGen/generic_enums.swift and Reflection/TypeLowering.swift? Can we just add a simple case to the ir test? I'm not sure the intention of that test is to test the emptiness of an enum. With the reflection test, can we just remove the empty enum?

@CodaFi
Copy link
Contributor

CodaFi commented Oct 23, 2018

The condition IRGen/generic_enums.swift is testing for should now be structurally impossible to write down (used to be that you could lower metadata for a generic member that had no cases and get a crash). You can stick a case in that Swift file and be good.

@slavapestov Can speak about the empty member in Reflection/TypeLowering.swift.

@jrose-apple
Copy link
Contributor

jrose-apple commented Oct 23, 2018

I think we can still contrive an uninhabited local by using generics:

struct Wrapper<T> {
  var value: T
}

struct HasEmptyMember {
  var empty: Wrapper<Never>
}

(Slava is out right now.)

@Azoy
Copy link
Contributor Author

Azoy commented Oct 23, 2018

@jrose-apple how does this look?


if (VD->getInterfaceType()->is<TupleType>()) {
uninhabitedTypeDiag = diag::pattern_no_uninhabited_tuple_type;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add an assertion that the type is an enum otherwise? That way we'll know if we ever add any new ways for something to be structurally uninhabited.

Copy link
Contributor

Choose a reason for hiding this comment

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

Heh. It could be a BoundGenericEnumType too…

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops 😅

@jrose-apple
Copy link
Contributor

Looks pretty good. I still don't love the diagnostic text, but I can't really think of something nicer, and this is probably pretty rare anyway. Any other onlookers have any remaining thoughts?

@swift-ci Please smoke test

@jrose-apple
Copy link
Contributor

@swift-ci Please test source compatibility

@jrose-apple
Copy link
Contributor

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 7991aec

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 7991aec

@Azoy
Copy link
Contributor Author

Azoy commented Oct 26, 2018

@jrose-apple is this ready for merge?

@jrose-apple
Copy link
Contributor

I wanted to see if @CodaFi or @brentdax had any remaining thoughts, but I guess they didn't. Or they can add them post-merge.

@jrose-apple jrose-apple merged commit 4710c43 into swiftlang:master Oct 26, 2018
@jrose-apple
Copy link
Contributor

Thanks for doing this!

@jckarter
Copy link
Contributor

Maybe this makes sense as a warning, but it does not make sense IMO to make it an error to define properties with uninhabited types. The original motivating issue in https://bugs.swift.org/browse/SR-8811 indicates an issue with the unreachable code analysis, and while this makes it impossible to get into that situation, I think we should still look into the underlying issue, and reduce this to a warning.

@jrose-apple
Copy link
Contributor

@jckarter convinced me too in a side conversation. Mind doing a follow-up PR to downgrade it to a warning, @Azoy? (And rephrase the diagnostic a little.)

@jckarter
Copy link
Contributor

As a warning, I think it'd also make sense to follow the behavior of the Void warning, where we warn if a variable infers its type as some uninhabited type, but allow you to make it explicit.

@Azoy
Copy link
Contributor Author

Azoy commented Oct 26, 2018

@jrose-apple will do!

@Azoy
Copy link
Contributor Author

Azoy commented Oct 26, 2018

@jckarter which warning are you referring to? I looked through the diagnostics to find something for Void but couldn't find anything that seemed related.

@jckarter
Copy link
Contributor

This warning:

$ cat ~/foo.swift
let foo = print("hi")
$ xcrun swift ~/foo.swift
/Users/jgroff/foo.swift:1:5: warning: constant 'foo' inferred to have type '()', which may be unexpected
let foo = print("hi")
    ^
/Users/jgroff/foo.swift:1:5: note: add an explicit type annotation to silence this warning
let foo = print("hi")
    ^

Void is a typealias for ().

@Azoy
Copy link
Contributor Author

Azoy commented Oct 26, 2018

Yea, I had just expected void to be in the diagnostic name. Would it make sense to just reuse this warning?

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.

7 participants