Skip to content

Commit 2ffe9d5

Browse files
committed
[Type checker] Represent "initializable" let instance property references as lvalues
As we do with references to initializable local lets, teach the type checker to produce ASTs where member references to initializable instance property lets (e.g., within an initializer) treat the `let` as an lvalue and then immediately load. This modeling addresses a source compatibility issue uncovered in swift-syntax, where code that *technically* has a use-before-definition on a `let` property in an initializer wasn't diagnosed as such because the loaded value wasn't actually used for anything.
1 parent 39f4e38 commit 2ffe9d5

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

lib/Sema/CSApply.cpp

+22-2
Original file line numberDiff line numberDiff line change
@@ -1716,10 +1716,24 @@ namespace {
17161716
// For properties, build member references.
17171717
if (auto *varDecl = dyn_cast<VarDecl>(member)) {
17181718
// \returns result of the given function type
1719-
auto resultType = [](Type fnTy) -> Type {
1720-
return fnTy->castTo<FunctionType>()->getResult();
1719+
bool loadImmediately = false;
1720+
auto resultType = [&loadImmediately](Type fnTy) -> Type {
1721+
Type resultTy = fnTy->castTo<FunctionType>()->getResult();
1722+
if (loadImmediately)
1723+
return LValueType::get(resultTy);
1724+
return resultTy;
17211725
};
17221726

1727+
// If we have an instance property that's treated as an rvalue
1728+
// but allows assignment (for initialization) in the current
1729+
// context, treat it as an rvalue that we immediately load.
1730+
// This is the AST that's expected by SILGen.
1731+
if (baseIsInstance && !resultType(refTy)->hasLValueType() &&
1732+
varDecl->mutability(dc, dyn_cast<DeclRefExpr>(base))
1733+
== StorageMutability::Initializable) {
1734+
loadImmediately = true;
1735+
}
1736+
17231737
if (isUnboundInstanceMember) {
17241738
assert(memberLocator.getBaseLocator() &&
17251739
cs.UnevaluatedRootExprs.count(
@@ -1765,6 +1779,12 @@ namespace {
17651779
result, conversionTy));
17661780
}
17671781
}
1782+
1783+
// If we need to load, do so now.
1784+
if (loadImmediately) {
1785+
result = cs.addImplicitLoadExpr(result);
1786+
}
1787+
17681788
return forceUnwrapIfExpected(result, memberLocator);
17691789
}
17701790

test/SILOptimizer/definite_init_value_types_diagnostics.swift

+13
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,16 @@ struct AddressStruct {
7878
self = AddressStruct()
7979
} // expected-error {{return from initializer without initializing all stored properties}}
8080
}
81+
82+
// Old versions of swift-syntax have this logical use-before-definition; make
83+
// sure we keep it working.
84+
struct InitLogicalUseBeforeDef {
85+
let offset: UInt16
86+
87+
init?(value: Int) {
88+
if value > type(of: self.offset).max {
89+
return nil
90+
}
91+
offset = UInt16(value)
92+
}
93+
}

0 commit comments

Comments
 (0)