Skip to content

Commit 151950d

Browse files
authored
Merge pull request #68930 from jckarter/disable-let-stored-property-destructuring
Disable destructuring initializations in struct `let` stored properties.
2 parents ad10c72 + b4f5369 commit 151950d

File tree

10 files changed

+103
-11
lines changed

10 files changed

+103
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,9 @@ ERROR(pattern_binds_no_variables,none,
21752175
ERROR(variable_bound_by_no_pattern,none,
21762176
"variable %0 is not bound by any pattern",
21772177
(const VarDecl *))
2178+
ERROR(destructuring_let_struct_stored_property_unsupported,none,
2179+
"binding multiple 'let' stored properties from a single initializer expression in a struct is unsupported",
2180+
())
21782181

21792182
WARNING(optional_ambiguous_case_ref,none,
21802183
"assuming you mean '%0.%2'; did you mean '%1.%2' instead?",

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ EXPERIMENTAL_FEATURE(NoncopyableGenerics, false)
242242
/// Enables typed throws.
243243
EXPERIMENTAL_FEATURE(TypedThrows, true)
244244

245+
/// Allow destructuring stored `let` bindings in structs.
246+
EXPERIMENTAL_FEATURE(StructLetDestructuring, true)
247+
245248
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
246249
#undef EXPERIMENTAL_FEATURE
247250
#undef UPCOMING_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3488,6 +3488,26 @@ static bool usesFeatureRawLayout(Decl *decl) {
34883488
return decl->getAttrs().hasAttribute<RawLayoutAttr>();
34893489
}
34903490

3491+
static bool usesFeatureStructLetDestructuring(Decl *decl) {
3492+
auto sd = dyn_cast<StructDecl>(decl);
3493+
if (!sd)
3494+
return false;
3495+
3496+
for (auto member : sd->getStoredProperties()) {
3497+
if (!member->isLet())
3498+
continue;
3499+
3500+
auto init = member->getParentPattern();
3501+
if (!init)
3502+
continue;
3503+
3504+
if (!init->getSingleVar())
3505+
return true;
3506+
}
3507+
3508+
return false;
3509+
}
3510+
34913511
static bool hasParameterPacks(Decl *decl) {
34923512
if (auto genericContext = decl->getAsGenericContext()) {
34933513
auto sig = genericContext->getGenericSignature();

lib/SILGen/SILGenConstructor.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,13 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
470470
.forwardInto(SGF, Loc, init.get());
471471
++elti;
472472
} else {
473+
// TODO: This doesn't correctly take into account destructuring
474+
// pattern bindings on `let`s, for example `let (a, b) = foo()`. In
475+
// cases like that, we ought to evaluate the initializer expression once
476+
// and then do a pattern assignment to the variables in the pattern.
477+
// That case is currently forbidden with an "unsupported" error message
478+
// in Sema.
479+
473480
assert(field->getTypeInContext()->getReferenceStorageReferent()->isEqual(
474481
field->getParentExecutableInitializer()->getType()) &&
475482
"Initialization of field with mismatched type!");
@@ -534,6 +541,13 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
534541
++elti;
535542
} else {
536543
// Otherwise, use its initializer.
544+
// TODO: This doesn't correctly take into account destructuring
545+
// pattern bindings on `let`s, for example `let (a, b) = foo()`. In
546+
// cases like that, we ought to evaluate the initializer expression once
547+
// and then do a pattern assignment to the variables in the pattern.
548+
// That case is currently forbidden with an "unsupported" error message
549+
// in Sema.
550+
537551
assert(field->isParentExecutabledInitialized());
538552
Expr *init = field->getParentExecutableInitializer();
539553

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
882882
if (hadError)
883883
PBD->setInvalid();
884884
PBD->setInitializerChecked(patternNumber);
885+
885886
return hadError;
886887
}
887888

lib/Sema/TypeCheckStorage.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,21 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
567567
: GlobalVariable);
568568
}
569569
}
570+
571+
// If the pattern binding appears as a compound stored `let` property with an
572+
// initializer inside of a struct type, diagnose it as unsupported.
573+
// This hasn't ever been implemented properly.
574+
if (!Context.LangOpts.hasFeature(Feature::StructLetDestructuring)
575+
&& !binding->isStatic()
576+
&& binding->isInitialized(entryNumber)
577+
&& isa<StructDecl>(binding->getDeclContext())
578+
&& !pattern->getSingleVar()
579+
&& !vars.empty()
580+
&& vars[0]->isLet()) {
581+
Context.Diags.diagnose(binding->getPattern(entryNumber)->getLoc(),
582+
diag::destructuring_let_struct_stored_property_unsupported);
583+
}
584+
570585
return &pbe;
571586
}
572587

test/ModuleInterface/stored-properties-client.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
// 1. Build ../stored-properties.swift to a dylib and emit its interface in %t
66

7-
// RUN: %target-build-swift-dylib(%t/%target-library-name(StoredProperties)) -emit-module-interface-path %t/StoredProperties.swiftinterface %S/stored-properties.swift -module-name StoredProperties -swift-version 5
7+
// RUN: %target-build-swift-dylib(%t/%target-library-name(StoredProperties)) -enable-experimental-feature StructLetDestructuring -emit-module-interface-path %t/StoredProperties.swiftinterface %S/stored-properties.swift -module-name StoredProperties -swift-version 5
88
// RUN: %target-swift-typecheck-module-from-interface(%t/StoredProperties.swiftinterface) -module-name StoredProperties
99

1010
// 2. Build this file and link with StoredProperties
1111

12-
// RUN: %target-build-swift %s -I %t -L %t -lStoredProperties -o %t/stored-properties-client %target-rpath(%t)
12+
// RUN: %target-build-swift -enable-experimental-feature StructLetDestructuring %s -I %t -L %t -lStoredProperties -o %t/stored-properties-client %target-rpath(%t)
1313

