**Overview**:
This PR introduces the basic infrastructure needed to eventually migrate
derived macros generation from hand-crafted AST nodes to macros. No
conformance have been migrated yet.
**Motivation**:
Derived conformances (e.g. `Equatable`, `Hashable`, `Codable`, ...) are
currently implemented as a special case in the compiler, producing
synthetic AST nodes directly. Migrating this to macros will hopefully
unify the code path with the existing macro expansion infrastructure,
make conformance synthesis easier to extend and test as well as reducing
the amount of special cases in the compiler.
**Changes**:
- New experimental feature flag `DeriveConformancesViaMacros`:
Introduces the flag that will eventually gate the new derived
conformance code paths. It does not control any behaviour for the moment
as none have been migrated yet but this enables future changes to be
built incrementally.
- New GeneratedSourceInfo and SourceFile kinds `SyntheticMacro`:
Introduces new GSI and SourceFile kinds named `SyntheticMacro` to
represent macros synthesized by the compiler. Since macros need a real
buffer to expand, this is the kind of source file and GSI associated
with those buffers.
- Conformance derivation via macros API:
Introduces the `deriveRequirementViaMacro` function that produces the
required witness via macro expansion.
See https://github.com/swiftlang/llvm-project/pull/13124 for
llvm-related changes.
**Next steps**:
- Macros do not contain any semantic information, especially regarding
types. Therefore it is necessary to provide them with type information
as an argument so they can eventually derive the conformances. A
separate PR is being created to generate this type information as
strings containing swift-parsable code for easy parsing on the macro
end.
- Implement derived conformance synthesis for individual protocols using
the new infrastructure, like `Equatable` or `Hashable` for starters.
- Wire the experimental flag to gate the new path once an implementation
exists
---------
Co-authored-by: Hamish Knight <hamish_knight@apple.com>
### **Explanation:**
When a property wrapper's initializer references the enclosing type's
CodingKeys enum (e.g. @Wrapper(key: CodingKeys.bar)), the compiler
enters a dependency cycle: StoredPropertiesRequest →
PropertyWrapperBackingPropertyTypeRequest → ResolveImplicitMemberRequest
(resolve CodingKeys) → ResolveValueWitnessesRequest (Codable
conformance) → StoredPropertiesRequest (cycle).
### **Scope:**
Codable synthesis, property wrappers
### **Issues:**
Fixes#88459
### **Original PRs:**
N/A
### **Risk:**
Low. The change only affects the ResolveCodingKeys path in
ResolveImplicitMemberRequest and is guarded by two conditions: (1)
StoredPropertiesRequest must be active for the same type, and (2) the
user must have explicitly defined a CodingKeys enum. All 74 existing
Codable synthesis tests pass.
### **Testing:**
Added
test/decl/protocol/special/coding/struct_codable_property_wrapper_codingkeys.swift
with 5 test cases: simple wrappers with CodingKeys, custom key mappings,
mixed wrapped/unwrapped properties, Decodable-only, Encodable-only. All
74 Codable tests pass. Runtime encode/decode verified.
### **Reviewers:**
This commit adds a check for the '@concurrent' attribute as part
of hasExplicitIsolationAttribute. Concurrent is an isolation
attribute, so we should consider it for this check. This change
should not change behavior in any existing consumer, since a
concurrent function is already an async function; it's only used in
contextRequiresStrictConcurrencyChecking, which will also return true
for async function. However, I was surprised this check didn't include
@concurrent when I tried to use it for file-level default isolation, and
I think leaving it like this could lead to a bug in the future?
The test added by this commit would pass without this change, since the
function is also async.
The initializer of a 'lazy' stored property is type-checked as 'nonisolated'
even when the property (and its enclosing context) is actor-isolated, because
getActorIsolationOfContext reports the lazy var's PatternBindingInitializer as
having unspecified isolation. Closures in the initializer therefore inherit
nonisolated isolation, and region-based isolation flags calls inside them as
crossing into the actor, emitting spurious cross-isolation data-race
diagnostics, e.g.:
@MainActor class Picker {
var variants: [AnyObject] = []
lazy var allViews = variants.map { item in process(item) } // spurious warning
func process(_ item: AnyObject) -> Int { 0 }
}
Unlike an ordinary stored-property default value -- whose required isolation is
computed and validated separately, and is intentionally reported as unspecified
here (e.g. under IsolatedDefaultValues) -- a 'lazy' property's initializer is
emitted into the property's synthesized getter, which is isolated to the
property. The initializer, and any closures within it, genuinely run with the
lazy variable's actor isolation.
Fix getActorIsolationOfContext to report a lazy var's initializer context as
isolated to the lazy variable (when the variable is actor-isolated). The
existing closure-isolation machinery (determineClosureIsolation /
computeClosureIsolationFromParent) then makes the initializer's closures inherit
that isolation, including nested and immediately-invoked ('{ ... }()') closures.
Closures that are isolation inference boundaries -- '@Sendable' closures or
closures passed to a 'sending' parameter -- still do not inherit, because that
check runs before the parent isolation is applied; so a lazy initializer now
behaves exactly like an equivalent computed-property getter.
A regression test verifies the isolation of the initializer's closures across
classes/structs, final/non-final, MainActor and a custom global actor,
property-only isolation, explicit type annotations, IIFE/nested closures, and
the '@Sendable' / 'sending' boundary cases.
rdar://178533556
When `MemberImportVisibility` upcoming feature is enabled, the typechecker tries to determine the owning module of C/C++ macros used in Swift.
That logic didn't handle bridging headers correctly, and triggered an assertion failure:
```
Assertion failed: (Node.getAsMacroInfo()), function getClangOwningModule, file ClangImporter.cpp, line 3612.
```
rdar://178264720
`getAccessScopeForFormalAccess` walks a declaration's own DeclContext
chain to find enclosing types whose formal access should restrict its
own. For a member declared in an extension, that chain steps directly
from the extension to file scope, so any types enclosing the extended
nominal were silently skipped. As a result, members of an extension of
a nested type were treated as having the formal access of the
immediately extended type, ignoring the types that contain it.
For example, the public method below was treated as truly public, even
though `Outer` is internal and so the effective access of any member
of an extension of `Inner` is internal:
```
struct Outer {
public struct Inner { }
}
internal struct InternalType { }
extension Outer.Inner {
public func f(x: InternalType) { }
}
```
This incorrect access scope could cause a range of misbehavior, from
spurious access-control diagnostics to incorrect SIL linkage decisions.
Refactor the walk to use a helper that handles nominals and extensions
uniformly, and have the extension branch chain through into the
extended nominal's enclosing types. Don't redirect `resultDC` itself,
since `fileprivate` and `private` scopes must continue to resolve to
the file containing the declaration, which may differ from the file
containing the extended type.
Resolves rdar://150448686.
Somehow we had missed this restriction before, but it's crucial to
prevent IR generation from trying to emit unspecialized generics.
Fixes rdar://177755296.
Just like we do with SILFunction, allow a code generation model to be
specified on a SILGlobalVariable and maintain that through the printed
and serialized forms.
The code generation model for a particular declaration or conformance
can be defined explicitly with `@export(interface)`,
`@export(implementation)`, or `@inlinable` (for declarations),
indicating where the definition will occur.
Embedded Swift also has some limitations on what can be emitted into
IR. For example, a generic function cannot be `@export(interface)`
because Embedded Swift does not support unspecialized generics.
Compute the effective code generation model based on what was
explicitly specified, the limitations of the model, and the default
code generation model for the given module, which defaults to
"inlinable" but can be made "implementation" by the DeferredCodeGen
feature. Use the effective code generation model for IR- and SIL-level
determinations of linkage and where to emit symbols.
[WIP] Start computing and using the "effective" code generation model
FIXUP linkage of the alias symbol
Adds a new DynamicMemberLookupSubscriptRequest type for evaluating and
caching the validity of a `SubscriptDecl`'s usage to fulfill a
`@dynamicMemberLookup` requirement for a specific usage.
`SubscriptDecl`s may get checked multiple times for eligibility in
fulfilling `@dynamicMemberLookup` requirements; since the checks are
non-trivial and the result doesn't change, this eligibility can be
cached in the decl's `Bits`.
Pending swift evolution discussion: https://github.com/swiftlang/swift-evolution/pull/3133
replaces #87171
update new error message according to proposal
also handle untyped throws in _nonDiscardableWhenThrowing attr
Rename the internal attr _nonDiscardableWhenThrowingOperation
A fileprivate access scope should always be rooted in the outermost
SourceFile since macros do not introduce their own file access scopes.
rdar://174872704
For a given function, we might end up emitting it's definition as
object code, serialized SIL, or both. The @export, @inlinable, and
@inline(always) attributes provide control of this behavior at the
declaration level.
Centralize the query function that will look for each of these
attributes and map down to a specific "code generation model", whose 3
options follow the naming from SE-0497: interface, inlinable, and
implementation. Use this one computation to back the queries for
"always emit into client", "never emit into client", and "inlinable"
so we can't get inconsistent results from places that are doing
one-off checks for these attributes.
Back in January, I updated the swiftinterface _reading_ code to accept either
`read`/`modify` or `yielding borrow`/`yielding mutate`. That update has been
around for long enough that we can now switch over the swiftinterface _writing_
code to emit the standard final `yielding borrow`/`yielding mutate` spellings.
Interface files written with the old spellings will continue to be
accepted for some time (likely a year or more).
When hiding dependencies in embedded mode there are special rules for
classes. Classes properties can safely reference the hidden
dependencies, however code referencing these properties must be marked
`@export(interface)`.
We previously added a check to report implicit code without the requited
`@export(interface)`. However explicit references from user written code
wasn't fully checked, only explicit references to the imported type or
the type's services would be reported, not references to the property
itself.
We patch that hole here by introducing new requirements and a new layer
of check specific to class properies in embedded mode.
---
Class properties referencing a hidden dependency must be marked
`@_implementationOnly`. This adds on top of the requirement for the
class itself to have an explicit `@export(interface) deinit`.
This allows to report references from user written code using existing
diagnostics.
Without library-evolution we can be more permissive about references to
hidden dependencies from classes properties. However, lifting these
checks broke other checks on properties. Here we fix this hole and
ensure that while we allow references from stored properties we still
checking implicit initializers.
rdar://173011223
Even without library-evolution, we allow references to hidden
dependencies from class properties as long as the class is not marked
open. In embedded, references from functions are only accepted when
marked `@export(interface)` as it can't be inlined in clients.
Combine both requirements to protect the implicitly generated destructor
as well. Add a requirement for classes with such a property to
explicitly declare a `@export(interface)` deinit. Otherwise that deinit
may be inlined in clients and cause a deserialization failure.
rdar://170855491