Skip to content

Tweak Parse and SILGen to support loading swiftinterface files #18764

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 5 commits into from
Aug 17, 2018
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
54 changes: 37 additions & 17 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4086,11 +4086,23 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags,
SourceLoc &LastValidLoc, SourceLoc StaticLoc,
SourceLoc VarLBLoc) {
// Properties in protocols use a very limited syntax.
// SIL mode uses the same syntax.
// SIL mode and textual interfaces use the same syntax.
// Otherwise, we have a normal var or subscript declaration and we need
// parse the full complement of specifiers, along with their bodies.
bool parsingLimitedSyntax =
Flags.contains(PD_InProtocol) || isInSILMode();
bool parsingLimitedSyntax = Flags.contains(PD_InProtocol);
if (!parsingLimitedSyntax) {
switch (SF.Kind) {
case SourceFileKind::Interface:
// FIXME: Textual interfaces /can/ have inlinable code but don't have to.
case SourceFileKind::SIL:
parsingLimitedSyntax = true;
break;
case SourceFileKind::Library:
case SourceFileKind::Main:
case SourceFileKind::REPL:
break;
}
}

// If the body is completely empty, preserve it. This is at best a getter with
// an implicit fallthrough off the end.
Expand Down Expand Up @@ -6305,34 +6317,42 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
SourceLoc DestructorLoc = consumeToken(tok::kw_deinit);

// Parse extraneous parentheses and remove them with a fixit.
if (Tok.is(tok::l_paren)) {
SourceRange ParenRange;
SourceLoc LParenLoc = consumeToken();
auto skipParameterListIfPresent = [this] {
SourceLoc LParenLoc;
if (!consumeIf(tok::l_paren, LParenLoc))
return;
SourceLoc RParenLoc;
skipUntil(tok::r_paren);

if (Tok.is(tok::r_paren)) {
SourceLoc RParenLoc = consumeToken();
ParenRange = SourceRange(LParenLoc, RParenLoc);

diagnose(ParenRange.Start, diag::destructor_params)
.fixItRemoveChars(Lexer::getLocForEndOfToken(Context.SourceMgr,
DestructorLoc),
Lexer::getLocForEndOfToken(Context.SourceMgr,
ParenRange.End));
diagnose(LParenLoc, diag::destructor_params)
.fixItRemove(SourceRange(LParenLoc, RParenLoc));
} else {
diagnose(Tok, diag::opened_destructor_expected_rparen);
diagnose(LParenLoc, diag::opening_paren);
}
}
};

// '{'
if (!Tok.is(tok::l_brace)) {
if (!Tok.is(tok::l_brace) && !isInSILMode()) {
switch (SF.Kind) {
case SourceFileKind::Interface:
case SourceFileKind::SIL:
// It's okay to have no body for SIL code or textual interfaces.
break;
case SourceFileKind::Library:
case SourceFileKind::Main:
case SourceFileKind::REPL:
if (Tok.is(tok::identifier)) {
diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc());
} else
diagnose(Tok, diag::expected_lbrace_destructor);
consumeToken();
}
skipParameterListIfPresent();
if (Tok.is(tok::l_brace))
break;

diagnose(Tok, diag::expected_lbrace_destructor);
return nullptr;
}
}
Expand Down
26 changes: 14 additions & 12 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,9 +776,9 @@ void SILGenModule::emitConstructor(ConstructorDecl *decl) {
postEmitFunction(constant, f);
});

