Skip to content

[ParseableInterfaces] Handle lazy vars #21996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions include/swift/Parse/Lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ enum class HashbangMode : bool {
Allowed,
};

enum class LexerMode {
Swift,
SwiftInterface,
SIL
};

/// Kinds of conflict marker which the lexer might encounter.
enum class ConflictMarkerKind {
/// A normal or diff3 conflict marker, initiated by at least 7 "<"s,
Expand Down Expand Up @@ -98,9 +104,10 @@ class Lexer {

Token NextToken;

/// This is true if we're lexing a .sil file instead of a .swift
/// file. This enables the 'sil' keyword.
const bool InSILMode;
/// The kind of source we're lexing. This either enables special behavior for
/// parseable interfaces, or enables things like the 'sil' keyword if lexing
/// a .sil file.
const LexerMode LexMode;

/// True if we should skip past a `#!` line at the start of the file.
const bool IsHashbangAllowed;
Expand Down Expand Up @@ -135,8 +142,8 @@ class Lexer {
/// everything.
Lexer(const PrincipalTag &, const LangOptions &LangOpts,
const SourceManager &SourceMgr, unsigned BufferID,
DiagnosticEngine *Diags, bool InSILMode, HashbangMode HashbangAllowed,
CommentRetentionMode RetainComments,
DiagnosticEngine *Diags, LexerMode LexMode,
HashbangMode HashbangAllowed, CommentRetentionMode RetainComments,
TriviaRetentionMode TriviaRetention);

void initialize(unsigned Offset, unsigned EndOffset);
Expand All @@ -150,21 +157,21 @@ class Lexer {
/// identifier), but not things like how many characters are
/// consumed. If that changes, APIs like getLocForEndOfToken will
/// need to take a LangOptions explicitly.
/// \param InSILMode - whether we're parsing a SIL source file.
/// \param LexMode - the kind of source file we're lexing.
/// Unlike language options, this does affect primitive lexing, which
/// means that APIs like getLocForEndOfToken really ought to take
/// this flag; it's just that we don't care that much about fidelity
/// when parsing SIL files.
Lexer(
const LangOptions &Options, const SourceManager &SourceMgr,
unsigned BufferID, DiagnosticEngine *Diags, bool InSILMode,
unsigned BufferID, DiagnosticEngine *Diags, LexerMode LexMode,
HashbangMode HashbangAllowed = HashbangMode::Disallowed,
CommentRetentionMode RetainComments = CommentRetentionMode::None,
TriviaRetentionMode TriviaRetention = TriviaRetentionMode::WithoutTrivia);

/// Create a lexer that scans a subrange of the source buffer.
Lexer(const LangOptions &Options, const SourceManager &SourceMgr,
unsigned BufferID, DiagnosticEngine *Diags, bool InSILMode,
unsigned BufferID, DiagnosticEngine *Diags, LexerMode LexMode,
HashbangMode HashbangAllowed, CommentRetentionMode RetainComments,
TriviaRetentionMode TriviaRetention, unsigned Offset,
unsigned EndOffset);
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ PrintOptions PrintOptions::printParseableInterfaceFile() {
result.PrintAccess = true;

result.ExcludeAttrList = {DAK_ImplicitlyUnwrappedOptional, DAK_AccessControl,
DAK_SetterAccess};
DAK_SetterAccess, DAK_Lazy};

return result;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/RawComment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static RawComment toRawComment(ASTContext &Context, CharSourceRange Range) {
unsigned Offset = SourceMgr.getLocOffsetInBuffer(Range.getStart(), BufferID);
unsigned EndOffset = SourceMgr.getLocOffsetInBuffer(Range.getEnd(), BufferID);
LangOptions FakeLangOpts;
Lexer L(FakeLangOpts, SourceMgr, BufferID, nullptr, /*InSILMode=*/false,
Lexer L(FakeLangOpts, SourceMgr, BufferID, nullptr, LexerMode::Swift,
HashbangMode::Disallowed,
CommentRetentionMode::ReturnAsTokens,
TriviaRetentionMode::WithoutTrivia,
Expand Down
2 changes: 1 addition & 1 deletion lib/Immediate/REPL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ class REPLEnvironment {
unsigned BufferID =
CI.getSourceMgr().addMemBufferCopy(Line, "<REPL Input>");
Lexer L(CI.getASTContext().LangOpts,
CI.getSourceMgr(), BufferID, nullptr, false /*not SIL*/);
CI.getSourceMgr(), BufferID, nullptr, LexerMode::Swift);
Token Tok;
L.lex(Tok);
assert(Tok.is(tok::colon));
Expand Down
31 changes: 17 additions & 14 deletions lib/Parse/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,11 @@ uint32_t swift::validateUTF8CharacterAndAdvance(const char *&Ptr,

Lexer::Lexer(const PrincipalTag &, const LangOptions &LangOpts,
const SourceManager &SourceMgr, unsigned BufferID,
DiagnosticEngine *Diags, bool InSILMode,
DiagnosticEngine *Diags, LexerMode LexMode,
HashbangMode HashbangAllowed, CommentRetentionMode RetainComments,
TriviaRetentionMode TriviaRetention)
: LangOpts(LangOpts), SourceMgr(SourceMgr), BufferID(BufferID),
Diags(Diags), InSILMode(InSILMode),
Diags(Diags), LexMode(LexMode),
IsHashbangAllowed(HashbangAllowed == HashbangMode::Allowed),
RetainComments(RetainComments), TriviaRetention(TriviaRetention) {}

Expand Down Expand Up @@ -216,28 +216,28 @@ void Lexer::initialize(unsigned Offset, unsigned EndOffset) {
}

Lexer::Lexer(const LangOptions &Options, const SourceManager &SourceMgr,
unsigned BufferID, DiagnosticEngine *Diags, bool InSILMode,
unsigned BufferID, DiagnosticEngine *Diags, LexerMode LexMode,
HashbangMode HashbangAllowed, CommentRetentionMode RetainComments,
TriviaRetentionMode TriviaRetention)
: Lexer(PrincipalTag(), Options, SourceMgr, BufferID, Diags, InSILMode,
: Lexer(PrincipalTag(), Options, SourceMgr, BufferID, Diags, LexMode,
HashbangAllowed, RetainComments, TriviaRetention) {
unsigned EndOffset = SourceMgr.getRangeForBuffer(BufferID).getByteLength();
initialize(/*Offset=*/0, EndOffset);
}

Lexer::Lexer(const LangOptions &Options, const SourceManager &SourceMgr,
unsigned BufferID, DiagnosticEngine *Diags, bool InSILMode,
unsigned BufferID, DiagnosticEngine *Diags, LexerMode LexMode,
HashbangMode HashbangAllowed, CommentRetentionMode RetainComments,
TriviaRetentionMode TriviaRetention, unsigned Offset,
unsigned EndOffset)
: Lexer(PrincipalTag(), Options, SourceMgr, BufferID, Diags, InSILMode,
: Lexer(PrincipalTag(), Options, SourceMgr, BufferID, Diags, LexMode,
HashbangAllowed, RetainComments, TriviaRetention) {
initialize(Offset, EndOffset);
}

Lexer::Lexer(Lexer &Parent, State BeginState, State EndState)
: Lexer(PrincipalTag(), Parent.LangOpts, Parent.SourceMgr, Parent.BufferID,
Parent.Diags, Parent.InSILMode,
Parent.Diags, Parent.LexMode,
Parent.IsHashbangAllowed
? HashbangMode::Allowed
: HashbangMode::Disallowed,
Expand All @@ -264,7 +264,7 @@ Token Lexer::getTokenAt(SourceLoc Loc) {
SourceMgr.findBufferContainingLoc(Loc)) &&
"location from the wrong buffer");

Lexer L(LangOpts, SourceMgr, BufferID, Diags, InSILMode,
Lexer L(LangOpts, SourceMgr, BufferID, Diags, LexMode,
HashbangMode::Allowed, CommentRetentionMode::None,
TriviaRetentionMode::WithoutTrivia);
L.restoreState(State(Loc));
Expand Down Expand Up @@ -672,7 +672,8 @@ void Lexer::lexIdentifier() {
// Lex [a-zA-Z_$0-9[[:XID_Continue:]]]*
while (advanceIfValidContinuationOfIdentifier(CurPtr, BufferEnd));

tok Kind = kindOfIdentifier(StringRef(TokStart, CurPtr-TokStart), InSILMode);
tok Kind = kindOfIdentifier(StringRef(TokStart, CurPtr-TokStart),
LexMode == LexerMode::SIL);
return formToken(Kind, TokStart);
}

Expand Down Expand Up @@ -944,9 +945,11 @@ void Lexer::lexDollarIdent() {
return formToken(tok::identifier, tokStart);
}

// We reserve $nonNumeric for persistent bindings in the debugger.
// We reserve $nonNumeric for persistent bindings in the debugger and implicit
// variables, like storage for lazy properties.
if (!isAllDigits) {
if (!LangOpts.EnableDollarIdentifiers && !InSILBody)
if (!LangOpts.EnableDollarIdentifiers && !InSILBody &&
LexMode != LexerMode::SwiftInterface)
diagnose(tokStart, diag::expected_dollar_numeric);

// Even if we diagnose, we go ahead and form an identifier token,
Expand Down Expand Up @@ -2515,7 +2518,7 @@ Token Lexer::getTokenAtLocation(const SourceManager &SM, SourceLoc Loc) {
// comments and normally we won't be at the beginning of a comment token
// (making this option irrelevant), or the caller lexed comments and
// we need to lex just the comment token.
Lexer L(FakeLangOpts, SM, BufferID, nullptr, /*InSILMode=*/ false,
Lexer L(FakeLangOpts, SM, BufferID, nullptr, LexerMode::Swift,
HashbangMode::Allowed, CommentRetentionMode::ReturnAsTokens);
L.restoreState(State(Loc));
return L.peekNextToken();
Expand Down Expand Up @@ -2671,7 +2674,7 @@ static SourceLoc getLocForStartOfTokenInBuf(SourceManager &SM,
// and the exact token produced.
LangOptions FakeLangOptions;

Lexer L(FakeLangOptions, SM, BufferID, nullptr, /*InSILMode=*/false,
Lexer L(FakeLangOptions, SM, BufferID, nullptr, LexerMode::Swift,
HashbangMode::Allowed, CommentRetentionMode::None,
TriviaRetentionMode::WithoutTrivia, BufferStart, BufferEnd);

Expand Down Expand Up @@ -2799,7 +2802,7 @@ SourceLoc Lexer::getLocForEndOfLine(SourceManager &SM, SourceLoc Loc) {
// comments and normally we won't be at the beginning of a comment token
// (making this option irrelevant), or the caller lexed comments and
// we need to lex just the comment token.
Lexer L(FakeLangOpts, SM, BufferID, nullptr, /*InSILMode=*/ false,
Lexer L(FakeLangOpts, SM, BufferID, nullptr, LexerMode::Swift,
HashbangMode::Allowed, CommentRetentionMode::ReturnAsTokens);
L.restoreState(State(Loc));
L.skipToEndOfLine(/*EatNewline=*/true);
Expand Down
21 changes: 17 additions & 4 deletions lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void tokenize(const LangOptions &LangOpts, const SourceManager &SM,
if (Offset == 0 && EndOffset == 0)
EndOffset = SM.getRangeForBuffer(BufferID).getByteLength();

Lexer L(LangOpts, SM, BufferID, Diags, /*InSILMode=*/false,
Lexer L(LangOpts, SM, BufferID, Diags, LexerMode::Swift,
HashbangMode::Allowed, RetainComments, TriviaRetention, Offset,
EndOffset);

Expand Down Expand Up @@ -345,6 +345,19 @@ swift::tokenizeWithTrivia(const LangOptions &LangOpts, const SourceManager &SM,
//===----------------------------------------------------------------------===//


static LexerMode sourceFileKindToLexerMode(SourceFileKind kind) {
switch (kind) {
case swift::SourceFileKind::Interface:
return LexerMode::SwiftInterface;
case swift::SourceFileKind::SIL:
return LexerMode::SIL;
case swift::SourceFileKind::Library:
case swift::SourceFileKind::Main:
case swift::SourceFileKind::REPL:
return LexerMode::Swift;
}
}

Parser::Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL,
PersistentParserState *PersistentState,
std::shared_ptr<SyntaxParseActions> SPActions,
Expand All @@ -361,7 +374,7 @@ Parser::Parser(unsigned BufferID, SourceFile &SF, DiagnosticEngine* LexerDiags,
std::unique_ptr<Lexer>(new Lexer(
SF.getASTContext().LangOpts, SF.getASTContext().SourceMgr,
BufferID, LexerDiags,
/*InSILMode=*/SIL != nullptr,
sourceFileKindToLexerMode(SF.Kind),
SF.Kind == SourceFileKind::Main
? HashbangMode::Allowed
: HashbangMode::Disallowed,
Expand Down Expand Up @@ -399,7 +412,7 @@ class TokenRecorder: public ConsumeTokenReceiver {

void relexComment(CharSourceRange CommentRange,
llvm::SmallVectorImpl<Token> &Scratch) {
Lexer L(Ctx.LangOpts, Ctx.SourceMgr, BufferID, nullptr, /*InSILMode=*/false,
Lexer L(Ctx.LangOpts, Ctx.SourceMgr, BufferID, nullptr, LexerMode::Swift,
HashbangMode::Disallowed,
CommentRetentionMode::ReturnAsTokens,
TriviaRetentionMode::WithoutTrivia,
Expand Down Expand Up @@ -1119,7 +1132,7 @@ ParserUnit::ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned Buffer
std::unique_ptr<Lexer> Lex;
Lex.reset(new Lexer(Impl.LangOpts, SM,
BufferID, &Impl.Diags,
/*InSILMode=*/false,
LexerMode::Swift,
HashbangMode::Allowed,
CommentRetentionMode::None,
TriviaRetentionMode::WithoutTrivia,
Expand Down
5 changes: 3 additions & 2 deletions lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1346,8 +1346,9 @@ void swift::completeLazyVarImplementation(VarDecl *VD) {
assert(!VD->isStatic() && "Static vars are already lazy on their own");

// Create the storage property as an optional of VD's type.
SmallString<64> NameBuf = VD->getName().str();
NameBuf += ".storage";
SmallString<64> NameBuf;
NameBuf += "$__lazy_storage_$_";
NameBuf += VD->getName().str();
auto StorageName = Context.getIdentifier(NameBuf);
auto StorageTy = OptionalType::get(VD->getType());
auto StorageInterfaceTy = OptionalType::get(VD->getInterfaceType());
Expand Down
41 changes: 41 additions & 0 deletions test/ParseableInterface/lazy-vars.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend -typecheck -module-name Test -emit-parseable-module-interface-path %t/Test.swiftinterface %s
// RUN: %FileCheck %s < %t/Test.swiftinterface --check-prefix CHECK --check-prefix NONRESILIENT
// RUN: %target-swift-frontend -build-module-from-parseable-interface %t/Test.swiftinterface -o %t/Test.swiftmodule
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules -emit-parseable-module-interface-path - %t/Test.swiftmodule -module-name Test | %FileCheck %s --check-prefix CHECK --check-prefix NONRESILIENT

// RUN: %target-swift-frontend -typecheck -module-name TestResilient -emit-parseable-module-interface-path %t/TestResilient.swiftinterface -enable-resilience %s
// RUN: %FileCheck %s < %t/TestResilient.swiftinterface --check-prefix CHECK --check-prefix RESILIENT

// RUN: %target-swift-frontend -build-module-from-parseable-interface %t/TestResilient.swiftinterface -o %t/TestResilient.swiftmodule
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules -emit-parseable-module-interface-path - %t/TestResilient.swiftmodule -module-name TestResilient | %FileCheck %s --check-prefix CHECK --check-prefix RESILIENT

// CHECK: @_fixed_layout public struct HasLazyVarsFixedLayout {
// CHECK-NEXT: public var foo: [[INT:(Swift\.)?Int]] {
// CHECK-NEXT: mutating get
// CHECK-NEXT: set
// CHECK-NEXT: }
// CHECK: private var $__lazy_storage_$_foo: [[INT]]?
// CHECK-NOT: private var bar
// CHECK: private var $__lazy_storage_$_bar: [[INT]]?
// CHECK-NEXT: }
@_fixed_layout
public struct HasLazyVarsFixedLayout {
public lazy var foo: Int = 0
private lazy var bar: Int = 0
}

// CHECK: public struct HasLazyVars {
// CHECK-NEXT: public var foo: [[INT:(Swift\.)?Int]] {
// CHECK-NEXT: mutating get
// CHECK-NEXT: set
// CHECK-NEXT: }
// NONRESILIENT: private var $__lazy_storage_$_foo: [[INT]]?
// CHECK-NOT: private var bar
// NONRESILIENT: private var $__lazy_storage_$_bar: [[INT]]?
// CHECK-NEXT: }
public struct HasLazyVars {
public lazy var foo: Int = 0
private lazy var bar: Int = 0
}
2 changes: 1 addition & 1 deletion test/api-digester/Outputs/Cake-abi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ cake1: Var fixedLayoutStruct.b in a non-resilient type changes position from 0 t
cake1: Var fixedLayoutStruct2.BecomeFixedBinaryOrder is now a stored property
cake1: Var fixedLayoutStruct2.NoLongerWithFixedBinaryOrder is no longer a stored property
cake2: EnumElement FrozenKind.AddedCase is added to a non-resilient type
cake2: Var fixedLayoutStruct.$__lazy_storage_$_lazy_d is added to a non-resilient type
cake2: Var fixedLayoutStruct.c is added to a non-resilient type
cake2: Var fixedLayoutStruct.lazy_d.storage is added to a non-resilient type

/* Conformance changes */
cake1: Func ObjCProtocol.addOptional() is now an optional requirement
Expand Down
Loading