Skip to content

Commit 0fe28ea

Browse files
committed
Fix witness substitution computation for property behaviors.
My recent refactoring of witnesses in Sema and the AST disabled a test for property behaviors, because they were no longer handling substitutions correctly. Introduce a type checker entrypoint to record information about a known witness, using the normal witness-matching logic rather than trying to synthesize the correct answer (and getting it wrong). Note that I had to manually introduce some type witnesses to get the property behavior tests passing, because the property-behavior code is (intentionally) not introducing implicit typealiases for the type witnesses it synthesized. The old witness-synthesizing code worked around this issue, but the new code does not. A different fix is in the works (i.e., better handling of type witnesses in the constraint solver), so we'll take this temporary regression in an experimental feature.
1 parent 4d05096 commit 0fe28ea

File tree

9 files changed

+85
-17
lines changed

9 files changed

+85
-17
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,8 @@ ERROR(property_behavior_invalid_parameter,none,
19031903
"parameter expression provided, but property behavior %0 does not "
19041904
"use it",
19051905
(Identifier))
1906+
ERROR(property_behavior_conformance_broken,none,
1907+
"property behavior for %0 in type %1 is broken", (DeclName, Type))
19061908

19071909
//------------------------------------------------------------------------------
19081910
// Type Check Attributes

lib/Sema/CodeSynthesis.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,15 +1270,17 @@ void TypeChecker::completePropertyBehaviorStorage(VarDecl *VD,
12701270
// Add accessors to the storage, since we'll need them to satisfy the
12711271
// conformance requirements.
12721272
addTrivialAccessorsToStorage(Storage, *this);
1273-
1273+
1274+
// FIXME: Hack to eliminate spurious diagnostics.
1275+
if (BehaviorStorage->isStatic() != Storage->isStatic()) return;
1276+
12741277
// Add the witnesses to the conformance.
1275-
// FIXME: Dropping substitution.
1276-
BehaviorConformance->setWitness(BehaviorStorage, Storage);
1277-
BehaviorConformance->setWitness(BehaviorStorage->getGetter(),
1278-
Storage->getGetter());
1278+
recordKnownWitness(BehaviorConformance, BehaviorStorage, Storage);
1279+
recordKnownWitness(BehaviorConformance, BehaviorStorage->getGetter(),
1280+
Storage->getGetter());
12791281
if (BehaviorStorage->isSettable(DC))
1280-
BehaviorConformance->setWitness(BehaviorStorage->getSetter(),
1281-
Storage->getSetter());
1282+
recordKnownWitness(BehaviorConformance, BehaviorStorage->getSetter(),
1283+
Storage->getSetter());
12821284
}
12831285

