[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:
Harlan
2018-10-05 18:21:46 -07:00
committed by GitHub
parent 690c6c374f
commit 2c86e3249c
10 changed files with 262 additions and 59 deletions

View File

@@ -1864,38 +1864,49 @@ public:
/// Pattern and Initialization expression. The pattern is always present, but
/// the initializer can be null if there is none.
class PatternBindingEntry {
Pattern *ThePattern;
/// The location of the equal '=' token.
SourceLoc EqualLoc;
enum class Flags {
Checked = 1 << 0,
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
// because we might need to get initializer's source range. Since the
// initializer is ASTContext-allocated it is safe.
llvm::PointerIntPair<Expr *, 3, OptionSet<Flags>> InitAndFlags;
union {
/// The initializer expression and its '=' token loc.
ExprAndEqualLoc InitExpr;
/// The text of the initializer expression if deserialized from a module.
StringRef InitStringRepresentation;
};
/// The initializer context used for this pattern binding entry.
DeclContext *InitContext = nullptr;
llvm::PointerIntPair<DeclContext *, 1, bool> InitContextAndIsText;
friend class PatternBindingInitializer;
public:
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
DeclContext *InitContext)
: ThePattern(P), EqualLoc(EqualLoc), InitAndFlags(E, {}),
InitContext(InitContext) {}
: PatternAndFlags(P, {}), InitExpr({E, EqualLoc}),
InitContextAndIsText({InitContext, false}) {
}
Pattern *getPattern() const { return ThePattern; }
void setPattern(Pattern *P) { ThePattern = P; }
Pattern *getPattern() const { return PatternAndFlags.getPointer(); }
void setPattern(Pattern *P) { PatternAndFlags.setPointer(P); }
Expr *getInit() const {
return (InitAndFlags.getInt().contains(Flags::Removed))
? nullptr : InitAndFlags.getPointer();
if (PatternAndFlags.getInt().contains(Flags::Removed) ||
InitContextAndIsText.getInt())
return nullptr;
return InitExpr.Node;
}
Expr *getNonLazyInit() const {
return isInitializerLazy() ? nullptr : getInit();
@@ -1903,37 +1914,64 @@ public:
SourceRange getOrigInitRange() const;
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.
SourceLoc getEqualLoc() const { return EqualLoc; }
SourceLoc getEqualLoc() const {
return InitContextAndIsText.getInt() ? SourceLoc() : InitExpr.EqualLoc;
}
/// 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.
Expr *getInitAsWritten() const { return InitAndFlags.getPointer(); }
Expr *getInitAsWritten() const {
return InitContextAndIsText.getInt() ? nullptr : InitExpr.Node;
}
bool isInitializerChecked() const {
return InitAndFlags.getInt().contains(Flags::Checked);
return PatternAndFlags.getInt().contains(Flags::Checked);
}
void setInitializerChecked() {
InitAndFlags.setInt(InitAndFlags.getInt() | Flags::Checked);
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Checked);
}
bool isInitializerLazy() const {
return InitAndFlags.getInt().contains(Flags::Lazy);
return PatternAndFlags.getInt().contains(Flags::Lazy);
}
void setInitializerLazy() {
InitAndFlags.setInt(InitAndFlags.getInt() | Flags::Lazy);
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Lazy);
}
// Return the first variable initialized by this pattern.
VarDecl *getAnchoringVarDecl() const;
// Retrieve the declaration context for the initializer.
DeclContext *getInitContext() const { return InitContext; }
DeclContext *getInitContext() const {
return InitContextAndIsText.getPointer();
}
/// 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.
///
@@ -2007,6 +2045,10 @@ public:
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
}
void setInitStringRepresentation(unsigned i, StringRef str) {
getMutablePatternList()[i].setInitStringRepresentation(str);
}
Expr *getInit(unsigned i) const {
return getPatternList()[i].getInit();
}
@@ -2039,7 +2081,8 @@ public:
/// Return the PatternEntry (a pattern + initializer pair) for the specified
/// VarDecl.
PatternBindingEntry getPatternEntryForVarDecl(const VarDecl *VD) const {
const PatternBindingEntry &getPatternEntryForVarDecl(
const VarDecl *VD) const {
return getPatternList()[getPatternEntryIndexForVarDecl(VD)];
}
@@ -2097,7 +2140,7 @@ public:
static bool classof(const Decl *D) {
return D->getKind() == DeclKind::PatternBinding;
}
private:
MutableArrayRef<PatternBindingEntry> getMutablePatternList() {
// Pattern entries are tail allocated.
@@ -4606,6 +4649,14 @@ public:
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 {
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
}
@@ -4687,6 +4738,13 @@ public:
void setHasNonPatternBindingInit(bool V = true) {
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?
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }