Skip to content

sema: reject enum element call with payloads as compile-time constant #41796

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
Mar 12, 2022

Conversation

nkcsgexi
Copy link
Contributor

rdar://90168664

@nkcsgexi
Copy link
Contributor Author

@swift-ci please smoke test

@@ -1146,7 +1146,9 @@ bool NotCompileTimeConst::diagnose(const Solution &solution, bool asNote) const
// Referencing an enum element directly is considered a compile-time literal.
if (auto *d = solution.resolveLocatorToDecl(locator).getDecl()) {
if (isa<EnumElementDecl>(d)) {
return true;
if (!d->hasParameterList()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please factor the checks out of the fix, as I mentioned on the precious PR - a fix shouldn’t be created if it’s not going to be diagnosed…

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do in a follow-up PR! I'm still figuring out how to refactor this code...

Copy link
Contributor

@xedin xedin Mar 13, 2022

Choose a reason for hiding this comment

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

I spent some time thinking about this and it's going to be hard to properly detect that argument is non-const because sometimes e.g. leading-dot syntax the overload is resolved long after argument conversion constraint has been simplified (result gets bound, then base gets bound and only after that the member is resolved). I think one way to archive it might to be add a new flag to a type variable e.g. const required which is going to get associated with "argument" type variable and get propagated to the base of the chain and from it to the member.

Also note that the check you added here is incorrect because NotCompileTimeConst would get a base expression as a locator but the leading-dot syntax chain this base belongs to might have more members than just one.

Copy link
Contributor Author

@nkcsgexi nkcsgexi Mar 13, 2022

Choose a reason for hiding this comment

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

Also not that the check you added here is incorrect because NotCompileTimeConst would get a base expression as a locator but the leading-dot syntax chain this base belongs to might have more members than just one.

Thanks! Not sure I understand the situation you are describing here. Could you give a test case?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, something like:

enum E {
  case a
  case b(Int)
}

using .a.b(42) is going to get accepted because the the base is just .a and .b(42) is not checked.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this following case:

$cat /tmp/t.swift
enum E {
  case a
  case b(Int)
}
func foo(_ c: _const E) {

}
foo(.a.b(3))
foo(E.a.b(3))

I got:

$../build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/bin/swift-frontend -typecheck /tmp/t.swift
/tmp/t.swift:8:6: error: enum case 'b' cannot be used as an instance member
foo(.a.b(3))
    ~^
    E
/tmp/t.swift:9:7: error: enum case 'b' cannot be used as an instance member
foo(E.a.b(3))
    ~~^
    E
/tmp/t.swift:9:9: error: expect a compile-time constant literal
foo(E.a.b(3))
        ^

They seem to be rejected.

Copy link
Contributor

Choose a reason for hiding this comment

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

How about this one:

enum E {
  case a
  case b(Int)

  var c: E { .b(42) }
}

func test(_: _const E) {
}

test(.a.c)

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, this one seems to be wrongly accepted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filed rdar://90210674

@nkcsgexi nkcsgexi merged commit b6047e2 into swiftlang:main Mar 12, 2022
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