12841286
void TypeChecker::completePropertyBehaviorParameter(VarDecl *VD,
@@ -1433,8 +1435,7 @@ void TypeChecker::completePropertyBehaviorParameter(VarDecl *VD,
14331435
addMemberToContextIfNeeded(Parameter, DC);
14341436

14351437
// Add the witnesses to the conformance.
1436-
// FIXME: Should compute substitutions.
1437-
BehaviorConformance->setWitness(BehaviorParameter, Parameter);
1438+
recordKnownWitness(BehaviorConformance, BehaviorParameter, Parameter);
14381439
}
14391440

14401441
void TypeChecker::completePropertyBehaviorAccessors(VarDecl *VD,

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5436,3 +5436,18 @@ bool TypeChecker::isProtocolExtensionUsable(DeclContext *dc, Type type,
54365436
return cs.solveSingle().hasValue();
54375437
}
54385438

5439+
void TypeChecker::recordKnownWitness(NormalProtocolConformance *conformance,
5440+
ValueDecl *req, ValueDecl *witness) {
5441+
// Match the witness. This should never fail, but it does allow renaming
5442+
// (because property behaviors rely on renaming).
5443+
auto match = matchWitness(*this, conformance->getProtocol(), conformance,
5444+
conformance->getDeclContext(), req, witness);
5445+
if (match.Kind != MatchKind::ExactMatch &&
5446+
match.Kind != MatchKind::RenamedMatch) {
5447+
diagnose(witness, diag::property_behavior_conformance_broken,
5448+
witness->getFullName(), conformance->getType());
5449+
return;
5450+
}
5451+
5452+
conformance->setWitness(req, match.getWitness(Context));
5453+
}

lib/Sema/TypeChecker.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,15 @@ class TypeChecker final : public LazyResolver {
16401640
NominalTypeDecl *nominal,
16411641
AssociatedTypeDecl *assocType);
16421642

1643+
/// Record the witness information into the given conformance that maps
1644+
/// the given requirement to the given witness declaration.
1645+
///
1646+
/// Use this routine only when the given witness is known to satisfy the
1647+
/// requirement, e.g., because the witness itself was synthesized. This
1648+
/// function is not allowed to fail.
1649+
void recordKnownWitness(NormalProtocolConformance *conformance,
1650+
ValueDecl *req, ValueDecl *witness);
1651+
16431652
/// Perform unqualified name lookup at the given source location
16441653
/// within a particular declaration context.
16451654
///

test/Prototypes/property_behaviors/delayed.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ extension delayedImmutable {
3939

4040
class Foo {
4141
var x: Int __behavior delayedImmutable
42+
43+
// FIXME: Hack because we can't find the synthesized associated type witness
44+
// during witness matching.
45+
typealias Value = Int
4246
}
4347

4448
var DelayedImmutable = TestSuite("DelayedImmutable")

test/Prototypes/property_behaviors/lazy.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ func evaluateLazy() -> Int {
4444

4545
class Foo {
4646
var y: Int __behavior lazy { evaluateLazy() }
47+
48+
// FIXME: Hack because we can't find the synthesized associated type witness
49+
// during witness matching.
50+
typealias Value = Int
4751
}
4852

4953
var Lazy = TestSuite("Lazy")

test/SILGen/property_behavior.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
// RUN: %target-swift-frontend -emit-silgen -enable-experimental-property-behaviors %s | %FileCheck %s
2-
3-
// Note: CodeSynthesis is forming witnesses without proper substitutions.
4-
// XFAIL: *
5-
62
protocol behavior {
73
associatedtype Value
84
}
@@ -100,9 +96,17 @@ extension withStorage {
10096
// TODO: storage behaviors in non-instance context
10197
struct S2<T> {
10298
var instance: T __behavior withStorage
99+
100+
// FIXME: Hack because we can't find the synthesized associated type witness
101+
// during witness matching.
102+
typealias Value = T
103103
}
104104
class C2<T> {
105105
var instance: T __behavior withStorage
106+
107+
// FIXME: Hack because we can't find the synthesized associated type witness
108+
// during witness matching.
109+
typealias Value = T
106110
}
107111

108112
func exerciseStorage<T>(_ sx: inout S2<T>, _ sy: inout S2<Int>,
@@ -139,10 +143,18 @@ extension withInit {
139143
func any<T>() -> T { }
140144

141145
struct S3<T> {
146+
147+
// FIXME: Hack because we can't find the synthesized associated type witness
148+
// during witness matching.
149+
typealias Value = T
142150
var instance: T __behavior withInit { any() }
143151
}
144152
class C3<T> {
145153
var instance: T __behavior withInit { any() }
154+
155+
// FIXME: Hack because we can't find the synthesized associated type witness
156+
// during witness matching.
157+
typealias Value = T
146158
}
147159

148160
func exerciseStorage<T>(_ sx: inout S3<T>, _ sy: inout S3<Int>,

test/SILGen/property_behavior_init.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ func whack<T>(_ x: inout T) {}
1717
struct Foo {
1818
var x: Int __behavior diBehavior
1919

20+
// FIXME: Hack because we can't find the synthesized associated type witness
21+
// during witness matching.
22+
typealias Value = Int
23+
2024
// TODO
2125
// var xx: (Int, Int) __behavior diBehavior
2226

test/decl/var/behaviors.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,9 @@ struct Foo<T> {
126126
static var staticStorage1: T __behavior hasStorage // expected-error{{static stored properties not supported in generic types}}
127127
var storage2: T __behavior hasStorage
128128

129-
var storage3: Int = 0 // expected-error {{initializer expression provided, but property behavior 'hasStorage' does not use it}}
130-
__behavior hasStorage
131-
var (storage4, storage5) = tuple // expected-error* {{initializer expression provided, but property behavior 'hasStorage' does not use it}}
132-
__behavior hasStorage
129+
// FIXME: Hack because we can't find the synthesized associated type witness
130+
// during witness matching.
131+
typealias Value = T
133132

134133
func foo<U>(_: U) {
135134
var storage1: T __behavior hasStorage // expected-error {{not supported}}
@@ -139,6 +138,20 @@ struct Foo<T> {
139138
_ = storage2
140139
}
141140
}
141+
142+
struct Foo2<T> {
143+
var storage3: Int = 0 // expected-error {{initializer expression provided, but property behavior 'hasStorage' does not use it}}
144+
__behavior hasStorage
145+
146+
var (storage4, storage5) = tuple // expected-error* {{initializer expression provided, but property behavior 'hasStorage' does not use it}}
147+
__behavior hasStorage
148+
149+
// FIXME: Hack because we can't find the synthesized associated type witness
150+
// during witness matching.
151+
typealias Value = Int
152+
}
153+
154+
142155
extension Foo {
143156
static var y: T __behavior hasStorage // expected-error{{static stored properties not supported in generic types}}
144157
var y: T __behavior hasStorage // expected-error {{extensions may not contain stored properties}}
@@ -240,4 +253,8 @@ struct TestStorageWithInitialValue {
240253
var y = 0 __behavior storageWithInitialValue
241254
var z: Int = 5.5 __behavior storageWithInitialValue // expected-error {{cannot convert value of type 'Double' to type 'Int' in coercion}}
242255
var (a, b) = tuple __behavior storageWithInitialValue // expected-error* {{do not support destructuring}}
256+
257+
// FIXME: Hack because we can't find the synthesized associated type witness
258+
// during witness matching.
259+
typealias Value = Int
243260
}

0 commit comments

Comments
 (0)