From 3394616e6fe3f8d1c4e10b61d8de427f860e5703 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 14 Jun 2019 16:50:26 -0700 Subject: [PATCH 1/2] [Sema] Always create memberwise init when deriving `AdditiveArithmetic`. Previously, during `AdditiveArithmetic` derived conformances, memberwise initializers were synthesized only when synthesizing `static var zero`. This led to a crash for types that specified `static var zero` but not other requirements. Resolves TF-579. --- .../DerivedConformanceAdditiveArithmetic.cpp | 26 ++++++++++++------- test/Sema/struct_additive_arithmetic.swift | 7 +++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp index e5d38c28d892c..bdb730f2a03ef 100644 --- a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp +++ b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp @@ -61,6 +61,20 @@ static ValueDecl *getProtocolRequirement(ProtocolDecl *proto, Identifier name) { return lookup.front(); } +// Get the effective memberwise initializer of the given nominal type, or create +// it if it does not exist. +static ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer( + TypeChecker &TC, NominalTypeDecl *nominal) { + auto &C = nominal->getASTContext(); + if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer()) + return initDecl; + auto *initDecl = createImplicitConstructor( + TC, nominal, ImplicitConstructorKind::Memberwise); + nominal->addMember(initDecl); + C.addSynthesizedDecl(initDecl); + return initDecl; +} + // Return true if given nominal type has a `let` stored with an initial value. static bool hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal) { return llvm::any_of(nominal->getStoredProperties(), [&](VarDecl *v) { @@ -302,16 +316,6 @@ static ValueDecl *deriveAdditiveArithmetic_zero(DerivedConformance &derived) { auto &TC = derived.TC; auto &C = TC.Context; - // The implicit memberwise constructor must be explicitly created so that it - // can called when synthesizing the `zero` property getter. Normally, the - // memberwise constructor is synthesized during SILGen, which is too late. - if (!nominal->getEffectiveMemberwiseInitializer()) { - auto *initDecl = createImplicitConstructor( - TC, nominal, ImplicitConstructorKind::Memberwise); - nominal->addMember(initDecl); - C.addSynthesizedDecl(initDecl); - } - auto returnInterfaceTy = nominal->getDeclaredInterfaceType(); auto returnTy = parentDC->mapTypeIntoContext(returnInterfaceTy); @@ -338,6 +342,8 @@ DerivedConformance::deriveAdditiveArithmetic(ValueDecl *requirement) { // Diagnose conformances in disallowed contexts. if (checkAndDiagnoseDisallowedContext(requirement)) return nullptr; + // Create memberwise initializer for nominal type if it doesn't already exist. + getOrCreateEffectiveMemberwiseInitializer(TC, Nominal); if (requirement->getBaseName() == TC.Context.getIdentifier("+")) return deriveMathOperator(*this, Add); if (requirement->getBaseName() == TC.Context.getIdentifier("-")) diff --git a/test/Sema/struct_additive_arithmetic.swift b/test/Sema/struct_additive_arithmetic.swift index 31ff16727734a..cdc8bd0a494dc 100644 --- a/test/Sema/struct_additive_arithmetic.swift +++ b/test/Sema/struct_additive_arithmetic.swift @@ -91,6 +91,13 @@ struct NoMemberwiseInitializer : AdditiveArithmetic { var value: T init(randomLabel value: T) { self.value = value } } +struct NoMemberwiseInitializerCustomZero: AdditiveArithmetic { + var x: Float + static var zero: Self { return NoMemberwiseInitializerCustomZero(0) } + init(_ x: Float) { + self.x = x + } +} struct NoMemberwiseInitializerExtended { var value: T init(_ value: T) { From 6d1a4464925e166c0b7e4bd73b3fc2144b56e9b4 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 14 Jun 2019 17:13:31 -0700 Subject: [PATCH 2/2] Address review feedback. Co-Authored-By: Richard Wei --- lib/Sema/DerivedConformanceAdditiveArithmetic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp index bdb730f2a03ef..6974aca531492 100644 --- a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp +++ b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp @@ -64,7 +64,7 @@ static ValueDecl *getProtocolRequirement(ProtocolDecl *proto, Identifier name) { // Get the effective memberwise initializer of the given nominal type, or create // it if it does not exist. static ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer( - TypeChecker &TC, NominalTypeDecl *nominal) { + TypeChecker &TC, NominalTypeDecl *nominal) { auto &C = nominal->getASTContext(); if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer()) return initDecl;