1414
// 3. Codesign and run this, and ensure it exits successfully.
1515

@@ -20,9 +20,9 @@
2020

2121
// RUN: %empty-directory(%t)
2222

23-
// RUN: %target-build-swift-dylib(%t/%target-library-name(StoredProperties)) -emit-module-interface-path %t/StoredProperties.swiftinterface %S/stored-properties.swift -module-name StoredProperties -swift-version 5 -enable-library-evolution
23+
// RUN: %target-build-swift-dylib(%t/%target-library-name(StoredProperties)) -enable-experimental-feature StructLetDestructuring -emit-module-interface-path %t/StoredProperties.swiftinterface %S/stored-properties.swift -module-name StoredProperties -swift-version 5 -enable-library-evolution
2424

25-
// RUN: %target-build-swift %s -I %t -L %t -lStoredProperties -o %t/stored-properties-client %target-rpath(%t)
25+
// RUN: %target-build-swift -enable-experimental-feature StructLetDestructuring %s -I %t -L %t -lStoredProperties -o %t/stored-properties-client %target-rpath(%t)
2626
// RUN: %target-codesign %t/stored-properties-client %t/%target-library-name(StoredProperties)
2727
// RUN: %target-run %t/stored-properties-client %t/%target-library-name(StoredProperties)
2828

test/ModuleInterface/stored-properties.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t.swiftinterface -module-name StoredProperties %s
3+
// RUN: %target-swift-frontend -enable-experimental-feature StructLetDestructuring -typecheck -emit-module-interface-path %t.swiftinterface -module-name StoredProperties %s
44
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name StoredProperties
55
// RUN: %FileCheck %s < %t.swiftinterface --check-prefix CHECK --check-prefix COMMON
66

7-
// RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t-resilient.swiftinterface -module-name StoredProperties -enable-library-evolution %s
7+
// RUN: %target-swift-frontend -enable-experimental-feature StructLetDestructuring -typecheck -emit-module-interface-path %t-resilient.swiftinterface -module-name StoredProperties -enable-library-evolution %s
88
// RUN: %target-swift-typecheck-module-from-interface(%t-resilient.swiftinterface) -module-name StoredProperties
99
// RUN: %FileCheck %s < %t-resilient.swiftinterface --check-prefix RESILIENT --check-prefix COMMON
1010

11-
// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule -module-name StoredProperties %t.swiftinterface -disable-objc-attr-requires-foundation-module
12-
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -module-name StoredProperties -emit-module-interface-path - | %FileCheck %s --check-prefix CHECK --check-prefix COMMON
11+
// RUN: %target-swift-frontend -enable-experimental-feature StructLetDestructuring -emit-module -o %t/Test.swiftmodule -module-name StoredProperties %t.swiftinterface -disable-objc-attr-requires-foundation-module
12+
// RUN: %target-swift-frontend -enable-experimental-feature StructLetDestructuring -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -module-name StoredProperties -emit-module-interface-path - | %FileCheck %s --check-prefix CHECK --check-prefix COMMON
1313

14-
// RUN: %target-swift-frontend -emit-module -o %t/TestResilient.swiftmodule -module-name StoredProperties -enable-library-evolution %t-resilient.swiftinterface -disable-objc-attr-requires-foundation-module
15-
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/TestResilient.swiftmodule -module-name StoredProperties -enable-library-evolution -emit-module-interface-path - | %FileCheck %s --check-prefix RESILIENT --check-prefix COMMON
14+
// RUN: %target-swift-frontend -enable-experimental-feature StructLetDestructuring -emit-module -o %t/TestResilient.swiftmodule -module-name StoredProperties -enable-library-evolution %t-resilient.swiftinterface -disable-objc-attr-requires-foundation-module
15+
// RUN: %target-swift-frontend -enable-experimental-feature StructLetDestructuring -emit-module -o /dev/null -merge-modules %t/TestResilient.swiftmodule -module-name StoredProperties -enable-library-evolution -emit-module-interface-path - | %FileCheck %s --check-prefix RESILIENT --check-prefix COMMON
1616

1717
// COMMON: public struct HasStoredProperties {
1818
public struct HasStoredProperties {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-swift-frontend -typecheck -verify %s
2+
3+
// https://github.com/apple/swift/issues/68915
4+
// Destructuring initializations for `let` properties in structs isn't
5+
// implemented correctly in SILGen, so diagnose it as unsupported for now.
6+
7+
struct Foo {
8+
var value: Int = 42
9+
10+
let (aaa, bbb) = ("aaa", "bbb") // expected-error{{unsupported}}
11+
12+
let (z1, z2, z3) = ("one", 1, Double.pi) // expected-error{{unsupported}}
13+
14+
15+
func tellMe() {
16+
print(foo.aaa)
17+
print(foo.bbb) // output: aaa
18+
19+
20+
assert(aaa == "aaa")
21+
assert(bbb == "bbb", "bbb should be bbb but it's \(bbb)")
22+
}
23+
24+
}
25+
26+
27+
let foo = Foo(/*value: 1*/)
28+
29+
30+
foo.tellMe()
31+
32+
33+
34+
35+
print("Hello")

test/decl/var/properties.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,8 @@ _ = r19874152S5() // ok
12151215

12161216

12171217
struct r19874152S6 {
1218-
let (a,b) = (1,2) // Cannot handle implicit synth of this yet.
1218+
// Cannot handle implicit synth of this yet.
1219+
let (a,b) = (1,2) // expected-error {{unsupported}}
12191220
}
12201221
_ = r19874152S5() // ok
12211222

0 commit comments

Comments
 (0)