Skip to content

Commit a17dbfb

Browse files
authored
Merge pull request #18778 from jrose-apple/towards-stability
[ModuleInterface] More changes to printing and parsing .swiftinterface files
2 parents a8cbfd1 + c62fcad commit a17dbfb

File tree

7 files changed

+129
-34
lines changed

7 files changed

+129
-34
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ class AnyAttrKind {
112112
};
113113

114114
struct ShouldPrintChecker {
115-
virtual bool shouldPrint(const Decl *D, PrintOptions &Options);
116-
bool shouldPrint(const Pattern *P, PrintOptions &Options);
115+
virtual bool shouldPrint(const Decl *D, const PrintOptions &Options);
116+
bool shouldPrint(const Pattern *P, const PrintOptions &Options);
117117
virtual ~ShouldPrintChecker() = default;
118118
};
119119

lib/AST/ASTPrinter.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,39 @@ PrintOptions PrintOptions::printTextualInterfaceFile() {
7272
result.FullyQualifiedTypes = true;
7373
result.SkipImports = true;
7474

75-
class UsableFromInlineOnly : public ShouldPrintChecker {
76-
bool shouldPrint(const Decl *D, PrintOptions &options) override {
75+
class ShouldPrintForTextualInterface : public ShouldPrintChecker {
76+
bool shouldPrint(const Decl *D, const PrintOptions &options) override {
77+
// Skip anything that isn't 'public' or '@usableFromInline'.
7778
if (auto *VD = dyn_cast<ValueDecl>(D)) {
7879
AccessScope accessScope =
7980
VD->getFormalAccessScope(/*useDC*/nullptr,
8081
/*treatUsableFromInlineAsPublic*/true);
8182
if (!accessScope.isPublic())
8283
return false;
8384
}
85+
86+
// Skip typealiases that just redeclare generic parameters.
87+
if (auto *alias = dyn_cast<TypeAliasDecl>(D)) {
88+
if (alias->isImplicit()) {
89+
const Decl *parent =
90+
D->getDeclContext()->getAsDeclOrDeclExtensionContext();
91+
if (auto *genericCtx = parent->getAsGenericContext()) {
92+
bool matchesGenericParam =
93+
llvm::any_of(genericCtx->getInnermostGenericParamTypes(),
94+
[alias](const GenericTypeParamType *param) {
95+
return param->getName() == alias->getName();
96+
});
97+
if (matchesGenericParam)
98+
return false;
99+
}
100+
}
101+
}
102+
84103
return ShouldPrintChecker::shouldPrint(D, options);
85104
}
86105
};
87-
result.CurrentPrintabilityChecker = std::make_shared<UsableFromInlineOnly>();
106+
result.CurrentPrintabilityChecker =
107+
std::make_shared<ShouldPrintForTextualInterface>();
88108

89109
// FIXME: We don't really need 'public' on everything; we could just change
90110
// the default to 'public' and mark the 'internal' things.
@@ -1308,15 +1328,17 @@ void PrintAST::printPatternType(const Pattern *P) {
13081328
}
13091329
}
13101330

1311-
bool ShouldPrintChecker::shouldPrint(const Pattern *P, PrintOptions &Options) {
1331+
bool ShouldPrintChecker::shouldPrint(const Pattern *P,
1332+
const PrintOptions &Options) {
13121333
bool ShouldPrint = false;
13131334
P->forEachVariable([&](const VarDecl *VD) {
13141335
ShouldPrint |= shouldPrint(VD, Options);
13151336
});
13161337
return ShouldPrint;
13171338
}
13181339

1319-
bool ShouldPrintChecker::shouldPrint(const Decl *D, PrintOptions &Options) {
1340+
bool ShouldPrintChecker::shouldPrint(const Decl *D,
1341+
const PrintOptions &Options) {
13201342
if (auto *ED= dyn_cast<ExtensionDecl>(D)) {
13211343
if (Options.printExtensionContentAsMembers(ED))
13221344
return false;

lib/IDE/IDETypeChecking.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
using namespace swift;
2828

29-
static bool shouldPrintAsFavorable(const Decl *D, PrintOptions &Options) {
29+
static bool shouldPrintAsFavorable(const Decl *D, const PrintOptions &Options) {
3030
if (!Options.TransformContext ||
3131
!D->getDeclContext()->isExtensionContext() ||
3232
!Options.TransformContext->isPrintingSynthesizedExtension())
@@ -42,7 +42,7 @@ static bool shouldPrintAsFavorable(const Decl *D, PrintOptions &Options) {
4242
}
4343

4444
class ModulePrinterPrintableChecker: public ShouldPrintChecker {
45-
bool shouldPrint(const Decl *D, PrintOptions &Options) override {
45+
bool shouldPrint(const Decl *D, const PrintOptions &Options) override {
4646
if (!shouldPrintAsFavorable(D, Options))
4747
return false;
4848
return ShouldPrintChecker::shouldPrint(D, Options);

lib/Parse/ParseDecl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,6 +5481,8 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
54815481
{ }, nullptr, CurDeclContext);
54825482
setLocalDiscriminator(ED);
54835483
ED->getAttrs() = Attributes;
5484+
if (SF.Kind == SourceFileKind::Interface)
5485+
ED->setAddedImplicitInitializers();
54845486

54855487
ContextChange CC(*this, ED);
54865488

@@ -5753,6 +5755,8 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
57535755
CurDeclContext);
57545756
setLocalDiscriminator(SD);
57555757
SD->getAttrs() = Attributes;
5758+
if (SF.Kind == SourceFileKind::Interface)
5759+
SD->setAddedImplicitInitializers();
57565760

57575761
ContextChange CC(*this, SD);
57585762

@@ -5840,9 +5844,9 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
58405844
ClassDecl *CD = new (Context) ClassDecl(ClassLoc, ClassName, ClassNameLoc,
58415845
{ }, nullptr, CurDeclContext);
58425846
setLocalDiscriminator(CD);
5843-
5844-
// Attach attributes.
58455847
CD->getAttrs() = Attributes;
5848+
if (SF.Kind == SourceFileKind::Interface)
5849+
CD->setAddedImplicitInitializers();
58465850

58475851
ContextChange CC(*this, CD);
58485852

lib/Sema/TypeCheckDecl.cpp

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,45 +2520,61 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25202520
if (!var->hasStorage())
25212521
return;
25222522

2523+
if (var->isInvalid() || PBD->isInvalid())
2524+
return;
2525+
25232526
auto *varDC = var->getDeclContext();
25242527

2525-
// Non-member observing properties need an initializer.
2526-
if (var->getWriteImpl() == WriteImplKind::StoredWithObservers &&
2527-
!isTypeContext && !var->isInvalid() && !PBD->isInvalid()) {
2528-
TC.diagnose(var->getLoc(), diag::observingprop_requires_initializer);
2528+
auto markVarAndPBDInvalid = [PBD, var] {
25292529
PBD->setInvalid();
25302530
var->setInvalid();
2531-
if (!var->hasType()) {
2531+
if (!var->hasType())
25322532
var->markInvalid();
2533-
}
2533+
};
2534+
2535+
// Non-member observing properties need an initializer.
2536+
if (var->getWriteImpl() == WriteImplKind::StoredWithObservers &&
2537+
!isTypeContext) {
2538+
TC.diagnose(var->getLoc(), diag::observingprop_requires_initializer);
2539+
markVarAndPBDInvalid();
25342540
return;
25352541
}
25362542

25372543
// Static/class declarations require an initializer unless in a
25382544
// protocol.
2539-
if (var->isStatic() && !isa<ProtocolDecl>(varDC) &&
2540-
!var->isInvalid() && !PBD->isInvalid()) {
2545+
if (var->isStatic() && !isa<ProtocolDecl>(varDC)) {
2546+
// ...but don't enforce this for SIL or textual interface files.
2547+
switch (varDC->getParentSourceFile()->Kind) {
2548+
case SourceFileKind::Interface:
2549+
case SourceFileKind::SIL:
2550+
return;
2551+
case SourceFileKind::Main:
2552+
case SourceFileKind::REPL:
2553+
case SourceFileKind::Library:
2554+
break;
2555+
}
2556+
25412557
TC.diagnose(var->getLoc(), diag::static_requires_initializer,
25422558
var->getCorrectStaticSpelling());
2543-
PBD->setInvalid();
2544-
var->setInvalid();
2545-
if (!var->hasType()) {
2546-
var->markInvalid();
2547-
}
2559+
markVarAndPBDInvalid();
25482560
return;
25492561
}
25502562

2551-
// Global variables require an initializer (except in top level code).
2552-
if (varDC->isModuleScopeContext() &&
2553-
!varDC->getParentSourceFile()->isScriptMode() &&
2554-
!var->isInvalid() && !PBD->isInvalid()) {
2555-
TC.diagnose(var->getLoc(),
2556-
diag::global_requires_initializer, var->isLet());
2557-
PBD->setInvalid();
2558-
var->setInvalid();
2559-
if (!var->hasType()) {
2560-
var->markInvalid();
2563+
// Global variables require an initializer in normal source files.
2564+
if (varDC->isModuleScopeContext()) {
2565+
switch (varDC->getParentSourceFile()->Kind) {
2566+
case SourceFileKind::Main:
2567+
case SourceFileKind::REPL:
2568+
case SourceFileKind::Interface:
2569+
case SourceFileKind::SIL:
2570+
return;
2571+
case SourceFileKind::Library:
2572+
break;
25612573
}
2574+
2575+
TC.diagnose(var->getLoc(), diag::global_requires_initializer,
2576+
var->isLet());
2577+
markVarAndPBDInvalid();
25622578
return;
25632579
}
25642580
});
@@ -5122,6 +5138,19 @@ static void diagnoseClassWithoutInitializers(TypeChecker &tc,
51225138
}
51235139

51245140
void TypeChecker::maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
5141+
if (auto *SF = classDecl->getParentSourceFile()) {
5142+
// Allow classes without initializers in SIL and textual interface files.
5143+
switch (SF->Kind) {
5144+
case SourceFileKind::SIL:
5145+
case SourceFileKind::Interface:
5146+
return;
5147+
case SourceFileKind::Library:
5148+
case SourceFileKind::Main:
5149+
case SourceFileKind::REPL:
5150+
break;
5151+
}
5152+
}
5153+
51255154
// Some heuristics to skip emitting a diagnostic if the class is already
51265155
// irreperably busted.
51275156
if (classDecl->isInvalid() ||

test/ModuleInterface/SmokeTest.swiftinterface

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,21 @@ public class TestClass {
2222
// CHECK: public var prop: Int{{$}}
2323
public var prop: Int { get set }
2424

25+
// CHECK: public static var propWithNoAccessors: Int{{$}}
26+
public static var propWithNoAccessors: Int
27+
2528
// NEGATIVE-NOT: deinit
2629
deinit
2730
} // CHECK: {{^}$}}
2831

32+
// CHECK-LABEL: public class TestEmptyClass {
33+
public class TestEmptyClass {
34+
} // CHECK-NEXT: {{^}$}}
35+
36+
// CHECK-LABEL: public struct TestEmptyStruct {
37+
public struct TestEmptyStruct {
38+
} // CHECK-NEXT: {{^}$}}
39+
2940
// CHECK-LABEL: public enum TestEnum
3041
public enum TestEnum {
3142
// CHECK: case a
@@ -42,6 +53,9 @@ public enum TestEnum {
4253

4354
// CHECK: public var prop: Int{{$}}
4455
public var prop: Int { get set }
56+
57+
// CHECK: public static var propWithNoAccessors: Int{{$}}
58+
public static var propWithNoAccessors: Int
4559
} // CHECK: {{^}$}}
4660

4761
// CHECK-LABEL: public struct TestStruct
@@ -57,8 +71,14 @@ public struct TestStruct {
5771

5872
// CHECK: public var prop: Int{{$}}
5973
public var prop: Int { get set }
74+
75+
// CHECK: public static var propWithNoAccessors: Int{{$}}
76+
public static var propWithNoAccessors: Int
6077
} // CHECK: {{^}$}}
6178

79+
// CHECK: public let globalWithNoAccessors: Int{{$}}
80+
public let globalWithNoAccessors: Int
81+
6282
// CHECK: public var readOnlyVar: Int { get }{{$}}
6383
public var readOnlyVar: Int { get }
6484

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend -emit-interface-path %t.swiftinterface -emit-module -o /dev/null %s
2+
// RUN: %FileCheck %s < %t.swiftinterface
3+
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface
4+
5+
// CHECK-LABEL: public protocol SimpleProto {
6+
public protocol SimpleProto {
7+
// CHECK: associatedtype Element
8+
associatedtype Element
9+
// CHECK: associatedtype Inferred
10+
associatedtype Inferred
11+
func inference(_: Inferred)
12+
} // CHECK: {{^}$}}
13+
14+
// CHECK-LABEL: public struct SimplImpl<Element> : SimpleProto {
15+
public struct SimplImpl<Element>: SimpleProto {
16+
// NEGATIVE-NOT: typealias Element =
17+
// CHECK: public func inference(_: Int){{$}}
18+
public func inference(_: Int) {}
19+
// CHECK: public typealias Inferred = Swift.Int
20+
} // CHECK: {{^}$}}

0 commit comments

Comments
 (0)