mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
AST/SILGen: Requestify var initializer expression typechecking.
Allow initializer expressions to be emitted during SILGen when `-experimental-lazy-typecheck` is specified by introducing a new request that fully typechecks the init expressions of pattern binding declarations on-demand. There are still a few rough edges, like missing support for wrapped properties and incomplete handling of subsumed initializers. Fixing these issues is not an immediate priority because in the short term `-experimental-lazy-typecheck` will always be accompanied by `-enable-library-evolution` and `-experimental-skip-non-exportable-decls`. This means that only the initializers of properties on `@frozen` types will need to be emitted and property wrappers are not yet fully supported on properties belonging to `@frozen` types. Resolves rdar://117448868
This commit is contained in:
@@ -2276,6 +2276,10 @@ public:
|
|||||||
getMutablePatternList()[i].setOriginalInit(E);
|
getMutablePatternList()[i].setOriginalInit(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a fully typechecked executable init expression for the pattern at
|
||||||
|
/// the given index.
|
||||||
|
Expr *getCheckedExecutableInit(unsigned i) const;
|
||||||
|
|
||||||
Pattern *getPattern(unsigned i) const {
|
Pattern *getPattern(unsigned i) const {
|
||||||
return getPatternList()[i].getPattern();
|
return getPatternList()[i].getPattern();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,10 +68,11 @@ protected:
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
union { uint64_t OpaqueBits;
|
union { uint64_t OpaqueBits;
|
||||||
|
|
||||||
SWIFT_INLINE_BITFIELD_BASE(Pattern, bitmax(NumPatternKindBits,8)+1+1,
|
SWIFT_INLINE_BITFIELD_BASE(Pattern, bitmax(NumPatternKindBits,8)+1+1+1,
|
||||||
Kind : bitmax(NumPatternKindBits,8),
|
Kind : bitmax(NumPatternKindBits,8),
|
||||||
isImplicit : 1,
|
isImplicit : 1,
|
||||||
hasInterfaceType : 1
|
hasInterfaceType : 1,
|
||||||
|
executableInitChecked : 1
|
||||||
);
|
);
|
||||||
|
|
||||||
SWIFT_INLINE_BITFIELD_FULL(TuplePattern, Pattern, 32,
|
SWIFT_INLINE_BITFIELD_FULL(TuplePattern, Pattern, 32,
|
||||||
@@ -104,6 +105,7 @@ protected:
|
|||||||
Bits.Pattern.Kind = unsigned(kind);
|
Bits.Pattern.Kind = unsigned(kind);
|
||||||
Bits.Pattern.isImplicit = false;
|
Bits.Pattern.isImplicit = false;
|
||||||
Bits.Pattern.hasInterfaceType = false;
|
Bits.Pattern.hasInterfaceType = false;
|
||||||
|
Bits.Pattern.executableInitChecked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -136,6 +138,11 @@ public:
|
|||||||
bool isImplicit() const { return Bits.Pattern.isImplicit; }
|
bool isImplicit() const { return Bits.Pattern.isImplicit; }
|
||||||
void setImplicit() { Bits.Pattern.isImplicit = true; }
|
void setImplicit() { Bits.Pattern.isImplicit = true; }
|
||||||
|
|
||||||
|
bool executableInitChecked() const {
|
||||||
|
return Bits.Pattern.executableInitChecked;
|
||||||
|
}
|
||||||
|
void setExecutableInitChecked() { Bits.Pattern.executableInitChecked = true; }
|
||||||
|
|
||||||
/// Find the smallest subpattern which obeys the property that matching it is
|
/// Find the smallest subpattern which obeys the property that matching it is
|
||||||
/// equivalent to matching this pattern.
|
/// equivalent to matching this pattern.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -2347,6 +2347,27 @@ public:
|
|||||||
void cacheResult(const PatternBindingEntry *value) const;
|
void cacheResult(const PatternBindingEntry *value) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PatternBindingCheckedExecutableInitRequest
|
||||||
|
: public SimpleRequest<PatternBindingCheckedExecutableInitRequest,
|
||||||
|
Expr *(PatternBindingDecl *, unsigned),
|
||||||
|
RequestFlags::SeparatelyCached> {
|
||||||
|
public:
|
||||||
|
using SimpleRequest::SimpleRequest;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend SimpleRequest;
|
||||||
|
|
||||||
|
// Evaluation.
|
||||||
|
Expr *evaluate(Evaluator &evaluator, PatternBindingDecl *PBD,
|
||||||
|
unsigned i) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Separate caching.
|
||||||
|
bool isCached() const { return true; }
|
||||||
|
llvm::Optional<Expr *> getCachedResult() const;
|
||||||
|
void cacheResult(Expr *expr) const;
|
||||||
|
};
|
||||||
|
|
||||||
class NamingPatternRequest
|
class NamingPatternRequest
|
||||||
: public SimpleRequest<NamingPatternRequest, NamedPattern *(VarDecl *),
|
: public SimpleRequest<NamingPatternRequest, NamedPattern *(VarDecl *),
|
||||||
RequestFlags::SeparatelyCached> {
|
RequestFlags::SeparatelyCached> {
|
||||||
|
|||||||
@@ -258,6 +258,9 @@ SWIFT_REQUEST(TypeChecker, OverriddenDeclsRequest,
|
|||||||
SWIFT_REQUEST(TypeChecker, PatternBindingEntryRequest,
|
SWIFT_REQUEST(TypeChecker, PatternBindingEntryRequest,
|
||||||
const PatternBindingEntry *(PatternBindingDecl *, unsigned, bool),
|
const PatternBindingEntry *(PatternBindingDecl *, unsigned, bool),
|
||||||
SeparatelyCached, NoLocationInfo)
|
SeparatelyCached, NoLocationInfo)
|
||||||
|
SWIFT_REQUEST(TypeChecker, PatternBindingCheckedExecutableInitRequest,
|
||||||
|
Expr *(PatternBindingDecl *, unsigned),
|
||||||
|
SeparatelyCached, NoLocationInfo)
|
||||||
SWIFT_REQUEST(TypeChecker, PrimarySourceFilesRequest,
|
SWIFT_REQUEST(TypeChecker, PrimarySourceFilesRequest,
|
||||||
ArrayRef<SourceFile *>(ModuleDecl *), Cached, NoLocationInfo)
|
ArrayRef<SourceFile *>(ModuleDecl *), Cached, NoLocationInfo)
|
||||||
SWIFT_REQUEST(TypeChecker, PropertyWrapperAuxiliaryVariablesRequest,
|
SWIFT_REQUEST(TypeChecker, PropertyWrapperAuxiliaryVariablesRequest,
|
||||||
|
|||||||
@@ -2198,6 +2198,13 @@ PatternBindingDecl::getInitializerIsolation(unsigned i) const {
|
|||||||
return var->getInitializerIsolation();
|
return var->getInitializerIsolation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr *PatternBindingDecl::getCheckedExecutableInit(unsigned i) const {
|
||||||
|
return evaluateOrDefault(getASTContext().evaluator,
|
||||||
|
PatternBindingCheckedExecutableInitRequest{
|
||||||
|
const_cast<PatternBindingDecl *>(this), i},
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool PatternBindingDecl::hasStorage() const {
|
bool PatternBindingDecl::hasStorage() const {
|
||||||
// Walk the pattern, to check to see if any of the VarDecls included in it
|
// Walk the pattern, to check to see if any of the VarDecls included in it
|
||||||
// have storage.
|
// have storage.
|
||||||
|
|||||||
@@ -1022,6 +1022,26 @@ void PatternBindingEntryRequest::cacheResult(
|
|||||||
PBD->getMutablePatternList()[idx].setFullyValidated();
|
PBD->getMutablePatternList()[idx].setFullyValidated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------//
|
||||||
|
// PatternCheckedExecutableInitRequest computation.
|
||||||
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
llvm::Optional<Expr *>
|
||||||
|
PatternBindingCheckedExecutableInitRequest::getCachedResult() const {
|
||||||
|
auto *PBD = std::get<0>(getStorage());
|
||||||
|
auto idx = std::get<1>(getStorage());
|
||||||
|
if (!PBD->getPattern(idx)->executableInitChecked())
|
||||||
|
return llvm::None;
|
||||||
|
return PBD->getExecutableInit(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PatternBindingCheckedExecutableInitRequest::cacheResult(Expr *expr) const {
|
||||||
|
auto *PBD = std::get<0>(getStorage());
|
||||||
|
auto idx = std::get<1>(getStorage());
|
||||||
|
assert(expr == PBD->getExecutableInit(idx));
|
||||||
|
PBD->getPattern(idx)->setExecutableInitChecked();
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
// NamingPatternRequest computation.
|
// NamingPatternRequest computation.
|
||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|||||||
@@ -1656,6 +1656,10 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
|
|||||||
!pbd->getAnchoringVarDecl(i)->isInitExposedToClients())
|
!pbd->getAnchoringVarDecl(i)->isInitExposedToClients())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Force the executable init to be type checked before emission.
|
||||||
|
if (!pbd->getCheckedExecutableInit(i))
|
||||||
|
return;
|
||||||
|
|
||||||
auto *var = pbd->getAnchoringVarDecl(i);
|
auto *var = pbd->getAnchoringVarDecl(i);
|
||||||
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
|
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
|
||||||
emitOrDelayFunction(constant);
|
emitOrDelayFunction(constant);
|
||||||
@@ -1666,6 +1670,9 @@ emitPropertyWrapperBackingInitializer(VarDecl *var) {
|
|||||||
auto initInfo = var->getPropertyWrapperInitializerInfo();
|
auto initInfo = var->getPropertyWrapperInitializerInfo();
|
||||||
|
|
||||||
if (initInfo.hasInitFromWrappedValue()) {
|
if (initInfo.hasInitFromWrappedValue()) {
|
||||||
|
// FIXME: Fully typecheck the original property's init expression on-demand
|
||||||
|
// for lazy typechecking mode.
|
||||||
|
|
||||||
SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperBackingInitializer);
|
SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperBackingInitializer);
|
||||||
emitOrDelayFunction(constant);
|
emitOrDelayFunction(constant);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,6 +219,10 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd,
|
|||||||
->areAllParamsConcrete());
|
->areAllParamsConcrete());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force the executable init to be type checked before emission.
|
||||||
|
if (!pd->getCheckedExecutableInit(pbdEntry))
|
||||||
|
return;
|
||||||
|
|
||||||
Mangle::ASTMangler TokenMangler;
|
Mangle::ASTMangler TokenMangler;
|
||||||
std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(pd, pbdEntry,
|
std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(pd, pbdEntry,
|
||||||
false);
|
false);
|
||||||
|
|||||||
@@ -2662,22 +2662,9 @@ public:
|
|||||||
// as a replacement.
|
// as a replacement.
|
||||||
diagnoseWrittenPlaceholderTypes(Ctx, PBD->getPattern(i), init);
|
diagnoseWrittenPlaceholderTypes(Ctx, PBD->getPattern(i), init);
|
||||||
|
|
||||||
// If we entered an initializer context, contextualize any
|
// Trigger a request that will complete typechecking for the
|
||||||
// auto-closures we might have created.
|
// initializer.
|
||||||
// Note that we don't contextualize the initializer for a property
|
(void)PBD->getCheckedExecutableInit(i);
|
||||||
// with a wrapper, because the initializer will have been subsumed
|
|
||||||
// by the backing storage property.
|
|
||||||
if (!DC->isLocalContext() &&
|
|
||||||
!(PBD->getSingleVar() &&
|
|
||||||
PBD->getSingleVar()->hasAttachedPropertyWrapper())) {
|
|
||||||
auto *initContext = cast_or_null<PatternBindingInitializer>(
|
|
||||||
PBD->getInitContext(i));
|
|
||||||
if (initContext) {
|
|
||||||
TypeChecker::contextualizeInitializer(initContext, init);
|
|
||||||
(void)PBD->getInitializerIsolation(i);
|
|
||||||
TypeChecker::checkInitializerEffects(initContext, init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2686,6 +2673,7 @@ public:
|
|||||||
// If this is an init accessor property with a default initializer,
|
// If this is an init accessor property with a default initializer,
|
||||||
// make sure that it subsumes initializers of all of its "initializes"
|
// make sure that it subsumes initializers of all of its "initializes"
|
||||||
// stored properties.
|
// stored properties.
|
||||||
|
// FIXME: This should be requestified.
|
||||||
auto *initAccessor = var->getAccessor(AccessorKind::Init);
|
auto *initAccessor = var->getAccessor(AccessorKind::Init);
|
||||||
if (initAccessor && PBD->isInitialized(0)) {
|
if (initAccessor && PBD->isInitialized(0)) {
|
||||||
for (auto *property : initAccessor->getInitializedProperties()) {
|
for (auto *property : initAccessor->getInitializedProperties()) {
|
||||||
|
|||||||
@@ -585,6 +585,43 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
|
|||||||
return &pbe;
|
return &pbe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr *PatternBindingCheckedExecutableInitRequest::evaluate(
|
||||||
|
Evaluator &eval, PatternBindingDecl *binding, unsigned i) const {
|
||||||
|
// Force the entry to be checked.
|
||||||
|
(void)binding->getCheckedPatternBindingEntry(i);
|
||||||
|
if (binding->isInvalid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!binding->isInitialized(i))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!binding->isInitializerChecked(i))
|
||||||
|
TypeChecker::typeCheckPatternBinding(binding, i);
|
||||||
|
|
||||||
|
if (binding->isInvalid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If we entered an initializer context, contextualize any auto-closures we
|
||||||
|
// might have created. Note that we don't contextualize the initializer for a
|
||||||
|
// property with a wrapper, because the initializer will have been subsumed by
|
||||||
|
// the backing storage property.
|
||||||
|
auto *init = binding->getInit(i);
|
||||||
|
|
||||||
|
if (!binding->getDeclContext()->isLocalContext() &&
|
||||||
|
!(binding->getSingleVar() &&
|
||||||
|
binding->getSingleVar()->hasAttachedPropertyWrapper())) {
|
||||||
|
auto *initContext =
|
||||||
|
cast_or_null<PatternBindingInitializer>(binding->getInitContext(i));
|
||||||
|
if (initContext) {
|
||||||
|
TypeChecker::contextualizeInitializer(initContext, init);
|
||||||
|
(void)binding->getInitializerIsolation(i);
|
||||||
|
TypeChecker::checkInitializerEffects(initContext, init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding->getExecutableInit(i);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsGetterMutatingRequest::evaluate(Evaluator &evaluator,
|
IsGetterMutatingRequest::evaluate(Evaluator &evaluator,
|
||||||
AbstractStorageDecl *storage) const {
|
AbstractStorageDecl *storage) const {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ struct InternalWrapper {
|
|||||||
|
|
||||||
// MARK: - Global vars
|
// MARK: - Global vars
|
||||||
|
|
||||||
public var publicGlobalVar: Int = 0
|
public var publicGlobalVar: Int = NoTypecheck.int
|
||||||
public var publicGlobalVarInferredType = ""
|
public var publicGlobalVarInferredType = ""
|
||||||
public var (publicGlobalVarInferredTuplePatX, publicGlobalVarInferredTuplePatY) = (0, 1)
|
public var (publicGlobalVarInferredTuplePatX, publicGlobalVarInferredTuplePatY) = (0, 1)
|
||||||
|
|
||||||
@@ -131,16 +131,17 @@ protocol InternalProtoConformingToPublicProto: PublicProto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct PublicStruct {
|
public struct PublicStruct {
|
||||||
public var publicProperty: Int
|
public var publicProperty: Int = NoTypecheck.int
|
||||||
public var publicPropertyInferredType = ""
|
public var publicPropertyInferredType = ""
|
||||||
@PublicWrapper public var publicWrappedProperty = 3.14
|
@PublicWrapper public var publicWrappedProperty = 3.14
|
||||||
@_transparent public var publicTransparentProperty: Int {
|
@_transparent public var publicTransparentProperty: Int {
|
||||||
get { return 1 }
|
get { return 1 }
|
||||||
}
|
}
|
||||||
public dynamic var publicDynamicProperty: Int = 5
|
public dynamic var publicDynamicProperty: Int = 5
|
||||||
|
public static let publicStaticProperty: Int = NoTypecheck.int
|
||||||
|
public static let publicStaticPropertyInferred = 2
|
||||||
|
|
||||||
public init(x: Int) {
|
public init(x: Int) {
|
||||||
self.publicProperty = 1
|
|
||||||
_ = NoTypecheck()
|
_ = NoTypecheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,9 +190,11 @@ struct InternalStruct: NoTypecheckProto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class PublicClass {
|
public class PublicClass {
|
||||||
public var publicProperty: Int
|
public var publicProperty: Int = NoTypecheck.int
|
||||||
public var publicPropertyInferredType = ""
|
public var publicPropertyInferredType = ""
|
||||||
@PublicWrapper public final var publicFinalWrappedProperty: Bool = false
|
@PublicWrapper public final var publicFinalWrappedProperty: Bool = false
|
||||||
|
public static let publicStaticProperty: Int = NoTypecheck.int
|
||||||
|
public static let publicStaticPropertyInferred = 2
|
||||||
|
|
||||||
public init(x: Int) {
|
public init(x: Int) {
|
||||||
self.publicProperty = x
|
self.publicProperty = x
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ func testPublicStructs() {
|
|||||||
let _: Int = s.publicDynamicProperty
|
let _: Int = s.publicDynamicProperty
|
||||||
PublicStruct.publicStaticMethod()
|
PublicStruct.publicStaticMethod()
|
||||||
PublicStruct.activeMethod()
|
PublicStruct.activeMethod()
|
||||||
|
let _: Int = PublicStruct.publicStaticProperty
|
||||||
|
let _: Int = PublicStruct.publicStaticPropertyInferred
|
||||||
|
|
||||||
let _ = FrozenPublicStruct(1)
|
let _ = FrozenPublicStruct(1)
|
||||||
}
|
}
|
||||||
@@ -59,12 +61,16 @@ func testPublicClasses() {
|
|||||||
let _: String = c.publicPropertyInferredType
|
let _: String = c.publicPropertyInferredType
|
||||||
c.publicFinalWrappedProperty = true
|
c.publicFinalWrappedProperty = true
|
||||||
PublicClass.publicClassMethod()
|
PublicClass.publicClassMethod()
|
||||||
|
let _: Int = PublicClass.publicStaticProperty
|
||||||
|
let _: Int = PublicClass.publicStaticPropertyInferred
|
||||||
|
|
||||||
let d = PublicDerivedClass(x: 3)
|
let d = PublicDerivedClass(x: 3)
|
||||||
let _: Int = d.publicMethod()
|
let _: Int = d.publicMethod()
|
||||||
let _: Int = d.publicProperty
|
let _: Int = d.publicProperty
|
||||||
let _: String = d.publicPropertyInferredType
|
let _: String = d.publicPropertyInferredType
|
||||||
PublicDerivedClass.publicClassMethod()
|
PublicDerivedClass.publicClassMethod()
|
||||||
|
let _: Int = PublicDerivedClass.publicStaticProperty
|
||||||
|
let _: Int = PublicDerivedClass.publicStaticPropertyInferred
|
||||||
|
|
||||||
class DerivedFromPublicClassSynthesizedDesignatedInit: PublicClassSynthesizedDesignatedInit {
|
class DerivedFromPublicClassSynthesizedDesignatedInit: PublicClassSynthesizedDesignatedInit {
|
||||||
init() {}
|
init() {}
|
||||||
|
|||||||
60
test/SILGen/lazy_typecheck_var_init.swift
Normal file
60
test/SILGen/lazy_typecheck_var_init.swift
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// RUN: %target-swift-frontend -emit-silgen %s -parse-as-library -module-name Test | %FileCheck %s --check-prefixes=CHECK,CHECK-NON-LAZY
|
||||||
|
// RUN: %target-swift-frontend -emit-silgen %s -parse-as-library -module-name Test -experimental-lazy-typecheck | %FileCheck %s --check-prefixes=CHECK,CHECK-LAZY
|
||||||
|
|
||||||
|
enum E {
|
||||||
|
case a, b
|
||||||
|
}
|
||||||
|
|
||||||
|
func internalFunc(_ e: E = .a) -> Int {
|
||||||
|
switch e {
|
||||||
|
case .a: return 1
|
||||||
|
case .b: return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil private [global_init_once_fn]{{.*}} @$s4Test9globalVar_WZ : $@convention(c) (Builtin.RawPointer) -> () {
|
||||||
|
public var globalVar = internalFunc()
|
||||||
|
|
||||||
|
public struct S {
|
||||||
|
// CHECK-LABEL: sil [transparent]{{.*}} @$s4Test1SV11instanceVarSivpfi : $@convention(thin) () -> Int {
|
||||||
|
public var instanceVar = internalFunc()
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil [transparent]{{.*}} @$s4Test1SV12instanceVar2Sivpfi : $@convention(thin) () -> Int {
|
||||||
|
public var instanceVar2 = internalFunc(.b)
|
||||||
|
|
||||||
|
// FIXME: This initializer should be subsumed.
|
||||||
|
// CHECK-LAZY: sil [transparent] [ossa] @$s4Test1SV15lazyInstanceVarSivpfi : $@convention(thin) () -> Int {
|
||||||
|
// CHECK-NON-LAZY-NOT: sil [transparent] [ossa] @$s4Test1SV15lazyInstanceVarSivpfi : $@convention(thin) () -> Int {
|
||||||
|
// CHECK-LABEL: sil [transparent]{{.*}} @$s4Test1SV018$__lazy_storage_$_B11InstanceVar33_0E4F053AA3AB7D4CDE3A37DBA8EF0430LLSiSgvpfi : $@convention(thin) () -> Optional<Int> {
|
||||||
|
public lazy var lazyInstanceVar = internalFunc()
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil private [global_init_once_fn]{{.*}} @$s4Test1SV9staticVar_WZ : $@convention(c) (Builtin.RawPointer) -> () {
|
||||||
|
public static var staticVar = internalFunc()
|
||||||
|
|
||||||
|
// FIXME: This initializer should be subsumed.
|
||||||
|
// CHECK-LAZY: sil [transparent] [ossa] @$s4Test1SV15subsumedInitVarSivpfi : $@convention(thin) () -> Int {
|
||||||
|
// CHECK-NON-LAZY-NOT: sil [transparent] [ossa] @$s4Test1SV15subsumedInitVarSivpfi : $@convention(thin) () -> Int {
|
||||||
|
public var subsumedInitVar = internalFunc()
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil [transparent] [ossa] @$s4Test1SV19varWithInitAccessorSivpfi : $@convention(thin) () -> Int {
|
||||||
|
public var varWithInitAccessor: Int = internalFunc() {
|
||||||
|
@storageRestrictions(initializes: subsumedInitVar)
|
||||||
|
init {
|
||||||
|
subsumedInitVar = newValue
|
||||||
|
}
|
||||||
|
get { subsumedInitVar }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Test vars with property wrappers.
|
||||||
|
}
|
||||||
|
|
||||||
|
extension S {
|
||||||
|
// CHECK-LABEL: sil private [global_init_once_fn]{{.*}} @$s4Test1SV20staticVarInExtension_WZ : $@convention(c) (Builtin.RawPointer) -> () {
|
||||||
|
public static var staticVarInExtension = internalFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func returnsS() -> S {
|
||||||
|
// Force the synthesized initializer for S to be emitted.
|
||||||
|
// CHECK: function_ref @$s4Test1SVACycfC : $@convention(method) (@thin S.Type) -> S
|
||||||
|
return S()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user