mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[InterfaceGen] Print property initializers in resilient, fixed-layout types (#19619)
Augment the ASTPrinter to print the name and text of initializer expressions if a property has an initializer and the type is @_fixed_layout and resides in a resilient module, and serialize the text for partial modules. With this change, all .swiftinterface files in the project (except for SwiftLang) compile to swiftmodules on macOS. rdar://43774580 rdar://43812188
This commit is contained in:
@@ -1864,38 +1864,49 @@ public:
|
|||||||
/// Pattern and Initialization expression. The pattern is always present, but
|
/// Pattern and Initialization expression. The pattern is always present, but
|
||||||
/// the initializer can be null if there is none.
|
/// the initializer can be null if there is none.
|
||||||
class PatternBindingEntry {
|
class PatternBindingEntry {
|
||||||
Pattern *ThePattern;
|
|
||||||
|
|
||||||
/// The location of the equal '=' token.
|
|
||||||
SourceLoc EqualLoc;
|
|
||||||
|
|
||||||
enum class Flags {
|
enum class Flags {
|
||||||
Checked = 1 << 0,
|
Checked = 1 << 0,
|
||||||
Removed = 1 << 1,
|
Removed = 1 << 1,
|
||||||
Lazy = 1 << 2,
|
Lazy = 1 << 2
|
||||||
|
};
|
||||||
|
llvm::PointerIntPair<Pattern *, 3, OptionSet<Flags>> PatternAndFlags;
|
||||||
|
|
||||||
|
struct ExprAndEqualLoc {
|
||||||
|
// When the initializer is removed we don't actually clear the pointer
|
||||||
|
// because we might need to get initializer's source range. Since the
|
||||||
|
// initializer is ASTContext-allocated it is safe.
|
||||||
|
Expr *Node;
|
||||||
|
/// The location of the equal '=' token.
|
||||||
|
SourceLoc EqualLoc;
|
||||||
};
|
};
|
||||||
|
|
||||||
// When the initializer is removed we don't actually clear the pointer
|
union {
|
||||||
// because we might need to get initializer's source range. Since the
|
/// The initializer expression and its '=' token loc.
|
||||||
// initializer is ASTContext-allocated it is safe.
|
ExprAndEqualLoc InitExpr;
|
||||||
llvm::PointerIntPair<Expr *, 3, OptionSet<Flags>> InitAndFlags;
|
|
||||||
|
/// The text of the initializer expression if deserialized from a module.
|
||||||
|
StringRef InitStringRepresentation;
|
||||||
|
};
|
||||||
|
|
||||||
/// The initializer context used for this pattern binding entry.
|
/// The initializer context used for this pattern binding entry.
|
||||||
DeclContext *InitContext = nullptr;
|
llvm::PointerIntPair<DeclContext *, 1, bool> InitContextAndIsText;
|
||||||
|
|
||||||
friend class PatternBindingInitializer;
|
friend class PatternBindingInitializer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
|
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
|
||||||
DeclContext *InitContext)
|
DeclContext *InitContext)
|
||||||
: ThePattern(P), EqualLoc(EqualLoc), InitAndFlags(E, {}),
|
: PatternAndFlags(P, {}), InitExpr({E, EqualLoc}),
|
||||||
InitContext(InitContext) {}
|
InitContextAndIsText({InitContext, false}) {
|
||||||
|
}
|
||||||
|
|
||||||
Pattern *getPattern() const { return ThePattern; }
|
Pattern *getPattern() const { return PatternAndFlags.getPointer(); }
|
||||||
void setPattern(Pattern *P) { ThePattern = P; }
|
void setPattern(Pattern *P) { PatternAndFlags.setPointer(P); }
|
||||||
Expr *getInit() const {
|
Expr *getInit() const {
|
||||||
return (InitAndFlags.getInt().contains(Flags::Removed))
|
if (PatternAndFlags.getInt().contains(Flags::Removed) ||
|
||||||
? nullptr : InitAndFlags.getPointer();
|
InitContextAndIsText.getInt())
|
||||||
|
return nullptr;
|
||||||
|
return InitExpr.Node;
|
||||||
}
|
}
|
||||||
Expr *getNonLazyInit() const {
|
Expr *getNonLazyInit() const {
|
||||||
return isInitializerLazy() ? nullptr : getInit();
|
return isInitializerLazy() ? nullptr : getInit();
|
||||||
@@ -1903,37 +1914,64 @@ public:
|
|||||||
SourceRange getOrigInitRange() const;
|
SourceRange getOrigInitRange() const;
|
||||||
void setInit(Expr *E);
|
void setInit(Expr *E);
|
||||||
|
|
||||||
|
/// Gets the text of the initializer expression, stripping out inactive
|
||||||
|
/// branches of any #ifs inside the expression.
|
||||||
|
StringRef getInitStringRepresentation(SmallVectorImpl<char> &scratch) const;
|
||||||
|
|
||||||
|
/// Sets the initializer string representation to the string that was
|
||||||
|
/// deserialized from a partial module.
|
||||||
|
void setInitStringRepresentation(StringRef str) {
|
||||||
|
InitStringRepresentation = str;
|
||||||
|
InitContextAndIsText.setInt(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether this pattern entry can generate a string representation of its
|
||||||
|
/// initializer expression.
|
||||||
|
bool hasInitStringRepresentation() const;
|
||||||
|
|
||||||
/// Retrieve the location of the equal '=' token.
|
/// Retrieve the location of the equal '=' token.
|
||||||
SourceLoc getEqualLoc() const { return EqualLoc; }
|
SourceLoc getEqualLoc() const {
|
||||||
|
return InitContextAndIsText.getInt() ? SourceLoc() : InitExpr.EqualLoc;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the location of the equal '=' token.
|
/// Set the location of the equal '=' token.
|
||||||
void setEqualLoc(SourceLoc equalLoc) { EqualLoc = equalLoc; }
|
void setEqualLoc(SourceLoc equalLoc) {
|
||||||
|
assert(!InitContextAndIsText.getInt() &&
|
||||||
|
"cannot set equal loc for textual initializer");
|
||||||
|
InitExpr.EqualLoc = equalLoc;
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve the initializer as it was written in the source.
|
/// Retrieve the initializer as it was written in the source.
|
||||||
Expr *getInitAsWritten() const { return InitAndFlags.getPointer(); }
|
Expr *getInitAsWritten() const {
|
||||||
|
return InitContextAndIsText.getInt() ? nullptr : InitExpr.Node;
|
||||||
|
}
|
||||||
|
|
||||||
bool isInitializerChecked() const {
|
bool isInitializerChecked() const {
|
||||||
return InitAndFlags.getInt().contains(Flags::Checked);
|
return PatternAndFlags.getInt().contains(Flags::Checked);
|
||||||
}
|
}
|
||||||
void setInitializerChecked() {
|
void setInitializerChecked() {
|
||||||
InitAndFlags.setInt(InitAndFlags.getInt() | Flags::Checked);
|
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInitializerLazy() const {
|
bool isInitializerLazy() const {
|
||||||
return InitAndFlags.getInt().contains(Flags::Lazy);
|
return PatternAndFlags.getInt().contains(Flags::Lazy);
|
||||||
}
|
}
|
||||||
void setInitializerLazy() {
|
void setInitializerLazy() {
|
||||||
InitAndFlags.setInt(InitAndFlags.getInt() | Flags::Lazy);
|
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Lazy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the first variable initialized by this pattern.
|
// Return the first variable initialized by this pattern.
|
||||||
VarDecl *getAnchoringVarDecl() const;
|
VarDecl *getAnchoringVarDecl() const;
|
||||||
|
|
||||||
// Retrieve the declaration context for the initializer.
|
// Retrieve the declaration context for the initializer.
|
||||||
DeclContext *getInitContext() const { return InitContext; }
|
DeclContext *getInitContext() const {
|
||||||
|
return InitContextAndIsText.getPointer();
|
||||||
|
}
|
||||||
|
|
||||||
/// Override the initializer context.
|
/// Override the initializer context.
|
||||||
void setInitContext(DeclContext *dc) { InitContext = dc; }
|
void setInitContext(DeclContext *dc) {
|
||||||
|
InitContextAndIsText.setPointer(dc);
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve the source range covered by this pattern binding.
|
/// Retrieve the source range covered by this pattern binding.
|
||||||
///
|
///
|
||||||
@@ -2007,6 +2045,10 @@ public:
|
|||||||
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
|
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setInitStringRepresentation(unsigned i, StringRef str) {
|
||||||
|
getMutablePatternList()[i].setInitStringRepresentation(str);
|
||||||
|
}
|
||||||
|
|
||||||
Expr *getInit(unsigned i) const {
|
Expr *getInit(unsigned i) const {
|
||||||
return getPatternList()[i].getInit();
|
return getPatternList()[i].getInit();
|
||||||
}
|
}
|
||||||
@@ -2039,7 +2081,8 @@ public:
|
|||||||
|
|
||||||
/// Return the PatternEntry (a pattern + initializer pair) for the specified
|
/// Return the PatternEntry (a pattern + initializer pair) for the specified
|
||||||
/// VarDecl.
|
/// VarDecl.
|
||||||
PatternBindingEntry getPatternEntryForVarDecl(const VarDecl *VD) const {
|
const PatternBindingEntry &getPatternEntryForVarDecl(
|
||||||
|
const VarDecl *VD) const {
|
||||||
return getPatternList()[getPatternEntryIndexForVarDecl(VD)];
|
return getPatternList()[getPatternEntryIndexForVarDecl(VD)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2097,7 +2140,7 @@ public:
|
|||||||
static bool classof(const Decl *D) {
|
static bool classof(const Decl *D) {
|
||||||
return D->getKind() == DeclKind::PatternBinding;
|
return D->getKind() == DeclKind::PatternBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MutableArrayRef<PatternBindingEntry> getMutablePatternList() {
|
MutableArrayRef<PatternBindingEntry> getMutablePatternList() {
|
||||||
// Pattern entries are tail allocated.
|
// Pattern entries are tail allocated.
|
||||||
@@ -4606,6 +4649,14 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return whether this VarDecl has an initial value, either by checking
|
||||||
|
// if it has an initializer in its parent pattern binding or if it has
|
||||||
|
// the @_hasInitialValue attribute.
|
||||||
|
bool hasInitialValue() const {
|
||||||
|
return getAttrs().hasAttribute<HasInitialValueAttr>() ||
|
||||||
|
getParentInitializer();
|
||||||
|
}
|
||||||
|
|
||||||
VarDecl *getOverriddenDecl() const {
|
VarDecl *getOverriddenDecl() const {
|
||||||
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
|
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
|
||||||
}
|
}
|
||||||
@@ -4687,6 +4738,13 @@ public:
|
|||||||
void setHasNonPatternBindingInit(bool V = true) {
|
void setHasNonPatternBindingInit(bool V = true) {
|
||||||
Bits.VarDecl.HasNonPatternBindingInit = V;
|
Bits.VarDecl.HasNonPatternBindingInit = V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines if this var has an initializer expression that should be
|
||||||
|
/// exposed to clients.
|
||||||
|
/// There's a very narrow case when we would: if the decl is an instance
|
||||||
|
/// member with an initializer expression and the parent type is
|
||||||
|
/// @_fixed_layout and resides in a resilient module.
|
||||||
|
bool isInitExposedToClients() const;
|
||||||
|
|
||||||
/// Is this a special debugger variable?
|
/// Is this a special debugger variable?
|
||||||
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
|
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
|
||||||
|
|||||||
@@ -887,6 +887,9 @@ public:
|
|||||||
|
|
||||||
/// Reads inlinable body text from \c DeclTypeCursor, if present.
|
/// Reads inlinable body text from \c DeclTypeCursor, if present.
|
||||||
Optional<StringRef> maybeReadInlinableBodyText();
|
Optional<StringRef> maybeReadInlinableBodyText();
|
||||||
|
|
||||||
|
/// Reads pattern initializer text from \c DeclTypeCursor, if present.
|
||||||
|
Optional<StringRef> maybeReadPatternInitializerText();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename RawData>
|
template <typename T, typename RawData>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
|
|||||||
/// describe what change you made. The content of this comment isn't important;
|
/// describe what change you made. The content of this comment isn't important;
|
||||||
/// it just ensures a conflict if two people change the module format.
|
/// it just ensures a conflict if two people change the module format.
|
||||||
/// Don't worry about adhering to the 80-column limit for this line.
|
/// Don't worry about adhering to the 80-column limit for this line.
|
||||||
const uint16_t VERSION_MINOR = 450; // Last change: don't serialize requirement environment
|
const uint16_t VERSION_MINOR = 451; // Last change: pattern initializer text
|
||||||
|
|
||||||
using DeclIDField = BCFixed<31>;
|
using DeclIDField = BCFixed<31>;
|
||||||
|
|
||||||
@@ -1478,7 +1478,8 @@ namespace decls_block {
|
|||||||
using PatternBindingInitializerLayout = BCRecordLayout<
|
using PatternBindingInitializerLayout = BCRecordLayout<
|
||||||
PATTERN_BINDING_INITIALIZER_CONTEXT,
|
PATTERN_BINDING_INITIALIZER_CONTEXT,
|
||||||
DeclIDField, // parent pattern binding decl
|
DeclIDField, // parent pattern binding decl
|
||||||
BCVBR<3> // binding index in the pattern binding decl
|
BCVBR<3>, // binding index in the pattern binding decl
|
||||||
|
BCBlob // initializer text, if present
|
||||||
>;
|
>;
|
||||||
|
|
||||||
using DefaultArgumentInitializerLayout = BCRecordLayout<
|
using DefaultArgumentInitializerLayout = BCRecordLayout<
|
||||||
|
|||||||
@@ -842,26 +842,35 @@ void PrintAST::printAttributes(const Decl *D) {
|
|||||||
if (Options.SkipAttributes)
|
if (Options.SkipAttributes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't print a redundant 'final' if we are printing a 'static' decl.
|
// Save the current number of exclude attrs to restore once we're done.
|
||||||
unsigned originalExcludeAttrCount = Options.ExcludeAttrList.size();
|
unsigned originalExcludeAttrCount = Options.ExcludeAttrList.size();
|
||||||
if (Options.PrintImplicitAttrs &&
|
|
||||||
D->getDeclContext()->getSelfClassDecl() &&
|
|
||||||
getCorrectStaticSpelling(D) == StaticSpellingKind::KeywordStatic) {
|
|
||||||
Options.ExcludeAttrList.push_back(DAK_Final);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't print any contextual decl modifiers.
|
if (Options.PrintImplicitAttrs) {
|
||||||
// We will handle 'mutating' and 'nonmutating' separately.
|
|
||||||
if (Options.PrintImplicitAttrs && isa<AccessorDecl>(D)) {
|
// Don't print a redundant 'final' if we are printing a 'static' decl.
|
||||||
|
if (D->getDeclContext()->getSelfClassDecl() &&
|
||||||
|
getCorrectStaticSpelling(D) == StaticSpellingKind::KeywordStatic) {
|
||||||
|
Options.ExcludeAttrList.push_back(DAK_Final);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't print @_hasInitialValue if we're printing an initializer
|
||||||
|
// expression.
|
||||||
|
if (auto vd = dyn_cast<VarDecl>(D)) {
|
||||||
|
if (vd->isInitExposedToClients())
|
||||||
|
Options.ExcludeAttrList.push_back(DAK_HasInitialValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't print any contextual decl modifiers.
|
||||||
|
// We will handle 'mutating' and 'nonmutating' separately.
|
||||||
|
if (isa<AccessorDecl>(D)) {
|
||||||
#define EXCLUDE_ATTR(Class) Options.ExcludeAttrList.push_back(DAK_##Class);
|
#define EXCLUDE_ATTR(Class) Options.ExcludeAttrList.push_back(DAK_##Class);
|
||||||
#define CONTEXTUAL_DECL_ATTR(X, Class, Y, Z) EXCLUDE_ATTR(Class)
|
#define CONTEXTUAL_DECL_ATTR(X, Class, Y, Z) EXCLUDE_ATTR(Class)
|
||||||
#define CONTEXTUAL_SIMPLE_DECL_ATTR(X, Class, Y, Z) EXCLUDE_ATTR(Class)
|
#define CONTEXTUAL_SIMPLE_DECL_ATTR(X, Class, Y, Z) EXCLUDE_ATTR(Class)
|
||||||
#define CONTEXTUAL_DECL_ATTR_ALIAS(X, Class) EXCLUDE_ATTR(Class)
|
#define CONTEXTUAL_DECL_ATTR_ALIAS(X, Class) EXCLUDE_ATTR(Class)
|
||||||
#include "swift/AST/Attr.def"
|
#include "swift/AST/Attr.def"
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the declaration is implicitly @objc, print the attribute now.
|
// If the declaration is implicitly @objc, print the attribute now.
|
||||||
if (Options.PrintImplicitAttrs) {
|
|
||||||
if (auto VD = dyn_cast<ValueDecl>(D)) {
|
if (auto VD = dyn_cast<ValueDecl>(D)) {
|
||||||
if (VD->isObjC() && !VD->getAttrs().hasAttribute<ObjCAttr>()) {
|
if (VD->isObjC() && !VD->getAttrs().hasAttribute<ObjCAttr>()) {
|
||||||
Printer.printAttrName("@objc");
|
Printer.printAttrName("@objc");
|
||||||
@@ -899,7 +908,10 @@ void PrintAST::printPattern(const Pattern *pattern) {
|
|||||||
recordDeclLoc(decl, [&]{
|
recordDeclLoc(decl, [&]{
|
||||||
if (Options.OmitNameOfInaccessibleProperties &&
|
if (Options.OmitNameOfInaccessibleProperties &&
|
||||||
contributesToParentTypeStorage(decl) &&
|
contributesToParentTypeStorage(decl) &&
|
||||||
!isPublicOrUsableFromInline(decl))
|
!isPublicOrUsableFromInline(decl) &&
|
||||||
|
// FIXME: We need to figure out a way to generate an entry point
|
||||||
|
// for the initializer expression without revealing the name.
|
||||||
|
!decl->hasInitialValue())
|
||||||
Printer << "_";
|
Printer << "_";
|
||||||
else
|
else
|
||||||
Printer.printName(named->getBoundName());
|
Printer.printName(named->getBoundName());
|
||||||
@@ -2045,7 +2057,7 @@ void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isFirst = true;
|
bool isFirst = true;
|
||||||
for (auto entry : decl->getPatternList()) {
|
for (auto &entry : decl->getPatternList()) {
|
||||||
if (!shouldPrintPattern(entry.getPattern()))
|
if (!shouldPrintPattern(entry.getPattern()))
|
||||||
continue;
|
continue;
|
||||||
if (isFirst)
|
if (isFirst)
|
||||||
@@ -2065,6 +2077,13 @@ void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) {
|
|||||||
if (Options.VarInitializers) {
|
if (Options.VarInitializers) {
|
||||||
// FIXME: Implement once we can pretty-print expressions.
|
// FIXME: Implement once we can pretty-print expressions.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto vd = entry.getAnchoringVarDecl();
|
||||||
|
if (entry.hasInitStringRepresentation() &&
|
||||||
|
vd->isInitExposedToClients()) {
|
||||||
|
SmallString<128> scratch;
|
||||||
|
Printer << " = " << entry.getInitStringRepresentation(scratch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1181,18 +1181,19 @@ unsigned PatternBindingDecl::getPatternEntryIndexForVarDecl(const VarDecl *VD) c
|
|||||||
}
|
}
|
||||||
|
|
||||||
SourceRange PatternBindingEntry::getOrigInitRange() const {
|
SourceRange PatternBindingEntry::getOrigInitRange() const {
|
||||||
auto Init = InitAndFlags.getPointer();
|
auto Init = getInitAsWritten();
|
||||||
return Init ? Init->getSourceRange() : SourceRange();
|
return Init ? Init->getSourceRange() : SourceRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatternBindingEntry::setInit(Expr *E) {
|
void PatternBindingEntry::setInit(Expr *E) {
|
||||||
auto F = InitAndFlags.getInt();
|
auto F = PatternAndFlags.getInt();
|
||||||
if (E) {
|
if (E) {
|
||||||
InitAndFlags.setInt(F - Flags::Removed);
|
PatternAndFlags.setInt(F - Flags::Removed);
|
||||||
InitAndFlags.setPointer(E);
|
|
||||||
} else {
|
} else {
|
||||||
InitAndFlags.setInt(F | Flags::Removed);
|
PatternAndFlags.setInt(F | Flags::Removed);
|
||||||
}
|
}
|
||||||
|
InitExpr.Node = E;
|
||||||
|
InitContextAndIsText.setInt(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
VarDecl *PatternBindingEntry::getAnchoringVarDecl() const {
|
VarDecl *PatternBindingEntry::getAnchoringVarDecl() const {
|
||||||
@@ -1225,6 +1226,25 @@ SourceRange PatternBindingEntry::getSourceRange(bool omitAccessors) const {
|
|||||||
return SourceRange(startLoc, endLoc);
|
return SourceRange(startLoc, endLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PatternBindingEntry::hasInitStringRepresentation() const {
|
||||||
|
if (InitContextAndIsText.getInt())
|
||||||
|
return !InitStringRepresentation.empty();
|
||||||
|
return getInit() && getInit()->getSourceRange().isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef PatternBindingEntry::getInitStringRepresentation(
|
||||||
|
SmallVectorImpl<char> &scratch) const {
|
||||||
|
|
||||||
|
assert(hasInitStringRepresentation() &&
|
||||||
|
"must check if pattern has string representation");
|
||||||
|
|
||||||
|
if (InitContextAndIsText.getInt() && !InitStringRepresentation.empty())
|
||||||
|
return InitStringRepresentation;
|
||||||
|
auto &sourceMgr = getAnchoringVarDecl()->getASTContext().SourceMgr;
|
||||||
|
auto init = getInit();
|
||||||
|
return extractInlinableText(sourceMgr, init, scratch);
|
||||||
|
}
|
||||||
|
|
||||||
SourceRange PatternBindingDecl::getSourceRange() const {
|
SourceRange PatternBindingDecl::getSourceRange() const {
|
||||||
SourceLoc startLoc = getStartLoc();
|
SourceLoc startLoc = getStartLoc();
|
||||||
SourceLoc endLoc = getPatternList().back().getSourceRange().End;
|
SourceLoc endLoc = getPatternList().back().getSourceRange().End;
|
||||||
@@ -1279,6 +1299,19 @@ VarDecl *PatternBindingDecl::getSingleVar() const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VarDecl::isInitExposedToClients() const {
|
||||||
|
auto parent = dyn_cast<NominalTypeDecl>(getDeclContext());
|
||||||
|
if (!parent) return false;
|
||||||
|
if (!hasInitialValue())
|
||||||
|
return false;
|
||||||
|
if (isStatic())
|
||||||
|
return false;
|
||||||
|
if (!parent->getAttrs().hasAttribute<FixedLayoutAttr>())
|
||||||
|
return false;
|
||||||
|
auto *module = parent->getModuleContext();
|
||||||
|
return module->getResilienceStrategy() == ResilienceStrategy::Resilient;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether the given type representation will be
|
/// Check whether the given type representation will be
|
||||||
/// default-initializable.
|
/// default-initializable.
|
||||||
static bool isDefaultInitializable(const TypeRepr *typeRepr) {
|
static bool isDefaultInitializable(const TypeRepr *typeRepr) {
|
||||||
|
|||||||
@@ -2483,7 +2483,7 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
|
|||||||
// Add the attribute that preserves the "has an initializer" value across
|
// Add the attribute that preserves the "has an initializer" value across
|
||||||
// module generation, as required for TBDGen.
|
// module generation, as required for TBDGen.
|
||||||
PBD->getPattern(patternNumber)->forEachVariable([&](VarDecl *VD) {
|
PBD->getPattern(patternNumber)->forEachVariable([&](VarDecl *VD) {
|
||||||
if (VD->hasStorage())
|
if (VD->hasStorage() && !VD->getAttrs().hasAttribute<HasInitialValueAttr>())
|
||||||
VD->getAttrs().add(new (ctx) HasInitialValueAttr(/*IsImplicit=*/true));
|
VD->getAttrs().add(new (ctx) HasInitialValueAttr(/*IsImplicit=*/true));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1837,6 +1837,9 @@ DeclContext *ModuleFile::getLocalDeclContext(DeclContextID DCID) {
|
|||||||
if (!declContextOrOffset.isComplete())
|
if (!declContextOrOffset.isComplete())
|
||||||
declContextOrOffset = new (ctx)
|
declContextOrOffset = new (ctx)
|
||||||
SerializedPatternBindingInitializer(binding, bindingIndex);
|
SerializedPatternBindingInitializer(binding, bindingIndex);
|
||||||
|
|
||||||
|
if (!blobData.empty())
|
||||||
|
binding->setInitStringRepresentation(bindingIndex, blobData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2438,9 +2438,19 @@ void Serializer::writePatternBindingInitializer(PatternBindingDecl *binding,
|
|||||||
unsigned bindingIndex) {
|
unsigned bindingIndex) {
|
||||||
using namespace decls_block;
|
using namespace decls_block;
|
||||||
auto abbrCode = DeclTypeAbbrCodes[PatternBindingInitializerLayout::Code];
|
auto abbrCode = DeclTypeAbbrCodes[PatternBindingInitializerLayout::Code];
|
||||||
|
|
||||||
|
StringRef initStr;
|
||||||
|
SmallString<128> scratch;
|
||||||
|
auto &entry = binding->getPatternList()[bindingIndex];
|
||||||
|
auto varDecl = entry.getAnchoringVarDecl();
|
||||||
|
if (entry.hasInitStringRepresentation() &&
|
||||||
|
varDecl->isInitExposedToClients()) {
|
||||||
|
initStr = entry.getInitStringRepresentation(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
PatternBindingInitializerLayout::emitRecord(Out, ScratchRecord,
|
PatternBindingInitializerLayout::emitRecord(Out, ScratchRecord,
|
||||||
abbrCode, addDeclRef(binding),
|
abbrCode, addDeclRef(binding),
|
||||||
bindingIndex);
|
bindingIndex, initStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// RUN: %empty-directory(%t)
|
||||||
|
|
||||||
|
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.swiftinterface %s
|
||||||
|
// RUN: %FileCheck %s < %t.swiftinterface --check-prefix CHECK --check-prefix COMMON
|
||||||
|
|
||||||
|
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t-resilient.swiftinterface -enable-resilience %s
|
||||||
|
// RUN: %FileCheck %s --check-prefix RESILIENT --check-prefix COMMON < %t-resilient.swiftinterface
|
||||||
|
|
||||||
|
// FIXME(rdar44993525): %target-swift-frontend -emit-module -o %t/Test.swiftmodule %t.swiftinterface -disable-objc-attr-requires-foundation-module
|
||||||
|
// FIXME(rdar44993525): %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -module-name Test -emit-parseable-module-interface-path - | %FileCheck %s --check-prefix CHECK --check-prefix COMMON
|
||||||
|
|
||||||
|
// RUN: %target-swift-frontend -emit-module -o %t/TestResilient.swiftmodule -enable-resilience %t-resilient.swiftinterface -disable-objc-attr-requires-foundation-module
|
||||||
|
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/TestResilient.swiftmodule -module-name TestResilient -enable-resilience -emit-parseable-module-interface-path - | %FileCheck %s --check-prefix RESILIENT --check-prefix COMMON
|
||||||
|
|
||||||
|
// COMMON: @_fixed_layout public struct MyStruct {
|
||||||
|
@_fixed_layout
|
||||||
|
public struct MyStruct {
|
||||||
|
// CHECK: @_hasInitialValue public var publicVar: [[BOOL:(Swift\.)?Bool]]{{$}}
|
||||||
|
// RESILIENT: public var publicVar: [[BOOL:(Swift\.)?Bool]] = false
|
||||||
|
public var publicVar: Bool = false
|
||||||
|
|
||||||
|
// CHECK: @_hasInitialValue internal var internalVar: ([[BOOL]], [[BOOL]]){{$}}
|
||||||
|
// RESILIENT: internal var internalVar: ([[BOOL]], [[BOOL]]) = (false, true)
|
||||||
|
internal var internalVar: (Bool, Bool) = (false, true)
|
||||||
|
|
||||||
|
// CHECK: @_hasInitialValue private var privateVar: [[BOOL]]{{$}}
|
||||||
|
// RESILIENT: private var privateVar: [[BOOL]] = Bool(4 < 10)
|
||||||
|
private var privateVar: Bool = Bool(4 < 10)
|
||||||
|
|
||||||
|
// CHECK: @usableFromInline
|
||||||
|
// CHECK-NEXT: internal var ufiVar: [[BOOL]]{{$}}
|
||||||
|
// RESILIENT: @usableFromInline
|
||||||
|
// RESILIENT-NEXT: internal var ufiVar: [[BOOL]] = true
|
||||||
|
@usableFromInline internal var ufiVar: Bool = true
|
||||||
|
|
||||||
|
// CHECK: @_hasInitialValue public var multiVar1: [[BOOL]], (multiVar2, multiVar3): ([[BOOL]], [[BOOL]])
|
||||||
|
// RESILIENT: public var multiVar1: [[BOOL]] = Bool(false), (multiVar2, multiVar3): ([[BOOL]], [[BOOL]]) = (true, 3 == 0)
|
||||||
|
public var multiVar1: Bool = Bool(false), (multiVar2, multiVar3): (Bool, Bool) = (true, 3 == 0)
|
||||||
|
|
||||||
|
// COMMON: @_hasInitialValue public static var staticVar: [[BOOL]]
|
||||||
|
public static var staticVar: Bool = Bool(true && false)
|
||||||
|
|
||||||
|
// COMMON: @inlinable internal init() {}
|
||||||
|
@inlinable init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// COMMON: @_fixed_layout public class MyClass {
|
||||||
|
@_fixed_layout
|
||||||
|
public class MyClass {
|
||||||
|
// CHECK: @_hasInitialValue public var publicVar: [[BOOL]]{{$}}
|
||||||
|
// RESILIENT: public var publicVar: [[BOOL]] = false
|
||||||
|
public var publicVar: Bool = false
|
||||||
|
|
||||||
|
// CHECK: @_hasInitialValue internal var internalVar: [[BOOL]]{{$}}
|
||||||
|
// RESILIENT: internal var internalVar: [[BOOL]] = false
|
||||||
|
internal var internalVar: Bool = false
|
||||||
|
|
||||||
|
// CHECK: @_hasInitialValue private var privateVar: {{(Swift\.)?}}UInt8{{$}}
|
||||||
|
// RESILIENT: private var privateVar: {{(Swift\.)?}}UInt8 = UInt8(2)
|
||||||
|
private var privateVar: UInt8 = UInt8(2)
|
||||||
|
|
||||||
|
// CHECK: @usableFromInline
|
||||||
|
// CHECK-NEXT: internal var ufiVar: [[BOOL]]{{$}}
|
||||||
|
// RESILIENT: @usableFromInline
|
||||||
|
// RESILIENT: internal var ufiVar: [[BOOL]] = true
|
||||||
|
@usableFromInline internal var ufiVar: Bool = true
|
||||||
|
|
||||||
|
// COMMON: @_hasInitialValue public static var staticVar: [[BOOL]]
|
||||||
|
public static var staticVar: Bool = Bool(true && false)
|
||||||
|
|
||||||
|
// COMMON: @inlinable internal init() {}
|
||||||
|
@inlinable init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// COMMON: @_hasInitialValue public var topLevelVar: [[BOOL]]
|
||||||
|
public var topLevelVar: Bool = Bool(false && !true)
|
||||||
@@ -69,12 +69,12 @@ public class MyClass {
|
|||||||
// COMMON-NEXT: let publicLet: [[BOOL]]{{$}}
|
// COMMON-NEXT: let publicLet: [[BOOL]]{{$}}
|
||||||
public let publicLet: Bool = true
|
public let publicLet: Bool = true
|
||||||
|
|
||||||
// CHECK-NEXT: internal var _: [[INT64]]{{$}}
|
// CHECK-NEXT: internal var internalVar: [[INT64]]{{$}}
|
||||||
// RESILIENT-NOT: internal var _: [[INT64]]{{$}}
|
// RESILIENT-NOT: internal var internalVar: [[INT64]]{{$}}
|
||||||
var internalVar: Int64 = 0
|
var internalVar: Int64 = 0
|
||||||
|
|
||||||
// CHECK-NEXT: internal let _: [[BOOL]]{{$}}
|
// CHECK-NEXT: internal let internalLet: [[BOOL]]{{$}}
|
||||||
// RESILIENT-NOT: internal let _: [[BOOL]]{{$}}
|
// RESILIENT-NOT: internal let internalLet: [[BOOL]]{{$}}
|
||||||
let internalLet: Bool = true
|
let internalLet: Bool = true
|
||||||
|
|
||||||
// COMMON-NEXT: @usableFromInline
|
// COMMON-NEXT: @usableFromInline
|
||||||
@@ -85,12 +85,12 @@ public class MyClass {
|
|||||||
// COMMON-NEXT: internal let ufiLet: [[BOOL]]{{$}}
|
// COMMON-NEXT: internal let ufiLet: [[BOOL]]{{$}}
|
||||||
@usableFromInline let ufiLet: Bool = true
|
@usableFromInline let ufiLet: Bool = true
|
||||||
|
|
||||||
// CHECK-NEXT: private var _: [[INT64]]{{$}}
|
// CHECK-NEXT: private var privateVar: [[INT64]]{{$}}
|
||||||
// RESILIENT-NOT: private var _: [[INT64]]{{$}}
|
// RESILIENT-NOT: private var privateVar: [[INT64]]{{$}}
|
||||||
private var privateVar: Int64 = 0
|
private var privateVar: Int64 = 0
|
||||||
|
|
||||||
// CHECK-NEXT: private let _: [[BOOL]]{{$}}
|
// CHECK-NEXT: private let privateLet: [[BOOL]]{{$}}
|
||||||
// RESILIENT-NOT: private let _: [[BOOL]]{{$}}
|
// RESILIENT-NOT: private let privateLet: [[BOOL]]{{$}}
|
||||||
private let privateLet: Bool = true
|
private let privateLet: Bool = true
|
||||||
|
|
||||||
// CHECK-NOT: private var
|
// CHECK-NOT: private var
|
||||||
|
|||||||
Reference in New Issue
Block a user