Commit Graph

36 Commits

Author SHA1 Message Date
Alexis Laferrière
4d814d0506 Sema: Add @cdecl @implementation type-checking test variant
Based off the test for `@_cdecl @implementation`. Split between need of
the ObjC interop.
2025-07-07 09:52:27 -07:00
Becca Royal-Gordon
9a1f6aeb8a Tweak missing impl diagnostic for async members
The diagnostic mentions both possible names, but only provides a stub for the `async` variant.
2025-04-09 16:48:42 -07:00
Becca Royal-Gordon
0cfda873b6 Suggest stub stored properties where possible
When generating a stub fix-it for a protocol conformance or implementation extension, Swift will now evaluate whether the context allows the declaration of stored properties and, if so, will suggest one. It will also use the `let` keyword instead of `var` if the property has no setter.
2025-04-09 16:48:41 -07:00
Becca Royal-Gordon
93188f81cc Stub fix-its for missing objcImpl requirements
Changes the diagnostics emitted when an `@objc @implementation` extension is missing some of the members required by the extension:

• We now emit one error on the extension, plus a note for each missing member.
• Where possible, we also emit a note with a fix-it adding stubs.

For example:

```
  9 | @objc @implementation extension ObjCClass {
    |                       |- error: extension for main class interface does not provide all required implementations
    |                       |- note: missing instance method 'method(fromHeader3:)'
    |                       |- note: missing instance method 'method(fromHeader4:)'
    |                       |- note: missing property 'propertyFromHeader7'
    |                       |- note: missing property 'propertyFromHeader8'
    |                       |- note: missing property 'propertyFromHeader9'
    |                       |- note: missing instance method 'extensionMethod(fromHeader2:)'
    |                       `- note: add stubs for missing '@implementation' requirements
```

With a fix-it on the last note to insert the following after the open brace:

```

  @objc(methodFromHeader3:)
  open func method(fromHeader3 param: Int32) {
      <#code#>
  }

  @objc(methodFromHeader4:)
  open func method(fromHeader4 param: Int32) {
      <#code#>
  }

  @objc(propertyFromHeader7)
  open var propertyFromHeader7: Int32 {
      get {
          <#code#>
      }
      set {
          <#code#>
      }
  }

  @objc(propertyFromHeader8)
  open var propertyFromHeader8: Int32 {
      get {
          <#code#>
      }
      set {
          <#code#>
      }
  }

  @objc(propertyFromHeader9)
  open var propertyFromHeader9: Int32 {
      get {
          <#code#>
      }
      set {
          <#code#>
      }
  }

  @objc(extensionMethodFromHeader2:)
  open func extensionMethod(fromHeader2 param: Int32) {
      <#code#>
  }