// If this constructor was imported, we don't need the initializing
// constructor to be emitted.
if (!decl->hasClangNode()) {
// Constructors may not have bodies if they've been imported, or if they've
// been parsed from a textual interface.
if (decl->hasBody()) {
SILDeclRef initConstant(decl, SILDeclRef::Kind::Initializer);
emitOrDelayFunction(
*this, initConstant,
Expand All @@ -796,14 +796,16 @@ void SILGenModule::emitConstructor(ConstructorDecl *decl) {
}
} else {
// Struct and enum constructors do everything in a single function.
emitOrDelayFunction(
*this, constant, [this, constant, decl, declCtx](SILFunction *f) {
preEmitFunction(constant, decl, f, decl);
PrettyStackTraceSILFunction X("silgen emitConstructor", f);
f->setProfiler(getOrCreateProfilerForConstructors(declCtx, decl));
SILGenFunction(*this, *f, decl).emitValueConstructor(decl);
postEmitFunction(constant, f);
});
if (decl->hasBody()) {
emitOrDelayFunction(
*this, constant, [this, constant, decl, declCtx](SILFunction *f) {
preEmitFunction(constant, decl, f, decl);
PrettyStackTraceSILFunction X("silgen emitConstructor", f);
f->setProfiler(getOrCreateProfilerForConstructors(declCtx, decl));
SILGenFunction(*this, *f, decl).emitValueConstructor(decl);
postEmitFunction(constant, f);
});
}
}
}

Expand Down Expand Up @@ -941,7 +943,7 @@ void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) {

// Emit the destroying destructor.
// Destructors are a necessary part of class metadata, so can't be delayed.
{
if (dd->hasBody()) {
SILDeclRef destroyer(dd, SILDeclRef::Kind::Destroyer);
SILFunction *f = getFunction(destroyer, ForDefinition);
preEmitFunction(destroyer, dd, f, dd);
Expand Down
61 changes: 60 additions & 1 deletion test/ModuleInterface/SmokeTest.swiftinterface
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,66 @@
// ...and then make sure parse-and-typecheck-and-serialize works.
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/SmokeTest.swiftmodule %s
// RUN: %target-swift-ide-test -print-module -module-to-print SmokeTest -I %t -source-filename x -print-access | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print SmokeTest -I %t -source-filename x -print-interface > %t/SmokeTest.txt
// RUN: %FileCheck %s < %t/SmokeTest.txt
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t/SmokeTest.txt

// CHECK-LABEL: public class TestClass
public class TestClass {
// CHECK: public init(){{$}}
public init()

// CHECK: public func method(){{$}}
public func method()

// CHECK: public subscript(_: Int) -> Void{{$}}
public subscript(_: Int) -> Void { get set }

// CHECK: public var prop: Int{{$}}
public var prop: Int { get set }

// NEGATIVE-NOT: deinit
deinit
} // CHECK: {{^}$}}

// CHECK-LABEL: public enum TestEnum
public enum TestEnum {
// CHECK: case a
case a

// CHECK: public init(){{$}}
public init()

// CHECK: public func method(){{$}}
public func method()

// CHECK: public subscript(_: Int) -> Void{{$}}
public subscript(_: Int) -> Void { get set }

// CHECK: public var prop: Int{{$}}
public var prop: Int { get set }
} // CHECK: {{^}$}}

// CHECK-LABEL: public struct TestStruct
public struct TestStruct {
// CHECK: public init(){{$}}
public init()

// CHECK: public func method(){{$}}
public func method()

// CHECK: public subscript(_: Int) -> Void{{$}}
public subscript(_: Int) -> Void { get set }

// CHECK: public var prop: Int{{$}}
public var prop: Int { get set }
} // CHECK: {{^}$}}

// CHECK: public var readOnlyVar: Int { get }{{$}}
public var readOnlyVar: Int { get }

// CHECK: public var readWriteVar: Int{{$}}
public var readWriteVar: Int { get set }

// CHECK: public func verySimpleFunction(){{$}}
public func verySimpleFunction()
8 changes: 6 additions & 2 deletions test/Parse/init_deinit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ struct FooStructConstructorC {

struct FooStructDeinitializerA {
deinit // expected-error {{expected '{' for deinitializer}}
deinit x // expected-error {{deinitializers cannot have a name}} {{10-12=}}
deinit x() // expected-error {{deinitializers cannot have a name}} {{10-11=}}
deinit x // expected-error {{deinitializers cannot have a name}} {{10-12=}} expected-error {{expected '{' for deinitializer}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small drive-by diagnostic improvement too!

deinit x() // expected-error {{deinitializers cannot have a name}} {{10-11=}} expected-error {{no parameter clause allowed on deinitializer}} {{11-13=}} expected-error {{expected '{' for deinitializer}}
}

struct FooStructDeinitializerB {
Expand All @@ -37,6 +37,10 @@ class FooClassDeinitializerB {
deinit { }
}

class FooClassDeinitializerC {
deinit x (a : Int) {} // expected-error {{deinitializers cannot have a name}} {{10-12=}} expected-error{{no parameter clause allowed on deinitializer}}{{12-22=}}
}

init {} // expected-error {{initializers may only be declared within a type}} expected-error {{expected '('}} {{5-5=()}}
init() // expected-error {{initializers may only be declared within a type}}
init() {} // expected-error {{initializers may only be declared within a type}}
Expand Down