mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Sema] TypeWrappers: convert variable init expr into initializer default
All of the stored properties are wrapped which means that their initializers are subsummed and moved to the synthesized `init` as default arguments.
This commit is contained in:
@@ -188,6 +188,28 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
|
||||
arg->setDefaultArgumentKind(DefaultArgumentKind::StoredProperty);
|
||||
}
|
||||
|
||||
static void maybeAddTypeWrapperDefaultArg(ParamDecl *arg, VarDecl *var,
|
||||
ASTContext &ctx) {
|
||||
assert(var->isAccessedViaTypeWrapper());
|
||||
|
||||
if (!var->getParentPattern()->getSingleVar())
|
||||
return;
|
||||
|
||||
auto *PBD = var->getParentPatternBinding();
|
||||
|
||||
auto *initExpr = PBD->getInit(/*index=*/0);
|
||||
if (!initExpr)
|
||||
return;
|
||||
|
||||
// Type wrapper variables are never initialized directly,
|
||||
// initialization expression (if any) becomes an default
|
||||
// argument of the initializer synthesized by the type wrapper.
|
||||
PBD->setInitializerSubsumed(/*index=*/0);
|
||||
|
||||
arg->setDefaultExpr(initExpr, /*isTypeChecked=*/false);
|
||||
arg->setDefaultArgumentKind(DefaultArgumentKind::Normal);
|
||||
}
|
||||
|
||||
/// Describes the kind of implicit constructor that will be
|
||||
/// generated.
|
||||
enum class ImplicitConstructorKind {
|
||||
@@ -339,6 +361,8 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
|
||||
arg->setInterfaceType(var->getValueInterfaceType());
|
||||
arg->setImplicit();
|
||||
|
||||
maybeAddTypeWrapperDefaultArg(arg, var, ctx);
|
||||
|
||||
params.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,9 @@ public class Person<T> {
|
||||
public var name: String
|
||||
public var projects: [T]
|
||||
}
|
||||
|
||||
@Wrapper
|
||||
public struct PersonWithDefaults {
|
||||
public var name: String = "<no name>"
|
||||
public var age: Int = 99
|
||||
}
|
||||
|
||||
@@ -37,3 +37,48 @@ print(p.name)
|
||||
print(p.projects)
|
||||
// CHECK: in getter
|
||||
// CHECK-NEXT: ["A", "B", "C", "D"]
|
||||
|
||||
var pDefaults = PersonWithDefaults()
|
||||
// CHECK: Wrapper.init($Storage(name: "<no name>", age: 99))
|
||||
|
||||
print(pDefaults.name)
|
||||
// CHECK: in getter
|
||||
// CHECK: <no name>
|
||||
|
||||
print(pDefaults.age)
|
||||
// CHECK: in getter
|
||||
// CHECK: 99
|
||||
|
||||
pDefaults.name = "Actual Name"
|
||||
// CHECK-NEXT: in setter => Actual Name
|
||||
|
||||
pDefaults.age = 0
|
||||
// CHECK-NEXT: in setter => 0
|
||||
|
||||
print(pDefaults.name)
|
||||
// CHECK: in getter
|
||||
// CHECK: Actual Name
|
||||
|
||||
print(pDefaults.age)
|
||||
// CHECK: in getter
|
||||
// CHECK: 0
|
||||
|
||||
let pDefaultsAge = PersonWithDefaults(name: "Actual Name")
|
||||
|
||||
print(pDefaultsAge.name)
|
||||
// CHECK: in getter
|
||||
// CHECK: Actual Name
|
||||
|
||||
print(pDefaultsAge.age)
|
||||
// CHECK: in getter
|
||||
// CHECK: 99
|
||||
|
||||
let pDefaultsName = PersonWithDefaults(age: 31337)
|
||||
|
||||
print(pDefaultsName.name)
|
||||
// CHECK: in getter
|
||||
// CHECK: <no name>
|
||||
|
||||
print(pDefaultsName.age)
|
||||
// CHECK: in getter
|
||||
// CHECK: 31337
|
||||
|
||||
@@ -147,3 +147,18 @@ func testLocalWithNestedWrapper() {
|
||||
_ = t.test // Ok
|
||||
_ = t.computed // Ok
|
||||
}
|
||||
|
||||
func testTypeWrapperWithDefaults() {
|
||||
@NoopWrapper
|
||||
struct A {
|
||||
var question: String = "Ultimate Question"
|
||||
var answer: Int = 42
|
||||
}
|
||||
|
||||
let a = A()
|
||||
_ = a.question
|
||||
_ = a.answer
|
||||
|
||||
_ = A(question: "")
|
||||
_ = A(answer: 0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user