```

Fixes rdar://130038221.
2025-04-07 17:53:15 -07:00
Becca Royal-Gordon
d0a2564581 Make behavior change detection generic
Automatically detect when shouldMarkAsObjC() will behave differently based on the objcImpl early adopter flag and diagnose it. This works in either direction, although there isn’t anything yet that will emit diag:: objc_implementation_will_become_nonobjc.

NFC except for some minor changes to the wording of notes.
2024-09-20 13:39:44 -07:00
Becca Royal-Gordon
94ec99c7f0 Avoid invalidating @_objcImplementation
In #69257, we modified `ObjCReason` to carry a pointer to the @implementation attribute for the `MemberOfObjCImplementationExtension` kind. This made it mark the @implementation attribute as invalid, suppressing diagnostics from the ObjCImplementationChecker.

However, invalidating the attribute *also* causes it to be skipped by serialization. That isn’t a problem if the diagnostics are errors, since we’ll never emit the serialized module, but #74135 softened these diagnostics to warnings for early adopters.

The upshot was that if Swift emitted one of these warnings when it compiled a library, clients of that library would see the objcImpl extension as a normal extension instead. This would cause various kinds of mischief: ambiguous name lookups because implementations weren’t being excluded, overrides failing because an implementation was `public` instead of `open`, asserts and crashes in SILGen and IRGen because stored properties were found in seemingly normal extensions, etc.

Fix this by setting a separate bit on ObjCImplementationAttr, rather than the invalid bit, and modifying the implementation checker to manually suppress many diagnostics when that bit is set.

Fixes rdar://134730183.
2024-09-05 17:55:12 -07:00
Becca Royal-Gordon
9db14c36ad Require @objc to be used with @implementation
…for extensions. This change also removes @implementation(CategoryName); you should attach the category name to the @objc attribute instead. And there are small changes to how much checking the compiler will do on an @objc @implementation after the decl checker has discovered a problem with it.
2024-05-17 14:57:32 -07:00
Becca Royal-Gordon
858b557762 Tweak @_objcImpl deprecation warning behavior
• Simpler wording
• Now emitted only if there are no other @objcImpl diagnostics (so @implementation would not emit any new errors)
2024-03-27 17:47:22 -07:00
Becca Royal-Gordon
d2e9fb20cb Guard uses of ObjC in objc_implementation.h
Helps allow test/decl/ext/cdecl_implementation.swift to run on non-ObjC platforms.
2024-03-27 14:29:57 -07:00
Becca Royal-Gordon
6438b96577 Fix crash checking objcImpl block property
ObjCImplementationChecker::matchTypes() implicitly assumed that if it was comparing function types, it must be working on an AbstractFunctionDecl. This isn’t true for a property of block type, which could cause crashes when checking their parameter types. Fix this oversight.

Fixes rdar://122280735.
2024-02-15 12:33:06 -08:00
Becca Royal-Gordon
68ec6b68de Support class extensions in objcImpl
Their requirements are now included when typechecking the main body extension, and their conformances are emitted in IRGen.

Fixes rdar://118535473.
2024-02-09 21:32:06 -08:00
Becca Royal-Gordon
e5dbe40367 Stub out basic tests for future extensions
We eventually want to be able to implement functions imported as globals or members in Swift, but we’re not there yet. Add some basic tests to make sure we get reasonable diagnostics for them.
2023-12-13 11:09:50 -08:00
Becca Royal-Gordon
9bd70f3aec Test cImpl type and name mismatches 2023-12-13 11:09:50 -08:00
Becca Royal-Gordon
8651af4325 Make @objcImpl work with @_cdecl
No real diagnostics yet, but we’re emitting mostly correct code.
2023-12-13 11:09:49 -08:00
Becca Royal-Gordon
6b795a493e Diagnose lightweight generic classes with objcImpl
Extensions to lightweight generic classes are such a huge mess that we’re just removing these from the feature’s scope for now.

Fixes rdar://116066409.
2023-10-25 16:20:16 -07:00
Becca Royal-Gordon
81b5d59363 Diagnose root classes with @objcImpl
@objcImpl, like @objc, cannot be used to implement root classes. Diagnose an attempt to do so.

Fixes rdar://109130979.
2023-10-25 16:20:16 -07:00
Becca Royal-Gordon
b69e416f7c Support overrides of unavailable inits in objcImpl
Suppose a superclass declares an initializer unavailable and then a subclass wants to redeclare and use it. Formally, the subclass declaration overrides the superclass one; however, Swift will not actually require the subclass to use the `override` keyword. As currently implemented, this means that the requirement will be skipped as an override, but the candidate will be included as a member implementation. Result: a “candidate does not match any requirement” diagnostic.

Fix this by skipping requirements that are overrides *only* if the declaration they override is not unavailable.

Fixes rdar://109541045.
2023-10-19 15:42:20 -07:00
Becca Royal-Gordon
37e42d178f Handle inherited required inits in @objcImpl
Because `required init`s do not have the `override` keyword, they are always treated as member implementations (if they pass other checks). However, these methods sometimes actually are overrides, and when they are, they should not be treated as member implementations. This results in required inits being treated as candidates when there won’t be a requirement for them to match.

Hack around this by separately checking for this situation and skipping the affected members.

Fixes rdar://112910098.
2023-08-14 11:06:35 -07:00
Becca Royal-Gordon
a8fbad3551 Match @objcImpl members’ foreign error conventions
ClangImporter can import some methods as throwing that `@objc` cannot generate. For instance, an imported Objective-C method with an error out parameter in an unconventional position can still be imported as throwing no matter its selector, but `@objc` can only generate an error out parameter in an unconventional position if the matching selector part consists of the word `error` or (for the first part) ends with `Error`. Detect and diagnose these situations.

Note that the tests do not cover all of the new diagnostics because some of these conditions (like the `Void` parameter) cause selector mismatches and others (like the owned error parameter) are representable in the compiler but cannot currently be imported. I have chosen to add these diagnostics anyway in case there is a corner case that I haven’t discovered.

Fixes rdar://110100071.
2023-06-27 16:08:49 -07:00
Becca Royal-Gordon
49831a9e93 Fix @objcImpl crash with async/sync overloads
The @objcImpl checker would accidentally dereference a null pointer when it tried to check if an async requirement could be satisfied by a non-async method. Fix that mistake.

Fixes rdar://111064481.
2023-06-22 13:15:56 -07:00
Becca Royal-Gordon
1532fb188c Merge pull request #66609 from beccadax/just-empty-protocol
Diagnose conformances on @objcImpl extensions
2023-06-14 14:12:13 -07:00
Becca Royal-Gordon
6758fdb518 Diagnose conformances on @objcImpl extensions
@objcImpl extensions aren’t allowed to declare new conformances; instead, they should either be declared in the header or in an ordinary extensions. (If they were permitted, they’d be ignored.)

Fixes rdar://110669366.
2023-06-13 17:21:44 -07:00
Becca Royal-Gordon
b14c00d521 Support required inits in @objcImpl
• Allow `required init`s in @objcImpl extensions of a class’s main body
• Validate that the presence or absence of a `required` modifier matches the imported header declaration.

Fixes rdar://110016760.
2023-06-01 13:21:02 -07:00
Becca Royal-Gordon
9f0928e239 Match @objcImpl member types
Check the types of @objcImpl candidates against their requirements and diagnose *most* mismatches.

Unlike typical type matching rules, @objcImpl allows an implementation’s parameter *and* result types to be an IUO when the requirement isn’t. This runs against the normal covariance rules in the case of the result type. It’s meant to allow an implementation to handle nils passed to it and return nils even if the declaration formally claims nils are not permitted; this is occasionally necessary to reimplement Objective-C APIs without breaking ABI compatibility.

Fixes rdar://102063730.
2023-05-23 11:34:51 -07:00
Becca Royal-Gordon
2333ff5a20 Diagnose @objcImpl kind and settability errors
Sema now diagnoses @objcImpl implementations with:

• The wrong settability (i.e. a `let` used for a `readwrite` property)
• The wrong kind (i.e. a method used for a property)
2023-05-19 11:48:25 -07:00
Becca Royal-Gordon
00e55cb92d Don’t require @optional ObjC methods in @objcImpl
rdar://108461441
2023-05-03 19:58:45 -07:00
Doug Gregor
79e26970ba Handle async vs. completion-handler mismatches in @_objcImplementation.
Fixes rdar://108160837.
2023-04-18 08:52:20 -07:00
Becca Royal-Gordon
a2f1d357ca Refactor and expand @objcImpl checking
Create a checker for @_objcImplementation member implementations that considers all of a class’s interface and implementation decls at once. This allows us to handle several things better:

• Unimplemented requirements are now diagnosed

• Header members that can match several implementations, or implementations that could match several header members, are now diagnosed

• Tailored diagnostic when the implementation's Swift name matches the header's selector instead of its Swift name

• Recommends inserting `@objc(<selector>)` when a Swift name matches but the implicit ObjC name doesn't

• An `@objc(<selector>)` on one implementation can eliminate its requirement from being considered for other implementations, resolving ambiguities

This does unfortunately regress the diagnostics when a requirement is implemented in the wrong extension. Some sort of whole-module checking would be needed to address this problem.
2023-03-25 14:53:29 -07:00
Becca Royal-Gordon
3bcefc0731 Diagnose objcImpl members with wrong name 2023-03-25 14:52:40 -07:00
Doug Gregor
ef7f707fcc Revert "Improve @objcImplementation member checking" 2023-03-10 12:00:33 -08:00
Becca Royal-Gordon
7f688ef2c1 Refactor and expand @objcImpl checking
Create a checker for @_objcImplementation member implementations that considers all of a class’s interface and implementation decls at once. This allows us to handle several things better:

• Unimplemented requirements are now diagnosed

• Header members that can match several implementations, or implementations that could match several header members, are now diagnosed

• Tailored diagnostic when the implementation's Swift name matches the header's selector instead of its Swift name

• Recommends inserting `@objc(<selector>)` when a Swift name matches but the implicit ObjC name doesn't

• An `@objc(<selector>)` on one implementation can eliminate its requirement from being considered for other implementations, resolving ambiguities

This does unfortunately regress the diagnostics when a requirement is implemented in the wrong extension. Some sort of whole-module checking would be needed to address this problem.
2023-03-03 17:40:48 -08:00
Becca Royal-Gordon
e7c91b2236 Diagnose objcImpl members with wrong name 2023-03-01 09:00:43 -08:00
Becca Royal-Gordon
3e4ea43adf Don’t diagnose @_objcImpl conflicts with inherited inits
Previously, Swift would reject an `override public init(…)` in an `@_objcImplementation` because ClangImporter would have already synthesized inherited initializers that conflicted with the overrides. Ignore these spurious conflicts, and also move a check out of IsObjCRequest and into the conflict-handling code.

Additional work towards rdar://70730077.
2022-10-27 17:00:43 -07:00
Becca Royal-Gordon
75965d0588 Exclude overrides from being member impls
Without this change, an `@_objcImplementation` cannot override parent class methods, because the special access control behavior breaks the access control checks for overrides.
2022-10-27 17:00:43 -07:00
Becca Royal-Gordon
3a2f12a099 Allow stored properties in @_objcImpls
Stored properties are only allowed in the extension implementing the class's main interface, not its categories. This also means banning `@objc final`, which is unenforceable anyway when ObjC subclasses are allowed, and therefore allowing `@objc let` and `@objc static` properties to be overridden if they're declared in objcImplementations.
2022-10-18 17:21:56 -07:00
Becca Royal-Gordon
f2a0ab79c7 Add basic Sema support for @_objcImplementation
Does not validate members yet; nor does it emit different metadata.
2022-10-18 17:21:56 -07:00