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] Require function builders to have at least one buildBlock method #33798

Merged
merged 1 commit into from Sep 9, 2020

Conversation

Jumhyn
Copy link
Collaborator

@Jumhyn Jumhyn commented Sep 4, 2020

If the supplied method is not static, offer a fix-it to make it static

This is technically source breaking, though AFAICT any function builders which don't have at least one valid buildBlock member aren't usable anyway, so maybe okay? If necessary, could downgrade this to a warning.

@Jumhyn
Copy link
Collaborator Author

Jumhyn commented Sep 4, 2020

@hborla (or anyone else) would you mind requesting the relevant reviewers?

lib/Sema/TypeCheckAttr.cpp Outdated Show resolved Hide resolved
lib/Sema/TypeCheckAttr.cpp Outdated Show resolved Hide resolved
lib/Sema/TypeCheckAttr.cpp Outdated Show resolved Hide resolved
@xedin
Copy link
Member

xedin commented Sep 4, 2020

I wonder whether it should be allowed to declare a static method in an extension instead of requiring it to be always attached to a type declaration, that might be helpful for file management. After all the requirement is that it buildBlock should exist is vague enough...

@Jumhyn Jumhyn force-pushed the function-builder-static-buildblock branch 2 times, most recently from 8568db7 to cdaf54b Compare September 4, 2020 03:23
@Jumhyn
Copy link
Collaborator Author

Jumhyn commented Sep 4, 2020

Hm, @xedin could you clarify? I think this check already allows for that (though I just added a test to that effect, see ValidBuilder7)—if that's not what you were thinking of, please let me know. IMHO we shouldn't allow:

// Module A
@_functionBuilder
public struct Builder {}

// Module B
extension Builder {
  func buildBlock(_: Any...) -> Int { ... }
}

@Jumhyn
Copy link
Collaborator Author

Jumhyn commented Sep 4, 2020

Although, I guess with the support for callable types serving as build* functions, someone who really wanted to could do:

// Module A
@_functionBuilder
public struct Builder {
  public struct BuildBlock {}
  static var buildBlock = BuildBlock()
}

// Module B
extension Builder.BuildBlock {
  func callAsFunction(_ exprs: Any...) -> Int { ... }
}

@xedin
Copy link
Member

xedin commented Sep 4, 2020

@Jumhyn The way you made the check makes sense to me, I just wanted to point out that its should be allowed to declare buildBlock in extension in the same module (other module doesn't make much sense to me).

@Jumhyn Jumhyn force-pushed the function-builder-static-buildblock branch from cdaf54b to 6a1e64f Compare September 4, 2020 20:05
@Jumhyn
Copy link
Collaborator Author

Jumhyn commented Sep 4, 2020

Gotcha, thank you for clarifying @xedin!

I've brought back the check that validates the type of the buildBlock declaration, so that now we check:

    if (!(ty->is<AnyFunctionType>() || ty->isCallableNominalType(nominal)))
      continue;

This will reject the case I posted above where a non-callable buildBlock member's type is extended in another module to add a callAsFunction method. Are there other cases that should be allowed that this would reject?

I've also made a small tweak to allow the somewhat-pathological but still syntactically valid:

@_functionBuilder
enum ValidBuilder10 {
    case buildBlock(Any)
}

which can be used as

@ValidBuilder10 var v10: ValidBuilder10 { 1 }

@Jumhyn Jumhyn force-pushed the function-builder-static-buildblock branch from 6a1e64f to 479d75f Compare September 4, 2020 20:29
@Jumhyn Jumhyn force-pushed the function-builder-static-buildblock branch 2 times, most recently from e0dbb68 to 87937e2 Compare September 4, 2020 22:09
@Jumhyn
Copy link
Collaborator Author

Jumhyn commented Sep 4, 2020

@DougGregor Thank you for the suggestion! I've updated this to share the logic between builderSupports and visitFunctionBuilderAttr at the cost of disallowing case buildBlock(Any), static var buildBlock: (Any...) -> Int and static var buildBlock: SomeCallableNominal type declarations. Let me know if you have any thoughts about whether those constructions should be allowed!

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

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

Much improved, thank you!

lib/Sema/TypeCheckAttr.cpp Show resolved Hide resolved
If the supplied method is not static, offer a fix-it to make it static
@Jumhyn Jumhyn force-pushed the function-builder-static-buildblock branch from 87937e2 to b82c57a Compare September 5, 2020 05:46
@DougGregor
Copy link
Member

@swift-ci please smoke test

2 similar comments
@DougGregor
Copy link
Member

@swift-ci please smoke test

@DougGregor
Copy link
Member

@swift-ci please smoke test

@DougGregor
Copy link
Member

@swift-ci please smoke test macOS

@theblixguy
Copy link
Collaborator

Unexpectedly Passed Tests (1):
  lldb-api :: lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py

Looks like we need to un-XFAIL it.

@DougGregor DougGregor merged commit 7c81f49 into apple:master Sep 9, 2020
@DougGregor
Copy link
Member

I'll just merge, thank you!

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.

None yet

4 participants