Skip to content

[Property wrappers] Fix crash due to wrapped type/wrapper type confusion #28589

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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5102,16 +5102,16 @@ class VarDecl : public AbstractStorageDecl {
/// Retrieve the backing storage property for a lazy property.
VarDecl *getLazyStorageProperty() const;

/// Whether this is a property with a property wrapper that was initialized
/// via a value of the original type, e.g.,
/// Whether the memberwise initializer parameter for a property with a
/// property wrapper type uses the wrapped type. This will occur, for example,
/// when there is an explicitly-specified initializer like:
///
/// \code
/// @Lazy var i = 17
/// \end
bool isPropertyWrapperInitializedWithInitialValue() const;

/// Whether the memberwise initializer parameter for a property with a property wrapper type
/// uses the wrapped type.
///
/// Or when there is no initializer but each composed property wrapper has
/// a suitable `init(initialValue:)`.
bool isPropertyMemberwiseInitializedWithWrappedType() const;

/// If this property is the backing storage for a property with an attached
Expand Down
24 changes: 6 additions & 18 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5807,13 +5807,12 @@ VarDecl *VarDecl::getLazyStorageProperty() const {
{});
}

static bool propertyWrapperInitializedViaInitialValue(
const VarDecl *var, bool checkDefaultInit) {
auto customAttrs = var->getAttachedPropertyWrappers();
bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const {
auto customAttrs = getAttachedPropertyWrappers();
if (customAttrs.empty())
return false;

auto *PBD = var->getParentPatternBinding();
auto *PBD = getParentPatternBinding();
if (!PBD)
return false;

Expand All @@ -5828,23 +5827,12 @@ static bool propertyWrapperInitializedViaInitialValue(
return false;

// Default initialization does not use a value.
if (checkDefaultInit &&
var->getAttachedPropertyWrapperTypeInfo(0).defaultInit)
if (getAttachedPropertyWrapperTypeInfo(0).defaultInit)
return false;

// If all property wrappers have an initialValue initializer, the property
// If all property wrappers have a wrappedValue initializer, the property
// wrapper will be initialized that way.
return var->allAttachedPropertyWrappersHaveInitialValueInit();
}

bool VarDecl::isPropertyWrapperInitializedWithInitialValue() const {
return propertyWrapperInitializedViaInitialValue(
this, /*checkDefaultInit=*/true);
}

bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const {
return propertyWrapperInitializedViaInitialValue(
this, /*checkDefaultInit=*/false);
return allAttachedPropertyWrappersHaveInitialValueInit();
}

Identifier VarDecl::getObjCPropertyName() const {
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1887,7 +1887,7 @@ static CanAnyFunctionType getStoredPropertyInitializerInterfaceType(
// wrapper that was initialized with '=', the stored property initializer
// will be in terms of the original property's type.
if (auto originalProperty = VD->getOriginalWrappedProperty()) {
if (originalProperty->isPropertyWrapperInitializedWithInitialValue())
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType())
resultTy = originalProperty->getValueInterfaceType()->getCanonicalType();
}

Expand Down
4 changes: 2 additions & 2 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,8 +1115,8 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
->isPropertyMemberwiseInitializedWithWrappedType()) {
auto wrapperInfo =
originalProperty->getPropertyWrapperBackingPropertyInfo();
if (wrapperInfo.originalInitialValue)
init = wrapperInfo.originalInitialValue;
assert(wrapperInfo.originalInitialValue);
init = wrapperInfo.originalInitialValue;
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/SILGen/SILGenConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ static Type getInitializationTypeInContext(
// initialization type is the original property type.
if (auto singleVar = pattern->getSingleVar()) {
if (auto originalProperty = singleVar->getOriginalWrappedProperty()) {
if (originalProperty->isPropertyWrapperInitializedWithInitialValue())
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType())
interfaceType = originalProperty->getValueInterfaceType();
}
}
Expand Down Expand Up @@ -968,7 +968,7 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc,
if (auto singleVar = pbd->getSingleVar()) {
auto originalVar = singleVar->getOriginalWrappedProperty();
if (originalVar &&
originalVar->isPropertyWrapperInitializedWithInitialValue()) {
originalVar->isPropertyMemberwiseInitializedWithWrappedType()) {
result = maybeEmitPropertyWrapperInitFromValue(
*this, init, singleVar, std::move(result));
}
Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) {
// wrapper that was initialized with '=', the stored property initializer
// will be in terms of the original property's type.
if (auto originalProperty = var->getOriginalWrappedProperty()) {
if (originalProperty->isPropertyWrapperInitializedWithInitialValue()) {
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType()) {
interfaceType = originalProperty->getValueInterfaceType();
varType = originalProperty->getType();
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
var->getAttrs().hasAttribute<LazyAttr>() ||
(!isExplicitlyInitialized && isDefaultInitializable &&
var->getValueInterfaceType()->getAnyNominal() == ctx.getOptionalDecl() &&
!var->getAttachedPropertyWrapperTypeInfo(0).defaultInit);
(var->getAttachedPropertyWrappers().empty() ||
var->isPropertyMemberwiseInitializedWithWrappedType()));
if (isNilInitialized) {
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
return;
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/print_property_wrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct HasWrappers {
var z: String

// Memberwise initializer.
// CHECK: init(x: Wrapper<Int> = Wrapper(closure: foo), y: Bool = true, z: String = Wrapper())
// CHECK: init(x: Wrapper<Int> = Wrapper(closure: foo), y: Bool = true, z: Wrapper<String> = Wrapper())
}

func trigger() {
Expand Down
29 changes: 29 additions & 0 deletions test/SILGen/property_wrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,35 @@ struct SR_11603 {
}
}

// rdar://problem/57545381 - crash due to inconsistent decision about whether
// to initialize a wrapper property with an instance of the wrapper type vs.
// the wrapped type.
@propertyWrapper
class WrappedInt {
var intValue: Int?

var wrappedValue: Int? {
get {
return intValue
}
set {
intValue = newValue
}
}

init() { }

init(wrappedValue: Int?) {
self.wrappedValue = wrappedValue
}
}

struct WrappedIntContainer {
// CHECK: sil hidden [ossa] @$s17property_wrappers19WrappedIntContainerV3intAcA0cD0C_tcfcfA_ : $@convention(thin) () -> @owned WrappedInt
@WrappedInt var int: Int?
}


// CHECK-LABEL: sil_vtable ClassUsingWrapper {
// CHECK-NEXT: #ClassUsingWrapper.x!getter.1: (ClassUsingWrapper) -> () -> Int : @$s17property_wrappers17ClassUsingWrapperC1xSivg // ClassUsingWrapper.x.getter
// CHECK-NEXT: #ClassUsingWrapper.x!setter.1: (ClassUsingWrapper) -> (Int) -> () : @$s17property_wrappers17ClassUsingWrapperC1xSivs // ClassUsingWrapper.x.setter
Expand Down