Skip to content

Commit ca9d5a9

Browse files
authored
In Swift 3/4 mode, continue treating 'lazy override' as an override (#13335)
Follow-up for 7c707ce. Without this, the declaration would be accepted, but any uses of the overridden property would be treated as ambiguous because the property wouldn't really be marked as an override. rdar://problem/35900345
1 parent 316875e commit ca9d5a9

File tree

3 files changed

+53
-33
lines changed

3 files changed

+53
-33
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ static FuncDecl *createGetterPrototype(AbstractStorageDecl *storage,
172172
if (storage->isStatic())
173173
getter->setStatic();
174174

175+
if (auto *overridden = storage->getOverriddenDecl())
176+
if (auto *overriddenAccessor = overridden->getGetter())
177+
getter->setOverriddenDecl(overriddenAccessor);
178+
175179
return getter;
176180
}
177181

@@ -219,6 +223,14 @@ static FuncDecl *createSetterPrototype(AbstractStorageDecl *storage,
219223
if (isStatic)
220224
setter->setStatic();
221225

226+
if (auto *overridden = storage->getOverriddenDecl()) {
227+
auto *overriddenAccessor = overridden->getSetter();
228+
if (overriddenAccessor &&
229+
overridden->isSetterAccessibleFrom(storage->getDeclContext())) {
230+
setter->setOverriddenDecl(overriddenAccessor);
231+
}
232+
}
233+
222234
return setter;
223235
}
224236

@@ -351,7 +363,15 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage,
351363
// materializeForSet is final if the storage is.
352364
if (storage->isFinal())
353365
makeFinal(ctx, materializeForSet);
354-
366+
367+
if (auto *overridden = storage->getOverriddenDecl()) {
368+
auto *overriddenAccessor = overridden->getMaterializeForSetFunc();
369+
if (overriddenAccessor && !overriddenAccessor->hasForcedStaticDispatch() &&
370+
overridden->isSetterAccessibleFrom(storage->getDeclContext())) {
371+
materializeForSet->setOverriddenDecl(overriddenAccessor);
372+
}
373+
}
374+
355375
// If the storage is dynamic or ObjC-native, we can't add a dynamically-
356376
// dispatched method entry for materializeForSet, so force it to be
357377
// statically dispatched. ("final" would be inappropriate because the
@@ -709,11 +729,6 @@ static void synthesizeTrivialGetter(FuncDecl *getter,
709729
SourceLoc loc = storage->getLoc();
710730
getter->setBody(BraceStmt::create(ctx, loc, returnStmt, loc, true));
711731

712-
// Record the getter as an override, which can happen with addressors.
713-
if (auto *baseASD = storage->getOverriddenDecl())
714-
if (baseASD->isAccessibleFrom(storage->getDeclContext()))
715-
getter->setOverriddenDecl(baseASD->getGetter());
716-
717732
// Register the accessor as an external decl if the storage was imported.
718733
if (needsToBeRegisteredAsExternalDecl(storage))
719734
TC.Context.addExternalDecl(getter);
@@ -734,15 +749,6 @@ static void synthesizeTrivialSetter(FuncDecl *setter,
734749
setterBody, TC);
735750
setter->setBody(BraceStmt::create(ctx, loc, setterBody, loc, true));
736751

737-
// Record the setter as an override, which can happen with addressors.
738-
if (auto *baseASD = storage->getOverriddenDecl()) {
739-
auto *baseSetter = baseASD->getSetter();
740-
if (baseSetter != nullptr &&
741-
baseASD->isSetterAccessibleFrom(storage->getDeclContext())) {
742-
setter->setOverriddenDecl(baseSetter);
743-
}
744-
}
745-
746752
// Register the accessor as an external decl if the storage was imported.
747753
if (needsToBeRegisteredAsExternalDecl(storage))
748754
TC.Context.addExternalDecl(setter);
@@ -848,21 +854,6 @@ static FuncDecl *addMaterializeForSet(AbstractStorageDecl *storage,
848854
storage->getSetter());
849855
storage->setMaterializeForSetFunc(materializeForSet);
850856

851-
// Make sure we record the override.
852-
//
853-
// FIXME: Instead, we should just not call checkOverrides() on
854-
// storage until all accessors are in place.
855-
if (auto *baseASD = storage->getOverriddenDecl()) {
856-
// If the base storage has a private setter, we're not overriding
857-
// materializeForSet either.
858-
auto *baseMFS = baseASD->getMaterializeForSetFunc();
859-
if (baseMFS != nullptr &&
860-
!baseMFS->hasForcedStaticDispatch() &&
861-
baseASD->isSetterAccessibleFrom(storage->getDeclContext())) {
862-
materializeForSet->setOverriddenDecl(baseMFS);
863-
}
864-
}
865-
866857
return materializeForSet;
867858
}
868859

lib/Sema/TypeCheckDecl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6627,18 +6627,22 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
66276627

66286628
// Make sure that the overriding property doesn't have storage.
66296629
if (overrideASD->hasStorage() && !overrideASD->hasObservers()) {
6630-
auto diagID = diag::override_with_stored_property;
6630+
bool downgradeToWarning = false;
66316631
if (!TC.Context.isSwiftVersionAtLeast(5) &&
66326632
overrideASD->getAttrs().hasAttribute<LazyAttr>()) {
66336633
// Swift 4.0 had a bug where lazy properties were considered
66346634
// computed by the time of this check. Downgrade this diagnostic to
66356635
// a warning.
6636-
diagID = diag::override_with_stored_property_warn;
6636+
downgradeToWarning = true;
66376637
}
6638+
auto diagID = downgradeToWarning ?
6639+
diag::override_with_stored_property_warn :
6640+
diag::override_with_stored_property;
66386641
TC.diagnose(overrideASD, diagID,
66396642
overrideASD->getBaseName().getIdentifier());
66406643
TC.diagnose(baseASD, diag::property_override_here);
6641-
return true;
6644+
if (!downgradeToWarning)
6645+
return true;
66426646
}
66436647

66446648
// Make sure that an observing property isn't observing something
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-swift-frontend -swift-version 4 -emit-silgen %s | %FileCheck %s
2+
3+
class Base {
4+
var foo: Int { return 0 }
5+
var bar: Int = 0
6+
}
7+
8+
class Sub : Base {
9+
lazy override var foo: Int = 1
10+
lazy override var bar: Int = 1
11+
func test() -> Int {
12+
// CHECK-LABEL: sil {{.*}}@_T018attr_override_lazy3SubC4testSiyF
13+
// CHECK: class_method %0 : $Sub, #Sub.foo!getter.1
14+
// CHECK: class_method %0 : $Sub, #Sub.bar!getter.1
15+
// CHECK: // end sil function '_T018attr_override_lazy3SubC4testSiyF'
16+
return foo + bar // no ambiguity error here
17+
}
18+
}
19+
20+
// CHECK-LABEL: sil_vtable Sub {
21+
// CHECK: #Base.foo!getter.1: (Base) -> () -> Int : {{.*}} // Sub.foo.getter
22+
// CHECK: #Base.bar!getter.1: (Base) -> () -> Int : {{.*}} // Sub.bar.getter
23+
// CHECK: #Base.bar!setter.1: (Base) -> (Int) -> () : {{.*}} // Sub.bar.setter
24+
// CHECK: #Base.bar!materializeForSet.1: (Base) -> {{.*}} : {{.*}} // Sub.bar.materializeForSet
25+
// CHECK: }

0 commit comments

Comments
 (0)